کاربرد حساب های هوشمند Waves و دارایی های هوشمند در ابزارهای مالی

کاربرد حساب های هوشمند Waves و دارایی های هوشمند در ابزارهای مالی

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

انتخاب

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

اجرای گزینه می تواند به صورت زیر باشد:

ما از یک دارایی هوشمند برای خود گزینه ها به عنوان ابزار و یک حساب هوشمند برای شرکت کننده ای استفاده می کنیم که به عنوان یک مبادله عمل می کند و گزینه ها را صادر می کند. شرکت‌کننده مبادله قول می‌دهد که مقدار معینی از یک دارایی را با قیمت sellPrice بین ارتفاع بلوک expirationStart و ExpirationEnd بفروشد.

در کد دارایی هوشمند به سادگی بررسی می‌کنیم که فقط بین ارتفاع‌های تعیین‌شده معامله شود و چیز دیگری بررسی نمی‌کنیم؛ تمامی مسئولیت رعایت قوانین را به کد شرکت‌کننده بورس واگذار می‌کنیم.

کد دارایی هوشمند:

let expirationStart = 100000
let expirationEnd = 101440

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

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

در کد حساب هوشمند باید اطمینان حاصل کنیم که هر ExchangeTransactionی که برای خرید و فروش نهایی از آن عبور می کند شرایط مشخص شده را داشته باشد و شرکت کننده دقیقاً به تعداد واحدهایی که به حساب شرکت کننده بورس ارسال کرده است خریداری کند. خریدار بالقوه باید DataTransaction صحیح را در مورد انتقال ارسال کند تا شرکت کننده مبادله بتواند از هزینه مضاعف جلوگیری کند. در این DataTransaction، خریدار با توجه به کلید برابر با آدرس خود، مقداری معادل تعداد گزینه های انتقال یافته به حساب شرکت کننده بورس، یعنی تعداد واحدهای دارایی که می تواند خریداری کند، قرار می دهد.

کد حساب هوشمند:

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

آتی در حساب های هوشمند

برخلاف اختیار معامله، قرارداد آتی (قرارداد آتی) یک حق نیست، بلکه تعهد خریدار برای خرید دارایی به قیمتی است که قرارداد در نقطه معینی در آینده تعیین می کند.

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

همچنین باید مطمئن شوید که هم خریدار و هم فروشنده سفارش خرید را امضا می کنند. آینده تعهدی است که در هر صورت باید انجام شود. این بدان معنی است که اگر فروشنده یا شرکت کننده تعهدات خود را رد کند، هر شرکت کننده در شبکه می تواند تراکنش را ارسال کند و در نتیجه آینده را اجرا کند.

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

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

در حال حاضر، RIDE دارای یک تابع بومی برای تجزیه بایت های تراکنش نیست، بلکه شامل تمام ابزارهای لازم برای اجرای آن است. بنابراین، توسعه دهندگان می توانند سعی کنند این ویژگی را خودشان پیاده سازی کنند.

حساب چند امضایی / سپردن

یک حساب چند امضایی به چندین کاربر اجازه می دهد تا به طور مشترک دارایی ها را مدیریت کنند (به عنوان مثال، تراکنش با دارایی ها ممکن است تنها در صورتی امکان پذیر باشد که از هر چهار کاربر سه کاربر امضا داشته باشند). برای ایجاد حساب های چند امضایی در زبان RIDE، می توانیم از اثبات تراکنش ها استفاده کنیم.

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

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

رجیستری دارای توکن (TCR)

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

مشکل محافظت از کاربران و خود بلاک چین در برابر دارایی‌های سمی را می‌توان با یک رجیستری توکن سرپرست (TCR) که توسط دارندگان توکن ایجاد می‌شود، حل کرد.

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

در مثال ما، به کاربر اجازه می‌دهیم تا با استفاده از کلید حالت = نام دارایی، یک نشانه به لیست برای بررسی (در طول دوره چالش) اضافه کند، تنها در صورتی که مقدار فعلی تعداد = 0 باشد.

همچنین کاربر باید موجودی غیر صفر این توکن را در کیف پول خود داشته باشد. سپس دوره رای گیری فرا می رسد که در طی آن کاربر می تواند به هر دارایی در کیف پول خود رای دهد، اما تنها یک بار، و امتیازی از 1 تا 10 می دهد. آرای کاربر با کلیدهای فرم 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
}

هزینه اشتراک

در این مثال، ما به استفاده از حساب‌های هوشمند برای پرداخت‌های منظم برای یک محصول یا خدمات در فواصل زمانی مشخص - «هزینه اشتراک» نگاه خواهیم کرد.
اگر کاربر حساب هوشمند (از طریق اثبات تراکنش) را با شناسه TransferTransaction به همراه مقدار مورد نیاز وجه انتقالی ارائه کند، می‌تواند {key: آدرس، ارزش:) را به وضعیت حساب بنویسد. درست}.

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

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
}

رأی دادن

از حساب های هوشمند می توان برای اجرای رأی گیری در بلاک چین استفاده کرد. یک مثال می تواند رای دادن به بهترین گزارش سفیر در برنامه سفیر باشد. وضعیت حساب به عنوان بستری برای ثبت آرا برای یک گزینه خاص استفاده می شود.

در این مثال، تنها کسانی مجاز به رأی دادن هستند که توکن‌های ویژه «رای دادن» را خریداری کرده‌اند. شرکت‌کننده یک DataTransaction را از قبل با جفت (کلید، مقدار) = (purchaseTransactionId، buyTransactionId) ارسال می‌کند. تنظیم مقدار دیگری برای این کلید ممنوع است. با استفاده از آدرس و گزینه رای خود، می توانید DataEntry را فقط یک بار تنظیم کنید. رای گیری فقط در مدت زمان مشخص شده امکان پذیر است.

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
}

برات

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

در مثال ما از یک حساب هوشمند استفاده می کنیم که تاریخ انقضای آن با تاریخ پرداخت صورتحساب مطابقت دارد.

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
}

سپرده

سپرده گذاری عبارت است از قرار دادن وجوه در یک بانک تحت شرایط معین (مدت، سود).
در مثال ما، عملکرد یک بانک توسط یک حساب هوشمند انجام می شود. پس از تعداد مشخصی بلوک که مربوط به دوره سپرده گذاری است، کاربر می تواند پول خود را با بهره برگرداند. اسکریپت ارتفاع بلوک (finalHeight) را مشخص می کند که پس از رسیدن به آن کاربر می تواند پول را از حساب برداشت کند.

ارتفاع واحد - تعداد بلوک ها در یک واحد زمان (به عنوان مثال ماه، سال و غیره). ابتدا یک ورودی با جفت (کلید، مقدار) = (initialTransferTransaction، futureDataTransaction) را بررسی می کنیم. سپس کاربر باید یک TransferTransaction را با اطلاعات صحیح در مورد مبلغ سپرده و سود تعلق گرفته برای دوره سپرده ارسال کند. این اطلاعات در برابر TransferTransaction اصلی، که در گواهی TransferTransaction فعلی موجود است، بررسی می شود. depozitDivisor عدد معکوس سهم سپرده است (اگر سپرده با 10% پذیرفته شود، سهم سپرده 0,1 است، و 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)
}

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

منبع: www.habr.com

خرید هاست قابل اعتماد برای سایت های دارای حفاظت DDoS، سرورهای VPS VDS 🔥 خرید هاستینگ معتبر با محافظت در برابر حملات DDoS، سرورهای VPS و VDS | ProHoster