
Hello everyone!
В Այս մասում մենք մանրամասնորեն քննարկեցինք, թե ինչպես ստեղծել և աշխատել dApp (ապակենտրոնացված ծրագիր)-ի հետ։ .
Եկեք մի փոքր փորձարկենք ապամոնտաժվածը հիմա .
Քայլ 3. dApp հաշվի փորձարկում

Ի՞նչ խնդիրներ են անմիջապես գրավում Ալիսի ուշադրությունը դԱՊ Հաշիվ?
Առաջին
Բուբը և Քուփերը կարող են պատահաբար գումար ուղարկել dApp հասցեին՝ օգտագործելով սովորական փոխանցել գործարքները և, հետևաբար, դրանց հետադարձ հասանելիություն չի լինի։Երկրորդ `
Մենք որևէ կերպ չենք սահմանափակում Ալիսին Բուբի կամ (և) Քուփերի համաձայնության բացակայության դեպքում միջոցներ դուրս բերելու հարցում։ Քանի որ, ուշադրություն դարձրեք ստուգմանը, Ալիսի բոլոր գործարքները կկատարվեն։
Եկեք շտկենք երկրորդը՝ արգելափակելով Ալիսին։ փոխանցել գործարքներ։ Տեղակայեք ուղղված սկրիպտը։


Մենք փորձում ենք dApp Alice-ից և դրա ստորագրությունից մետաղադրամներ հանել։ Մենք սխալ ենք ստանում։

Եկեք փորձենք դուրսբերել գումարը դուրսբերման միջոցով.
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Սցենարը աշխատում է, և մենք լուծեցինք 2-րդ կետը։
Քայլ 4. Ստեղծեք DAO քվեարկությամբ
Դժբախտաբար, RIDE լեզուն դեռևս չի ապահովում հավաքածուների հետ աշխատելու հնարավորություն (բառարանների բառարաններ, իտերատորներ, ռեդուկտորներ և այլն): Այնուամենայնիվ, հարթ հավաքածուների հետ ցանկացած գործողության համար բանալի-արժեք Մենք կարող ենք նախագծել տողերի հետ աշխատելու համակարգ, համապատասխանաբար՝ բանալիների և դրանց վերծանման հետ։
Տողերը շատ հեշտ է միացնել, տողերը կարելի է բաժանել ինդեքսների։
Եկեք հավաքենք և ապամոնտաժենք տողը որպես փորձարկման օրինակ և ստուգենք, թե ինչպես է դա ազդում գործարքի արդյունքի վրա։
Արդյունքում Ալիսը չկարողացավ ստորագրել փոխանցման գործարքը, քանի որ այս հնարավորությունը արգելափակված էր @verifier-ում այս տեսակի գործարքի համար։
Եկեք մարզվենք լարերի հետ, ապա լուծենք սա։
RIDE լարեր
Գործարքը կրկին հնարավոր է, մենք գիտենք, թե ինչպես աշխատել տողերի հետ։


Այսպիսով, մենք ունենք ամեն ինչ, ինչ անհրաժեշտ է բարդ տրամաբանություն գրելու համար։ DAO dApp.
Տվյալների գործարքներ
Տվյալների գործարքներ՝
«Բանալու առավելագույն չափը 100 նիշ է, և բանալին կարող է պարունակել Unicode կոդի կամայական կետեր, ներառյալ բացատներ և այլ ոչ տպելի նշաններ: Տողային արժեքների սահմանափակումը 32,768 բայթ է, իսկ տվյալների գործարքում հնարավոր գրառումների առավելագույն քանակը՝ 100: Ընդհանուր առմամբ, տվյալների գործարքի առավելագույն չափը մոտ 140 կբ է՝ համեմատության համար, գրեթե ճիշտ այնքան, որքան Շեքսպիրի «Ռոմեո և Ջուլիետ» պիեսի երկարությունն է»:
Մենք ստեղծում ենք DAO հետևյալ պայմաններով՝
Որպեսզի ստարտափը ֆինանսավորում ստանա՝ զանգահարելով ստանալ միջոցներ() Պահանջվում է առնվազն 2 մասնակցի՝ DAO ներդրողների աջակցությունը։ Վերցրեք հնարավոր կլինի ունենալ ճիշտ այնքան, որքան նշված է ընդհանուրը քվեարկություն DAO-ի սեփականատերեր։
Եկեք ստեղծենք 3 տեսակի բանալի և ավելացնենք տրամաբանություն մնացորդների հետ աշխատելու համար 2 նոր ֆունկցիաներում՝ vote և getFunds։
xx…xx_իա = ներդրողներ, հասանելի մնացորդ (քվեարկություն, ավանդ, հետ վերցնել)
xx…xx_sv = ստարտափներ, ձայների քանակ (քվեարկեք, ստացեք միջոցներ)
xx…xx_sf = ստարտափներ, ձայների քանակ (քվեարկեք, ստացեք միջոցներ)
xx…xx = հանրային հասցե (35 նիշ)
Նկատի ունեցեք, որ «Քվեարկություն» բաժնում մենք պետք է միաժամանակ մի քանի դաշտ թարմացնեինք։
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet-ը թույլ է տալիս մեզ միաժամանակ ստեղծել մի քանի գրառում մեկ գրառման մեջ։ invokeScript գործարքներ։
Ահա թե ինչ տեսք ունի այն DAO dApp բանալի-արժեքի խանութում, Բոբի և Քուփերի համալրումից հետո։ ia-ավանդներ:

Մեր ավանդի գործառույթը փոքր-ինչ փոխվել է.

Հիմա գալիս է DAO-ի գործունեության ամենակարևոր պահը՝ քվեարկություն ֆինանսավորվող նախագծերի համար։
Բոբը քվեարկում է Նելիի նախագծի օգտին՝ 500000 ալիքային միավորով։
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Տվյալների պահեստում մենք տեսնում ենք Նելի հասցեի համար անհրաժեշտ բոլոր գրառումները.

Քուփերը նույնպես քվեարկեց Նելի նախագծի օգտին։

Եկեք նայենք ֆունկցիայի կոդին ստանալ միջոցներՆելին պետք է հավաքի առնվազն 2 ձայն՝ DAO-ից միջոցներ հանելու համար։

Նելին պատրաստվում է վերցնել իրեն վստահված գումարի կեսը։
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Նա հաջողության է հասնում, այսինքն՝ 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
}
}
Source: www.habr.com
