Waves smart hesablarının tətbiqi: auksionlardan bonus proqramlarına qədər

Waves smart hesablarının tətbiqi: auksionlardan bonus proqramlarına qədər

Blockchain çox vaxt yalnız kriptovalyutalarla əlaqələndirilir, lakin DLT texnologiyasının tətbiq sahələri daha genişdir. Blokçeynin istifadəsi üçün ən perspektivli sahələrdən biri avtomatik icra edilən və ona daxil olan tərəflər arasında etibar tələb etməyən ağıllı müqavilədir.

RIDE – ağıllı müqavilələr üçün dil

Waves ağıllı müqavilələr üçün xüsusi bir dil hazırlayıb - RIDE. Tam sənədləri var burada. Və burada - bu mövzuda məqalə Habr haqqında.

RIDE müqaviləsi bir predikatdır və çıxış kimi “doğru” və ya “yanlış” qaytarır. Müvafiq olaraq, əməliyyat ya blokçeyndə qeyd olunur, ya da rədd edilir. Ağıllı müqavilə müəyyən şərtlərin yerinə yetirilməsinə tam zəmanət verir. RIDE-də müqavilədən tranzaksiyaların yaradılması hazırda mümkün deyil.

Bu gün Waves ağıllı müqavilələrinin iki növü var: ağıllı hesablar və ağıllı aktivlər. Ağıllı hesab adi istifadəçi hesabıdır, lakin onun üçün bütün əməliyyatlara nəzarət edən bir skript qurulur. Ağıllı hesab skripti bu kimi görünə bilər, məsələn:

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

tx emal edilən əməliyyatdır və biz nümunə uyğunlaşdırma mexanizmindən yalnız köçürmə əməliyyatı olmadıqda istifadə etməyə icazə veririk. RIDE-də nümunə uyğunluğu əməliyyatın növünü yoxlamaq üçün istifadə olunur. Bütün mövcud hesablar smart hesab skriptində işlənə bilər əməliyyat növləri.

Skript həmçinin dəyişənləri elan edə bilər, şərtləri tam yoxlamaq üçün “if-then-else” konstruksiyalarından və digər üsullardan istifadə edə bilər. Müqavilələrin müqavilənin icrası başlamazdan əvvəl proqnozlaşdırmaq asan olan sübut edilə bilən tamlığa və mürəkkəbliyə (qiymətə) malik olmasını təmin etmək üçün RIDE-də döngələr və ya keçid ifadələri yoxdur.

Waves hesablarının digər xüsusiyyətlərinə "dövlətin" mövcudluğu, yəni hesabın vəziyyəti daxildir. Məlumat əməliyyatlarından (DataTransaction) istifadə edərək hesabın vəziyyətinə sonsuz sayda cüt (açar, dəyər) yaza bilərsiniz. Bu məlumat daha sonra həm REST API vasitəsilə, həm də birbaşa smart müqavilədə işlənə bilər.

Hər bir əməliyyatda iştirakçının imzası, tələb olunan əməliyyatın ID-si və s. daxil edilə bilən bir sıra sübutlar ola bilər.

vasitəsilə RIDE ilə işləmək IDE müqavilənin tərtib edilmiş görünüşünü (əgər o tərtib edilibsə) görməyə, yeni hesablar yaratmağa və onun üçün skriptlər təyin etməyə, həmçinin komanda xətti vasitəsilə əməliyyatlar göndərməyə imkan verir.

