Aplikimi i llogarive inteligjente të Waves dhe aseteve inteligjente në instrumentet financiare

Aplikimi i llogarive inteligjente të Waves dhe aseteve inteligjente në instrumentet financiare

Në të mëparshmen artikull Ne shikuam disa raste të përdorimit të llogarive inteligjente në biznes, duke përfshirë ankandet dhe programet e besnikërisë.
Sot do të flasim se si llogaritë inteligjente dhe aktivet inteligjente mund të përmirësojnë transparencën dhe besueshmërinë e instrumenteve financiare si opsionet, kontratat e së ardhmes dhe faturat.

Alternativë

Një opsion është një kontratë shkëmbimi që i jep blerësit të drejtën për të blerë një aktiv me një çmim të caktuar ose para një date të caktuar, por nuk e detyron atë për ta bërë këtë.

Zbatimi i opsionit mund të jetë si më poshtë:

Ne përdorim një aktiv të zgjuar për vetë opsionet si instrument dhe një llogari inteligjente për pjesëmarrësin që vepron si një shkëmbim dhe lëshon opsione. Pjesëmarrësi i shkëmbimit premton se do të shesë një sasi të caktuar të një aktivi të caktuar me një çmim të shitjes në mes të lartësive të bllokut të fillimit të skadimit dhe të skadimit.

Në kodin e aktivit inteligjent, ne thjesht do të kontrollojmë që ai të tregtohet vetëm midis lartësive të specifikuara dhe nuk do të kontrollojmë asgjë tjetër; do t'ia lëmë të gjithë përgjegjësinë për respektimin e rregullave kodit të pjesëmarrësit në shkëmbim.

Kodi i aktivit inteligjent:

let expirationStart = 100000
let expirationEnd = 101440

match tx {
   case some : ExchangeTransaction | TransferTransaction =>
       height > expirationStart && height <= expirationEnd
   case _ => false
}

Ne do të supozojmë se veprimet zhvillohen si më poshtë: një pjesëmarrës në shkëmbim shet opsione për të blerë një aktiv dhe pjesëmarrësit e tjerë mund t'i përcjellin këto opsione ose t'i tregtojnë ato. Për të ushtruar të drejtën e tij për të blerë, blerësi potencial duhet të transferojë numrin e dëshiruar të opsioneve në llogarinë e shitësit, domethënë pjesëmarrësit në shkëmbim. Më pas, ai shkruan informacion në lidhje me transferimin e përfunduar në llogarinë shtetërore të pjesëmarrësit në shkëmbim dhe vetëm atëherë Transaksioni i Exchange do të mund të vazhdojë sipas kushteve të specifikuara të blerjes dhe shitjes.

Në kodin e llogarisë inteligjente, duhet të sigurohemi që çdo ExchangeTransaction që kalon në të për aktin përfundimtar të blerjes dhe shitjes të plotësojë kushtet e specifikuara dhe pjesëmarrësi të blejë saktësisht numrin e njësive që ka dërguar në llogarinë e pjesëmarrësit në shkëmbim. Blerësi potencial duhet të dërgojë transaksionin e saktë të të dhënave në lidhje me transferimin në mënyrë që pjesëmarrësi i shkëmbimit të shmangë shpenzimet e dyfishta. Në këtë Transaksion të Dhënave, blerësi vendos, sipas çelësit të barabartë me adresën e tij, një vlerë të barabartë me numrin e opsioneve të transferuara në llogarinë e pjesëmarrësit në shkëmbim, domethënë numrin e njësive të aktiveve që ai mund të blejë.

Kodi i llogarisë inteligjente:

#владелец аккаунта дает обязательство продать определенное количество юнитов ассета
#по цене sellPrice между высотами блоков expirationStart и expirationEnd

