Umsóknir Waves snjallreikninga: allt frá uppboðum til bónusforrita

Umsóknir Waves snjallreikninga: allt frá uppboðum til bónusforrita

Blockchain tengist oft aðeins dulritunargjaldmiðlum, en notkunarsvið DLT tækni eru miklu víðtækari. Eitt af vænlegustu sviðunum fyrir notkun blockchain er snjall samningur sem framkvæmur sjálfkrafa og krefst ekki trausts milli aðila sem gengu inn í hann.

RIDE – tungumál fyrir snjalla samninga

Waves hefur þróað sérstakt tungumál fyrir snjalla samninga - RIDE. Heildar skjöl þess eru staðsett hér. Og hér - grein um þetta efni á Habr.

RIDE samningurinn er forsaga og skilar „satt“ eða „ósatt“ sem framleiðsla. Í samræmi við það eru viðskiptin annað hvort skráð í blockchain eða hafnað. Snjallsamningurinn tryggir að fullu að tilgreind skilyrði séu uppfyllt. Ekki er hægt að búa til færslur úr samningi í RIDE eins og er.

Í dag eru tvær tegundir af Waves snjallsamningum: snjallreikningar og snjalleignir. Snjallreikningur er venjulegur notendareikningur en fyrir hann er stillt forskrift sem stjórnar öllum viðskiptum. Snjallt reikningsskrift gæti litið svona út, til dæmis:

match tx {
  case t: TransferTransaction | MassTransferTransaction => false
  case _ => true
}

tx er færsla í vinnslu sem við leyfum að nota aðeins mynstursamsvörun ef það er ekki millifærslufærsla. Mynstursamsvörun í RIDE er notuð til að athuga tegund viðskipta. Hægt er að vinna úr öllum núverandi reikningum í snjallreikningsskriftinni tegundir viðskipta.

Handritið getur einnig lýst breytum, notað „ef-þá-annar“ smíðar og aðrar aðferðir til að athuga aðstæður að fullu. Til að tryggja að samningar hafi sannanlegan heilleika og margbreytileika (kostnað) sem auðvelt er að spá fyrir um áður en framkvæmd samnings hefst, inniheldur RIDE ekki lykkjur eða stökkyfirlýsingar.

Aðrir eiginleikar Waves reikninga fela í sér tilvist „ríkis“, það er ástand reikningsins. Þú getur skrifað óendanlega mörg pör (lykill, gildi) í reikningsstöðuna með því að nota gagnafærslur (DataTransaction). Þessar upplýsingar er síðan hægt að vinna bæði í gegnum REST API og beint í snjallsamningnum.

Hver viðskipti geta innihaldið fjölda sönnunargagna, þar sem hægt er að slá inn undirskrift þátttakanda, auðkenni nauðsynlegrar viðskipta o.s.frv.

Að vinna með RIDE í gegnum IDE gerir þér kleift að sjá samantekt á samningnum (ef hann er settur saman), búa til nýja reikninga og stilla forskriftir fyrir hann, sem og senda færslur í gegnum skipanalínuna.

