เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

Hello!

В ครั้งแรก ส่วนหนึ่ง เราได้ตรวจสอบรายละเอียดวิธีการสร้างและทำงานกับ dApp (แอปพลิเคชันแบบกระจายอำนาจ) ใน เวฟ ไรด์ ไอดี.

ตอนนี้เรามาทดสอบการถอดประกอบกันเล็กน้อย ตัวอย่าง.

ขั้นตอนที่ 3 ทดสอบบัญชี dApp

เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

ปัญหาอะไรรีบไปหาเสียงกับอลิซทันที Dapp บัญชี?
ประการแรก:
Boob และ Cooper อาจส่งเงินไปยังที่อยู่ dApp โดยไม่ตั้งใจโดยใช้ที่อยู่ปกติ โอน การทำธุรกรรมและจะไม่สามารถเข้าถึงได้กลับ

ประการที่สอง:
เราไม่ได้จำกัด Alice จากการถอนเงินโดยไม่ได้รับความยินยอมจาก Boob และ/หรือ Cooper แต่อย่างใด เนื่องจากให้ความสนใจกับการตรวจสอบ ธุรกรรมทั้งหมดจาก Alice จะถูกดำเนินการ

มาแก้ไข 2 โดยห้ามอลิซ โอน ธุรกรรม ปรับใช้สคริปต์ที่แก้ไขแล้ว:
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

เรากำลังพยายามถอนเหรียญด้วย dApp Alice และลายเซ็นของเธอ เราได้รับข้อผิดพลาด:
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

กำลังพยายามถอนผ่านการถอน:

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

สคริปต์ใช้งานได้และเราพบจุดที่ 2 แล้ว!

ขั้นตอนที่ 4 สร้าง DAO ด้วยการลงคะแนน

น่าเสียดายที่ภาษา RIDE ยังไม่มีความสามารถในการทำงานกับคอลเลกชัน (พจนานุกรม พจนานุกรม ตัววนซ้ำ ตัวลดขนาด ฯลฯ) อย่างไรก็ตาม สำหรับการดำเนินการใด ๆ กับคอลเลกชันแบบแบน คีย์ - ค่า เราสามารถออกแบบระบบการทำงานกับสตริงตามลำดับด้วยคีย์และการถอดรหัส

สตริงนั้นเชื่อมได้ง่ายมาก สตริงสามารถคั่นด้วยดัชนี
มารวบรวมและแยกวิเคราะห์สตริงเป็นกรณีทดสอบ และตรวจสอบว่าสิ่งนี้จะส่งผลต่อผลลัพธ์ของธุรกรรมอย่างไร
เราตัดสินจากข้อเท็จจริงที่ว่า Alice ไม่สามารถลงนามในธุรกรรม Transfer เนื่องจากความเป็นไปได้นี้ถูกบล็อกใน @verifier สำหรับธุรกรรมประเภทนี้

ลองฝึกกับสตริงแล้วแก้ไขปัญหานี้

RIDE สตริง

ธุรกรรมเป็นไปได้อีกครั้ง เรารู้วิธีทำงานกับสตริง
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)


โดยรวมแล้ว เรามีทุกสิ่งที่คุณต้องการในการเขียนตรรกะที่ซับซ้อน DAO ดีแอพ.

ธุรกรรมข้อมูล

การทำธุรกรรมข้อมูล:
“ขนาดสูงสุดสำหรับคีย์คือ 100 อักขระ และคีย์สามารถมีจุดรหัส Unicode ตามอำเภอใจ รวมถึงช่องว่างและสัญลักษณ์อื่น ๆ ที่ไม่สามารถพิมพ์ได้ ค่าสตริงมีขีดจำกัดที่ 32,768 ไบต์ และจำนวนสูงสุดของรายการที่เป็นไปได้ในการทำธุรกรรมข้อมูลคือ 100 รายการ โดยรวมแล้ว ขนาดสูงสุดของธุรกรรมข้อมูลคือประมาณ 140kb สำหรับการอ้างอิง เกือบจะเท่ากับความยาวของบทละคร 'โรมิโอและจูเลียต' ของเชคสเปียร์ '.”

เราสร้าง DAO ด้วยเงื่อนไขต่อไปนี้:
เพื่อให้สตาร์ทอัพได้ทุนโทร รับเงินทุน() การสนับสนุนจากผู้เข้าร่วมอย่างน้อย 2 คน - จำเป็นต้องมีนักลงทุนของ DAO ถอน มันจะเป็นไปได้เท่าที่ผลรวมที่ระบุไว้ การลงคะแนนเสียง เจ้าของ DAO

มาสร้างคีย์ 3 ประเภทและเพิ่มตรรกะสำหรับการทำงานกับเครื่องชั่งใน 2 ฟังก์ชันใหม่ โหวตและรับทุน:
xx…xx_ia = นักลงทุน ยอดเงินที่มีอยู่ (โหวต ฝาก ถอน)
xx…xx_sv = สตาร์ทอัพ จำนวนโหวต (โหวตรับเงิน)
xx…xx_sf = สตาร์ทอัพ จำนวนโหวต (โหวตรับเงิน)
xx…xx = ที่อยู่สาธารณะ (35 ตัวอักษร)

ประกาศในการโหวต เราจำเป็นต้องอัปเดตหลายฟิลด์พร้อมกัน:

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

WriteSet ช่วยให้เราสามารถสร้างบันทึกหลายรายการพร้อมกันภายในชุดเดียว เรียกใช้สคริปต์ ธุรกรรม

นี่คือลักษณะของที่เก็บคีย์-ค่าของ DAO dApp หลังจากที่ Bob และ Cooper เติมเต็ม ia- เงินฝาก:
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

ฟังก์ชั่นการฝากของเรามีการเปลี่ยนแปลงเล็กน้อย:
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

มาถึงช่วงเวลาที่สำคัญที่สุดในกิจกรรมของ DAO - โหวต สำหรับโครงการหาทุน

Bob โหวตให้กับโครงการ Neli ด้วยเวฟเล็ต 500000 เวฟเล็ต:

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

เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

ในที่เก็บข้อมูล เราจะเห็นรายการที่จำเป็นทั้งหมดสำหรับที่อยู่ Neli:
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)
คูเปอร์ยังลงคะแนนให้กับโครงการเนลี
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

มาดูรหัสฟังก์ชั่นกัน รับเงิน. เนลีต้องรวบรวมคะแนนเสียงอย่างน้อย 2 เสียงจึงจะสามารถถอนเงินจาก DAO ได้
เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

เนลีกำลังจะถอนเงินครึ่งหนึ่งของจำนวนเงินที่ฝากไว้กับเธอ:

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

เรียนรู้วิธีเขียน Waves smart contract บน RIDE และ RIDE4DAPPS ส่วนที่ 2 (อพท. - องค์กรปกครองตนเองแบบกระจายอำนาจ)

เธอทำสำเร็จ นั่นคือ DAO ทำงาน!

เราได้ทบทวนกระบวนการสร้าง DAO ในภาษา RIDE4DAPPS.
ในส่วนต่อไปนี้ เราจะตรวจสอบการปรับโครงสร้างโค้ดและการทดสอบเคสอย่างละเอียดยิ่งขึ้น

รหัสเต็มใน คลื่น RIDE IDE:

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

ส่วนแรก
รหัสบน GitHub
เวฟ ไรด์ ไอดี
ประกาศโครงการทุน

ที่มา: will.com

เพิ่มความคิดเห็น