let expirationStart = 100000
let expirationEnd = 101440
let sellPrice = 10000
let amountAsset = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
let priceAsset = base58'9jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
#ID ассета-опциона
let optionsAsset = base58'7jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
#извлекаем из транзакции адрес отправителя
let this = tx.sender
match tx {
   case dataTx : DataTransaction =>
       #извлекаем количество юнитов из дата-транзакции по ключу (ID пользователя)
       let units = extract(getInteger(dataTx.data, dataTx.data[0].key))

       #извлекаем трансфер-транзакцию опционов из пруфа
       let e = transactionById(dataTx.proofs[2]) #
       match e {
           case transferTx : TransferTransaction =>
               #убеждаемся, что трансфер был на текущий адрес
               (transferTx.recipient == this) &&
               #убеждаемся, что отправитель транзакции написал в качестве ключа свой ID
               dataTx.data[0].key == toBase58String(transferTx.sender.bytes) &&
               sigVerify(dataTx.bodyBytes, dataTx.proofs[0], transferTx.senderPublicKey) &&
               #убеждаемся, что указанное количество юнитов соответствует посланному количеству опционов
               (units == transferTx.amount) &&
               #убеждаемся, что был переведен именно ассет-опцион
               (transferTx.assetId == optionsAsset)              
           case _ => false
       } &&
       size(dataTx.data) == 1 && !isDefined(getInteger(this, dataTx.data[0].key))
       && height > expirationStart && height <= expirationEnd
   case exchangeTx : ExchangeTransaction =>
       #убеждаемся, что итоговый обмен происходит по указанным заранее правилам
       let correctAssetPair = exchangeTx.sellOrder.assetPair.amountAsset == amountAsset &&
                                   exchangeTx.sellOrder.assetPair.priceAsset == priceAsset
       let correctPrice = exchangeTx.sellOrder.price == sellPrice
       #извлекаем дата-транзакцию из пруфа      
       let d = transactionById(exchangeTx.proofs[2])
       match d{
           case dataTx : DataTransaction =>
               let buyOrderSender = dataTx.data[0].key
               toBase58String(exchangeTx.buyOrder.sender.bytes) == buyOrderSender &&
               exchangeTx.amount == extract(getInteger(dataTx.data, buyOrderSender))
           case _ => false
       } &&
       exchangeTx.sellOrder.sender == this &&
       correctAssetPair && correctPrice &&
       height > expirationStart && height <= expirationEnd
   case _ => false
}

E ardhmja në llogaritë inteligjente

Ndryshe nga një opsion, një kontratë e së ardhmes (kontrata e së ardhmes) nuk është një e drejtë, por një detyrim i blerësit për të blerë një aktiv me një çmim të caktuar nga kontrata në një moment të caktuar në të ardhmen.

Në përgjithësi, shkrimi i një të ardhmeje është i ngjashëm me shkrimin e një opsioni. Këtu aseti inteligjent vepron si një e ardhme.

Ju gjithashtu duhet të siguroheni që blerësi dhe shitësi të nënshkruajnë urdhrin e blerjes. E ardhmja është një detyrim që duhet përmbushur në çdo rast. Kjo do të thotë që nëse shitësi ose pjesëmarrësi refuzon detyrimet e tyre, çdo pjesëmarrës në rrjet mund të dërgojë një transaksion, duke ekzekutuar kështu të ardhmen.

Skripti i aktivit inteligjent kontrollon të gjitha Transferimet dhe Transaksionet e Shkëmbimit të aktivit të së ardhmes, duke i miratuar ato vetëm nëse pjesëmarrësi blerës ka krijuar një porosi për një blerje të ardhshme të aktivit të së ardhmes nga pjesëmarrësi i shkëmbimit.

Ky urdhër duhet të jetë i vlefshëm dhe të plotësojë kushtet në të cilat lëshohen kontratat e së ardhmes. Për të vërtetuar një porosi, mund të futni të gjitha fushat e saj në gjendjen e llogarisë së blerësit së bashku me paraqitjen e bajtit të porosisë së nënshkruar dhe më pas të kryeni vërtetimin e jashtëm.

Për momentin, RIDE nuk përmban një funksion vendas për analizimin e bajteve të transaksionit, por përfshin të gjitha mjetet e nevojshme për zbatimin e tij. Prandaj, zhvilluesit mund të përpiqen ta zbatojnë vetë këtë veçori.

Llogaria me shumë nënshkrime / Ruajtje