Hesab yaratmaq, ona ağıllı müqavilə quraşdırmaq və əməliyyatlar göndərmək daxil olmaqla tam dövr üçün siz REST API ilə qarşılıqlı əlaqə üçün kitabxanadan da istifadə edə bilərsiniz (məsələn, C#, C, Java, JavaScript, Python, Rust, Elixir) . IDE ilə işə başlamaq üçün YENİ düyməsini sıxmağınız kifayətdir.

Ağıllı müqavilələrdən istifadə imkanları genişdir: əməliyyatları qadağan etməkdən müəyyən ünvanlara (“qara siyahı”) qədər mürəkkəb dApp-lara qədər.

İndi biznesdə ağıllı müqavilələrdən istifadənin konkret nümunələrinə baxaq: auksionlar keçirərkən, sığorta edərkən və loyallıq proqramları yaratarkən.

Hərraclar

Uğurlu hərracın şərtlərindən biri şəffaflıqdır: iştirakçılar əmin olmalıdırlar ki, təklifləri manipulyasiya etmək mümkün deyil. Buna blokçeyn sayəsində nail olmaq olar, burada bütün mərclər və onların edildiyi vaxt haqqında dəyişməz məlumatlar bütün iştirakçılar üçün əlçatan olacaq.

Waves blokçeynində təkliflər DataTransaction vasitəsilə hərrac hesabı vəziyyətində qeydə alına bilər.

Siz həmçinin blok nömrələrindən istifadə edərək auksionun başlama və bitmə vaxtını təyin edə bilərsiniz: Waves blokçeynində blok yaratma tezliyi təxminən bərabərdir. 60 saniyə.

1. İngilis artan qiymət auksionu

İngilis auksionunun iştirakçıları bir-biri ilə rəqabət aparırlar. Hər yeni mərc əvvəlkindən çox olmalıdır. Hərrac son təklifi aşa biləcək daha çox iddiaçı olmadıqda başa çatır. Bu halda ən yüksək qiymət təklif edən şəxs qeyd olunan məbləği təqdim etməlidir.

Satıcının lot üçün minimum qiyməti təyin etdiyi və son qiymətin onu üstələdiyi hərrac opsionu da var. Əks halda lot satılmamış qalır.

Bu nümunədə biz xüsusi olaraq hərrac üçün yaradılmış hesabla işləyirik. Hərracın müddəti 3000 blok, lotun başlanğıc qiyməti isə 0,001 DALĞA-dır. İştirakçı “qiymət” açarı və öz təklifinin dəyəri ilə DataTransaction göndərməklə təklif verə bilər.

Yeni təklifin qiyməti bu açarın cari qiymətindən yüksək olmalıdır və iştirakçının hesabında ən azı [new_bid + komissiya] tokenləri olmalıdır. İddiaçının ünvanı DataTransaction-da "göndərən" sahəsində qeyd edilməli və cari təklif blokunun hündürlüyü hərrac müddətində olmalıdır.

Əgər hərracın sonunda iştirakçı ən yüksək qiyməti təyin edibsə, o, müəyyən edilmiş qiymət və valyuta cütü üzrə müvafiq lot üzrə ödəniş etmək üçün Mübadilə Əməliyyatı göndərə bilər.

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. Hollandiyada ucuzlaşan qiymətlərin hərracı

Hollandiya auksionunda ilkin olaraq bir çox şey alıcının ödəməyə hazır olduğundan daha yüksək qiymətə təklif olunur. İştirakçılardan biri lotu cari qiymətə almağa razı olana qədər qiymət addım-addım azalır.

Bu nümunədə biz əvvəlki kimi eyni sabitlərdən, həmçinin delta azaldıqda qiymət addımından istifadə edirik. Hesab skripti iştirakçının həqiqətən mərc edən ilk şəxs olub-olmadığını yoxlayır. Əks halda, DataTransaction blokçeyn tərəfindən qəbul edilmir.

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. Auksion “hamısı ödənişlidir”

“All-pay” lotu kimin qazanmasından asılı olmayaraq, bütün iştirakçıların təklifi ödədiyi hərracdır. Hər bir yeni iştirakçı bir təklif ödəyir və maksimum təklifi verən iştirakçı lotu qazanır.

Bizim nümunəmizdə hər bir auksion iştirakçısı DataTransaction vasitəsilə (açar, dəyər)* = (“qalib”, ünvan), (“qiymət”, qiymət) ilə təklif verir. Belə DataTransaction o halda təsdiq edilir ki, bu iştirakçının artıq öz imzası ilə TransferTransaction var və onun təklifi bütün əvvəlkilərdən yüksəkdir. Hərrac endHeight-a çatana qədər davam edir.

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

Sığorta/Crowdfunding

İstifadəçilərin aktivlərini maliyyə itkilərindən sığortalamağınız lazım olan bir vəziyyəti nəzərdən keçirək. Məsələn, istifadəçi bir token dəyərsizləşərsə, bu tokenlər üçün ödənilən tam məbləği geri ala biləcəyinə dair zəmanət istəyir və ağlabatan məbləğdə sığorta ödəməyə hazırdır.

Bunu həyata keçirmək üçün “sığorta nişanları” buraxılmalıdır. Sonra sığortalının hesabına yalnız müəyyən şərtlərə cavab verən ExchangeTransactions-ın icrasına imkan verən skript quraşdırılır.

İkiqat xərclərin qarşısını almaq üçün siz istifadəçidən əvvəlcədən (açar, dəyər) = (purchaseTransactionId, sellOrderId) ilə sığortalının hesabına DataTransaction göndərməsini tələb etməli və artıq istifadə edilmiş açarla DataTransactions göndərilməsini qadağan etməlisiniz.

Buna görə də, istifadəçinin sübutlarında sığorta nişanı alışının əməliyyat identifikatoru olmalıdır. Valyuta cütü alış əməliyyatında olduğu kimi olmalıdır. Xərc də sığortanın qiyməti çıxılmaqla satın alınma zamanı müəyyən edilmiş qiymətə bərabər olmalıdır.

Anlaşılır ki, sonradan sığorta hesabı istifadəçidən sığorta tokenlərini aldığı qiymətdən aşağı olmayan qiymətə alır: sığorta hesabı ExchangeTransaction yaradır, istifadəçi sifarişi imzalayır (əməliyyat düzgün başa çatdırılıbsa), sığorta hesabı ikinci sifarişi və bütün əməliyyatı imzalayır və onu blokçeynə göndərir.

Heç bir alış baş vermədikdə, istifadəçi skriptdə təsvir olunan qaydalara uyğun olaraq ExchangeTransaction yarada və əməliyyatı blokçeynə göndərə bilər. Bu yolla istifadəçi sığortalanmış tokenlərin alınmasına sərf etdiyi pulu geri qaytara bilər.

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

Sığorta nişanı, məsələn, üçüncü tərəflərə ötürülməsini qadağan etmək üçün ağıllı bir aktivə çevrilə bilər.

Bu sxem tələb olunan məbləğ toplanmadıqda sahiblərinə qaytarılan kraudfundinq tokenləri üçün də həyata keçirilə bilər.

Əməliyyat vergiləri

Ağıllı müqavilələr, bir neçə növ aktivlə hər bir əməliyyat üçün vergi toplamaq lazım olduğu hallarda da tətbiq edilir. Bu, quraşdırılmış yeni aktiv vasitəsilə edilə bilər sponsorluq smart aktivlərlə əməliyyatlar üçün:

1. Biz istifadəçilərə sabit qiymətə göndəriləcək FeeCoin buraxırıq: 0,01 WAVES = 0,001 FeeCoin.

2. FeeCoin və valyuta məzənnəsi üçün sponsorluq təyin edin: 0,001 WAVES = 0,001 FeeCoin.

3. Ağıllı aktiv üçün aşağıdakı skripti təyin edin:

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
}

