tx · 5HhyJBJbgECjtjZWksCmRUaJKdPVFDAwJnEiL4qso1Ps

3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc:  -0.00100000 Waves

2023.11.20 20:42 [2852023] smart account 3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc > SELF 0.00000000 Waves

{ "type": 13, "id": "5HhyJBJbgECjtjZWksCmRUaJKdPVFDAwJnEiL4qso1Ps", "fee": 100000, "feeAssetId": null, "timestamp": 1700502196777, "version": 2, "chainId": 84, "sender": "3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc", "senderPublicKey": "242mibE5dTci8wD6vghuCGxjDZdnNJr88H7gcWWehpEX", "proofs": [ "4H3oSPk19XwsmM2CTy8fmSQYKSxJbRyfua1mzEnXhcqrhSk1CrL1DUyqiNfgFJKB1kYcdsVKLUMjvWE6njDorR1U" ], "script": null, "height": 2852023, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: BLkGpTER364v5dYwS5DP78cGnj4hCKtceNRnMcWRupXv Next: none Full:
OldNewDifferences
1-{-# STDLIB_VERSION 6 #-}
2-{-# SCRIPT_TYPE ACCOUNT #-}
3-{-# CONTENT_TYPE DAPP #-}
4-let revisionNum = ""
5-
6-let SEP = "__"
7-
8-let LISTSEP = ":"
9-
10-let DEFAULTQUORUM = 500000
11-
12-let URLPATTERN = "https://forum.neutrino.at/"
13-
14-let MAXTITLE = 250
15-
16-let MAXURL = 250
17-
18-let MAXVOTINGTIME = 1209600000
19-
20-let MULT6 = 1000000
21-
22-let DEFAULTPAYMENT = 1000000000
23-
24-let DEFAULTCREATIONGNSBT = 1000000000
25-
26-let PASTMARGIN = 7200000
27-
28-let FUTUREMARGIN = 5400000
29-
30-let DEFAULTFIRSTPROPOSAL = 111
31-
32-let govIdxProposalTxId = 1
33-
34-let govIdxType = 2
35-
36-let govIdxAuthor = 3
37-
38-let govIdxUrl = 4
39-
40-let govIdxTitle = 5
41-
42-let govIdxCreationTime = 6
43-
44-let govIdxStart = 7
45-
46-let govIdxEnd = 8
47-
48-let govIdxTxIds = 9
49-
50-let govIdxQuorum = 10
51-
52-let govIdxOptions = 11
53-
54-let govStatusIdxIsValid = 1
55-
56-let govStatusIdxWinOpt = 2
57-
58-let govStatusIdxWinVotes = 3
59-
60-let govStatusIdxTotalVotes = 4
61-
62-let govStatusIdxScApplied = 5
63-
64-let govStatusIdxScTime = 6
65-
66-let govStatusIdxIsCanceled = 7
67-
68-let govStatusIdxImplStatus = 8
69-
70-func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
71-
72-
73-func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal)
74-
75-
76-let IdxControlCfgNeutrinoDapp = 1
77-
78-let IdxControlCfgAuctionDapp = 2
79-
80-let IdxControlCfgRpdDapp = 3
81-
82-let IdxControlCfgMathDapp = 4
83-
84-let IdxControlCfgLiquidationDapp = 5
85-
86-let IdxControlCfgRestDapp = 6
87-
88-let IdxControlCfgNodeRegistryDapp = 7
89-
90-let IdxControlCfgNsbtStakingDapp = 8
91-
92-let IdxControlCfgMediatorDapp = 9
93-
94-let IdxControlCfgSurfStakingDapp = 10
95-
96-let IdxControlCfgGnsbtControllerDapp = 11
97-
98-let IdxControlCfgRestV2Dapp = 12
99-
100-let IdxControlCfgGovernanceDapp = 13
101-
102-func keyControlAddress () = "%s%s__config__controlAddress"
103-
104-
105-func keyControlCfg () = "%s__controlConfig"
106-
107-
108-func readControlCfgOrFail (control) = split_4C(getStringOrFail(control, keyControlCfg()), SEP)
109-
110-
111-func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
112-
113-
114-let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3N4NS7d4Jo9a6F14LiFUKKYVdUkkf2eP4Zx"))
115-
116-let controlCfg = readControlCfgOrFail(controlContract)
117-
118-let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp)
119-
120-let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
121-
122-let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
123-
124-func keyLastBase58Proposal () = "%s__lastBase58Proposal"
125-
126-
127-func keyQuorumRequiredPercent (type) = ("%s%s__quorumRequired__" + type)
128-
129-
130-func keyPaymentRequired () = "%s__paymentRequired"
131-
132-
133-func keyGnsbtRequired () = "%s__gNsbtRequired"
134-
135-
136-func keyLastProposalId () = "%s__proposalId"
137-
138-
139-func keyFirstProposalId () = "%s__firstProposalId"
140-
141-
142-func keyLastUpdateVersion () = "%s__updateVersion"
143-
144-
145-func keyProposalStatusDataById (proposalId) = ("%s%d__proposalStatusData__" + toString(proposalId))
146-
147-
148-func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
149-
150-
151-func keyProposalVotesByIdAndOption (proposalId,opt) = makeString(["%s%d%d", "votesByOpt", toString(proposalId), toString(opt)], SEP)
152-
153-
154-func keyProposalVotesByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "votesByUser", toString(proposalId), userAddr], SEP)
155-
156-
157-func keyProposalChoiceByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "optionByUser", toString(proposalId), userAddr], SEP)
158-
159-
160-func keyApplyInProgress () = "%s__applyInProgress"
161-
162-
163-func keyProposalIdByTopicId (topicId) = ("%s%d__proposalIdByTopicId__" + toString(topicId))
164-
165-
166-func keyUserGnsbtReleaseTime (userAddr) = ("%s%s_userGnsbtReleaseTime__" + userAddr)
167-
168-
169-func keyNumUniqueVotersByProposalId (proposalId) = ("%s%d__numVoters__" + toString(proposalId))
170-
171-
172-func keyStatsAverUniqueVoters () = "%s%s%s__stats__avg__uniqueVoters"
173-
174-
175-func keyStatsAverGnsbtVoted () = "%s%s%s__stats__avg__gnsbtVoted"
176-
177-
178-func keyStatsUniqueAuthors () = "%s%s__stats__uniqueAuthors"
179-
180-
181-func keyNumProposalsByAuthor (addressStr) = ("%s%s__numProposalsByAuthor__" + addressStr)
182-
183-
184-func keyApplyHistory (timestamp) = ("%s%d__applyHistory__" + toString(timestamp))
185-
186-
187-func asAnyList (v) = match v {
188- case l: List[Any] =>
189- l
190- case _ =>
191- throw("fail to cast into List[Any]")
192-}
193-
194-
195-func asInt (v) = match v {
196- case i: Int =>
197- i
198- case _ =>
199- throw("fail to cast into Int")
200-}
201-
202-
203-func statusData (isVotingValid,winOption,winOptionVotes,totalVotes,areScriptsApplied,scriptsTimestamp,canceledByTeam,implStatus) = makeString(["%b%d%d%d%b%d%b%s", toString(isVotingValid), toString(winOption), toString(winOptionVotes), toString(totalVotes), toString(areScriptsApplied), toString(scriptsTimestamp), toString(canceledByTeam), implStatus], SEP)
204-
205-
206-func proposalData (proposalTxId,type,author,forumLink,title,proposalTime,votingStartTime,votingEndTime,txIds,quorumInGnsbt,options) = makeString(["%s%s%s%s%s%d%d%d%s%d%s", proposalTxId, type, author, forumLink, title, toString(proposalTime), toString(votingStartTime), toString(votingEndTime), txIds, toString(quorumInGnsbt), options], SEP)
207-
208-
209-func checkTxList (txList) = if ((size(txList) > 20))
210- then throw(("Too many transactions: " + toString(size(txList))))
211- else {
212- func combiner (acc,tx) = if ((size(fromBase58String(tx)) != 32))
213- then throw(("Wrong txId: " + tx))
214- else if ((acc == ""))
215- then tx
216- else ((acc + LISTSEP) + tx)
217-
218- let $l = txList
219- let $s = size($l)
220- let $acc0 = ""
221- func $f0_1 ($a,$i) = if (($i >= $s))
222- then $a
223- else combiner($a, $l[$i])
224-
225- func $f0_2 ($a,$i) = if (($i >= $s))
226- then $a
227- else throw("List size exceeds 20")
228-
229- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
230- }
231-
232-
233-let IdxEffTotal = 0
234-
235-let IdxEffUser = 1
236-
237-func getEffectiveGnsbt (userAddrStrOrEmpty) = {
238- let upd = if (isDefined(addressFromString(userAddrStrOrEmpty)))
239- then invoke(surfStakingContract, "updateVotingPower", [userAddrStrOrEmpty], nil)
240- else unit
241- if ((upd == upd))
242- then {
243- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddrStrOrEmpty, 0, 0], nil))
244- let nsbtData = asAnyList(gnsbtData[2])
245- let userFromNsbt = asInt(nsbtData[2])
246- let totalFromNsbt = asInt(nsbtData[3])
247- let userMatureFromSurf = asInt(gnsbtData[9])
248- let totalMatureFromSurf = asInt(gnsbtData[6])
249-[(totalFromNsbt + totalMatureFromSurf), (userFromNsbt + userMatureFromSurf)]
250- }
251- else throw("Strict value is not equal to itself.")
252- }
253-
254-
255-func validateLink (url) = if ((value(indexOf(url, URLPATTERN)) != 0))
256- then throw("Invalid url")
257- else if ((size(url) > MAXURL))
258- then throw("Url too long!")
259- else {
260- let topicId = valueOrErrorMessage(parseInt(drop(url, (value(lastIndexOf(url, "/")) + 1))), "Wrong topicId")
261- let registeredId = getInteger(keyProposalIdByTopicId(topicId))
262- if (isDefined(registeredId))
263- then throw(("Voting with such forum link is already registered by id=" + toString(value(registeredId))))
264- else topicId
265- }
266-
267-
268-func initiateVoting (payment,proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList,optionsList) = if ((payment.assetId != unit))
269- then throw("Allowed WAVES payment only!")
270- else {
271- let pmtReq = getIntOrElse(keyPaymentRequired(), DEFAULTPAYMENT)
272- if ((pmtReq > payment.amount))
273- then throw(("Payment attached should be at least " + toString(pmtReq)))
274- else {
275- let topicId = validateLink(forumLink)
276- if ((title == ""))
277- then throw("Title is empty")
278- else if ((size(title) > MAXTITLE))
279- then throw("Too long title")
280- else {
281- let proposalTime = lastBlock.timestamp
282- if ((proposalTime > votingStartTime))
283- then throw(((("votingStartTime=" + toString(votingStartTime)) + " < proposalTime=") + toString(proposalTime)))
284- else if ((votingStartTime > votingEndTime))
285- then throw(((("votingEndTime=" + toString(votingEndTime)) + " < votingStartTime=") + toString(votingStartTime)))
286- else if (((votingEndTime - votingStartTime) > MAXVOTINGTIME))
287- then throw(((("Voting period exceeds max: " + toString((votingEndTime - votingStartTime))) + " > ") + toString(MAXVOTINGTIME)))
288- else {
289- let txIds = if ((type == "IDEA"))
290- then ""
291- else checkTxList(txList)
292- if ((1 >= size(optionsList)))
293- then throw("Too few choices to vote")
294- else {
295- let eff = getEffectiveGnsbt(author)
296- let gnsbtTotal = eff[IdxEffTotal]
297- let gNsbtUser = eff[IdxEffUser]
298- let gnsbtReq = getIntOrElse(keyGnsbtRequired(), DEFAULTCREATIONGNSBT)
299- if ((gnsbtReq > gNsbtUser))
300- then throw((("You need at least " + toString(gnsbtReq)) + " gNsbt to create voting"))
301- else {
302- let amountLeased = invoke(neutrinoContract, "acceptWaves", nil, [payment])
303- if ((amountLeased == amountLeased))
304- then {
305- let quorum = getIntOrElse(keyQuorumRequiredPercent(type), DEFAULTQUORUM)
306- let quorumInGnsbt = fraction(quorum, gnsbtTotal, MULT6)
307- let proposalId = (getIntOrElse(keyLastProposalId(), 0) + 1)
308- let numProposalsByAuthor = (getIntOrElse(keyNumProposalsByAuthor(author), 0) + 1)
309- let uniqAuthors = (getIntOrElse(keyStatsUniqueAuthors(), 0) + (if ((numProposalsByAuthor == 1))
310- then 1
311- else 0))
312- let optionsStr = makeString(optionsList, LISTSEP)
313- let lastBase58Proposal = getInteger(keyLastBase58Proposal())
314- let optionallastBase58Proposal = if ((lastBase58Proposal != unit))
315- then nil
316- else [IntegerEntry(keyLastBase58Proposal(), (proposalId - 1))]
317- $Tuple2(([IntegerEntry(keyLastProposalId(), proposalId), IntegerEntry(keyProposalIdByTopicId(topicId), proposalId), StringEntry(keyProposalStatusDataById(proposalId), statusData(false, 0, 0, 0, false, votingEndTime, false, "ACTIVE")), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, toBase16String(toBytes(forumLink)), toBase16String(toBytes(title)), proposalTime, votingStartTime, votingEndTime, txIds, quorumInGnsbt, optionsStr)), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)] ++ optionallastBase58Proposal), proposalTxId)
318- }
319- else throw("Strict value is not equal to itself.")
320- }
321- }
322- }
323- }
324- }
325- }
326-
327-
328-func calcWinOption (proposalId,optionsList,isPrevOptional,oldChoice,optionalTotalOld,newChoice,newTotalByNewChoice) = {
329- func findBest (acc,elem) = {
330- let idx = value(indexOf(optionsList, elem))
331- let val = if (isPrevOptional)
332- then if ((idx == newChoice))
333- then newTotalByNewChoice
334- else getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
335- else if ((idx == value(oldChoice)))
336- then optionalTotalOld
337- else if ((idx == newChoice))
338- then newTotalByNewChoice
339- else getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
340- if ((acc._2 > val))
341- then acc
342- else $Tuple2(idx, val)
343- }
344-
345- let $l = optionsList
346- let $s = size($l)
347- let $acc0 = $Tuple2(0, 0)
348- func $f0_1 ($a,$i) = if (($i >= $s))
349- then $a
350- else findBest($a, $l[$i])
351-
352- func $f0_2 ($a,$i) = if (($i >= $s))
353- then $a
354- else throw("List size exceeds 10")
355-
356- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
357- }
358-
359-
360-func updateStatusData (oldData,isValid,newWinOpt,newTotalVotes) = makeString(["%b%d%d%d%b%d%b%s", toString(isValid), toString(newWinOpt._1), toString(newWinOpt._2), toString(newTotalVotes), oldData[govStatusIdxScApplied], oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled], oldData[govStatusIdxImplStatus]], SEP)
361-
362-
363-func statusApplyScript (oldData) = makeString(["%b%d%d%d%b%d%b%s", oldData[govStatusIdxIsValid], oldData[govStatusIdxWinOpt], oldData[govStatusIdxWinVotes], oldData[govStatusIdxTotalVotes], "true", oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled], oldData[govStatusIdxImplStatus]], SEP)
364-
365-
366-func ExecutionHistory (updateVersion,title,url,proposalId) = {
367- let gnsbtTotal = getEffectiveGnsbt("")[IdxEffTotal]
368- let turnout = 500000
369- StringEntry(keyApplyHistory(lastBlock.timestamp), makeString(["%d%d%d%s%s%d", toString(updateVersion), toString(gnsbtTotal), toString(turnout), title, url, toString(proposalId)], SEP))
370- }
371-
372-
373-@Callable(i)
374-func constructorV1 (controlAddr,gNsbtReqToInit,wavesReqToInit,quorumReqPercIdea,quorumReqPercUpdate) = if ((i.caller != this))
375- then throw("Permission denied")
376- else [StringEntry(keyControlAddress(), controlAddr), IntegerEntry(keyGnsbtRequired(), gNsbtReqToInit), IntegerEntry(keyPaymentRequired(), wavesReqToInit), IntegerEntry(keyQuorumRequiredPercent("IDEA"), quorumReqPercIdea), IntegerEntry(keyQuorumRequiredPercent("UPDATE"), quorumReqPercUpdate)]
377-
378-
379-
380-@Callable(i)
381-func castVote (proposalId,choice) = {
382- let userAddressStr = toString(i.caller)
383- let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
384- if ((dynamicData[govStatusIdxIsCanceled] == "true"))
385- then throw("Voting is canceled by team")
386- else {
387- let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
388- let start = parseIntValue(propData[govIdxStart])
389- let end = parseIntValue(propData[govIdxEnd])
390- let now = lastBlock.timestamp
391- if ((start > now))
392- then throw("Voting not started yet")
393- else if ((now >= end))
394- then throw("Voting already finished")
395- else {
396- let availableOptions = split(propData[govIdxOptions], LISTSEP)
397- let numOptions = size(availableOptions)
398- if ((1 >= numOptions))
399- then throw("Too few choices to vote")
400- else if ((choice >= numOptions))
401- then throw(("Unknown choice! Must be 0.." + toString((numOptions - 1))))
402- else {
403- let eff = getEffectiveGnsbt(userAddressStr)
404- let gnsbtAmt = eff[IdxEffUser]
405- if ((0 >= gnsbtAmt))
406- then throw("no gnsbt to vote")
407- else {
408- let gnsbtTotal = eff[IdxEffTotal]
409- let oldChoice = getInteger(keyProposalChoiceByIdAndUser(proposalId, userAddressStr))
410- let oldUserVotes = if (!(isDefined(oldChoice)))
411- then 0
412- else getIntOrElse(keyProposalVotesByIdAndUser(proposalId, userAddressStr), 0)
413- let oldTotalByOldChoice = if (isDefined(oldChoice))
414- then getIntOrElse(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), 0)
415- else 0
416- let oldTotalByNewChoice = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, choice), 0)
417- let oldTotal = parseIntValue(dynamicData[govStatusIdxTotalVotes])
418- let newTotalByOldChoice = if (!(isDefined(oldChoice)))
419- then 0
420- else ((oldTotalByOldChoice - oldUserVotes) + (if ((value(oldChoice) == choice))
421- then gnsbtAmt
422- else 0))
423- let newTotalByNewChoice = if (if (isDefined(oldChoice))
424- then (value(oldChoice) == choice)
425- else false)
426- then newTotalByOldChoice
427- else (oldTotalByNewChoice + gnsbtAmt)
428- let newTotal = ((oldTotal - oldUserVotes) + gnsbtAmt)
429- let isQuorumReached = (newTotal >= parseIntValue(propData[govIdxQuorum]))
430- let numVotersByProposalId = getIntOrElse(keyNumUniqueVotersByProposalId(proposalId), 0)
431- let oldAverUniqueVoters6 = getIntOrElse(keyStatsAverUniqueVoters(), 0)
432- let numProposals = ((getIntegerValue(keyLastProposalId()) - valueOrElse(getInteger(keyFirstProposalId()), DEFAULTFIRSTPROPOSAL)) + 1)
433- let uniqueDiff = if ((oldUserVotes == 0))
434- then 1
435- else 0
436- let newAverUniqueVoters6 = (oldAverUniqueVoters6 + fraction(uniqueDiff, MULT6, numProposals))
437- let oldAverGnsbt = getIntOrElse(keyStatsAverGnsbtVoted(), 0)
438- let newAverGnsbt = (oldAverGnsbt + ((gnsbtAmt - oldUserVotes) / numProposals))
439- let isPrevOptional = if (!(isDefined(oldChoice)))
440- then true
441- else (value(oldChoice) == choice)
442- let optionalTotalOld = if (isPrevOptional)
443- then nil
444- else [IntegerEntry(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), newTotalByOldChoice)]
445- let winOpt = calcWinOption(proposalId, availableOptions, isPrevOptional, oldChoice, newTotalByOldChoice, choice, newTotalByNewChoice)
446- let releaseTime = max([end, getIntOrElse(keyUserGnsbtReleaseTime(userAddressStr), 0)])
447- $Tuple2(([IntegerEntry(keyProposalChoiceByIdAndUser(proposalId, userAddressStr), choice), IntegerEntry(keyProposalVotesByIdAndUser(proposalId, userAddressStr), gnsbtAmt), IntegerEntry(keyProposalVotesByIdAndOption(proposalId, choice), newTotalByNewChoice), IntegerEntry(keyNumUniqueVotersByProposalId(proposalId), (numVotersByProposalId + uniqueDiff)), IntegerEntry(keyUserGnsbtReleaseTime(userAddressStr), releaseTime), IntegerEntry(keyStatsAverUniqueVoters(), newAverUniqueVoters6), IntegerEntry(keyStatsAverGnsbtVoted(), newAverGnsbt), StringEntry(keyProposalStatusDataById(proposalId), updateStatusData(dynamicData, isQuorumReached, winOpt, newTotal))] ++ optionalTotalOld), unit)
448- }
449- }
450- }
451- }
452- }
453-
454-
455-
456-@Callable(i)
457-func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime,optionsList) = if ((size(i.payments) != 1))
458- then throw("Exactly one payment required")
459- else if ((size(optionsList) != 2))
460- then throw("Exactly 2 option ['NO', 'YES'] are expected")
461- else if ((optionsList[0] != "NO"))
462- then throw("Option NO should be the first")
463- else if ((optionsList[1] != "YES"))
464- then throw("Option YES should be the second")
465- else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil, optionsList)
466-
467-
468-
469-@Callable(i)
470-func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = if ((size(i.payments) != 1))
471- then throw("Exactly one payment required")
472- else if ((1 > size(txList)))
473- then throw("Transactions list is empty")
474- else if ((i.caller != this))
475- then throw("not authorized")
476- else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
477-
478-
479-
480-@Callable(i)
481-func cancelVoting (proposalId) = if ((i.caller != this))
482- then throw("not authorized")
483- else {
484- let currentData = getStringOrFail(this, keyProposalStatusDataById(proposalId))
485- let updatedData = ((take(currentData, value(lastIndexOf(currentData, SEP))) + SEP) + "true")
486- $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updatedData)], unit)
487- }
488-
489-
490-
491-@Callable(i)
492-func applyUpdate (proposalId) = {
493- let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
494- let end = parseIntValue(propData[govIdxEnd])
495- let now = lastBlock.timestamp
496- if ((end > now))
497- then throw("Voting is not finished yet")
498- else if (("UPDATE" != propData[govIdxType]))
499- then throw("Only UPDATE type can be applied")
500- else {
501- let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
502- if ((dynamicData[govStatusIdxIsCanceled] == "true"))
503- then throw("Voting is canceled")
504- else if ((dynamicData[govStatusIdxIsValid] != "true"))
505- then throw("Voting status invalid")
506- else if ((dynamicData[govStatusIdxWinOpt] != "1"))
507- then throw("Winner is 'NO' - nothing to apply")
508- else if ((dynamicData[govStatusIdxScApplied] == "true"))
509- then throw("Scripts are already applied")
510- else {
511- let scriptTime = parseIntValue(dynamicData[govStatusIdxScTime])
512- if (((now - PASTMARGIN) > scriptTime))
513- then throw((("Scripts timestamp=" + toString(scriptTime)) + " is too far in the past, max 2 hrs allowed"))
514- else if ((scriptTime > (now + FUTUREMARGIN)))
515- then throw((("Scripts timestamp=" + toString(scriptTime)) + " is too far in the future, max 1.5 hrs allowed"))
516- else {
517- let inProgressId = getIntOrElse(keyApplyInProgress(), -1)
518- if ((inProgressId != -1))
519- then throw((("proposalId=" + toString(inProgressId)) + " is already being applied. Finish it first!"))
520- else {
521- let shutdown = invoke(controlContract, "callEmergencyShutdown", ["Applying Governance UPDATE"], nil)
522- if ((shutdown == shutdown))
523- then $Tuple2([IntegerEntry(keyApplyInProgress(), proposalId)], unit)
524- else throw("Strict value is not equal to itself.")
525- }
526- }
527- }
528- }
529- }
530-
531-
532-
533-@Callable(i)
534-func finishApply () = {
535- let proposalId = valueOrErrorMessage(getInteger(keyApplyInProgress()), "No apply in progress, nothing to finish")
536- let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
537- let txList = split(propData[govIdxTxIds], LISTSEP)
538- let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
539- if ((dynamicData[govStatusIdxScApplied] == "true"))
540- then throw("Scripts are already applied")
541- else {
542- func checker (acc,tx) = if (!(isDefined(transactionHeightById(fromBase58String(tx)))))
543- then throw(("NOT applied txId: " + tx))
544- else unit
545-
546- let ignored = {
547- let $l = txList
548- let $s = size($l)
549- let $acc0 = unit
550- func $f0_1 ($a,$i) = if (($i >= $s))
551- then $a
552- else checker($a, $l[$i])
553-
554- func $f0_2 ($a,$i) = if (($i >= $s))
555- then $a
556- else throw("List size exceeds 20")
557-
558- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
559- }
560- let version = (getIntOrElse(keyLastUpdateVersion(), 0) + 1)
561- $Tuple2([DeleteEntry(keyApplyInProgress()), IntegerEntry(keyLastUpdateVersion(), version), StringEntry(keyProposalStatusDataById(proposalId), statusApplyScript(dynamicData)), ExecutionHistory(version, propData[govIdxTitle], propData[govIdxUrl], proposalId)], ignored)
562- }
563- }
564-
565-
566-
567-@Callable(i)
568-func changeImplStatus (proposalId,newStatus) = if ((i.caller != this))
569- then throw("not authorized")
570- else if (if ((newStatus != "ACTIVE"))
571- then (newStatus != "OUTDATED")
572- else false)
573- then throw("Unknown implementation status")
574- else {
575- let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
576- let updated = makeString(["%b%d%d%d%b%d%b%s", dynamicData[govStatusIdxIsValid], dynamicData[govStatusIdxWinOpt], dynamicData[govStatusIdxWinVotes], dynamicData[govStatusIdxTotalVotes], dynamicData[govStatusIdxScApplied], dynamicData[govStatusIdxScTime], dynamicData[govStatusIdxIsCanceled], newStatus], SEP)
577- $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updated)], unit)
578- }
579-
580-
1+# no script

github/deemru/w8io/3ef1775 
53.29 ms