Një llogari me shumë nënshkrime lejon përdorues të shumtë të menaxhojnë së bashku asetet (për shembull, transaksionet me asetet mund të jenë të mundshme vetëm nëse tre nga katër përdorues kanë nënshkrime). Për të krijuar llogari me shumë nënshkrime në gjuhën RIDE, ne mund të përdorim provat e transaksioneve.

Një llogari me shumë nënshkrime mund të përdoret gjithashtu si një llogari ruajtjeje në të cilën mbahen fondet derisa palët në kontratë të përmbushin detyrimet e tyre.

let alicePubKey  = base58'5AzfA9UfpWVYiwFwvdr77k6LWupSTGLb14b24oVdEpMM'
let bobPubKey    = base58'2KwU4vzdgPmKyf7q354H9kSyX9NZjNiq4qbnH2wi2VDF'
let cooperPubKey = base58'GbrUeGaBfmyFJjSQb9Z8uTCej5GzjXfRDVGJGrmgt5cD'
#выясняем, кто предоставил корректные подписи
let aliceSigned  = if(sigVerify(tx.bodyBytes, tx.proofs[0], alicePubKey)) then 1 else 0
let bobSigned    = if(sigVerify(tx.bodyBytes, tx.proofs[1], bobPubKey)) then 1 else 0
let cooperSigned = if(sigVerify(tx.bodyBytes, tx.proofs[2], cooperPubKey)) then 1 else 0
#суммируем все корректные подписи и проверяем их количество
aliceSigned + bobSigned + cooperSigned >= 2

Regjistri i zgjedhur me shenja (TCR)

Shumë platforma blockchain kanë një problem me asetet toksike. Për shembull, çdo adresë që ka paguar një komision mund të krijojë një aktiv në Waves.

Problemi i mbrojtjes së përdoruesve dhe vetë blockchain nga asetet toksike mund të zgjidhet nga një regjistër i kuruar me token (TCR) i krijuar nga mbajtësit e tokenit.

Për të votuar për një shenjë specifike që do të shtohet në listë, mbajtësi vendos një ofertë të barabartë me pjesën e tij të numrit të përgjithshëm të argumenteve të lëshuara. Një shenjë përfshihet në regjistër nëse shumica e zotëruesve të tij votojnë për të.

Në shembullin tonë, ne e lejojmë përdoruesin të shtojë një shenjë në listë për t'u marrë në konsideratë (gjatë periudhës së "sfidës") duke përdorur çelësin e gjendjes = emri i asetit, vetëm nëse vlera aktuale e numërimit = 0.

Gjithashtu, përdoruesi duhet të ketë një bilanc jo zero të këtij tokeni në portofolin e tij. Më pas vjen periudha e votimit, gjatë së cilës përdoruesi mund të votojë për çdo aktiv në portofolin e tij, por vetëm një herë, duke dhënë një vlerësim nga 1 në 10. Votat e përdoruesve përfaqësohen nga çelësat e formës user_address+assetID.

let asset = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
let addingStartHeight = 1000
let votingStartHeight = 2000
let votingEndHeight = 3000

#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)

#извлекаем адрес из пруфа транзакции
let address = addressFromPublicKey(tx.proofs[1])
match tx {
   case t: DataTransaction =>
       if(height > addingStartHeight)
       then(
           if(height < votingStartHeight)
           then(
               #adding
               #выясняем, есть ли этот ассет у этого адреса
               let hasTokens = assetBalance(address, asset) > 0
               size(t.data) == 1
                     #убеждаемся, что этот ассет еще не был добавлен
                     && !isDefined(getInteger(this, toBase58String(asset)))
                     #убеждаемся, что по ключу-ассету добавляется значение равное 0
                     && extract(getInteger(t.data, toBase58String(asset))) == 0
                     && hasTokens
           )
           else(
               if(height < votingEndHeight)
               then
               (
                   #voting
                   #узнаем текущее количество голосов за данный ассет и задаваемое количество
                   let currentAmount = extract(getInteger(this, toBase58String(asset)))
                   let newAmount = extract(getInteger(t.data, toBase58String(asset)))
                   let betString = toBase58String(address.bytes) + toBase58String(asset)

                   #убеждаемся, что этот адрес еще не голосовал за этот ассет
                   let noBetBefore = !isDefined(getInteger(this, betString))
                   let isBetCorrect = extract(getInteger(t.data, betString)) > 0
                       && extract(getInteger(t.data, betString)) <= 10
                  
                   #убеждаемся, что у голосующего есть необходимые токены
                   let hasTokens = assetBalance(address, asset) > 0
                   #проверяем корректность значений транзакции
                   size(t.data) == 2 && isDefined(getInteger(this, toBase58String(asset)))
                       && newAmount == currentAmount + 1
                       && noBetBefore && isBetCorrect && hasTokens
               )
               else false
           ) && sigVerify(tx.bodyBytes, tx.proofs[0], tx.proofs[1])
       )
       else false
   case _ => false
}

