باستخدام Waves Smart Accounts: من المزادات إلى برامج المكافآت

الصورة

غالبًا ما يرتبط Blockchain بالعملات المشفرة فقط ، ولكن نطاق تقنية DLT أوسع بكثير. أحد أكثر المجالات الواعدة لاستخدام blockchain هو عقد ذكي يعمل تلقائيًا ولا يتطلب الثقة بين الأطراف التي أبرمت ذلك.

RIDE - لغة العقود الذكية

قامت Waves بتطوير لغة خاصة للعقود الذكية - RIDE. وثائقها كاملة هنا . وهنا - مقال عن هذا الموضوع عن حبري.

العقد على RIDE هو تقييم حقيقي وإرجاع "صواب" أو "خطأ" في الإخراج. وفقًا لذلك ، تتم كتابة المعاملة إلى blockchain أو رفضها. يضمن العقد الذكي تمامًا الوفاء بالشروط المحددة. توليد المعاملات من عقد في RIDE غير ممكن حاليًا.

اليوم ، هناك نوعان من العقود الذكية للموجات: الحسابات الذكية والأصول الذكية. الحساب الذكي هو حساب مستخدم عادي ، ولكن يتم تعيين برنامج نصي له يتحكم في جميع المعاملات. قد يبدو النص البرمجي للحساب الذكي كما يلي:

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

tx هي المعاملة المجهزة التي نسمح باستخدام آلية مطابقة الأنماط فقط إذا لم تكن معاملة نقل. يتم استخدام مطابقة نمط RIDE للتحقق من نوع المعاملة. في البرنامج النصي للحساب الذكي ، يمكن معالجة جميع أنواع المعاملات الحالية.

أيضًا ، يمكن الإعلان عن المتغيرات في البرنامج النصي ، ويمكن استخدام إنشاءات "if-then-else" وغيرها من الطرق للتحقق الكامل من الشروط. من أجل أن يكون للعقود اكتمال وتعقيد يمكن تكهنهما ، وهو أمر يسهل التنبؤ به قبل بدء العقد ، فإن RIDE لا يحتوي على حلقات ومشغلات مثل القفز.

من بين الميزات الأخرى لحسابات Waves وجود "حالة" ، أي حالة الحساب. يمكن كتابة عدد لا حصر له من أزواج (المفتاح ، القيمة) إلى حالة الحساب باستخدام معاملات البيانات (DataTransaction). علاوة على ذلك ، يمكن معالجة هذه المعلومات من خلال واجهة برمجة تطبيقات REST ومباشرة في العقد الذكي.

يمكن أن تحتوي كل معاملة على مجموعة من الأدلة ، والتي يمكنك من خلالها إدخال توقيع المشارك ، ومعرف المعاملة اللازمة ، وما إلى ذلك.

يتيح لك العمل مع RIDE من خلال IDE رؤية النموذج المترجم للعقد (إذا تم تجميعه) ، وإنشاء حسابات جديدة وتعيين البرامج النصية له ، وكذلك إرسال المعاملات عبر سطر الأوامر.

