کاربردهای حساب های هوشمند Waves: از حراج تا برنامه های جایزه

کاربردهای حساب های هوشمند Waves: از حراج تا برنامه های جایزه

بلاک چین اغلب تنها با ارزهای رمزنگاری شده مرتبط است، اما حوزه های کاربرد فناوری DLT بسیار گسترده تر است. یکی از نویدبخش ترین زمینه ها برای استفاده از بلاک چین، قرارداد هوشمندی است که به صورت خودکار اجرا می شود و نیازی به اعتماد بین طرفینی که آن را منعقد کرده اند ندارد.

RIDE – زبانی برای قراردادهای هوشمند

Waves یک زبان ویژه برای قراردادهای هوشمند توسعه داده است - RIDE. مستندات کامل آن قرار دارد اینجا. و اینجا - مقاله در مورد این موضوع در هابر

قرارداد RIDE یک محمول است و "درست" یا "نادرست" را به عنوان خروجی برمی گرداند. بر این اساس، تراکنش یا در بلاک چین ثبت می شود یا رد می شود. قرارداد هوشمند به طور کامل انجام شرایط مشخص شده را تضمین می کند. ایجاد تراکنش از طریق قرارداد در 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 های پیچیده.

حال بیایید به مثال‌های خاصی از استفاده از قراردادهای هوشمند در تجارت نگاه کنیم: هنگام انجام حراج‌ها، بیمه و ایجاد برنامه‌های وفاداری.

حراج ها

یکی از شرایط یک مزایده موفق شفافیت است: شرکت کنندگان باید مطمئن باشند که دستکاری پیشنهادها غیرممکن است. این را می توان به لطف بلاک چین به دست آورد، جایی که داده های تغییرناپذیر در مورد همه شرط بندی ها و زمان انجام آنها برای همه شرکت کنندگان در دسترس خواهد بود.

در بلاک چین Waves، پیشنهادات را می توان در وضعیت حساب حراج از طریق DataTransaction ثبت کرد.

همچنین می توانید زمان شروع و پایان حراج را با استفاده از اعداد بلوک تنظیم کنید: فرکانس تولید بلاک در بلاک چین Waves تقریبا برابر است با 60 ثانیه

1. حراج قیمت صعودی انگلیسی

شرکت کنندگان در یک مکان حراج انگلیسی در رقابت با یکدیگر پیشنهاد می دهند. هر شرط جدید باید از شرط قبلی بیشتر باشد. مزایده زمانی به پایان می رسد که هیچ پیشنهاد دهنده ای بیش از آخرین پیشنهاد وجود نداشته باشد. در این صورت بالاترین قیمت پیشنهادی باید مبلغ ذکر شده را ارائه دهد.

یک گزینه حراج نیز وجود دارد که در آن فروشنده حداقل قیمت را برای لات تعیین می کند و قیمت نهایی باید از آن بیشتر باشد. در غیر این صورت، لات فروخته نشده باقی می ماند.

در این مثال، ما با حسابی کار می کنیم که به طور خاص برای حراج ایجاد شده است. مدت حراج 3000 بلوک است و قیمت شروع لات 0,001 WAVES است. یک شرکت‌کننده می‌تواند با ارسال یک 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 توسط بلاک چین پذیرفته نمی شود.

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. حراج "تمام پرداخت"

"همه پرداخت" حراجی است که در آن همه شرکت کنندگان، صرف نظر از اینکه چه کسی برنده لات شده است، پیشنهاد را پرداخت می کند. هر شرکت‌کننده جدید پیشنهادی را پرداخت می‌کند و شرکت‌کننده‌ای که حداکثر پیشنهاد را ارائه می‌کند برنده لات می‌شود.

در مثال ما، هر شرکت کننده در حراج پیشنهادی را از طریق DataTransaction با (کلید، ارزش)* = ("برنده"، آدرس)، ("قیمت"، قیمت) ارائه می دهد. چنین 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)
}

بیمه / تامین مالی جمعی

بیایید وضعیتی را در نظر بگیریم که در آن باید دارایی های کاربران را در برابر ضررهای مالی بیمه کنید. به عنوان مثال، یک کاربر تضمینی می خواهد که در صورت استهلاک یک توکن، بتواند کل مبلغ پرداخت شده برای این توکن ها را پس بگیرد و حاضر است مبلغ معقولی بیمه بپردازد.

برای اجرای این امر، باید "توکن های بیمه" صادر شود. سپس یک اسکریپت روی حساب بیمه‌گذار نصب می‌شود که فقط به آن دسته از ExchangeTransactionهایی که شرایط خاصی را دارا هستند اجازه می‌دهد اجرا شوند.

برای جلوگیری از هزینه مضاعف، باید از کاربر درخواست کنید تا یک DataTransaction را از قبل با (key, value) = (purchaseTransactionId, sellOrderId) به حساب بیمه‌گذار ارسال کند و ارسال DataTransaction با کلیدی که قبلاً استفاده شده است را ممنوع کند.

بنابراین، مدارک کاربر باید حاوی شناسه تراکنش خرید توکن بیمه باشد. جفت ارز باید مانند معامله خرید باشد. هزینه نیز باید برابر با هزینه ثابت در زمان خرید، منهای قیمت بیمه باشد.

قابل درک است که متعاقباً حساب بیمه توکن های بیمه را از کاربر با قیمتی کمتر از قیمتی که او خریداری کرده است خریداری می کند: حساب بیمه یک معامله تبادل ایجاد می کند ، کاربر سفارش را امضا می کند (اگر معامله به درستی انجام شود) حساب بیمه سفارش دوم و کل تراکنش را امضا می کند و به بلاکچین ارسال می کند.

در صورت عدم خرید، کاربر می تواند طبق قوانینی که در اسکریپت توضیح داده شده است، یک ExchangeTransaction ایجاد کرده و تراکنش را به بلاک چین ارسال کند. به این ترتیب کاربر می تواند پولی را که برای خرید توکن های بیمه شده خرج کرده است برگرداند.

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

توکن بیمه می تواند به عنوان دارایی هوشمند تبدیل شود، به عنوان مثال، انتقال آن به اشخاص ثالث ممنوع شود.

این طرح برای توکن های تامین مالی جمعی نیز قابل اجرا است که در صورت عدم جمع آوری مبلغ مورد نیاز به مالکان بازگردانده می شود.

مالیات بر معاملات

قراردادهای هوشمند همچنین در مواردی که نیاز به اخذ مالیات از هر تراکنش با چندین نوع دارایی باشد، قابل اجرا است. این را می توان از طریق یک دارایی جدید با نصب شده انجام داد حمایت برای معاملات با دارایی های هوشمند:

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
}

برنامه های بازگشت نقدی و وفاداری

بازگشت نقدی نوعی برنامه وفاداری است که در آن خریدار بخشی از مبلغی را که برای یک محصول یا خدمات خرج کرده است، پس می گیرد.

هنگام اجرای این مورد با استفاده از حساب هوشمند، باید به همان روشی که در مورد بیمه انجام دادیم، مدارک را بررسی کنیم. برای جلوگیری از هزینه مضاعف، کاربر باید قبل از دریافت وجه نقد، یک DataTransaction با (key, value) = (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)
}

سوآپ اتمی

مبادله اتمی به کاربران اجازه می دهد تا دارایی ها را بدون کمک صرافی مبادله کنند. با سوآپ اتمی، هر دو شرکت کننده در تراکنش ملزم به تایید آن در یک دوره زمانی معین هستند.

اگر حداقل یکی از شرکت کنندگان در مدت زمان تعیین شده برای تراکنش تایید درستی از تراکنش ارائه نکند، معامله لغو می شود و مبادله انجام نمی شود.

در مثال خود، از اسکریپت حساب هوشمند زیر استفاده خواهیم کرد:

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

اضافه کردن نظر