Tarifa e pajtimit

Në këtë shembull, ne do të shikojmë përdorimin e llogarive inteligjente për të bërë pagesa të rregullta për një produkt ose shërbim në intervale të caktuara - "tarifat e abonimit".
Nëse përdoruesi i siguron llogarisë inteligjente (përmes provave të transaksionit) një ID TransferTransaction me shumën e kërkuar të fondeve të transferuara, ai mund të shkruajë {key: adresa, vlera:) në gjendjen e llogarisë i vërtetë}.

Kjo do të thotë që përdoruesi konfirmon abonimin e tij për produktin ose shërbimin. Kur skadon abonimi, çdo përdorues i rrjetit mund të vendosë vlerën pranë çelësit përkatës në gjendje i rremë.

let subscriptionPeriod = 44000
let signature = tx.proofs[0]
let pk = tx.proofs[1]
let requiredAmount = 100000

#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
match tx {
   case d: DataTransaction =>
     #извлекаем дату последнего платежа
     let lastPaymentHeight = extract(getInteger(this, d.data[0].key + "_lastPayment"))
     size(d.data) == 1 && d.data[0].value == "false" && lastPaymentHeight + subscriptionPeriod < height
     ||
     (
       let address = d.data[0].key

       #извлекаем трансфер-транзакцию по ID, указанному в пруфах
       let ttx = transactionById(d.proofs[0])
       
       size(d.data) == 2
           && d.data[0].value == "true"
           && d.data[1].key == address + "_lastPayment"
           && match ttx {
             case purchase : TransferTransaction =>
               d.data[1].value == transactionHeightById(purchase.id)
               && toBase58String(purchase.sender.bytes) == address
               && purchase.amount == requiredAmount
               && purchase.recipient == this
               #убеждаемся, что ассет waves
               && !isDefined(purchase.assetId)
         case _ => false
       }
     )
   case _ => false
}

Votoni

Llogaritë inteligjente mund të përdoren për të zbatuar votimin në blockchain. Një shembull do të ishte votimi për raportin e ambasadorit më të mirë brenda programit të ambasadorit. Gjendja e llogarisë përdoret si një platformë për regjistrimin e votave për një opsion të caktuar.

Në këtë shembull, lejohen të votojnë vetëm ata që kanë blerë tokena të veçantë "votimi". Pjesëmarrësi dërgon një DataTransaction paraprakisht me çiftin (çelës, vlerë) = (purchaseTransactionId, buyTransactionId). Vendosja e një vlere tjetër për këtë çelës është e ndaluar. Duke përdorur adresën tuaj dhe opsionin e votimit, mund të vendosni Data Entry vetëm një herë. Votimi është i mundur vetëm gjatë periudhës së caktuar.

let asset = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
let address = addressFromPublicKey(tx.proofs[1])
let votingStartHeight = 2000
let votingEndHeight = 3000

