
Xin chào tất cả mọi người!
В phần chúng tôi đã xem xét chi tiết cách tạo và làm việc với dApp (ứng dụng phi tập trung) trong .
Bây giờ chúng ta hãy kiểm tra cái đã tháo rời một chút .
Giai đoạn 3. Kiểm tra tài khoản dApp

Vấn đề nào ngay lập tức xảy ra với bạn với Alice? ứng dụng Tài khoản?
Thứ nhất:
Boob và Cooper có thể vô tình gửi tiền đến địa chỉ dApp bằng cách sử dụng thông thường chuyển giao dịch và do đó sẽ không thể truy cập lại chúng.Thứ hai:
Chúng tôi không hạn chế Alice rút tiền dưới bất kỳ hình thức nào mà không có sự chấp thuận của Boob và/hoặc Cooper. Vì chú ý xác minh nên mọi giao dịch từ Alice sẽ được thực hiện.
Hãy sửa lỗi thứ 2 bằng cách cấm Alice chuyển giao dịch. Hãy triển khai tập lệnh đã sửa:


Chúng tôi đang cố gắng rút tiền từ dApp Alice và chữ ký của cô ấy. Chúng tôi gặp lỗi:

Hãy thử rút tiền bằng cách rút tiền:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Kịch bản hoạt động và chúng tôi đã tìm ra điểm thứ 2!
Giai đoạn 4. Tạo DAO bằng biểu quyết
Thật không may, ngôn ngữ RIDE chưa cung cấp khả năng làm việc với các bộ sưu tập (từ điển từ điển, bộ lặp, bộ rút gọn, v.v.). Tuy nhiên, đối với bất kỳ hoạt động nào với bộ sưu tập phẳng giá trị cốt lõi chúng ta có thể thiết kế một hệ thống để làm việc với các chuỗi, tương ứng với các khóa và giải mã chúng.
Các chuỗi rất dễ nối; các chuỗi có thể được phân tách bằng các chỉ mục.
Hãy thu thập và phân tích một chuỗi làm ví dụ thử nghiệm và kiểm tra xem điều này ảnh hưởng như thế nào đến kết quả của giao dịch.
Chúng tôi giải quyết vấn đề là Alice không thể ký giao dịch Chuyển khoản vì khả năng này đã bị chặn trong @verifier đối với loại giao dịch này.
Hãy thực hành với chuỗi và sau đó giải quyết vấn đề này.
Dây RIDE
Giao dịch có thể thực hiện được trở lại, chúng tôi biết cách làm việc với chuỗi.


Tổng cộng, chúng ta có mọi thứ cần thiết để viết logic phức tạp DAO dApp.
Giao dịch dữ liệu
Giao dịch dữ liệu:
“Kích thước tối đa cho một khóa là 100 ký tự và một khóa có thể chứa các điểm mã Unicode tùy ý bao gồm dấu cách và các ký hiệu không in được khác. Các giá trị chuỗi có giới hạn là 32,768 byte và số lượng mục nhập tối đa có thể có trong giao dịch dữ liệu là 100. Nhìn chung, kích thước tối đa của một giao dịch dữ liệu là khoảng 140kb - để tham khảo, gần như chính xác độ dài của vở kịch 'Romeo và Juliet' của Shakespeare '.
Chúng tôi tạo DAO với các điều kiện sau:
Để một công ty khởi nghiệp nhận được tài trợ bằng cách gọi điện getFunds() cần có sự hỗ trợ của ít nhất 2 người tham gia - nhà đầu tư DAO -. rút nó sẽ có thể chính xác bằng tổng số được chỉ ra trên bỏ phiếu Chủ sở hữu DAO.
Hãy tạo 3 loại khóa và thêm logic để làm việc với số dư trong 2 chức năng mới vote và getFunds:
xx…xx_ia = nhà đầu tư, số dư khả dụng (bỏ phiếu, gửi tiền, rút tiền)
xx…xx_sv = số công ty khởi nghiệp, số phiếu bầu (bỏ phiếu, getFunds)
xx…xx_sf = số công ty khởi nghiệp, số phiếu bầu (bỏ phiếu, getFunds)
xx…xx = địa chỉ công cộng (35 ký tự)
Xin lưu ý rằng trong Bình chọn, chúng tôi cần cập nhật một số trường cùng một lúc:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet cho phép chúng ta tạo nhiều bản ghi cùng lúc trong một gọiScript giao dịch.
Đây là giao diện trong kho lưu trữ khóa-giá trị của DAO dApp, sau khi Bob và Cooper bổ sung ia-tiền gửi:

Chức năng gửi tiền của chúng tôi đã thay đổi một chút:

Bây giờ là thời điểm quan trọng nhất trong hoạt động của DAO - bỏ phiếu cho các dự án được tài trợ.
Bob bỏ phiếu cho dự án 500000 wavelet của Neli:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Trong kho dữ liệu, chúng tôi thấy tất cả các mục cần thiết cho địa chỉ của Neli:

Cooper cũng đã bỏ phiếu cho dự án Neli.

Chúng ta hãy xem mã chức năng nhận tiền. Neli phải thu thập tối thiểu 2 phiếu bầu để có thể rút tiền từ DAO.

Neli sẽ rút một nửa số tiền được giao cho cô ấy:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Cô ấy thành công, nghĩa là DAO hoạt động!
Chúng tôi đã xem xét quá trình tạo DAO bằng ngôn ngữ RIDE4DAPPS.
Trong các phần sau, chúng ta sẽ xem xét kỹ hơn về tái cấu trúc mã và kiểm tra trường hợp.
Phiên bản đầy đủ của mã trong
# 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
}
}
Nguồn: www.habr.com