لدورة كاملة ، بما في ذلك إنشاء حساب وتثبيت عقد ذكي عليه وإرسال المعاملات ، يمكنك أيضًا استخدام المكتبة للتفاعل مع واجهة برمجة تطبيقات REST (على سبيل المثال ، C # و C و Java و JavaScript و Python و Rust و Elixir). لبدء العمل مع IDE ، فقط انقر فوق الزر NEW.

إمكانيات استخدام العقود الذكية واسعة: من حظر المعاملات إلى عناوين معينة ("القائمة السوداء") إلى dApps المعقدة.

الآن دعونا نلقي نظرة على أمثلة محددة لاستخدام العقود الذكية في الأعمال التجارية: أثناء المزادات والتأمين وإنشاء برامج الولاء.

مزادات

أحد الشروط لنجاح المزاد هو الشفافية: يجب على مقدمي العروض التأكد من أنه من المستحيل معالجة العروض. يمكن تحقيق ذلك بفضل blockchain ، حيث ستكون البيانات غير المتغيرة على جميع الرهانات والوقت الذي تم فيها إتاحة جميع المشاركين.

على blockchain Waves ، يمكن تسجيل العطاءات في حالة حساب المزاد عبر DataTransaction.

يمكنك أيضًا ضبط وقت بداية ونهاية المزاد باستخدام أرقام البلوكات: يبلغ تردد إنشاء الكتلة في Wchain blockchain حوالي 60 ثانية.

1. الانجليزية ارتفاع سعر المزاد

المشاركون في المزاد العلني باللغة الإنجليزية ، يتنافسون مع بعضهم البعض. يجب أن يتجاوز كل رهان جديد الرهان السابق. ينتهي المزاد عندما لا يكون هناك استعداد أكثر لتجاوز العرض الأخير. في هذه الحالة ، يجب على أعلى مزايد تقديم المبلغ المعلن.

يوجد أيضًا خيار مزاد يحدد فيه البائع الحد الأدنى لسعر العقد ، ويجب أن يتجاوزه السعر النهائي. خلاف ذلك ، يبقى الكثير غير المباعة.

في هذا المثال ، نحن نعمل مع حساب تم إنشاؤه خصيصًا للمزاد. مدة المزاد هي 3000 قطعة ، والسعر الأولي للوت هو 0.001 WAVES. يمكن للمشارك إجراء رهان عن طريق إرسال DataTransaction مع "السعر" الرئيسي وقيمة عرضه ؛ في أدلة المعاملة ، تحتاج إلى إضافة المفتاح العمومي وتوقيع المرسل.

يجب أن يكون سعر الرهان الجديد أعلى من السعر الحالي لهذا المفتاح ، ويجب أن يكون لدى المشارك على الأقل [new_state + Commission] رموز في الحساب. يجب إدخال عنوان العارض في حقل المرسل في 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 pk = d.proofs[1] let address = addressFromPublicKey(pk) let priceIsBigger = newPrice > currentPrice let fee = 700000 let hasMoney = wavesBalance(address) + fee >= newPrice let correctFields = size(d.data) == 2 && extract(getString(d.data, "sender")) == toBase58String(address.bytes) startHeight <= height && height <= finishHeight && priceIsBigger && hasMoney && correctFields && sigVerify(tx.bodyBytes, tx.proofs[0], tx.proofs[1]) case o : Order => #       let pk = o.proofs[1] let address = addressFromPublicKey(pk) let senderIsWinner = address == addressFromString(extract(getString(this, "sender"))) #,    ,    let correctAssetPair = o.assetPair.amountAsset == token && ! isDefined(o.assetPair.priceAsset) let correctAmount = o.amount == 1 let correctPrice = o.price == extract(getInteger(this, "price")) height > finishHeight && senderIsWinner && correctAssetPair && correctAmount && correctPrice && sigVerify(o.bodyBytes, o.proofs[0], o.proofs[1]) 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")) #       let pk = d.proofs[1] let address = addressFromPublicKey(pk) let correctFields = extract(getString(d.data, "sender")) == toBase58String(address.bytes) && size(d.data) == 2 && newPrice == currentPrice #,         "sender" let noBetsBefore = !isDefined(getInteger(this, "sender")) let fee = 700000 let hasMoney = wavesBalance(address) - fee >= newPrice startHeight <= height && height <= finishHeight && noBetsBefore && hasMoney && correctFields && sigVerify(tx.bodyBytes, tx.proofs[0], tx.proofs[1]) case o : Order => #       let pk = o.proofs[1] let address = addressFromPublicKey(pk) #,           sender let senderIsWinner = address == addressFromString(extract(getString(this, "sender"))) #,  mount   ,   - - waves let correctAssetPair = o.assetPair.amountAsset == token && ! isDefined(o.assetPair.priceAsset) let correctAmount = o.amount == 1 let correctPrice = o.price == extract(getInteger(this, "price")) height > finishHeight && senderIsWinner && correctAssetPair && correctAmount && correctPrice && sigVerify(o.bodyBytes, o.proofs[0], o.proofs[1]) case _ => false } 

3. جميع الأجر المزاد

"All-pay" - مزاد ، يدفع جميع المشاركين فيه العطاء ، بغض النظر عمن يفوز بالعرض. يدفع كل مشارك جديد الرهان ، ويفوز المشارك الذي حقق الحد الأقصى للرهان بالكثير.

في مثالنا ، يقدم كل مشارك بالمزاد عرضًا من خلال DataTransaction باستخدام (key ، value) * = ("الفائز" ، العنوان) ، ("السعر" ، السعر). يتم اعتماد DataTransaction فقط إذا كان لهذا المشارك بالفعل بالفعل TransferTransaction مع توقيعه ومعدله أعلى من جميع السابق. يستمر المزاد حتى الوصول إلى النهاية.

 let startHeight = 1000 let endHeight = 2000 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) } 

التأمين / التمويل الجماعي

فكر في موقف تحتاج فيه إلى تأمين أصول المستخدم من الخسائر المالية. على سبيل المثال ، يريد المستخدم الحصول على ضمان بأنه في حالة انخفاض قيمة الرمز المميز ، سيتمكن من إرجاع المبلغ الكامل المدفوع لهذه الرموز وهو مستعد لدفع مبلغ معقول من التأمين.

لتنفيذ ذلك ، تحتاج إلى إصدار "رموز التأمين". بعد ذلك ، يتم تثبيت البرنامج النصي على حساب حامل الوثيقة الذي يسمح لك بتنفيذ فقط معاملات ExchangeTransactions التي تفي بشروط معينة.

لمنع الإنفاق المزدوج ، تحتاج إلى مطالبة المستخدم بإرسال DataTransaction مسبقًا إلى حساب حامل الوثيقة باستخدام (key ، value) = (purchaseTransactionId، sellOrderId) وحظر إرسال DataTransactions باستخدام المفتاح المستخدم بالفعل.

لذلك ، يجب أن تحتوي أدلة المستخدم على معرف المعاملة عند شراء رمز التأمين. يجب أن يكون زوج العملة هو نفسه كما في عملية الشراء. يجب أن تكون التكلفة مساوية أيضًا للتكلفة المسجلة في وقت الشراء ، مطروحًا منها سعر التأمين.

من المعلوم أن حساب التأمين يسترد لاحقًا رموز التأمين من المستخدم بسعر لا يقل عن السعر الذي اشتراه به: ينشئ حساب التأمين ExchangeTransaction ، ويوقع المستخدم الطلب (في حالة اكتمال المعاملة بشكل صحيح) ، يوقع حساب التأمين على الطلب الثاني ويرسل المعاملة إلى blockchain .

إذا لم يحدث الشراء ، يمكن للمستخدم إنشاء أمر وفقًا للقواعد الموضحة في البرنامج النصي وإرسال المعاملة إلى 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 o : Order => #     ,    if !isDefined(o.proofs[7]) then sigVerify(o.bodyBytes, o.proofs[0], o.senderPublicKey) else #     ,         let purchaseTx = transactionById(o.proofs[7]) let purchaseTxHeight = extract(transactionHeightById(o.proofs[7])) #    match purchaseTx { case purchase : ExchangeTransaction => let correctSender = purchase.sender == o.sender let correctAssetPair = o.assetPair.amountAsset == insuranceToken && purchase.sellOrder.assetPair.amountAsset == insuranceToken && o.assetPair.priceAsset == purchase.sellOrder.assetPair.priceAsset let correctPrice = o.price == purchase.price - insurancePrice && o.amount == purchase.amount let correctHeight = height > purchaseTxHeight + freezePeriod #,   -   ID   let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == o.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 مع (مفتاح ، قيمة) = (purchaseTransactionId ، cashbackTransactionId).

يجب أيضًا حظر المفاتيح الحالية باستخدام DataTransaction. استرداد النقود - وحدة مقسومة على حصة استرداد النقود. أي إذا كانت حصة استرداد النقود 0.1 ، ثم استرداد النقودالمقسم 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 } 

في المقالة التالية ، سننظر في استخدام الحسابات الذكية في الأدوات المالية - مثل الخيارات والعقود الآجلة والسندات.

Source: https://habr.com/ru/post/ar442238/


All Articles