Εφαρμογές έξυπνων λογαριασμών Waves: από δημοπρασίες έως προγράμματα μπόνους

Εφαρμογές έξυπνων λογαριασμών Waves: από δημοπρασίες έως προγράμματα μπόνους

Το blockchain συχνά συνδέεται μόνο με κρυπτονομίσματα, αλλά οι τομείς εφαρμογής της τεχνολογίας DLT είναι πολύ ευρύτεροι. Ένας από τους πιο πολλά υποσχόμενους τομείς για τη χρήση του blockchain είναι ένα έξυπνο συμβόλαιο που εκτελείται αυτόματα και δεν απαιτεί εμπιστοσύνη μεταξύ των μερών που το συνήψαν.

RIDE – μια γλώσσα για έξυπνα συμβόλαια

Η Waves έχει αναπτύξει μια ειδική γλώσσα για έξυπνα συμβόλαια - RIDE. Βρίσκεται η πλήρης τεκμηρίωσή του εδώ. Και εδώ - άρθρο για αυτό το θέμα στο Habr.

Το συμβόλαιο RIDE είναι κατηγόρημα και επιστρέφει "true" ή "false" ως έξοδο. Αντίστοιχα, η συναλλαγή είτε καταγράφεται στο blockchain είτε απορρίπτεται. Το έξυπνο συμβόλαιο εγγυάται πλήρως την εκπλήρωση καθορισμένων προϋποθέσεων. Η δημιουργία συναλλαγών από συμβόλαιο στο RIDE δεν είναι προς το παρόν δυνατή.

Σήμερα υπάρχουν δύο τύποι έξυπνων συμβολαίων Waves: έξυπνοι λογαριασμοί και έξυπνα περιουσιακά στοιχεία. Ένας έξυπνος λογαριασμός είναι ένας κανονικός λογαριασμός χρήστη, αλλά έχει οριστεί ένα σενάριο για αυτόν που ελέγχει όλες τις συναλλαγές. Ένα σενάριο έξυπνου λογαριασμού μπορεί να μοιάζει με αυτό, για παράδειγμα:

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

Το tx είναι μια συναλλαγή υπό επεξεργασία και η οποία επιτρέπουμε τη χρήση του μηχανισμού αντιστοίχισης προτύπων μόνο εάν δεν πρόκειται για συναλλαγή μεταφοράς. Η αντιστοίχιση μοτίβων στο RIDE χρησιμοποιείται για τον έλεγχο του τύπου της συναλλαγής. Όλοι οι υπάρχοντες λογαριασμοί μπορούν να υποβληθούν σε επεξεργασία στο σενάριο έξυπνου λογαριασμού τύπους συναλλαγών.

Το σενάριο μπορεί επίσης να δηλώνει μεταβλητές, να χρησιμοποιεί κατασκευές «if-then-else» και άλλες μεθόδους για τον πλήρη έλεγχο των συνθηκών. Για να διασφαλιστεί ότι τα συμβόλαια έχουν αποδεδειγμένη πληρότητα και πολυπλοκότητα (κόστος) που είναι εύκολο να προβλεφθεί πριν από την έναρξη της εκτέλεσης του συμβολαίου, το RIDE δεν περιέχει βρόχους ή δηλώσεις άλματος.

Άλλα χαρακτηριστικά των λογαριασμών Waves περιλαμβάνουν την παρουσία μιας «κατάστασης», δηλαδή την κατάσταση του λογαριασμού. Μπορείτε να γράψετε έναν άπειρο αριθμό ζευγών (κλειδί, τιμή) στην κατάσταση λογαριασμού χρησιμοποιώντας συναλλαγές δεδομένων (DataTransaction). Αυτές οι πληροφορίες μπορούν στη συνέχεια να υποβληθούν σε επεξεργασία τόσο μέσω του REST API όσο και απευθείας στο έξυπνο συμβόλαιο.

Κάθε συναλλαγή μπορεί να περιέχει μια σειρά αποδεικτικών στοιχείων, στην οποία μπορεί να εισαχθεί η υπογραφή του συμμετέχοντος, το αναγνωριστικό της απαιτούμενης συναλλαγής κ.λπ.

Εργασία με το RIDE μέσω IDE σας επιτρέπει να δείτε τη μεταγλωττισμένη προβολή της σύμβασης (αν έχει μεταγλωττιστεί), να δημιουργήσετε νέους λογαριασμούς και να ορίσετε σενάρια για αυτήν, καθώς και να στείλετε συναλλαγές μέσω της γραμμής εντολών.

