Anvendelse af Waves smartkonti og smarte aktiver i finansielle instrumenter

Anvendelse af Waves smartkonti og smarte aktiver i finansielle instrumenter

I det foregående artiklen Vi har set på flere tilfælde af brug af smarte konti i erhvervslivet – herunder auktioner og loyalitetsprogrammer.
I dag vil vi tale om, hvordan smarte konti og smarte aktiver kan forbedre gennemsigtigheden og pålideligheden af ​​finansielle instrumenter såsom optioner, futures og regninger.

Option

En option er en byttekontrakt, der giver køberen ret til at købe et aktiv til en bestemt pris eller før en bestemt dato, men som ikke forpligter ham til at gøre det.

Implementeringen af ​​muligheden kan være som følger:

Vi bruger et smart aktiv til selve optionerne som et instrument og en smart konto for deltageren, der fungerer som børs og udsteder optioner. Børsdeltageren lover, at han vil sælge en vis mængde af et bestemt aktiv til en salgspris mellem udløbsstart- og udløbsslut-blokhøjderne).

I den smarte aktivkode vil vi blot kontrollere, at den kun handles mellem de angivne højder, og vil ikke kontrollere noget andet, vi overlader alt ansvar for overholdelse af reglerne til børsdeltagerens kode.

Smart aktivkode:

let expirationStart = 100000
let expirationEnd = 101440

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

Vi vil antage, at handlingerne finder sted som følger: en børsdeltager sælger optioner for at købe et aktiv, og andre deltagere kan videresende disse optioner eller handle dem. For at udnytte sin ret til at købe skal den potentielle køber overføre det ønskede antal optioner til sælgerens konto, det vil sige byttedeltageren. Dernæst skriver han information om den gennemførte overførsel til udvekslingsdeltagerens statskonto, og først derefter vil ExchangeTransactionen kunne fortsætte i henhold til de angivne betingelser for køb og salg.

I den smarte kontokode skal vi sikre os, at enhver ExchangeTransaction, der passerer gennem den for den endelige købs- og salgshandling, opfylder de angivne betingelser, og deltageren køber nøjagtigt det antal enheder, som han sendte til børsdeltagerens konto. Den potentielle køber skal sende den korrekte DataTransaktion om overførslen, således at byttedeltageren kan undgå dobbeltforbrug. I denne DataTransaction sætter køberen, ifølge nøglen svarende til hans adresse, en værdi svarende til antallet af optioner, der er overført til kontoen for børsdeltageren, det vil sige antallet af aktivenheder, som han kan købe.

Smart kontokode:

#владелец аккаунта дает обязательство продать определенное количество юнитов ассета
#по цене 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
}

Futures på smarte konti

I modsætning til en option er en futures (futures-kontrakt) ikke en rettighed, men en forpligtelse for køberen til at købe et aktiv til en pris fastsat af kontrakten på et bestemt tidspunkt i fremtiden.

Generelt svarer det at skrive en fremtid til at skrive en option. Her fungerer det smarte aktiv som en fremtid.

Du skal også sikre dig, at både køber og sælger underskriver købsordren. En fremtid er en forpligtelse, der skal opfyldes under alle omstændigheder. Det betyder, at hvis sælgeren eller deltageren nægter deres forpligtelser, kan enhver deltager i netværket sende en transaktion og dermed eksekvere fremtiden.

Det smarte aktiv-script styrer alle Overførselstransaktioner og Udvekslingstransaktioner af futures-aktivet og godkender dem kun, hvis køberdeltageren har oprettet en ordre for det fremtidige køb af futures-aktivet fra børsdeltageren.

Denne ordre skal være gyldig og opfylde de betingelser, hvorunder futures udstedes. For at validere en ordre kan du indtaste alle dens felter i tilstanden for køberens konto sammen med byte-repræsentationen af ​​den signerede ordre og derefter udføre ekstern validering.

I øjeblikket indeholder RIDE ikke en indbygget funktion til at parse transaktionsbytes, men inkluderer alle de værktøjer, der er nødvendige for dens implementering. Derfor kan udviklere selv prøve at implementere denne funktion.

Multi-signatur konto / Escrow

En multisignaturkonto giver flere brugere mulighed for i fællesskab at administrere aktiver (for eksempel kan transaktioner med aktiver kun være mulige, hvis tre ud af fire brugere har signaturer). For at oprette multisignaturkonti på RIDE-sproget kan vi bruge transaktionsbeviser.