Fyrir fulla lotu, þar á meðal að búa til reikning, setja upp snjallsamning á hann og senda færslur, geturðu líka notað bókasafn til að hafa samskipti við REST API (til dæmis C#, C, Java, JavaScript, Python, Rust, Elixir) . Til að byrja að vinna með IDE, smelltu bara á NÝTT hnappinn.

Möguleikarnir á að nota snjalla samninga eru breiðir: allt frá því að banna viðskipti yfir í ákveðin heimilisföng („svartur listi“) til flókinna dApps.

Nú skulum við skoða tiltekin dæmi um notkun snjallsamninga í viðskiptum: þegar uppboð eru framkvæmd, tryggingar og stofnað vildarkerfi.

Uppboð

Eitt af skilyrðum fyrir árangursríku uppboði er gagnsæi: þátttakendur verða að vera vissir um að ómögulegt sé að hagræða tilboðum. Þetta er hægt að ná þökk sé blockchain, þar sem óbreytanleg gögn um öll veðmál og tímann þegar þau voru gerð verða aðgengileg öllum þátttakendum.

Á Waves blockchain er hægt að skrá tilboð í stöðu uppboðsreiknings í gegnum DataTransaction.

Þú getur líka stillt upphafs- og lokatíma uppboðsins með því að nota blokkanúmer: tíðni blokkamyndunar í Waves blockchain er um það bil jöfn og 60 sekúndur.

1. Enskt hækkandi verðuppboð

Þátttakendur í ensku uppboði bjóða fram í samkeppni sín á milli. Hvert nýtt veðmál verður að fara yfir það fyrra. Uppboðinu lýkur þegar ekki eru fleiri bjóðendur sem fara yfir síðasta tilboð. Í þessu tilviki þarf hæstbjóðandi að gefa upp tilgreinda upphæð.

Einnig er uppboðsvalkostur þar sem seljandi setur lágmarksverð fyrir hlutinn og verður lokaverðið að fara yfir það. Að öðrum kosti er lóðin óseld.

Í þessu dæmi erum við að vinna með reikning sem er sérstaklega búinn til fyrir uppboðið. Uppboðstíminn er 3000 blokkir og upphafsverð hlutarins er 0,001 BYLGJA. Þátttakandi getur lagt fram tilboð með því að senda gagnafærslu með lykilverðinu og verðmæti tilboðsins.

Verð nýja tilboðsins verður að vera hærra en núverandi verð fyrir þennan lykil og þátttakandinn verður að hafa að minnsta kosti [new_bid + þóknun] tákn á reikningnum sínum. Heimilisfang tilboðsgjafa verður að vera skráð í reitinn „sendandi“ í Gagnaviðskiptum og núverandi hæð tilboðsblokkar verður að vera innan uppboðstímabilsins.

Ef þátttakandi hefur sett hæsta verð í lok uppboðs getur hann sent Exchange Transaction til að greiða fyrir samsvarandi hlut á tilgreindu verði og gjaldmiðlapari.

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. Hollenskt uppboð á lækkandi verði

Í hollensku uppboði er mikið í upphafi boðið á hærra verði en kaupandinn er tilbúinn að borga. Verðið lækkar skref fyrir skref þar til einn þátttakenda samþykkir að kaupa hlutinn á núverandi verði.

Í þessu dæmi notum við sömu fasta og í því fyrra, sem og verðþrepið þegar delta lækkar. Reikningshandritið athugar hvort þátttakandinn sé örugglega sá fyrsti til að leggja veðmál. Annars er DataTransaction ekki samþykkt af blockchain.

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. Uppboð „allt að borga“

„All-pay“ er uppboð þar sem allir þátttakendur greiða tilboðið, óháð því hver vinnur hlutinn. Hver nýr þátttakandi greiðir tilboð og sá þátttakandi sem gerir hámarkstilboð vinnur hlutinn.

Í dæminu okkar leggur hver þátttakandi í uppboði tilboð í gegnum DataTransaction með (lykill, gildi)* = ("vinningshafi", heimilisfang), ("verð", verð). Slík Gagnaviðskipti eru aðeins samþykkt ef þessi þátttakandi er þegar með Flutningsfærslu með undirskrift sinni og tilboð hans er hærra en öll fyrri. Uppboðið heldur áfram þar til lokahæð er náð.

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)
}

Tryggingar / Crowdfunding

Við skulum íhuga aðstæður þar sem þú þarft að tryggja eignir notenda fyrir fjárhagstjóni. Til dæmis vill notandi tryggingu fyrir því að ef tákn lækkar geti hann fengið til baka alla upphæðina sem greidd var fyrir þessi tákn og er tilbúinn að greiða hæfilega tryggingu.

Til að hrinda þessu í framkvæmd þarf að gefa út „tryggingamerki“. Síðan er forskrift sett upp á reikningi vátryggingartaka, sem gerir aðeins kleift að framkvæma þau ExchangeTransactions sem uppfylla ákveðin skilyrði.

Til að koma í veg fyrir tvöfalda eyðslu þarftu að biðja notandann um að senda DataTransaction á reikning vátryggingartaka fyrirfram með (key, value) = (purchaseTransactionId, sellOrderId) og banna sendingu DataTransactions með lykli sem hefur þegar verið notaður.

Þess vegna verða sönnunargögn notandans að innihalda færsluauðkenni kaupanna á tryggingartáknum. Gjaldmiðilsparið verður að vera það sama og í kaupfærslunni. Kostnaðurinn þarf einnig að vera jöfn því sem var fastur við kaup að frádregnu verði tryggingar.

Það er litið svo á að í kjölfarið kaupir tryggingareikningurinn tryggingartákn af notandanum á verði sem er ekki lægra en það sem hann keypti þau á: tryggingareikningurinn býr til ExchangeTransaction, notandinn skrifar undir pöntunina (ef viðskiptunum er rétt lokið), tryggingarreikningur undirritar seinni pöntunina og öll viðskiptin og sendir hana til blockchain.

Ef engin kaup eiga sér stað getur notandinn búið til ExchangeTransaction í samræmi við reglurnar sem lýst er í handritinu og sent viðskiptin til blockchain. Þannig getur notandinn skilað peningunum sem varið er í kaup á tryggðum táknum.

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)
}

Hægt er að gera tryggingartákn að snjöllri eign, til dæmis til að banna flutning þess til þriðja aðila.

Þetta kerfi er einnig hægt að útfæra fyrir hópfjármögnunartákn, sem er skilað til eigenda ef tilskilin upphæð hefur ekki verið innheimt.

Viðskiptaskattar

Snjallir samningar eiga einnig við í þeim tilvikum þar sem nauðsynlegt er að innheimta skatt af hverri færslu með nokkrar tegundir eigna. Þetta er hægt að gera í gegnum nýja eign með uppsettri kostun fyrir viðskipti með snjalleignir:

1. Við gefum út FeeCoin, sem verður sent til notenda á föstu verði: 0,01 WAVES = 0,001 FeeCoin.

2. Stilltu kostun fyrir FeeCoin og gengi: 0,001 WAVES = 0,001 FeeCoin.

3. Stilltu eftirfarandi skriftu fyrir snjalleignina:

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
}

Nú þegar einhver flytur N snjalleignir mun hann gefa þér FeeCoin að upphæð N/taxDivisor (sem hægt er að kaupa af þér á 10 *N/taxDivisor WAVES), og þú munt gefa námumanninum N/taxDivisor WAVES. Þar af leiðandi verður hagnaður þinn (skattur) 9*N / taxDivisor WAVES.

Þú getur líka framkvæmt skattlagningu með því að nota snjallt eignaforskrift og 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 og vildarkerfi

Cashback er tegund tryggðarkerfis þar sem kaupandinn fær til baka hluta af upphæðinni sem varið er í vöru eða þjónustu.

Þegar þetta mál er útfært með því að nota snjallreikning verðum við að athuga sönnunargögnin á sama hátt og við gerðum í tryggingamálinu. Til að koma í veg fyrir tvöfalda eyðslu verður notandinn að senda gagnafærslu með (lykill, gildi) = (purchaseTransactionId, cashbackTransactionId) áður en hann fær endurgreiðslu.

Við verðum líka að setja bann við núverandi lyklum með því að nota DataTransaction. cashbackDivisor - eining deilt með cashback hlut. Þeir. ef endurgreiðsluhlutfallið er 0.1, þá er 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)
}

Atómaskipti

Atomic swap gerir notendum kleift að skiptast á eignum án aðstoðar. Með atómaskiptum þurfa báðir þátttakendur í viðskiptunum að staðfesta það innan ákveðins tíma.

Ef a.m.k. einn þátttakenda veitir ekki rétta staðfestingu á viðskiptunum innan þess tíma sem úthlutað er til viðskiptanna, fellur viðskiptin niður og skiptin eiga sér ekki stað.

Í dæminu okkar munum við nota eftirfarandi snjallreikningsskrift:

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
}

Í næstu grein munum við skoða notkun snjallreikninga í fjármálagerningum eins og valréttum, framtíðarsamningum og víxlum.

Heimild: www.habr.com

Bæta við athugasemd