İndi kimsə hər dəfə N smart aktivi köçürəndə sizə N/taxDivisor məbləğində FeeCoin verəcək (onu sizdən 10 *N/taxDivisor WAVES-də almaq olar), siz isə mədənçiyə N/taxDivisor WAVES verəcəksiniz. Nəticədə, mənfəətiniz (vergi) 9*N / taxDivisor WAVES olacaq.

Siz həmçinin ağıllı aktiv skripti və MassTransferTransaction istifadə edərək vergitutma həyata keçirə bilərsiniz:

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 və loyallıq proqramları

Cashback, alıcının məhsul və ya xidmətə xərclədiyi məbləğin bir hissəsini geri aldığı loyallıq proqramı növüdür.

Ağıllı hesabdan istifadə edərək bu işi həyata keçirərkən sığorta hadisəsində etdiyimiz kimi sübutları yoxlamalıyıq. İkiqat xərclərin qarşısını almaq üçün istifadəçi cashback almadan əvvəl (açar, dəyər) = (purchaseTransactionId, cashbackTransactionId) ilə DataTransaction göndərməlidir.

Biz həmçinin DataTransaction istifadə edərək mövcud açarlara qadağa qoymalıyıq. cashbackDivisor - cashback payına bölünən vahid. Bunlar. cashback payı 0.1 olarsa, 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)
}

Atom mübadiləsi

Atom svop istifadəçilərə mübadilə köməyi olmadan aktivləri mübadilə etməyə imkan verir. Atom svop ilə, əməliyyatın hər iki iştirakçısından müəyyən bir müddət ərzində bunu təsdiqləmələri tələb olunur.

İştirakçılardan ən azı biri əməliyyat üçün ayrılmış vaxt ərzində əməliyyatın düzgün təsdiqini təqdim etmədikdə, əməliyyat ləğv edilir və mübadilə baş vermir.

Nümunəmizdə aşağıdakı smart hesab skriptindən istifadə edəcəyik:

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övbəti məqalədə opsion, fyuçers və veksellər kimi maliyyə alətlərində smart hesabların istifadəsinə baxacağıq.

Mənbə: www.habr.com

Добавить комментарий