En multisignaturkonto kan også bruges som en spærret konto, hvor midler opbevares, indtil kontraktens parter opfylder deres forpligtelser.

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

Token-kurateret register (TCR)

Mange blockchain-platforme har et problem med giftige aktiver. For eksempel kan enhver adresse, der har betalt en provision, oprette et aktiv på Waves.

Problemet med at beskytte brugere og selve blockchainen mod giftige aktiver kan løses af et token-kurateret register (TCR) genereret af token-indehavere.

For at stemme for, at en bestemt brik skal tilføjes til listen, afgiver indehaveren et bud svarende til hans andel af det samlede antal udstedte poletter. Et token er inkluderet i registret, hvis et flertal af dets indehavere stemmer for det.

I vores eksempel tillader vi brugeren at tilføje et token til listen til overvejelse (i "udfordringsperioden") ved hjælp af tilstandsnøglen = aktivnavn, hvis den aktuelle værdi af tæller = 0.

Brugeren skal også have en saldo på ikke-nul af dette token i sin pung. Derefter kommer afstemningsperioden, hvor brugeren kan stemme på hvert aktiv i sin pung, men kun én gang, hvilket giver en vurdering fra 1 til 10. Brugerstemmer repræsenteres af nøgler på formen 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
}

Abonnementsgebyr

I dette eksempel vil vi se på brugen af ​​smarte konti til at foretage regelmæssige betalinger for et produkt eller en tjeneste med bestemte intervaller - "abonnementsgebyrer".
Hvis brugeren forsyner smartkontoen (gennem transaktionsbeviser) med et TransferTransaction ID med det nødvendige beløb af overførte midler, kan han skrive {nøgle: adresse, værdi:) til kontostatus sand}.

Dette vil betyde, at brugeren bekræfter sit abonnement på produktet eller tjenesten. Når abonnementet udløber, kan enhver netværksbruger indstille værdien modsat den tilsvarende nøgle i tilstanden falsk.

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
}

stemme

Smart-konti kan bruges til at implementere afstemning på blockchain. Et eksempel kunne være at stemme på den bedste ambassadørrapport inden for ambassadørprogrammet. Kontotilstanden bruges som en platform til registrering af stemmer for en bestemt mulighed.

I dette eksempel er det kun dem, der har købt særlige "stemme"-tokens, der har lov til at stemme. Deltageren sender en DataTransaction på forhånd med parret (nøgle, værdi) = (purchaseTransactionId, buyTransactionId). Det er forbudt at indstille en anden værdi for denne nøgle. Ved at bruge din adresse og stemmemulighed kan du kun indstille DataEntry én gang. Det er kun muligt at stemme i den angivne periode.

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
}

veksel

Et gældsbrev er en skriftlig forpligtelse, der pålægger en part at betale en anden et fast beløb på opfordring eller på en forudbestemt dato.

I vores eksempel bruger vi en smart-konto, hvis udløbsdato svarer til regningens betalingsdato.

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
}

Depositum

Indskud er placering af midler i en bank under visse betingelser (løbetid, renter).
I vores eksempel udføres en banks funktion af en smart konto. Efter et vist antal blokeringer, som svarer til indbetalingsperioden, kan brugeren returnere sine penge med renter. Scriptet specificerer blokhøjden (finalHeight), efter at have nået hvilken brugeren kan hæve penge fra kontoen.

heightUnit - antallet af blokke i en tidsenhed (for eksempel måned, år osv.). Først tjekker vi for en post med parret (nøgle, værdi) = (initialTransferTransaction, futureDataTransaction). Brugeren skal derefter indsende en Overførselstransaktion med de korrekte oplysninger om indbetalingsbeløbet og de påløbne renter for indbetalingsperioden. Disse oplysninger kontrolleres i forhold til den originale TransferTransaction, som er indeholdt i det aktuelle TransferTransaction bevis. depositDivisor er det omvendte tal på indskudsandelen (hvis indbetalingen accepteres ved 10 %, er indskudsandelen 0,1, og depositDevisor = 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)
}

I den tredje og sidste artikel i denne serie vil vi se på flere anvendelser af smarte aktiver, herunder frysning og begrænsning af transaktioner for specifikke adresser.

Kilde: www.habr.com

Køb pålidelig hosting til websteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster