Uwendungen vu Waves Smart Konten: vun Auktioune bis Bonus Programmer

Uwendungen vu Waves Smart Konten: vun Auktioune bis Bonus Programmer

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 hei. An hei - Artikel zu dësem Thema op Habr.

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 Transaktiounen Zorte.

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 HEI erlaabt Iech d'kompiléiert Vue vum Kontrakt ze gesinn (wann et kompiléiert ass), nei Konten erstellen an Scripte dofir setzen, souwéi Transaktiounen iwwer d'Kommandozeil schécken.

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 Parrainage fir Transaktioune mat Smart Assets:

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

Setzt e Commentaire