Για έναν πλήρη κύκλο, συμπεριλαμβανομένης της δημιουργίας λογαριασμού, της εγκατάστασης ενός έξυπνου συμβολαίου σε αυτόν και της αποστολής συναλλαγών, μπορείτε επίσης να χρησιμοποιήσετε μια βιβλιοθήκη για αλληλεπίδραση με το REST API (για παράδειγμα, C#, C, Java, JavaScript, Python, Rust, Elixir) . Για να ξεκινήσετε να εργάζεστε με το IDE, απλώς κάντε κλικ στο κουμπί NEW.

Οι δυνατότητες χρήσης έξυπνων συμβολαίων είναι ευρείες: από την απαγόρευση συναλλαγών σε συγκεκριμένες διευθύνσεις («μαύρη λίστα») έως πολύπλοκα dApps.

Ας δούμε τώρα συγκεκριμένα παραδείγματα χρήσης έξυπνων συμβολαίων στις επιχειρήσεις: κατά τη διεξαγωγή δημοπρασιών, την ασφάλιση και τη δημιουργία προγραμμάτων επιβράβευσης.

δημοπρασίες

Μία από τις προϋποθέσεις για μια επιτυχημένη δημοπρασία είναι η διαφάνεια: οι συμμετέχοντες πρέπει να είναι σίγουροι ότι είναι αδύνατο να χειραγωγήσουν τις προσφορές. Αυτό μπορεί να επιτευχθεί χάρη στο blockchain, όπου αμετάβλητα δεδομένα για όλα τα στοιχήματα και την ώρα που έγιναν θα είναι διαθέσιμα σε όλους τους συμμετέχοντες.

Στο blockchain Waves, οι προσφορές μπορούν να καταγραφούν στην κατάσταση του λογαριασμού δημοπρασίας μέσω του DataTransaction.

Μπορείτε επίσης να ορίσετε την ώρα έναρξης και λήξης της δημοπρασίας χρησιμοποιώντας αριθμούς μπλοκ: η συχνότητα δημιουργίας μπλοκ στην αλυσίδα μπλοκ Waves είναι περίπου ίση με 60 δευτερόλεπτα.

1. Αγγλική δημοπρασία αύξουσας τιμής

Οι συμμετέχοντες σε μια αγγλική δημοπρασία κάνουν προσφορές ανταγωνιστικά μεταξύ τους. Κάθε νέο στοίχημα πρέπει να υπερβαίνει το προηγούμενο. Η δημοπρασία λήγει όταν δεν υπάρχουν άλλοι πλειοδότες που να υπερβαίνουν την τελευταία προσφορά. Στην περίπτωση αυτή, ο πλειοδότης πρέπει να παράσχει το αναγραφόμενο ποσό.

Υπάρχει επίσης μια επιλογή δημοπρασίας στην οποία ο πωλητής ορίζει μια ελάχιστη τιμή για την παρτίδα και η τελική τιμή πρέπει να την υπερβαίνει. Διαφορετικά, η παρτίδα παραμένει απούλητη.

Σε αυτό το παράδειγμα, εργαζόμαστε με έναν λογαριασμό που δημιουργήθηκε ειδικά για τη δημοπρασία. Η διάρκεια της δημοπρασίας είναι 3000 μπλοκ και η τιμή εκκίνησης της παρτίδας είναι 0,001 ΚΥΜΑΤΑ. Ένας συμμετέχων μπορεί να υποβάλει μια προσφορά στέλνοντας ένα DataTransaction με το κλειδί "τιμή" και την αξία της προσφοράς του.

Η τιμή της νέας προσφοράς πρέπει να είναι υψηλότερη από την τρέχουσα τιμή για αυτό το κλειδί και ο συμμετέχων πρέπει να έχει τουλάχιστον διακριτικά [new_bid + προμήθεια] στον λογαριασμό του. Η διεύθυνση του πλειοδότη πρέπει να καταγράφεται στο πεδίο "αποστολέας" στο DataTransaction και το τρέχον ύψος του μπλοκ προσφοράς πρέπει να βρίσκεται εντός της περιόδου δημοπρασίας.

Εάν στο τέλος της δημοπρασίας ο συμμετέχων έχει ορίσει την υψηλότερη τιμή, μπορεί να στείλει μια ExchangeTransaction για να πληρώσει για την αντίστοιχη παρτίδα στην καθορισμένη τιμή και ζεύγος νομισμάτων.

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. Ολλανδική δημοπρασία φθίνουσας τιμής

Σε μια ολλανδική δημοπρασία, αρχικά προσφέρονται πολλά σε τιμή υψηλότερη από αυτή που είναι διατεθειμένος να πληρώσει ο αγοραστής. Η τιμή μειώνεται βήμα προς βήμα έως ότου ένας από τους συμμετέχοντες συμφωνήσει να αγοράσει την παρτίδα στην τρέχουσα τιμή.

Σε αυτό το παράδειγμα χρησιμοποιούμε τις ίδιες σταθερές όπως στο προηγούμενο, καθώς και το βήμα τιμής όταν μειώνεται το δέλτα. Το σενάριο λογαριασμού ελέγχει εάν ο συμμετέχων είναι πράγματι ο πρώτος που στοιχηματίζει. Διαφορετικά, το DataTransaction δεν γίνεται αποδεκτό από το 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. Δημοπρασία "all-pay"

Το "All-pay" είναι μια δημοπρασία στην οποία όλοι οι συμμετέχοντες πληρώνουν την προσφορά, ανεξάρτητα από το ποιος κερδίζει την παρτίδα. Κάθε νέος συμμετέχων πληρώνει μια προσφορά και ο συμμετέχων που κάνει τη μέγιστη προσφορά κερδίζει την παρτίδα.

Στο παράδειγμά μας, κάθε συμμετέχων στη δημοπρασία υποβάλλει μια προσφορά μέσω DataTransaction με (κλειδί, τιμή)* = ("νικητής", διεύθυνση), ("τιμή", τιμή). Μια τέτοια συναλλαγή δεδομένων εγκρίνεται μόνο εάν αυτός ο συμμετέχων έχει ήδη μια TransferTransaction με την υπογραφή του και η προσφορά του είναι υψηλότερη από όλες τις προηγούμενες. Η δημοπρασία συνεχίζεται μέχρι να φτάσει το endHeight.

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

Ασφάλειες / Crowdfunding

Ας εξετάσουμε μια κατάσταση όπου πρέπει να ασφαλίσετε τα περιουσιακά στοιχεία των χρηστών έναντι οικονομικών ζημιών. Για παράδειγμα, ένας χρήστης θέλει μια εγγύηση ότι εάν ένα κουπόνι υποτιμηθεί, θα μπορεί να πάρει πίσω ολόκληρο το ποσό που καταβλήθηκε για αυτά τα διακριτικά και είναι πρόθυμος να πληρώσει ένα εύλογο ποσό ασφάλισης.

Για να εφαρμοστεί αυτό, πρέπει να εκδοθούν «ασφαλιστικές μάρκες». Στη συνέχεια, εγκαθίσταται ένα σενάριο στον λογαριασμό του αντισυμβαλλομένου, επιτρέποντας την εκτέλεση μόνο εκείνων των ExchangeTransactions που πληρούν ορισμένες προϋποθέσεις.

Για να αποφευχθεί η διπλή δαπάνη, πρέπει να ζητήσετε από τον χρήστη να στείλει εκ των προτέρων μια συναλλαγή δεδομένων στον λογαριασμό του αντισυμβαλλομένου με (κλειδί, αξία) = (purchaseTransactionId, sellOrderId) και να απαγορεύσει την αποστολή DataTransactions με κλειδί που έχει ήδη χρησιμοποιηθεί.

Επομένως, τα αποδεικτικά του χρήστη πρέπει να περιέχουν το αναγνωριστικό συναλλαγής της αγοράς του ασφαλιστικού διακριτικού. Το ζεύγος νομισμάτων πρέπει να είναι το ίδιο όπως στη συναλλαγή αγοράς. Το κόστος πρέπει επίσης να είναι ίσο με αυτό που καθορίστηκε κατά τη στιγμή της αγοράς, μείον την τιμή της ασφάλισης.

Εννοείται ότι στη συνέχεια ο ασφαλιστικός λογαριασμός αγοράζει μάρκες ασφάλισης από τον χρήστη σε τιμή όχι χαμηλότερη από αυτή στην οποία τα αγόρασε: ο ασφαλιστικός λογαριασμός δημιουργεί μια ExchangeTransaction, ο χρήστης υπογράφει την παραγγελία (αν η συναλλαγή έχει ολοκληρωθεί σωστά), ασφαλιστικός λογαριασμός υπογράφει τη δεύτερη παραγγελία και ολόκληρη τη συναλλαγή και τη στέλνει στο blockchain .

Εάν δεν πραγματοποιηθεί αγορά, ο χρήστης μπορεί να δημιουργήσει μια ExchangeTransaction σύμφωνα με τους κανόνες που περιγράφονται στο σενάριο και να στείλει τη συναλλαγή στο blockchain. Με αυτόν τον τρόπο ο χρήστης μπορεί να επιστρέψει τα χρήματα που δαπανήθηκαν για την αγορά ασφαλισμένων κουπονιών.

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

Ένα ασφαλιστικό κουπόνι μπορεί να γίνει έξυπνο περιουσιακό στοιχείο, για παράδειγμα, για να απαγορεύσει τη μεταφορά του σε τρίτους.

Αυτό το σχήμα μπορεί επίσης να εφαρμοστεί για μάρκες crowdfunding, τα οποία επιστρέφονται στους ιδιοκτήτες εάν δεν έχει συγκεντρωθεί το απαιτούμενο ποσό.

Φόροι συναλλαγών

Τα έξυπνα συμβόλαια ισχύουν επίσης σε περιπτώσεις όπου είναι απαραίτητη η είσπραξη φόρου σε κάθε συναλλαγή με διάφορους τύπους περιουσιακών στοιχείων. Αυτό μπορεί να γίνει μέσω ενός νέου στοιχείου με εγκατεστημένο αιγίδα για συναλλαγές με έξυπνα περιουσιακά στοιχεία:

1. Εκδίδουμε FeeCoin, το οποίο θα σταλεί στους χρήστες σε σταθερή τιμή: 0,01 WAVES = 0,001 FeeCoin.

2. Ορίστε χορηγία για FeeCoin και συναλλαγματική ισοτιμία: 0,001 WAVES = 0,001 FeeCoin.

3. Ορίστε το ακόλουθο σενάριο για το έξυπνο στοιχείο:

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 έξυπνα περιουσιακά στοιχεία, θα σας δίνει FeeCoin στο ποσό του N/taxDivisor (το οποίο μπορείτε να αγοράσετε από εσάς στο 10 *N/taxDivisor WAVES) και θα δίνετε στον εξορύκτη N/taxDivisor WAVES. Ως αποτέλεσμα, το κέρδος (φόρος) σας θα είναι 9*N / taxDivisor WAVES.

Μπορείτε επίσης να εκτελέσετε φορολογία χρησιμοποιώντας ένα έξυπνο σενάριο ενεργητικού και 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
}