#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
 match tx {
   case t: DataTransaction =>
     (height > votingStartHeight && height < votingEndHeight) &&
     #убеждаемся, что у транзакции правильная подпись
     sigVerify(tx.bodyBytes, tx.proofs[0], tx.proofs[1]) &&

     #проверяем, что пользователь отдает свой голос напротив своего адреса
     if (t.data[0].key == toBase58String(address.bytes))
     then (
       #извлекаем транзакцию перевод голосовательного токена из пруфов
       let purchaseTx = transactionById(t.proofs[7])
       
       match purchaseTx {
         case purchase : TransferTransaction =>
           let correctSender = purchase.sender == t.sender
           let correctAsset = purchase.assetId == asset
           let correctPrice = purchase.amount == 1
           let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == t.id
           correctSender && correctAsset && correctPrice && correctProof
         case _ => false
       }
     )
     else
         size(t.data) == 1 && !isDefined(getBinary(this, t.data[0].key))
   case _ => false
}

Kambial

Një kambial është një detyrim me shkrim që kërkon që njëra palë t'i paguajë tjetrës një shumë të caktuar sipas kërkesës ose në një datë të paracaktuar.

Në shembullin tonë, ne përdorim një llogari inteligjente, data e skadimit të së cilës korrespondon me datën e pagesës së faturës.

let expiration = 100000
let amount = 10
let asset =  base58'9jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
  
let Bob = Address(base58'3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8')
let Alice = Address(base58'3PNX6XwMeEXaaP1rf5MCk8weYeF7z2vJZBg')
  
match tx {
    case t: TransferTransaction =>
        (t.assetId == asset)&&      
        (t.amount == amount)&&       
        (t.sender == Bob)&&
        (t.recipient == Alice)&&
        (sigVerify(t.bodyBytes, t.proofs[0], t.senderPublicKey))&&
        (height >= expiration)
    case _ => false
}

depozitë

Depozita është vendosja e fondeve në një bankë në kushte të caktuara (afat, interes).
Në shembullin tonë, funksioni i një banke kryhet nga një llogari inteligjente. Pas një numri të caktuar blloqesh, që korrespondon me periudhën e depozitimit, përdoruesi mund t'i kthejë paratë e tij me interes. Skripti specifikon lartësinë e bllokut (finalHeight), pasi të arrijë, përdoruesi mund të tërheqë para nga llogaria.

Lartësia Njësia - numri i blloqeve në një njësi të kohës (për shembull, muaji, viti, etj.). Fillimisht kontrollojmë për një hyrje me çiftin (çelës, vlerë) = (initialTransferTransaction, futureDataTransaction). Më pas, përdoruesi duhet të paraqesë një TransferTransaksion me informacionin e saktë në lidhje me shumën e depozitës dhe interesin e përllogaritur për periudhën e depozitimit. Ky informacion kontrollohet kundrejt TransferTransaksionit origjinal, i cili gjendet në provën aktuale të TransferTransaction. DepozitaDivisor është numri i kundërt i pjesës së depozitës (nëse depozita pranohet me 10%, pjesa e depozitës është 0,1 dhe Devisor Devisor = 1/0,1 = 10).

let this = extract(tx.sender)
let depositDivisor = 10
let heightUnit = 1000
let finalHeight = 100000
 match tx {
   case e : TransferTransaction =>
     #извлекаем высоту транзакции по ID транзакции в седьмом пруфе  
     let depositHeight = extract(transactionHeightById(e.proofs[7]))

     #извлекаем транзакцию депозита
     let purchaseTx = transactionById(e.proofs[7])    
     match purchaseTx {
       case deposit : TransferTransaction =>
         let correctSender = deposit.sender == e.sender
         #убеждаемся, что пользователь переводит себе корректную сумму депозита + проценты
         let correctAmount = deposit.amount + deposit.amount / depositDivisor * (height - depositHeight) / heightUnit == e.amount
         let correctProof = extract(getBinary(this, toBase58String(deposit.id))) == e.id
         correctSender && correctProof && correctAmount
       case _ => false
     }
     && finalHeight <= height 
 case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}

Në artikullin e tretë dhe të fundit të kësaj serie, ne do të shikojmë më shumë përdorime të aktiveve inteligjente, duke përfshirë ngrirjen dhe kufizimin e transaksioneve për adresa specifike.

Burimi: www.habr.com

Bleni një host të besueshëm për faqet me mbrojtje DDoS, serverë VPS VDS 🔥 Bleni hosting të besueshëm të faqeve të internetit me mbrojtje DDoS, servera VPS VDS | ProHoster