Blockchain hè spessu assuciatu solu cù cripto muniti, ma i spazii di l'applicazione di a tecnulugia DLT sò assai più largu. Unu di i spazii più promettenti per l'usu di u blockchain hè un cuntrattu intelligente chì hè eseguitu automaticamente è ùn deve micca fiducia trà e partiti chì anu intrutu in questu.
RIDE - una lingua per i cuntratti intelligenti
Waves hà sviluppatu una lingua speciale per i cuntratti intelligenti - RIDE. A so documentazione cumpleta si trova
U cuntrattu RIDE hè un predicatu è torna "true" o "false" cum'è output. Per quessa, a transazzione hè o arregistrata in u blockchain o rifiutata. U cuntrattu intelligente guarantisci cumplettamente u cumpletu di e cundizioni specificate. A generazione di transazzione da un cuntrattu in RIDE ùn hè micca pussibule.
Oghje ci sò dui tipi di cuntratti intelligenti di Waves: cunti intelligenti è asset intelligenti. Un contu intelligente hè un contu d'utilizatore regulare, ma un script hè stallatu per ellu chì cuntrolla tutte e transazzione. Un script di contu intelligente puderia vede cusì, per esempiu:
match tx {
case t: TransferTransaction | MassTransferTransaction => false
case _ => true
}
tx hè una transazzione trattata chì permettemu di utilizà u mecanismu di currispondenza di mudelli solu s'ellu ùn hè micca una transazzione di trasferimentu. Pattern matching in RIDE hè utilizatu per verificà u tipu di transazzione. Tutti i cunti esistenti ponu esse trattati in u script di contu intelligente
U script pò ancu dichjarà variabili, utilizate custruzzioni "se-then-else" è altri metudi per cuntrollà cumplettamente e cundizioni. Per assicurà chì i cuntratti anu una cumplessità pruvata è cumplessità (costu) chì hè faciule da predichendu prima di l'esekzione di u cuntrattu principia, RIDE ùn cuntene micca loops o dichjarazioni di salto.
Altre caratteristiche di i cunti Waves includenu a prisenza di un "statu", vale à dì u statu di u contu. Pudete scrive un numeru infinitu di pariglii (chjavi, valore) à u statu di u contu utilizendu transazzione di dati (DataTransaction). Questa infurmazione pò esse trattata sia attraversu l'API REST sia direttamente in u cuntrattu intelligente.
Ogni transazzione pò cuntene una serie di prove, in quale a firma di u participante, l'ID di a transazzione necessaria, etc.
U travagliu cù RIDE via
Per un ciclu sanu, cumprese a creazione di un contu, l'installazione di un cuntrattu intelligente è l'inviu di transazzione, pudete ancu aduprà una biblioteca per interagisce cù l'API REST (per esempiu, C#, C, Java, JavaScript, Python, Rust, Elixir) . Per cumincià à travaglià cù l'IDE, basta à cliccà u buttone NEW.
E pussibulità di usu di cuntratti intelligenti sò largu: da pruibisce transacciones à certi indirizzi ("lista nera") à dApps cumplessi.
Avà fighjemu l'esempii specifichi di l'usu di cuntratti intelligenti in l'affari: quandu si facenu l'asta, l'assicuranza, è a creazione di prugrammi di fidelizazione.
L'asta
Una di e cundizioni per una subasta riescita hè a trasparenza: i participanti devenu esse cunfidenti chì hè impussibile di manipulà offerte. Questu pò esse ottenutu grazia à u blockchain, induve e dati immutabili nantu à tutte e scumesse è u tempu quandu sò stati fatti seranu dispunibili per tutti i participanti.
Nantu à u blockchain Waves, l'offerte ponu esse registrate in u statu di u contu di l'asta via DataTransaction.
Pudete ancu stabilisce l'ora di iniziu è di fine di l'asta usendu numeri di bloccu: a freccia di generazione di blocchi in u blockchain Waves hè apprussimatamente uguale à 60 seconde.
1. Auction English ascending price
I participanti in una subasta inglesa ponenu offerte in cuncurrenza cù l'altri. Ogni nova scumessa deve superà a precedente. L'asta finisce quandu ùn ci hè più offerenti per superà l'ultima offerta. In questu casu, u più altu offerente deve furnisce l'ammontu indicatu.
Ci hè ancu una opzione d'asta in quale u vinditore stabilisce un prezzu minimu per u lottu, è u prezzu finali deve esse sopra. Altrimenti, u lottu resta invendutu.
In questu esempiu, avemu travagliatu cù un contu creatu specificamente per l'asta. A durata di l'asta hè di 3000 blocchi, è u prezzu di partenza di u lottu hè 0,001 WAVES. Un participante pò fà una offerta mandendu una DataTransaction cù a chjave "prezzu" è u valore di a so offerta.
U prezzu di a nova offerta deve esse più altu ch'è u prezzu attuale per questa chjave, è u participante deve avè almenu [new_bid + commission] tokens in u so contu. L'indirizzu di l'offerente deve esse registratu in u campu "mittente" in DataTransaction, è l'altezza attuale di u bloccu di offerta deve esse in u periodu di l'asta.
Se à a fine di l'asta, u participante hà stabilitu u prezzu più altu, pò mandà una Transazzione di Scambio per pagà u lottu currispundente à u prezzu specificatu è a coppia di valuta.
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. Auction Olandese di i prezzi diminuenti
In una subasta Olandese, assai hè inizialmente offertu à un prezzu più altu di ciò chì u cumpratore hè dispostu à pagà. U prezzu diminuisce passu à passu finu à chì unu di i participanti accetta di cumprà u lottu à u prezzu attuale.
In questu esempiu usemu i stessi custanti cum'è in u precedente, è ancu u passu di prezzu quandu delta diminuisce. U script di u contu verifica se u participante hè veramente u primu à fà una scumessa. Altrimenti, a DataTransaction ùn hè micca accettata da u 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. Asta "all-pay"
"All-pay" hè una subasta in quale tutti i participanti paganu l'offerta, indipendentemente da quale vince u lottu. Ogni novu participante paga una offerta, è u participante chì face l'offerta massima vince u lottu.
In u nostru esempiu, ogni participante à l'asta mette una offerta via DataTransaction cù (chjave, valore) * = ("vincitore", indirizzu), ("prezzu", prezzu). Un tali DataTransaction hè appruvatu solu se stu participante hà digià un TransferTransaction cù a so firma è a so offerta hè più altu ch'è tutti i precedenti. L'asta cuntinueghja finu à a fine Height hè ghjunta.
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)
}
Assicuranza / Crowdfunding
Cunsideremu una situazione induve avete bisognu di assicurà l'assi di l'utilizatori contr'à perdite finanziarie. Per esempiu, un utilizatore vole una guaranzia chì, se un token si deprezza, puderà ritruvà a quantità tutale pagata per questi tokens, è hè dispostu à pagà una quantità raghjone d'assicuranza.
Per implementà questu, "tokens d'assicuranza" deve esse emessu. Allora un script hè stallatu nantu à u contu di l'assicuratore, chì permette solu quelli ExchangeTransactions chì scontranu certi cundizioni per esse eseguitu.
Per prevene a doppia spesa, avete bisognu di dumandà à l'utilizatore per mandà una DataTransaction à u contu di l'assicuratore in anticipu cù (key, value) = (purchaseTransactionId, sellOrderId) è pruibisce di mandà DataTransactions cù una chjave chì hè digià stata utilizata.
Dunque, e prove di l'utilizatori devenu cuntene l'ID di transazzione di l'acquistu di token d'assicuranza. A coppia di valute deve esse uguali à a transazzione di compra. U costu deve ancu esse uguali à quellu fissatu à u mumentu di a compra, minus u prezzu di l'assicuranza.
Hè intesu chì in seguitu u cuntu d'assicuranza compra tokens d'assicuranza da l'utilizatore à un prezzu micca più bassu di quellu à quale l'hà acquistatu: u cuntu d'assicuranza crea una Transazzione di Scambio, l'utilizatore firma l'ordine (se a transazzione hè cumpleta bè), u contu d'assicuranza firma u sicondu ordine è tutta a transazzione è u manda à u blockchain .
Se ùn ci hè micca una compra, l'utilizatore pò creà un ExchangeTransaction secondu e regule descritte in u script è mandà a transazzione à u blockchain. In questu modu, l'utilizatore pò rinvià i soldi spesi in a compra di tokens assicurati.
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)
}
Un token d'assicuranza pò esse fattu un attivu intelligente, per esempiu, per pruibisce u so trasferimentu à terzu.
Stu schema pò ancu esse implementatu per i tokens di crowdfunding, chì sò tornati à i pruprietarii se a quantità necessaria ùn hè micca stata cullata.
Tasse di transazzione
I cuntratti intelligenti sò ancu applicabili in i casi induve hè necessariu di cullà l'impositu nantu à ogni transazzione cù parechji tipi di assi. Questu pò esse fattu attraversu un novu attivu cù installatu
1. Emettemu FeeCoin, chì serà mandatu à l'utilizatori à un prezzu fissu: 0,01 WAVES = 0,001 FeeCoin.
2. Stabbilisce u sponsorizazione per FeeCoin è u scambiu: 0,001 WAVES = 0,001 FeeCoin.
3. Stabilite u script seguente per l'asset smart:
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
}
Avà ogni volta chì qualchissia trasferimentu N assi intelligenti, vi darà FeeCoin in a quantità di N/taxDivisor (chì pò esse acquistatu da voi à 10 *N/taxDivisor WAVES), è vi darà u minatore N/taxDivisor WAVES. In u risultatu, u vostru prufittu (tassa) serà 9*N / taxDivisor WAVES.
Pudete ancu eseguisce a tassazione cù un script di asset intelligente è 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 è prugrammi di fidelizazione
Cashback hè un tipu di prugramma di lealtà in u quale u cumpratore torna una parte di a quantità spesa in un pruduttu o serviziu.
Quandu l'implementazione di stu casu utilizendu un contu intelligente, duvemu verificà e prove in u listessu modu chì avemu fattu in u casu d'assicuranza. Per prevene a doppia spesa, l'utilizatore deve mandà una DataTransaction cù (key, value) = (purchaseTransactionId, cashbackTransactionId) prima di riceve cashback.
Avemu da ancu stabilisce una prohibizione di e chjave esistenti cù DataTransaction. cashbackDivisor - unità divisa da a parte di cashback. Quelli. se a parte di cashback hè 0.1, allora 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)
}
Scambiu atomicu
U scambiu atomicu permette à l'utilizatori di scambià l'assi senza l'aiutu di un scambiu. Cù un swap atomicu, i dui participanti in a transazzione sò tenuti à cunfirmà in un certu periodu di tempu.
Se almenu unu di i participanti ùn furnisce micca a cunferma curretta di a transazzione in u tempu attribuitu per a transazzione, a transazzione hè annullata è u scambiu ùn si faci micca.
In u nostru esempiu, useremu u seguente script di contu intelligente:
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
}
In u prossimu articulu avemu da circà à l'usu di cunti intelligenti in strumenti finanziarii cum'è opzioni, futures è bills.
Source: www.habr.com