Blockchain ass dacks nëmme mat Krypto-Währungen assoziéiert, awer d'Applikatiounsberäicher vun der DLT Technologie si vill méi breet. Ee vun de villverspriechendste Beräicher fir d'Benotzung vu Blockchain ass e Smart Kontrakt deen automatesch ausgefouert gëtt an net Vertrauen tëscht de Parteien erfuerdert, déi et eraginn hunn.
RIDE - eng Sprooch fir Smart Kontrakter
Waves huet eng speziell Sprooch fir Smart Kontrakter entwéckelt - RIDE. Seng komplett Dokumentatioun ass lokaliséiert
De RIDE Kontrakt ass e Prädikat a gëtt "richteg" oder "falsch" als Ausgang zréck. Deementspriechend gëtt d'Transaktioun entweder an der Blockchain opgeholl oder verworf. De Smart Kontrakt garantéiert voll d'Erfëllung vun spezifizéierte Konditiounen. Transaktiounen aus engem Kontrakt an RIDE generéieren ass momentan net méiglech.
Haut ginn et zwou Zorte vu Waves Smart Kontrakter: Smart Konten a Smart Verméigen. E Smart Kont ass e reguläre Benotzerkont, awer e Skript ass dofir ageriicht dat all Transaktiounen kontrolléiert. E Smart Account Skript kéint esou ausgesinn, zum Beispill:
match tx {
case t: TransferTransaction | MassTransferTransaction => false
case _ => true
}
tx ass eng Transaktioun déi veraarbecht gëtt, déi mir erlaben de Mustermatchmechanismus nëmmen ze benotzen wann et keng Transfertransaktioun ass. Muster Matching am RIDE gëtt benotzt fir d'Zort vun der Transaktioun ze kontrolléieren. All bestehend Konte kënnen am Smart Kont Skript veraarbecht ginn
D'Skript kann och Variabelen deklaréieren, "wann-dan-soen" Konstruktiounen an aner Methoden benotzen fir d'Konditioune voll ze kontrolléieren. Fir sécherzestellen datt Kontrakter beweisbar Vollständegkeet a Komplexitéit (Käschte) hunn, déi einfach virauszesoen ier d'Ausféierung vum Kontrakt ufänkt, enthält RIDE keng Loops oder Sprong Aussoen.
Aner Feature vu Waves Konten enthalen d'Präsenz vun engem "Staat", dat heescht de Staat vum Kont. Dir kënnt eng onendlech Zuel vu Puer (Schlëssel, Wäert) op de Kont Staat schreiwen mat Daten Transaktiounen (DataTransaction). Dës Informatioun kann dann souwuel duerch d'REST API an direkt am Smart Kontrakt veraarbecht ginn.
All Transaktioun kann eng Rei vu Beweiser enthalen, an deenen d'Ënnerschrëft vum Participant, d'ID vun der erfuerderter Transaktioun, etc.
Schafft mat RIDE iwwer
Fir e ganzen Zyklus, inklusiv e Kont erstellen, e Smart Kontrakt drop installéieren an Transaktiounen schécken, kënnt Dir och eng Bibliothéik benotzen fir mat der REST API ze interagéieren (zum Beispill C#, C, Java, JavaScript, Python, Rust, Elixir) . Fir mat der IDE ze schaffen, klickt einfach op den NEW Knäppchen.
D'Méiglechkeete fir Smart Kontrakter ze benotzen sinn breet: vun Transaktioune verbidden op bestëmmten Adressen ("schwaarz Lëscht") bis komplex dApps.
Loosst eis elo spezifesch Beispiller vun der Notzung vu Smart Kontrakter am Geschäft kucken: wann Dir Auktiounen, Versécherung a Loyalitéitsprogrammer erstellt.
Auktioune
Ee vun de Konditioune fir eng erfollegräich Auktioun ass Transparenz: Participanten mussen zouversiichtlech sinn datt et onméiglech ass Offeren ze manipuléieren. Dëst kann erreecht ginn dank der Blockchain, wou onverännerlech Daten iwwer all Wetten an d'Zäit wou se gemaach goufen fir all Participanten verfügbar sinn.
Op der Waves Blockchain kënnen Offeren am Auktiounskontostaat iwwer DataTransaction opgeholl ginn.
Dir kënnt och d'Start- an d'Ennzäit vun der Auktioun mat Blocknummeren astellen: d'Frequenz vun der Blockgeneratioun an der Waves Blockchain ass ongeféier d'selwecht wéi 60 Sekonnen.
1. Englesch opsteigend Präis Auktioun
D'Participanten an enger englescher Auktioun bidde sech a Konkurrenz mateneen. All nei Spillwette muss déi virdrun iwwerschreiden. D'Auktioun endet wann et keng Bidder méi sinn fir déi lescht Offer ze iwwerschreiden. An dësem Fall muss den héchste Bidder de uginnene Betrag ubidden.
Et gëtt och eng Auktiounsoptioun an där de Verkeefer e Mindestpräis fir de Lot setzt, an den definitive Präis muss et iwwerschreiden. Soss bleift d'Lot net verkaaft.
An dësem Beispill schaffe mir mat engem Kont speziell fir d'Auktioun erstallt. D'Auktiounsdauer ass 3000 Block, an den Startpräis vun der Lot ass 0,001 WAVES. E Participant kann eng Offer maachen andeems Dir eng DataTransaction mam Schlëssel "Präis" an de Wäert vun hirer Offer schéckt.
De Präis vun der neier Offer muss méi héich sinn wéi den aktuelle Präis fir dëse Schlëssel, an de Participant muss op d'mannst [new_bid + Kommissioun] Token op sengem Kont hunn. D'Adress vum Bidder muss am "Sender" Feld an der DataTransaction opgeholl ginn, an déi aktuell Offerblock Héicht muss bannent der Auktiounsperiod sinn.
Wann um Enn vun der Auktioun de Participant den héchste Präis festgeluecht huet, kann hien eng ExchangeTransaktioun schécken fir de entspriechende Lot zum spezifizéierte Präis a Währungspaar ze bezuelen.
let startHeight = 384120
let finishHeight = startHeight + 3000
let startPrice = 100000
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let token = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
match tx {
case d : DataTransaction =>
#проверяем, задана ли в стейте цена
let currentPrice = if isDefined(getInteger(this, "price"))
#извлекаем цену из стейта
then extract(getInteger(this, "price"))
else startPrice
#извлекаем цену из транзакции
let newPrice = extract(getInteger(d.data, "price"))
let priceIsBigger = newPrice > currentPrice
let fee = 700000
let hasMoney = wavesBalance(tx.sender) + fee >= newPrice
#убеждаемся, что в текущей транзакции два поля и что отправитель совпадает с указанным в транзакции
let correctFields = size(d.data) == 2 &&
d.sender == addressFromString(extract(getString(d.data,"sender")))
startHeight <= height && height <= finishHeight && priceIsBigger && hasMoney && correctFields
case e : ExchangeTransaction =>
let senderIsWinner = e.sender == addressFromString(extract(getString(this, "sender"))) #убеждаемся, что лот обменивает тот, кто его выиграл
let correctAssetPair = e.sellOrder.assetPair.amountAsset == token && ! isDefined(e.sellOrder.assetPair.priceAsset)
let correctAmount = e.amount == 1
let correctPrice = e.price == extract(getInteger(this, "price"))
height > finishHeight && senderIsWinner && correctAssetPair && correctAmount && correctPrice
case _ => false
}
2. Hollännesch Auktioun vun erofgoen Präisser
An enger hollännescher Auktioun gëtt vill am Ufank ugebueden zu engem Präis méi héich wéi dat wat de Keefer bereet ass ze bezuelen. De Präis gëtt Schrëtt fir Schrëtt reduzéiert bis ee vun de Participanten d'accord ass, de Lot zum aktuelle Präis ze kafen.
An dësem Beispill benotze mir déiselwecht Konstanten wéi an der viregter, souwéi de Präisschrëtt wann d'Delta erofgeet. De Kont Skript iwwerpréift ob de Participant wierklech deen Éischten ass fir eng Wette ze setzen. Soss gëtt d'Datentransaktioun net vum Blockchain ugeholl.
let startHeight = 384120
let finishHeight = startHeight + 3000
let startPrice = 100000000
let delta = 100
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let token = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
match tx {
case d : DataTransaction =>
let currentPrice = startPrice - delta * (height - startHeight)
#извлекаем из поступившей дата-транзакции поле "price"
let newPrice = extract(getInteger(d.data, "price"))
#убеждаемся, что в стейте текущего аккаунта не содержится поля "sender"
let noBetsBefore = !isDefined(getInteger(this, "sender"))
let fee = 700000
let hasMoney = wavesBalance(tx.sender) + fee >= newPrice
#убеждаемся, что в текущей транзакции только два поля
let correctFields = size(d.data) == 2 && newPrice == currentPrice && d.sender == addressFromString(extract(getString(d.data, "sender")))
startHeight <= height && height <= finishHeight && noBetsBefore && hasMoney && correctFields
case e : ExchangeTransaction =>
#убеждаемся, что отправитель текущей транзакции указан в стейте аккаунта по ключу sender
let senderIsWinner = e.sender == addressFromString(extract(getString(this, "sender")))
#убеждаемся, что аmount ассета указан корректно, и что прайс-ассет - waves
let correctAssetPair = e.sellOrder.assetPair.amountAsset == token && ! isDefined(e.sellOrder.assetPair.priceAsset)
let correctAmount = e.amount == 1
let correctPrice = e.price == extract(getInteger(this, "price"))
height > finishHeight && senderIsWinner && correctAssetPair && correctAmount && correctPrice
case _ => false
}
3. Auktioun "all-pay"
"All-Pay" ass eng Auktioun an där all Participanten d'Offer bezuelen, egal wien de Lot gewënnt. All neie Participant bezilt eng Offer, an de Participant, deen déi maximal Offer mécht, gewënnt de Lot.
An eisem Beispill bitt all Auktiounsparticipant eng Offer iwwer DataTransaction mat (Schlëssel, Wäert) * = ("Gewënner", Adress), ("Präis", Präis). Sou eng DataTransaktioun gëtt nëmme guttgeheescht wann dëse Participant schonn eng Transfertransaktioun mat senger Ënnerschrëft huet a seng Offer méi héich ass wéi all déi virdrun. D'Auktioun geet weider bis EnnHéicht erreecht ass.
let startHeight = 1000
let endHeight = 2000
let this = extract(tx.sender)
let token = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
match tx {
case d: DataTransaction =>
#извлекаем из поступившей дата-транзакции поле "price"
let newPrice = extract(getInteger(d.data, "price"))
#извлекаем из пруфов транзакции публичный ключ аккаунта
let pk = d.proofs[1]
let address = addressFromPublicKey(pk)
#извлекаем транзакцию доказательство из пруфов поступившей дата транзакции
let proofTx = extract(transactionById(d.proofs[2]))
height > startHeight && height < endHeight
&& size(d.data) == 2
#убеждаемся, что адрес победителя, извлеченный из текущей транзакции, совпадает с адресом, извлеченным из пруфов
&& extract(getString(d.data, "winner")) == toBase58String(address.bytes)
&& newPrice > extract(getInteger(this, "price"))
#проверяем, что транзакция подписана
&& sigVerify(d.bodyBytes, d.proofs[0], d.proofs[1])
#проверяем корректность транзакции, указанной в пруфах
&& match proofTx {
case tr : TransferTransaction =>
tr.sender == address &&
tr.amount == newPrice
case _ => false
}
case t: TransferTransaction =>
sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
|| (
height > endHeight
&& extract(getString(this, "winner")) == toBase58String((addressFromRecipient(t.recipient)).bytes)
&& t.assetId == token
&& t.amount == 1
)
case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}
Versécherung / Crowdfunding
Loosst eis eng Situatioun betruechten wou Dir d'Verméige vun de Benotzer géint finanziell Verloschter muss versécheren. Zum Beispill, e Benotzer wëll eng Garantie datt wann en Token depreciéiert, hien de ganze Betrag dee fir dës Tokens bezuelt gëtt zréckkréien, a gewëllt ass eng raisonnabel Versécherung ze bezuelen.
Fir dëst ëmzesetzen, mussen "Versécherungsstonnen" ausgestallt ginn. Duerno gëtt e Skript op de Kont vum Versécherungsbesëtzer installéiert, wat erlaabt nëmmen déi ExchangeTransaktiounen, déi bestëmmte Konditiounen erfëllen, auszeféieren.
Fir duebel Ausgaben ze vermeiden, musst Dir de Benotzer froen fir eng DataTransaction op de Kont vum Versécherungsbesëtzer am Viraus mat (Schlëssel, Wäert) = (purchaseTransactionId, sellOrderId) ze schécken an d'Verschécken vun DataTransactions mat engem Schlëssel verbidden dee scho benotzt gouf.
Dofir mussen d'Beweiser vum Benotzer d'Transaktiouns-ID vum Assurance Token Kaf enthalen. D'Währungspaar muss d'selwecht sinn wéi an der Akafstransaktioun. D'Käschte mussen och d'selwecht sinn wéi déi am Akafszäit fixéiert sinn, minus de Präis vun der Versécherung.
Et ass verstanen datt duerno de Versécherungskonto Versécherung Tokens vum Benotzer kaaft zu engem Präis net manner wéi dee bei deem hien se kaaft huet: de Versécherungskonto erstellt eng ExchangeTransaction, de Benotzer ënnerschreift d'Bestellung (wann d'Transaktioun richteg ofgeschloss ass), Versécherungskonto ënnerschreift déi zweet Bestellung an déi ganz Transaktioun a schéckt se un de Blockchain.
Wann kee Kaf geschitt ass, kann de Benotzer eng ExchangeTransaktioun erstellen no de Regelen, déi am Skript beschriwwe sinn, an d'Transaktioun op d'Blockchain schécken. Op dës Manéier kann de Benotzer d'Suen zréckginn, déi fir de Kaf vun versécherten Tokens ausginn.
let insuranceToken = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let freezePeriod = 150000
let insurancePrice = 10000
match tx {
#убеждаемся, что, если поступила дата-транзакция, то у нее ровно одно поле и в стейте еще нет такого ключа
case d : DataTransaction => size(d.data) == 1 && !isDefined(getBinary(this, d.data[0].key))
case e : ExchangeTransaction =>
#если у транзакции нет седьмого пруфа, проверяем корректность подписи
if !isDefined(e.proofs[7]) then
sigVerify(e.bodyBytes, e.proofs[0], e.senderPublicKey)
else
#если у транзакции есть седьмой пруф, извлекаем из него транзакцию и узнаём её высоту
let purchaseTx = transactionById(e.proofs[7])
let purchaseTxHeight = extract(transactionHeightById(e.proofs[7]))
#обрабатываем транзакцию из пруфа
match purchaseTx {
case purchase : ExchangeTransaction =>
let correctSender = purchase.sender == e.sellOrder.sender
let correctAssetPair = e.sellOrder.assetPair.amountAsset == insuranceToken &&
purchase.sellOrder.assetPair.amountAsset == insuranceToken &&
e.sellOrder.assetPair.priceAsset == purchase.sellOrder.assetPair.priceAsset
let correctPrice = e.price == purchase.price - insurancePrice && e.amount == purchase.amount
let correctHeight = height > purchaseTxHeight + freezePeriod
#убеждаемся, что в транзакции-пруфе указан верный ID текущей транзакции
let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == e.sellOrder.id
correctSender && correctAssetPair && correctPrice && correctHeight && correctProof
case _ => false
}
case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}
Eng Versécherung Token kann e Smart Verméigen gemaach ginn, zum Beispill, fir säin Transfert un Drëttubidder ze verbidden.
Dëse Schema kann och ëmgesat ginn fir Crowdfunding Tokens, déi un d'Besëtzer zréckginn wann de erfuerderleche Betrag net gesammelt gouf.
Transaktiounssteier
Smart Kontrakter sinn och applicabel an Fäll wou et néideg ass Steier op all Transaktioun mat verschidden Zorte vu Verméigen ze sammelen. Dëst kann duerch en neie Verméigen mat installéiert ginn
1. Mir erausginn FeeCoin, déi un Benotzer op engem fixen Präis geschéckt ginn: 0,01 WAVES = 0,001 FeeCoin.
2. Set Parrainage fir FeeCoin an Austausch Taux: 0,001 WAVES = 0,001 FeeCoin.
3. Setzt de folgende Skript fir de Smart Asset:
let feeAssetId = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
let taxDivisor = 10
match tx {
case t: TransferTransaction =>
t.feeAssetId == feeAssetId && t.fee == t.amount / taxDivisor
case e: ExchangeTransaction | MassTransferTransaction => false
case _ => true
}
Elo all Kéier wann iergendeen N Smart Verméigen transferéiert, ginn se Iech FeeCoin an der Quantitéit vun N / TaxDivisor (déi vun Iech bei 10 * N / TaxDivisor WAVES kaaft ka ginn), an Dir gitt dem Miner N / TaxDivisor WAVES. Als Resultat gëtt Äre Gewënn (Steier) 9*N / taxDivisor WAVES.
Dir kënnt och Besteierung ausféieren mat engem Smart Asset Skript a MassTransferTransaction:
let taxDivisor = 10
match tx {
case t : MassTransferTransaction =>
let twoTransfers = size(t.transfers) == 2
let issuerIsRecipient = t.transfers[0].recipient == addressFromString("3MgkTXzD72BTfYpd9UW42wdqTVg8HqnXEfc")
let taxesPaid = t.transfers[0].amount >= t.transfers[1].amount / taxDivisor
twoTransfers && issuerIsRecipient && taxesPaid
case _ => false
}
Cashback an Loyalitéit Programmer
Cashback ass eng Aart vu Loyalitéitsprogramm an deem de Keefer en Deel vum Betrag zréck kritt deen un e Produkt oder Service ausginn ass.
Wann Dir dëse Fall mat engem Smart Kont implementéiert, musse mir d'Beweiser op déiselwecht Manéier iwwerpréiwen wéi mir am Versécherungsfall gemaach hunn. Fir duebel Ausgaben ze vermeiden, muss de Benotzer eng DataTransaction mat (Schlëssel, Wäert) = (purchaseTransactionId, cashbackTransactionId) schécken ier hien Cashback kritt.
Mir mussen och e Verbuet op existent Schlësselen mat DataTransaction setzen. cashbackDivisor - Eenheet gedeelt duerch de Cashback Undeel. Déi. wann de Cashback Undeel 0.1 ass, dann CashbackDivisor 1 / 0.1 = 10.
let cashbackToken = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let cashbackDivisor = 10
match tx {
#убеждаемся, что, если поступила дата-транзакция, то у нее ровно одно поле и в стейте еще нет такого ключа
case d : DataTransaction => size(d.data) == 1 && !isDefined(getBinary(this, d.data[0].key))
case e : TransferTransaction =>
#если у транзакции нет седьмого пруфа, проверяем корректность подписи
if !isDefined(e.proofs[7]) then
sigVerify(e.bodyBytes, e.proofs[0], e.senderPublicKey)
else
#если у транзакции есть седьмой пруф, извлекаем из него транзакцию и узнаём её высоту
let purchaseTx = transactionById(e.proofs[7])
let purchaseTxHeight = extract(transactionHeightById(e.proofs[7]))
#обрабатываем транзакцию из пруфа
match purchaseTx {
case purchase : TransferTransaction =>
let correctSender = purchase.sender == e.sender
let correctAsset = e.assetId == cashbackToken
let correctPrice = e.amount == purchase.amount / cashbackDivisor
#убеждаемся, что в транзакции-пруфе указан верный ID текущей транзакции
let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == e.id
correctSender && correctAsset && correctPrice && correctProof
case _ => false
}
case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}
Atomeraustausch
Atomic Swap erlaabt d'Benotzer Verméigen ouni d'Hëllef vun engem Austausch auszetauschen. Mat engem Atomaustausch musse béid Participanten an der Transaktioun et bannent enger gewësser Zäit bestätegen.
Wann op d'mannst ee vun de Participanten net déi richteg Bestätegung vun der Transaktioun bannent der Zäit fir d'Transaktioun zougewisen gëtt, gëtt d'Transaktioun annuléiert an den Austausch geschitt net.
An eisem Beispill benotze mir de folgende Smart Account Skript:
let Bob = Address(base58'3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8')
let Alice = Address(base58'3PNX6XwMeEXaaP1rf5MCk8weYeF7z2vJZBg')
let beforeHeight = 100000
let secret = base58'BN6RTYGWcwektQfSFzH8raYo9awaLgQ7pLyWLQY4S4F5'
match tx {
case t: TransferTransaction =>
let txToBob = t.recipient == Bob && sha256(t.proofs[0]) == secret && 20 + beforeHeight >= height
let backToAliceAfterHeight = height >= 21 + beforeHeight && t.recipient == Alice
txToBob || backToAliceAfterHeight
case _ => false
}
Am nächsten Artikel kucke mir d'Benotzung vu Smart Konten a Finanzinstrumenter wéi Optiounen, Futures a Rechnungen.
Source: will.com