Waves akıllı hesaplarının uygulamaları: açık artırmalardan bonus programlarına

Waves akıllı hesaplarının uygulamaları: açık artırmalardan bonus programlarına

Blockchain genellikle yalnızca kripto para birimleriyle ilişkilendirilir ancak DLT teknolojisinin uygulama alanları çok daha geniştir. Blockchain kullanımı için en umut verici alanlardan biri, otomatik olarak yürütülen ve taraflar arasında güven gerektirmeyen akıllı sözleşmelerdir.

RIDE – akıllı sözleşmeler için bir dil

Waves akıllı sözleşmeler için özel bir dil geliştirdi: RIDE. Tam belgeleri bulunmaktadır burada. Ve burada - bu konuyla ilgili makale Habr'da.

RIDE sözleşmesi bir yüklemdir ve çıktı olarak “doğru” veya “yanlış” değerini döndürür. Buna göre işlem ya blok zincirine kaydedilir ya da reddedilir. Akıllı sözleşme, belirtilen koşulların yerine getirilmesini tam olarak garanti eder. RIDE'de bir sözleşmeden işlem oluşturmak şu anda mümkün değildir.

Bugün iki tür Waves akıllı sözleşmesi vardır: akıllı hesaplar ve akıllı varlıklar. Akıllı hesap normal bir kullanıcı hesabıdır, ancak bunun için tüm işlemleri kontrol eden bir komut dosyası ayarlanmıştır. Bir akıllı hesap komut dosyası şöyle görünebilir, örneğin:

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

tx, yalnızca bir aktarım işlemi olmaması durumunda kalıp eşleştirme mekanizmasının kullanılmasına izin verdiğimiz, işlenmekte olan bir işlemdir. RIDE'deki desen eşleştirme, işlem türünü kontrol etmek için kullanılır. Mevcut tüm hesaplar akıllı hesap komut dosyasında işlenebilir işlem türleri.

Komut dosyası ayrıca değişkenleri bildirebilir, koşulları tam olarak kontrol etmek için "if-then-else" yapılarını ve diğer yöntemleri kullanabilir. Sözleşmelerin, sözleşmenin yürütülmesi başlamadan önce tahmin edilmesi kolay, kanıtlanabilir bir bütünlüğe ve karmaşıklığa (maliyet) sahip olmasını sağlamak için RIDE, döngüler veya atlama ifadeleri içermez.

Waves hesaplarının diğer özellikleri arasında bir “durum”un, yani hesabın durumunun varlığı yer alır. Veri işlemlerini (DataTransaction) kullanarak hesap durumuna sonsuz sayıda çift (anahtar, değer) yazabilirsiniz. Bu bilgiler daha sonra hem REST API aracılığıyla hem de doğrudan akıllı sözleşmede işlenebilir.

Her işlem, katılımcının imzasının, gerekli işlemin kimliğinin vb. girilebileceği bir dizi kanıt içerebilir.

RIDE ile çalışma IDE Sözleşmenin derlenmiş görünümünü görmenize (derlenmişse), yeni hesaplar oluşturmanıza ve bunun için komut dosyaları ayarlamanıza ve komut satırı aracılığıyla işlemleri göndermenize olanak tanır.