Προγράμματα επιστροφής χρημάτων και αφοσίωσης

Η επιστροφή μετρητών είναι ένας τύπος προγράμματος αφοσίωσης στο οποίο ο αγοραστής λαμβάνει πίσω μέρος του ποσού που δαπανήθηκε για ένα προϊόν ή μια υπηρεσία.

Κατά την εφαρμογή αυτής της υπόθεσης χρησιμοποιώντας έναν έξυπνο λογαριασμό, πρέπει να ελέγξουμε τα αποδεικτικά στοιχεία με τον ίδιο τρόπο που κάναμε στην περίπτωση ασφάλισης. Για να αποφευχθεί η διπλή δαπάνη, ο χρήστης πρέπει να στείλει μια συναλλαγή δεδομένων με (κλειδί, τιμή) = (purchaseTransactionId, cashbackTransactionId) πριν λάβει επιστροφή μετρητών.

Πρέπει επίσης να θέσουμε απαγόρευση στα υπάρχοντα κλειδιά χρησιμοποιώντας το DataTransaction. cashbackDivisor - μονάδα διαιρούμενη με το μερίδιο επιστροφής μετρητών. Εκείνοι. εάν το μερίδιο επιστροφής μετρητών είναι 0.1, τότε το 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)
}

Ατομική ανταλλαγή

Το Atomic swap επιτρέπει στους χρήστες να ανταλλάσσουν περιουσιακά στοιχεία χωρίς τη βοήθεια ανταλλαγής. Με μια ατομική ανταλλαγή, και οι δύο συμμετέχοντες στη συναλλαγή απαιτείται να την επιβεβαιώσουν εντός ορισμένης χρονικής περιόδου.

Εάν τουλάχιστον ένας από τους συμμετέχοντες δεν παράσχει σωστή επιβεβαίωση της συναλλαγής εντός του χρόνου που έχει οριστεί για τη συναλλαγή, η συναλλαγή ακυρώνεται και η ανταλλαγή δεν πραγματοποιείται.

Στο παράδειγμά μας, θα χρησιμοποιήσουμε το ακόλουθο σενάριο έξυπνου λογαριασμού:

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
}

Στο επόμενο άρθρο θα εξετάσουμε τη χρήση έξυπνων λογαριασμών σε χρηματοοικονομικά μέσα όπως δικαιώματα προαίρεσης, συμβόλαια μελλοντικής εκπλήρωσης και γραμμάτια.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο