تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

مرحبا بالجميع!

В أولا لقد نظرنا بالتفصيل في كيفية إنشاء dApp (التطبيق اللامركزي) والعمل معه ركوب الأمواج IDE.

دعونا نختبر المفكك قليلاً الآن مثال.

المرحلة 3. اختبار حساب dApp

تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

ما هي المشاكل التي تقفز إليك على الفور مع أليس؟ DAPP الحساب؟
أولا:
قد يرسل Boob and Cooper أموالاً عن طريق الخطأ إلى عنوان dApp باستخدام النظام العادي تحويل المعاملات وبالتالي لن تكون قادرة على الوصول إليها مرة أخرى.

ثانيا:
نحن لا نمنع أليس بأي شكل من الأشكال من سحب الأموال دون موافقة بوب و/أو كوبر. نظرًا لأنه يجب الانتباه للتحقق، فسيتم تنفيذ جميع المعاملات من Alice.

دعونا نصلح المركز الثاني بحظر أليس تحويل المعاملات. دعونا ننشر البرنامج النصي المصحح:
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

نحن نحاول سحب العملات المعدنية من dApp Alice وتوقيعها. نحصل على خطأ:
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

دعونا نحاول الانسحاب عبر السحب:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))

السيناريو يعمل ولقد اكتشفنا النقطة الثانية!

المرحلة 4. إنشاء DAO مع التصويت

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

من السهل جدًا ربط السلاسل، حيث يمكن فصل السلاسل باستخدام الفهارس.
دعونا نجمع سلسلة ونحللها كمثال اختباري ونتحقق من مدى تأثير ذلك على نتيجة المعاملة.
لقد توصلنا إلى حقيقة أن Alice لم تتمكن من التوقيع على معاملة النقل، حيث تم حظر هذه القدرة في @verifier لهذا النوع من المعاملات.

دعونا نتدرب على السلاسل ثم نحل هذه المشكلة.

سلاسل ركوب

الصفقة ممكنة مرة أخرى، ونحن نعرف كيفية العمل مع السلاسل.
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)


في المجمل، لدينا كل ما هو ضروري لكتابة منطق معقد تطبيق داو اللامركزي.

معاملات البيانات

معاملات البيانات:
"الحد الأقصى لحجم المفتاح هو 100 حرف، ويمكن أن يحتوي المفتاح على نقاط ترميز Unicode عشوائية بما في ذلك المسافات والرموز الأخرى غير القابلة للطباعة. يبلغ الحد الأقصى لقيم السلسلة 32,768 بايت والحد الأقصى لعدد الإدخالات الممكنة في معاملة البيانات هو 100. بشكل عام، يبلغ الحد الأقصى لحجم معاملة البيانات حوالي 140 كيلو بايت — للإشارة، تقريبًا نفس طول مسرحية شكسبير "روميو وجولييت" "."

نقوم بإنشاء DAO بالشروط التالية:
لكي تحصل الشركة الناشئة على التمويل عن طريق الاتصال الحصول على الأموال () مطلوب دعم ما لا يقل عن 2 من المشاركين - مستثمري DAO. سحب سيكون من الممكن بالضبط بقدر المجموع المشار إليه التصويت أصحاب DAO.

لنقم بإنشاء 3 أنواع من المفاتيح وإضافة منطق للعمل مع الأرصدة في وظيفتين جديدتين: التصويت وgetFunds:
xx… xx_I ل = المستثمرين، الرصيد المتاح (التصويت، الإيداع، الانسحاب)
xx… xx_sv = الشركات الناشئة، عدد الأصوات (التصويت، getFunds)
xx… xx_sf = الشركات الناشئة، عدد الأصوات (التصويت، getFunds)
xx…xx = عنوان عام (35 حرفًا)

يرجى ملاحظة أننا في التصويت كنا بحاجة إلى تحديث عدة حقول مرة واحدة:

WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),

يتيح لنا WriteSet إنشاء عدة سجلات مرة واحدة في سجل واحد استدعاء المعاملات.

هذا هو ما يبدو عليه تخزين القيمة الأساسية لـ DAO dApp، بعد تجديد Bob وCooper ia-الودائع:
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

لقد تغيرت وظيفة الإيداع لدينا قليلاً:
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

الآن تأتي اللحظة الأكثر أهمية في أنشطة DAO - تصويت للمشاريع التي سيتم تمويلها.

يصوت بوب لصالح مشروع نيلي الذي يتضمن 500000 مويجة:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))

تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

في مخزن البيانات نرى كافة الإدخالات الضرورية لعنوان نيلي:
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)
صوت كوبر أيضًا لصالح مشروع نيلي.
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

دعونا نلقي نظرة على رمز الوظيفة getFunds. يجب على Neli جمع صوتين على الأقل حتى تتمكن من سحب الأموال من DAO.
تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

ستقوم نيلي بسحب نصف المبلغ الموكل إليها:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))

تعلم كتابة عقود Waves الذكية على RIDE وRIDE4DAPPS. الجزء الثاني (DAO - المنظمة اللامركزية المستقلة)

لقد نجحت، أي أن DAO يعمل!

لقد نظرنا في عملية إنشاء DAO باللغة RIDE4DAPPS.
في الأجزاء التالية، سنلقي نظرة فاحصة على إعادة هيكلة التعليمات البرمجية واختبار الحالة.

النسخة الكاملة من الكود في بيئة ركوب الأمواج:

# In this example multiple accounts can deposit their funds to DAO and safely take them back, no one can interfere with this.
# DAO participants can also vote for particular addresses and let them withdraw invested funds then quorum has reached.
# An inner state is maintained as mapping `address=>waves`.
# https://medium.com/waves-lab/waves-announces-funding-for-ride-for-dapps-developers-f724095fdbe1

# You can try this contract by following commands in the IDE (ide.wavesplatform.com)
# Run commands as listed below
# From account #0:
#      deploy()
# From account #1: deposit funds
#      broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))
# From account #2: deposit funds
#      broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))
# From account #1: vote for startup
#      broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
# From account #2: vote for startup
#      broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
# From account #3: get invested funds
#      broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))

{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}

@Callable(i)
func deposit() = {
   let pmt = extract(i.payment)
   if (isDefined(pmt.assetId)) then throw("can hodl waves only at the moment")
   else {
        let currentKey = toBase58String(i.caller.bytes)
        let xxxInvestorBalance = currentKey + "_" + "ib"
        let currentAmount = match getInteger(this, xxxInvestorBalance) {
            case a:Int => a
            case _ => 0
        }
        let newAmount = currentAmount + pmt.amount
        WriteSet([DataEntry(xxxInvestorBalance, newAmount)])
   }
}
@Callable(i)
func withdraw(amount: Int) = {
        let currentKey = toBase58String(i.caller.bytes)
        let xxxInvestorBalance = currentKey + "_" + "ib"
        let currentAmount = match getInteger(this, xxxInvestorBalance) {
            case a:Int => a
            case _ => 0
        }
        let newAmount = currentAmount - amount
     if (amount < 0)
            then throw("Can't withdraw negative amount")
    else if (newAmount < 0)
            then throw("Not enough balance")
            else ScriptResult(
                    WriteSet([DataEntry(xxxInvestorBalance, newAmount)]),
                    TransferSet([ScriptTransfer(i.caller, amount, unit)])
                )
    }
@Callable(i)
func getFunds(amount: Int) = {
        let quorum = 2
        let currentKey = toBase58String(i.caller.bytes)
        let xxxStartupFund = currentKey + "_" + "sf"
        let xxxStartupVotes = currentKey + "_" + "sv"
        let currentAmount = match getInteger(this, xxxStartupFund) {
            case a:Int => a
            case _ => 0
        }
        let totalVotes = match getInteger(this, xxxStartupVotes) {
            case a:Int => a
            case _ => 0
        }
        let newAmount = currentAmount - amount
    if (amount < 0)
            then throw("Can't withdraw negative amount")
    else if (newAmount < 0)
            then throw("Not enough balance")
    else if (totalVotes < quorum)
            then throw("Not enough votes. At least 2 votes required!")
    else ScriptResult(
                    WriteSet([
                        DataEntry(xxxStartupFund, newAmount)
                        ]),
                    TransferSet([ScriptTransfer(i.caller, amount, unit)])
                )
    }
@Callable(i)
func vote(amount: Int, address: String) = {
        let currentKey = toBase58String(i.caller.bytes)
        let xxxInvestorBalance = currentKey + "_" + "ib"
        let xxxStartupFund = address + "_" + "sf"
        let xxxStartupVotes = address + "_" + "sv"
        let currentAmount = match getInteger(this, xxxInvestorBalance) {
            case a:Int => a
            case _ => 0
        }
        let currentVotes = match getInteger(this, xxxStartupVotes) {
            case a:Int => a
            case _ => 0
        }
        let currentFund = match getInteger(this, xxxStartupFund) {
            case a:Int => a
            case _ => 0
        }
    if (amount <= 0)
            then throw("Can't withdraw negative amount")
    else if (amount > currentAmount)
            then throw("Not enough balance")
    else ScriptResult(
                    WriteSet([
                        DataEntry(xxxInvestorBalance, currentAmount - amount),
                        DataEntry(xxxStartupVotes, currentVotes + 1),
                        DataEntry(xxxStartupFund, currentFund + amount)
                        ]),
                    TransferSet([ScriptTransfer(i.caller, amount, unit)])
            )
    }
@Verifier(tx)
func verify() = {
    match tx {
        case t: TransferTransaction =>false
        case _ => true
    }
}

الجزء الأول
الكود على جيثب
ركوب الأمواج IDE
الإعلان عن برنامج المنح

المصدر: www.habr.com

إضافة تعليق