Hesap oluşturma, hesaba akıllı sözleşme yükleme ve işlemleri gönderme dahil olmak üzere tam bir döngü için REST API (örneğin, C#, C, Java, JavaScript, Python, Rust, Elixir) ile etkileşimde bulunmak için bir kitaplık da kullanabilirsiniz. . IDE ile çalışmaya başlamak için YENİ düğmesine tıklamanız yeterlidir.

Akıllı sözleşmeleri kullanma olanakları geniştir: işlemlerin yasaklanmasından belirli adreslere (“kara liste”) ve karmaşık dApp'lere kadar.

Şimdi akıllı sözleşmelerin iş dünyasında kullanımına ilişkin belirli örneklere bakalım: açık artırmalar gerçekleştirirken, sigorta yaparken ve sadakat programları oluştururken.

Müzayedeler

Başarılı bir açık artırmanın koşullarından biri şeffaflıktır: Katılımcılar, teklifleri manipüle etmenin imkansız olduğundan emin olmalıdır. Bu, tüm bahisler ve bahislerin yapıldığı zaman hakkındaki değişmez verilerin tüm katılımcılara açık olacağı blockchain sayesinde başarılabilir.

Waves blok zincirinde teklifler, DataTransaction aracılığıyla açık artırma hesabı durumuna kaydedilebilir.

Açık artırmanın başlangıç ​​ve bitiş zamanını blok numaralarını kullanarak da ayarlayabilirsiniz: Waves blok zincirinde blok oluşturma sıklığı yaklaşık olarak eşittir 60 saniye.

1. İngilizce artan fiyat açık artırması

Bir İngiliz müzayedesine katılanlar teklifleri birbirleriyle rekabet halinde verirler. Her yeni bahis bir öncekini aşmalıdır. Açık artırma, son teklifi aşacak teklif veren kalmadığında sona erer. Bu durumda en yüksek teklifi verenin belirtilen tutarı sağlaması gerekir.

Ayrıca satıcının lot için bir minimum fiyat belirlediği ve nihai fiyatın bu fiyatı aşması gerektiği bir açık artırma seçeneği de vardır. Aksi halde arsa satılmadan kalır.

Bu örnekte, açık artırma için özel olarak oluşturulmuş bir hesapla çalışıyoruz. Açık artırma süresi 3000 blok olup, lotun başlangıç ​​fiyatı 0,001 DALGA'dır. Bir katılımcı, "fiyat" anahtarını ve teklif değerini içeren bir DataTransaction göndererek teklif verebilir.

Yeni teklifin fiyatı bu anahtarın mevcut fiyatından yüksek olmalı ve katılımcının hesabında en az [new_bid + komisyon] token bulunmalıdır. Teklif verenin adresi DataTransaction'daki "gönderen" alanına kaydedilmeli ve mevcut teklif blok yüksekliği açık artırma dönemi içinde olmalıdır.

Açık artırmanın sonunda katılımcı en yüksek fiyatı belirlediyse, ilgili lot için belirtilen fiyat ve döviz çifti üzerinden ödeme yapmak üzere bir ExchangeTransaction gönderebilir.

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. Hollanda'da azalan fiyatlara ilişkin müzayede

Hollanda'da yapılan bir müzayedede, bir lot başlangıçta alıcının ödemeye razı olduğu fiyattan daha yüksek bir fiyatla teklif edilir. Katılımcılardan biri partiyi mevcut fiyattan satın almayı kabul edene kadar fiyat adım adım azaltılır.

Bu örnekte öncekiyle aynı sabitleri ve delta azaldığında fiyat adımını kullanıyoruz. Hesap komut dosyası, katılımcının gerçekten ilk bahis oynayan kişi olup olmadığını kontrol eder. Aksi halde DataTransaction blockchain tarafından kabul edilmez.

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. Açık artırma “tamamı ödenir”

"Tüm ödeme", lotu kimin kazandığına bakılmaksızın tüm katılımcıların teklifi ödediği bir açık artırmadır. Her yeni katılımcı bir teklif öder ve maksimum teklifi veren katılımcı kurayı kazanır.

Örneğimizde, her açık artırma katılımcısı DataTransaction aracılığıyla (anahtar, değer)* = (“kazanan”, adres),(“fiyat”, fiyat) ile bir teklif verir. Böyle bir Veri İşlemi, yalnızca bu katılımcının halihazırda imzalı bir Transfer İşlemi olması ve teklifinin önceki tüm tekliflerden yüksek olması durumunda onaylanır. Açık artırma endHeight'a ulaşılana kadar devam eder.

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

Sigorta / Kitlesel fonlama

Kullanıcıların varlıklarını mali kayıplara karşı sigortalamanız gereken bir durumu ele alalım. Örneğin bir kullanıcı, bir tokenın değer kaybetmesi durumunda bu tokenlar için ödediği tutarın tamamını geri alabileceğine dair bir garanti istiyor ve makul miktarda sigorta ödemeye hazır.

Bunu uygulamak için “sigorta jetonlarının” çıkarılması gerekiyor. Daha sonra poliçe sahibinin hesabına, yalnızca belirli koşulları karşılayan ExchangeTransaction'ların yürütülmesine izin veren bir komut dosyası yüklenir.

Çifte harcamayı önlemek için, kullanıcıdan poliçe sahibinin hesabına önceden (key, value) = (purchaseTransactionId, sellOrderId) ile bir DataTransaction göndermesini talep etmeniz ve halihazırda kullanılmış bir anahtarla DataTransactions gönderilmesini yasaklamanız gerekir.

Bu nedenle kullanıcının kanıtları, sigorta tokenı satın alımının işlem kimliğini içermelidir. Döviz çifti, satın alma işlemindeki ile aynı olmalıdır. Maliyet ayrıca, satın alma sırasında sabit olan tutardan sigorta bedelinin çıkarılmasıyla elde edilen tutara eşit olmalıdır.

Sigorta hesabının daha sonra kullanıcıdan sigorta tokenlarını satın aldığı fiyattan daha düşük olmayan bir fiyatla satın aldığı anlaşılmaktadır: sigorta hesabı bir ExchangeTransaction oluşturur, kullanıcı siparişi imzalar (işlem doğru bir şekilde tamamlanırsa), sigorta hesabı ikinci emri ve tüm işlemi imzalayıp blockchain'e gönderir.

Herhangi bir satın alma gerçekleşmezse kullanıcı, scriptte açıklanan kurallara göre bir ExchangeTransaction oluşturabilir ve işlemi blockchain'e gönderebilir. Bu şekilde kullanıcı, sigortalı token satın almak için harcadığı parayı iade edebilir.

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

Bir sigorta tokenı, örneğin üçüncü taraflara devredilmesini engellemek için akıllı bir varlık haline getirilebilir.

Bu plan, gerekli miktarın toplanmaması durumunda sahiplerine iade edilen kitlesel fonlama tokenleri için de uygulanabilir.

İşlem vergileri

Akıllı sözleşmeler, çeşitli varlık türleri ile yapılan her işlem üzerinden vergi tahsil edilmesinin gerekli olduğu durumlarda da uygulanabilir. Bu, kurulu yeni bir varlık aracılığıyla yapılabilir. kefillik akıllı varlıklarla yapılan işlemler için:

1. Kullanıcılara sabit bir fiyatla gönderilecek olan FeeCoin'i çıkarıyoruz: 0,01 WAVES = 0,001 FeeCoin.

2. FeeCoin sponsorluğunu ve döviz kurunu ayarlayın: 0,001 WAVES = 0,001 FeeCoin.

3. Akıllı varlık için aşağıdaki komut dosyasını ayarlayın:

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
}

Artık birisi N akıllı varlık transfer ettiğinde, size N/taxDivisor miktarında FeeCoin verecek (bu sizden 10 *N/taxDivisor WAVES karşılığında satın alınabilir) ve siz de madenciye N/taxDivisor WAVES vereceksiniz. Sonuç olarak kârınız (vergi) 9*N / TaxDivisor WAVES olacaktır.

Ayrıca akıllı varlık komut dosyasını ve MassTransferTransaction'ı kullanarak da vergilendirme gerçekleştirebilirsiniz:

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
}

Geri ödeme ve sadakat programları

Cashback, alıcının bir ürün veya hizmete harcadığı tutarın bir kısmını geri aldığı bir tür sadakat programıdır.

Bu vakayı akıllı hesap kullanarak uygularken, sigorta vakasında yaptığımız gibi kanıtları da kontrol etmeliyiz. Çifte harcamayı önlemek için kullanıcının, para iadesi almadan önce (key, value) = (purchaseTransactionId, nakitbackTransactionId) ile bir DataTransaction göndermesi gerekir.

Ayrıca DataTransaction'ı kullanarak mevcut anahtarlara da yasak koymalıyız. CashbackDivisor - birim, nakit iadesi payına bölünür. Onlar. geri ödeme payı 0.1 ise, geri ödemeDivisor 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)
}

Atomik takas

Atomik takas, kullanıcıların bir takasın yardımı olmadan varlıkları takas etmelerine olanak tanır. Atomik takasta, işlemdeki her iki tarafın da belirli bir süre içinde işlemi onaylaması gerekir.

Katılımcılardan en az birinin, işleme ayrılan süre içerisinde işlemin doğru teyidini sağlamaması durumunda işlem iptal edilir ve takas gerçekleşmez.

Örneğimizde aşağıdaki akıllı hesap komut dosyasını kullanacağız:

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
}

Bir sonraki yazımızda akıllı hesapların opsiyon, vadeli işlem ve bono gibi finansal araçlarda kullanımına bakacağız.

Kaynak: habr.com

Yorum ekle