tx · 6XaB8DfXtiKVLTwkGtUhtkA3pFU7QdshkSRRVkTte9ac 3PM6Wsfm2ePMqbY5PQXMSDVpYfYgzHPWRhQ: -0.01700000 Waves 2023.12.18 11:36 [3957809] smart account 3PM6Wsfm2ePMqbY5PQXMSDVpYfYgzHPWRhQ > SELF 0.00000000 Waves
{ "type": 13, "id": "6XaB8DfXtiKVLTwkGtUhtkA3pFU7QdshkSRRVkTte9ac", "fee": 1700000, "feeAssetId": null, "timestamp": 1702888564282, "version": 1, "sender": "3PM6Wsfm2ePMqbY5PQXMSDVpYfYgzHPWRhQ", "senderPublicKey": "Azj6CQbpigVMo3cysDxKDiqtXexMNjVzgdMaoeXeEmar", "proofs": [ "fWwvLPhi2khBCpA34CDFw229JUgadyX956Rnh5w5CpCdqkiR2edovggCs7x2ZjYMZCRDApwk2YZMKEGLG7uDV5P" ], "script": "base64:AAIFAAAAAAAAACgIAhIDCgEIEgUKAwgIAhIECgIIAhIDCgEIEgMKAQgSAwoBCBIDCgEIAAAANAEAAAAHdGhyb3dJZgAAAAIAAAAJY29uZGl0aW9uAAAABWVycm9yAwUAAAAJY29uZGl0aW9uCQAAAgAAAAEFAAAABWVycm9yBgEAAAALd3JpdGVCaW5hcnkAAAACAAAAA2tleQAAAAV2YWx1ZQkBAAAAC0JpbmFyeUVudHJ5AAAAAgUAAAADa2V5BQAAAAV2YWx1ZQEAAAAId3JpdGVJbnQAAAACAAAAA2tleQAAAAV2YWx1ZQMJAABmAAAAAgAAAAAAAAAAAAUAAAAFdmFsdWUJAAACAAAAAQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAAXd3JpdGluZyBuZWdhdGl2ZSB2YWx1ZSAJAAGkAAAAAQUAAAAFdmFsdWUCAAAACSBmb3Iga2V5IAUAAAADa2V5CQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAADa2V5BQAAAAV2YWx1ZQEAAAAQd3JpdGVDb25zdFN0cmluZwAAAAIAAAADa2V5AAAABXZhbHVlAwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkABB0AAAACBQAAAAR0aGlzBQAAAANrZXkJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAA2tleQUAAAAFdmFsdWUJAAACAAAAAQkAASwAAAACAgAAABVhbHJlYWR5IGluaXRpYWxpemVkOiAFAAAAA2tleQEAAAANd3JpdGVDb25zdEludAAAAAIAAAADa2V5AAAABXZhbHVlAwkBAAAAASEAAAABCQEAAAAJaXNEZWZpbmVkAAAAAQkABBoAAAACBQAAAAR0aGlzBQAAAANrZXkJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAANrZXkFAAAABXZhbHVlCQAAAgAAAAEJAAEsAAAAAgIAAAAQYWxyZWFkeSBleGlzdHM6IAUAAAADa2V5AQAAAAhjaGFuZ2VCeQAAAAIAAAADa2V5AAAABXZhbHVlCQEAAAAId3JpdGVJbnQAAAACBQAAAANrZXkJAABkAAAAAgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAANrZXkAAAAAAAAAAAAFAAAABXZhbHVlAQAAAAVhc0ludAAAAAEAAAAFdmFsdWUEAAAAByRtYXRjaDAFAAAABXZhbHVlAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAA2ludAUAAAAHJG1hdGNoMAUAAAADaW50CQAAAgAAAAECAAAAGXdyb25nIHR5cGUsIGV4cGVjdGVkOiBJbnQAAAAAEmNvbmZpZ0FkZHJlc3NTdG9yZQIAAAANY29uZmlnQWRkcmVzcwAAAAANY29uZmlnQWRkcmVzcwkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEJgAAAAEJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAR0aGlzBQAAABJjb25maWdBZGRyZXNzU3RvcmUCAAAAH21vdGhlciB2b3Rpbmc6IG5vIGNvbmZpZ0FkZHJlc3MCAAAAFmludmFsaWQgY29uZmlnIGFkZHJlc3MAAAAAFHZvdGluZ1Jlc3VsdENvbnRyYWN0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAADWNvbmZpZ0FkZHJlc3MCAAAAFmNvbnRyYWN0X3ZvdGluZ19yZXN1bHQCAAAAGW5vIGNvbnRyYWN0X3ZvdGluZ19yZXN1bHQCAAAAHmludmFsaWQgY29udHJhY3Rfdm90aW5nX3Jlc3VsdAAAAAAVdm90aW5nUmV3YXJkc0NvbnRyYWN0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAADWNvbmZpZ0FkZHJlc3MCAAAAF2NvbnRyYWN0X3ZvdGluZ19yZXdhcmRzAgAAABpubyBjb250cmFjdF92b3RpbmdfcmV3YXJkcwIAAAAfaW52YWxpZCBjb250cmFjdF92b3RpbmdfcmV3YXJkcwAAAAAPc3Rha2luZ0NvbnRyYWN0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAADWNvbmZpZ0FkZHJl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cmVzcwIAAAATX3VzZXJfcHJvcG9zZV9kZWxheQIAAAAhdXNlcl9wcm9wb3NlX2RlbGF5IGlzIG5vdCBkZWZpbmVkAAAAAAtxdW9ydW1SYXRpbwkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAADWNvbmZpZ0FkZHJlc3MJAAEsAAAAAgUAAAALdGhpc0FkZHJlc3MCAAAAFl9wcm9wb3NhbF9xdW9ydW1fcmF0aW8CAAAAInByb3Bvc2FsUXVvcnVtUmF0aW8gaXMgbm90IGRlZmluZWQBAAAAE3Byb3Bvc2FsUXVvcnVtU3RvcmUAAAABAAAABHR4aWQJAAEsAAAAAgIAAAAWcHJvcG9zYWxfcXVvcnVtX3JhdGlvXwUAAAAEdHhpZAAAAAALcGFzc2VkUmF0aW8JAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAA1jb25maWdBZGRyZXNzCQABLAAAAAIFAAAAC3RoaXNBZGRyZXNzAgAAABZfcHJvcG9zYWxfcGFzc2VkX3JhdGlvAgAAACVwcm9wb3NhbFRocmVzaG9sZFJhdGlvIGlzIG5vdCBkZWZpbmVkAAAAABNwcm9wb3NhbE1pblJlcXVpcmVkCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAANY29uZmlnQWRkcmVzcwkAASwAAAACBQAAAAt0aGlzQWRkcmVzcwIAAAAcX3Byb3Bvc2FsX21pbl9wb3dlcl9yZXF1aXJlZAIAAAAbbWluIHJlcXVpcmVkIGlzIG5vdCBkZWZpbmVkAAAAABF2b3RpbmdTdGFydE9mZnNldAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAADWNvbmZpZ0FkZHJlc3MJAAEsAAAAAgUAAAALdGhpc0FkZHJlc3MCAAAAHF9wcm9wb3NhbF92b3RpbmdzdGFydF9vZmZzZXQCAAAAKnByb3Bvc2FsX3ZvdGluZ3N0YXJ0X29mZnNldCBpcyBub3QgZGVmaW5lZAAAAAAPdm90aW5nRW5kT2Zmc2V0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAANY29uZmlnQWRkcmVzcwkAASwAAAACBQAAAAt0aGlzQWRkcmVzcwIAAAAaX3Byb3Bvc2FsX3ZvdGluZ2VuZF9vZmZzZXQCAAAAKHByb3Bvc2FsX3ZvdGluZ2VuZF9vZmZzZXQgaXMgbm90IGRlZmluZWQBAAAACnVzZXJTaGFyZXMAAAABAAAABHVzZXIJAQAAAAVhc0ludAAAAAEJAAP8AAAABAUAAAAPc3Rha2luZ0NvbnRyYWN0AgAAAAp1c2VyU2hhcmVzCQAETAAAAAIFAAAABHVzZXIFAAAAA25pbAUAAAADbmlsAQAAAAl1c2VyUG93ZXIAAAABAAAABHVzZXIJAQAAAAVhc0ludAAAAAEJAAP8AAAABAUAAAAPc3Rha2luZ0NvbnRyYWN0AgAAAAl1c2VyUG93ZXIJAARMAAAAAgUAAAAEdXNlcgUAAAADbmlsBQAAAANuaWwBAAAADnByb3Bvc2FsRXhpc3RzAAAAAQAAAAR0eElkBAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMJAQAAABNwcm9wb3NhbEhlaWdodFN0b3JlAAAAAQUAAAAEdHhJZAMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAVzdGFydAUAAAAHJG1hdGNoMAYHAQAAABBwcm9wb3NhbE9uVm90aW5nAAAAAQAAAAR0eElkBAAAAAtub25FeGlzdEVycgIAAAAWcHJvcG9zYWwgZG9lc24ndCBleGlzdAMJAQAAAAEhAAAAAQkBAAAADnByb3Bvc2FsRXhpc3RzAAAAAQUAAAAEdHhJZAkAAAIAAAABBQAAAAtub25FeGlzdEVycgQAAAALdm90aW5nU3RhcnQJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzCQEAAAAYcHJvcG9zYWxWb3RpbmdTdGFydFN0b3JlAAAAAQUAAAAEdHhJZAUAAAALbm9uRXhpc3RFcnIEAAAACXZvdGluZ0VuZAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMJAQAAABZwcm9wb3NhbFZvdGluZ0VuZFN0b3JlAAAAAQUAAAAEdHhJZAUAAAALbm9uRXhpc3RFcnIDCQAAZgAAAAIFAAAAC3ZvdGluZ1N0YXJ0BQAAAAZIRUlHSFQJ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AAAADXdyaXRlQ29uc3RJbnQAAAACCQEAAAAWcHJvcG9zYWxWb3RpbmdFbmRTdG9yZQAAAAEFAAAABHR4SWQFAAAACnZvdGluZ0VuZHMJAARMAAAAAgkBAAAAEHdyaXRlQ29uc3RTdHJpbmcAAAACCQEAAAAPcHJvcG9zYWxCeVN0b3JlAAAAAQUAAAAEdHhJZAkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIJAARMAAAAAgkBAAAACHdyaXRlSW50AAAAAgkBAAAAGnVzZXJMYXN0UHJvcG9zZUhlaWdodFN0b3JlAAAAAQUAAAAEdXNlcgUAAAAGSEVJR0hUCQAETAAAAAIJAQAAABB3cml0ZUNvbnN0U3RyaW5nAAAAAgkBAAAAFHByb3Bvc2FsQWRkcmVzc1N0b3JlAAAAAQUAAAAEdHhJZAUAAAAHYWRkcmVzcwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAE3Byb3Bvc2FsUXVvcnVtU3RvcmUAAAABBQAAAAR0eElkBQAAAAtxdW9ydW1SYXRpbwkABEwAAAACCQEAAAALd3JpdGVCaW5hcnkAAAACCQEAAAAYcHJvcG9zYWxBdHRhY2htZW50c1N0b3JlAAAAAQUAAAAEdHhJZAUAAAALYXR0YWNobWVudHMFAAAAA25pbAkAAAIAAAABAgAAACRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAACAAAAAQIAAAAkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAAAAWkBAAAAD2VkaXRBdHRhY2htZW50cwAAAAIAAAAEdHhJZAAAAAthdHRhY2htZW50cwQAAAAGY2hlY2tzAwkBAAAACW9wQWxsb3dlZAAAAAECAAAAG2dvdmVybmFuY2VfZWRpdF9hdHRhY2htZW50cwkBAAAAFHByb3Bvc2FsQmVmb3JlVm90aW5nAAAAAQUAAAAEdHhJZAcDCQAAAAAAAAIFAAAABmNoZWNrcwUAAAAGY2hlY2tzBAAAAAR1c2VyCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAACYnkJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAR0aGlzCQEAAAAPcHJvcG9z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AQkBAAAAD3Byb3Bvc2FsQnlTdG9yZQAAAAEFAAAABHR4SWQJAARMAAAAAgkBAAAAC0RlbGV0ZUVudHJ5AAAAAQkBAAAAF3Byb3Bvc2FsVG90YWxQb3dlclN0b3JlAAAAAQUAAAAEdHhJZAkABEwAAAACCQEAAAALRGVsZXRlRW50cnkAAAABCQEAAAAVcHJvcG9zYWxUb3RhbFllc1N0b3JlAAAAAQUAAAAEdHhJZAkABEwAAAACCQEAAAALRGVsZXRlRW50cnkAAAABCQEAAAAUcHJvcG9zYWxUb3RhbE5vU3RvcmUAAAABBQAAAAR0eElkCQAETAAAAAIJAQAAAAtEZWxldGVFbnRyeQAAAAEJAQAAABRwcm9wb3NhbFVzZXJZZXNTdG9yZQAAAAIFAAAABHVzZXIFAAAABHR4SWQJAARMAAAAAgkBAAAAC0RlbGV0ZUVudHJ5AAAAAQkBAAAAE3Byb3Bvc2FsVXNlck5vU3RvcmUAAAACBQAAAAR1c2VyBQAAAAR0eElkCQAETAAAAAIJAQAAAAtEZWxldGVFbnRyeQAAAAEJAQAAABp1c2VyTGFzdFByb3Bvc2VIZWlnaHRTdG9yZQAAAAEFAAAABHVzZXIJAARMAAAAAgkBAAAAC0RlbGV0ZUVudHJ5AAAAAQkBAAAAFHByb3Bvc2FsQWRkcmVzc1N0b3JlAAAAAQUAAAAEdHhJZAUAAAADbmlsCQAAAgAAAAECAAAAJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgAAAABQn+ZZ", "chainId": 87, "height": 3957809, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: CpbcRrsQL85Xk56XtbcjADsod9VcAmh9jjmfp5ie9WLg Next: none Diff:
Old | New | Differences | |
---|---|---|---|
4 | 4 | func throwIf (condition,error) = if (condition) | |
5 | 5 | then throw(error) | |
6 | 6 | else true | |
7 | + | ||
8 | + | ||
9 | + | func writeBinary (key,value) = BinaryEntry(key, value) | |
7 | 10 | ||
8 | 11 | ||
9 | 12 | func writeInt (key,value) = if ((0 > value)) | |
70 | 73 | ||
71 | 74 | ||
72 | 75 | func proposalByStore (id) = ("proposal_by_" + id) | |
76 | + | ||
77 | + | ||
78 | + | func proposalAttachmentsStore (id) = ("proposal_attachments_" + id) | |
73 | 79 | ||
74 | 80 | ||
75 | 81 | func proposalTotalPowerStore (id) = ("proposal_power_" + id) | |
186 | 192 | let votesNo = valueOrElse(getInteger(proposalTotalNoStore(txId)), 0) | |
187 | 193 | let totalPowerSnap = valueOrElse(getInteger(proposalTotalPowerStore(txId)), 0) | |
188 | 194 | let totalVotes = (votesYes + votesNo) | |
195 | + | let q = quorum(txId) | |
189 | 196 | let hasQuorum = if ((totalVotes > 0)) | |
190 | - | then (((totalVotes * BASE) / totalPowerSnap) >= | |
197 | + | then (((totalVotes * BASE) / totalPowerSnap) >= q) | |
191 | 198 | else false | |
192 | 199 | let hasPassed = if ((totalVotes > 0)) | |
193 | 200 | then (((votesYes * BASE) / totalVotes) >= passedRatio) | |
204 | 211 | else if ((inBlockchainHeight > 0)) | |
205 | 212 | then "inBlockchain" | |
206 | 213 | else "waitingForTx" | |
207 | - | ((((((((((((((((((((("proposal_id: " + txId) + ", proposal_address: ") + valueOrErrorMessage(proposalAddressStore(txId), "no address")) + ", proposal_status: ") + status) + ", proposal_by: ") + valueOrErrorMessage(getString(this, proposalByStore(txId)), "no proposal")) + ", proposal_height: ") + toString(proposalHeight)) + ", proposal_txheight: ") + toString(inBlockchainHeight)) + ", proposal_votingstart: ") + toString(votingStart)) + ", proposal_votingend: ") + toString(votingEnd)) + ", proposal_power: ") + toString(totalPowerSnap)) + ", vote_yes: ") + toString(votesYes)) + ", vote_no: ") + toString(votesNo)) | |
214 | + | ((((((((((((((((((((((("proposal_id: " + txId) + ", proposal_address: ") + valueOrErrorMessage(proposalAddressStore(txId), "no address")) + ", proposal_status: ") + status) + ", proposal_by: ") + valueOrErrorMessage(getString(this, proposalByStore(txId)), "no proposal")) + ", proposal_height: ") + toString(proposalHeight)) + ", proposal_txheight: ") + toString(inBlockchainHeight)) + ", proposal_votingstart: ") + toString(votingStart)) + ", proposal_votingend: ") + toString(votingEnd)) + ", proposal_power: ") + toString(totalPowerSnap)) + ", vote_yes: ") + toString(votesYes)) + ", vote_no: ") + toString(votesNo)) + ", proposal_quorum: ") + toString(q)) | |
208 | 215 | } | |
209 | 216 | ||
210 | 217 | ||
226 | 233 | ||
227 | 234 | ||
228 | 235 | @Callable(i) | |
229 | - | func propose (address,txId) = { | |
236 | + | func propose (address,txId,attachments) = { | |
230 | 237 | let checks = opAllowed("governance_propose_tx") | |
231 | 238 | if ((checks == checks)) | |
232 | 239 | then { | |
244 | 251 | let votingEnds = (HEIGHT + votingEndOffset) | |
245 | 252 | let e = invoke(votingRewardsContract, "votingEnds", [votingEnds], nil) | |
246 | 253 | if ((e == e)) | |
247 | - | then [writeConstInt(proposalHeightStore(txId), HEIGHT), writeConstInt(proposalVotingStartStore(txId), (HEIGHT + votingStartOffset)), writeConstInt(proposalVotingEndStore(txId), votingEnds), writeConstString(proposalByStore(txId), toString(i.caller)), writeInt(userLastProposeHeightStore(user), HEIGHT), writeConstString(proposalAddressStore(txId), address), IntegerEntry(proposalQuorumStore(txId), quorumRatio)] | |
254 | + | then [writeConstInt(proposalHeightStore(txId), HEIGHT), writeConstInt(proposalVotingStartStore(txId), (HEIGHT + votingStartOffset)), writeConstInt(proposalVotingEndStore(txId), votingEnds), writeConstString(proposalByStore(txId), toString(i.caller)), writeInt(userLastProposeHeightStore(user), HEIGHT), writeConstString(proposalAddressStore(txId), address), IntegerEntry(proposalQuorumStore(txId), quorumRatio), writeBinary(proposalAttachmentsStore(txId), attachments)] | |
248 | 255 | else throw("Strict value is not equal to itself.") | |
249 | 256 | } | |
250 | 257 | } | |
258 | + | } | |
259 | + | else throw("Strict value is not equal to itself.") | |
260 | + | } | |
261 | + | ||
262 | + | ||
263 | + | ||
264 | + | @Callable(i) | |
265 | + | func editAttachments (txId,attachments) = { | |
266 | + | let checks = if (opAllowed("governance_edit_attachments")) | |
267 | + | then proposalBeforeVoting(txId) | |
268 | + | else false | |
269 | + | if ((checks == checks)) | |
270 | + | then { | |
271 | + | let user = toString(i.caller) | |
272 | + | let by = valueOrErrorMessage(getString(this, proposalByStore(txId)), "proposal doesn't exist") | |
273 | + | if ((by != user)) | |
274 | + | then throw("only owner can edit proposal attachments") | |
275 | + | else [writeBinary(proposalAttachmentsStore(txId), attachments)] | |
251 | 276 | } | |
252 | 277 | else throw("Strict value is not equal to itself.") | |
253 | 278 | } |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | func throwIf (condition,error) = if (condition) | |
5 | 5 | then throw(error) | |
6 | 6 | else true | |
7 | + | ||
8 | + | ||
9 | + | func writeBinary (key,value) = BinaryEntry(key, value) | |
7 | 10 | ||
8 | 11 | ||
9 | 12 | func writeInt (key,value) = if ((0 > value)) | |
10 | 13 | then throw(((("writing negative value " + toString(value)) + " for key ") + key)) | |
11 | 14 | else IntegerEntry(key, value) | |
12 | 15 | ||
13 | 16 | ||
14 | 17 | func writeConstString (key,value) = if (!(isDefined(getString(this, key)))) | |
15 | 18 | then StringEntry(key, value) | |
16 | 19 | else throw(("already initialized: " + key)) | |
17 | 20 | ||
18 | 21 | ||
19 | 22 | func writeConstInt (key,value) = if (!(isDefined(getInteger(this, key)))) | |
20 | 23 | then IntegerEntry(key, value) | |
21 | 24 | else throw(("already exists: " + key)) | |
22 | 25 | ||
23 | 26 | ||
24 | 27 | func changeBy (key,value) = writeInt(key, (valueOrElse(getInteger(this, key), 0) + value)) | |
25 | 28 | ||
26 | 29 | ||
27 | 30 | func asInt (value) = match value { | |
28 | 31 | case int: Int => | |
29 | 32 | int | |
30 | 33 | case _ => | |
31 | 34 | throw("wrong type, expected: Int") | |
32 | 35 | } | |
33 | 36 | ||
34 | 37 | ||
35 | 38 | let configAddressStore = "configAddress" | |
36 | 39 | ||
37 | 40 | let configAddress = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, configAddressStore), "mother voting: no configAddress")), "invalid config address") | |
38 | 41 | ||
39 | 42 | let votingResultContract = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(configAddress, "contract_voting_result"), "no contract_voting_result")), "invalid contract_voting_result") | |
40 | 43 | ||
41 | 44 | let votingRewardsContract = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(configAddress, "contract_voting_rewards"), "no contract_voting_rewards")), "invalid contract_voting_rewards") | |
42 | 45 | ||
43 | 46 | let stakingContract = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(configAddress, "contract_staking"), "no staking_contract")), "invalid stakingContract") | |
44 | 47 | ||
45 | 48 | let HEIGHT = height | |
46 | 49 | ||
47 | 50 | func advise () = ("height: " + toString(HEIGHT)) | |
48 | 51 | ||
49 | 52 | ||
50 | 53 | let BASE = 1000 | |
51 | 54 | ||
52 | 55 | func opAllowed (op) = { | |
53 | 56 | let a = invoke(configAddress, "opAllowed", [op], nil) | |
54 | 57 | if ((a == a)) | |
55 | 58 | then true | |
56 | 59 | else throw("Strict value is not equal to itself.") | |
57 | 60 | } | |
58 | 61 | ||
59 | 62 | ||
60 | 63 | func proposalAddressStore (id) = ("proposal_address_" + id) | |
61 | 64 | ||
62 | 65 | ||
63 | 66 | func proposalHeightStore (id) = ("proposal_height_" + id) | |
64 | 67 | ||
65 | 68 | ||
66 | 69 | func proposalVotingStartStore (id) = ("proposal_votingstart_" + id) | |
67 | 70 | ||
68 | 71 | ||
69 | 72 | func proposalVotingEndStore (id) = ("proposal_votingend_" + id) | |
70 | 73 | ||
71 | 74 | ||
72 | 75 | func proposalByStore (id) = ("proposal_by_" + id) | |
76 | + | ||
77 | + | ||
78 | + | func proposalAttachmentsStore (id) = ("proposal_attachments_" + id) | |
73 | 79 | ||
74 | 80 | ||
75 | 81 | func proposalTotalPowerStore (id) = ("proposal_power_" + id) | |
76 | 82 | ||
77 | 83 | ||
78 | 84 | func proposalTotalYesStore (id) = ("proposal_yes_" + id) | |
79 | 85 | ||
80 | 86 | ||
81 | 87 | func proposalTotalNoStore (id) = ("proposal_no_" + id) | |
82 | 88 | ||
83 | 89 | ||
84 | 90 | func proposalUserYesStore (user,id) = ((("user_proposal_yes_" + user) + "_") + id) | |
85 | 91 | ||
86 | 92 | ||
87 | 93 | func proposalUserNoStore (user,id) = ((("user_proposal_no_" + user) + "_") + id) | |
88 | 94 | ||
89 | 95 | ||
90 | 96 | func userLastProposeHeightStore (user) = ("propose_lastheight_" + user) | |
91 | 97 | ||
92 | 98 | ||
93 | 99 | func userYes (user,id) = valueOrElse(getInteger(this, proposalUserYesStore(user, id)), 0) | |
94 | 100 | ||
95 | 101 | ||
96 | 102 | func userNo (user,id) = valueOrElse(getInteger(this, proposalUserNoStore(user, id)), 0) | |
97 | 103 | ||
98 | 104 | ||
99 | 105 | func userLastProposeHeight (user) = valueOrElse(getInteger(this, userLastProposeHeightStore(user)), -1) | |
100 | 106 | ||
101 | 107 | ||
102 | 108 | let thisAddress = toString(this) | |
103 | 109 | ||
104 | 110 | let userProposeDelay = valueOrErrorMessage(getInteger(configAddress, (thisAddress + "_user_propose_delay")), "user_propose_delay is not defined") | |
105 | 111 | ||
106 | 112 | let quorumRatio = valueOrErrorMessage(getInteger(configAddress, (thisAddress + "_proposal_quorum_ratio")), "proposalQuorumRatio is not defined") | |
107 | 113 | ||
108 | 114 | func proposalQuorumStore (txid) = ("proposal_quorum_ratio_" + txid) | |
109 | 115 | ||
110 | 116 | ||
111 | 117 | let passedRatio = valueOrErrorMessage(getInteger(configAddress, (thisAddress + "_proposal_passed_ratio")), "proposalThresholdRatio is not defined") | |
112 | 118 | ||
113 | 119 | let proposalMinRequired = valueOrErrorMessage(getInteger(configAddress, (thisAddress + "_proposal_min_power_required")), "min required is not defined") | |
114 | 120 | ||
115 | 121 | let votingStartOffset = valueOrErrorMessage(getInteger(configAddress, (thisAddress + "_proposal_votingstart_offset")), "proposal_votingstart_offset is not defined") | |
116 | 122 | ||
117 | 123 | let votingEndOffset = valueOrErrorMessage(getInteger(configAddress, (thisAddress + "_proposal_votingend_offset")), "proposal_votingend_offset is not defined") | |
118 | 124 | ||
119 | 125 | func userShares (user) = asInt(invoke(stakingContract, "userShares", [user], nil)) | |
120 | 126 | ||
121 | 127 | ||
122 | 128 | func userPower (user) = asInt(invoke(stakingContract, "userPower", [user], nil)) | |
123 | 129 | ||
124 | 130 | ||
125 | 131 | func proposalExists (txId) = match getInteger(this, proposalHeightStore(txId)) { | |
126 | 132 | case start: Int => | |
127 | 133 | true | |
128 | 134 | case _ => | |
129 | 135 | false | |
130 | 136 | } | |
131 | 137 | ||
132 | 138 | ||
133 | 139 | func proposalOnVoting (txId) = { | |
134 | 140 | let nonExistErr = "proposal doesn't exist" | |
135 | 141 | if (!(proposalExists(txId))) | |
136 | 142 | then throw(nonExistErr) | |
137 | 143 | else { | |
138 | 144 | let votingStart = valueOrErrorMessage(getInteger(this, proposalVotingStartStore(txId)), nonExistErr) | |
139 | 145 | let votingEnd = valueOrErrorMessage(getInteger(this, proposalVotingEndStore(txId)), nonExistErr) | |
140 | 146 | if ((votingStart > HEIGHT)) | |
141 | 147 | then throw(((("voting not started yet, discussion is in progress, voting will start at block " + toString(votingStart)) + ", now it's ") + toString(HEIGHT))) | |
142 | 148 | else if ((HEIGHT > votingEnd)) | |
143 | 149 | then throw(((("voting ended at block " + toString(votingEnd)) + ", now it's ") + toString(HEIGHT))) | |
144 | 150 | else true | |
145 | 151 | } | |
146 | 152 | } | |
147 | 153 | ||
148 | 154 | ||
149 | 155 | func proposalBeforeVoting (txId) = { | |
150 | 156 | let nonExistErr = "proposal doesn't exist" | |
151 | 157 | if (!(proposalExists(txId))) | |
152 | 158 | then throw(nonExistErr) | |
153 | 159 | else { | |
154 | 160 | let votingStart = valueOrErrorMessage(getInteger(this, proposalVotingStartStore(txId)), nonExistErr) | |
155 | 161 | if ((HEIGHT >= votingStart)) | |
156 | 162 | then throw("voting start is already happened") | |
157 | 163 | else true | |
158 | 164 | } | |
159 | 165 | } | |
160 | 166 | ||
161 | 167 | ||
162 | 168 | func totalVotingPower () = asInt(invoke(stakingContract, "totalShares", nil, nil)) | |
163 | 169 | ||
164 | 170 | ||
165 | 171 | func quorum (txId) = valueOrElse(getInteger(proposalQuorumStore(txId)), quorumRatio) | |
166 | 172 | ||
167 | 173 | ||
168 | 174 | func canBroadcast (id,yesInc,noInc) = { | |
169 | 175 | let votesYes = (valueOrElse(getInteger(("proposal_yes_" + id)), 0) + yesInc) | |
170 | 176 | let votesNo = (valueOrElse(getInteger(("proposal_no_" + id)), 0) + noInc) | |
171 | 177 | let totalPower = totalVotingPower() | |
172 | 178 | let totalVotes = (votesYes + votesNo) | |
173 | 179 | let hasQuorum = (((totalVotes * BASE) / totalPower) >= quorum(id)) | |
174 | 180 | let hasPassed = (((votesYes * BASE) / totalVotes) >= passedRatio) | |
175 | 181 | if (hasQuorum) | |
176 | 182 | then hasPassed | |
177 | 183 | else false | |
178 | 184 | } | |
179 | 185 | ||
180 | 186 | ||
181 | 187 | func adviseProposal (txId) = { | |
182 | 188 | let proposalHeight = valueOrErrorMessage(getInteger(proposalHeightStore(txId)), "no proposal") | |
183 | 189 | let votingStart = valueOrErrorMessage(getInteger(proposalVotingStartStore(txId)), "no proposal") | |
184 | 190 | let votingEnd = valueOrErrorMessage(getInteger(proposalVotingEndStore(txId)), "no proposal") | |
185 | 191 | let votesYes = valueOrElse(getInteger(proposalTotalYesStore(txId)), 0) | |
186 | 192 | let votesNo = valueOrElse(getInteger(proposalTotalNoStore(txId)), 0) | |
187 | 193 | let totalPowerSnap = valueOrElse(getInteger(proposalTotalPowerStore(txId)), 0) | |
188 | 194 | let totalVotes = (votesYes + votesNo) | |
195 | + | let q = quorum(txId) | |
189 | 196 | let hasQuorum = if ((totalVotes > 0)) | |
190 | - | then (((totalVotes * BASE) / totalPowerSnap) >= | |
197 | + | then (((totalVotes * BASE) / totalPowerSnap) >= q) | |
191 | 198 | else false | |
192 | 199 | let hasPassed = if ((totalVotes > 0)) | |
193 | 200 | then (((votesYes * BASE) / totalVotes) >= passedRatio) | |
194 | 201 | else false | |
195 | 202 | let inBlockchainHeight = valueOrElse(transactionHeightById(fromBase58String(txId)), 0) | |
196 | 203 | let status = if ((votingStart > HEIGHT)) | |
197 | 204 | then "discussion" | |
198 | 205 | else if ((votingEnd >= HEIGHT)) | |
199 | 206 | then "voting" | |
200 | 207 | else if (!(hasQuorum)) | |
201 | 208 | then "noQuorum" | |
202 | 209 | else if (!(hasPassed)) | |
203 | 210 | then "votingFailed" | |
204 | 211 | else if ((inBlockchainHeight > 0)) | |
205 | 212 | then "inBlockchain" | |
206 | 213 | else "waitingForTx" | |
207 | - | ((((((((((((((((((((("proposal_id: " + txId) + ", proposal_address: ") + valueOrErrorMessage(proposalAddressStore(txId), "no address")) + ", proposal_status: ") + status) + ", proposal_by: ") + valueOrErrorMessage(getString(this, proposalByStore(txId)), "no proposal")) + ", proposal_height: ") + toString(proposalHeight)) + ", proposal_txheight: ") + toString(inBlockchainHeight)) + ", proposal_votingstart: ") + toString(votingStart)) + ", proposal_votingend: ") + toString(votingEnd)) + ", proposal_power: ") + toString(totalPowerSnap)) + ", vote_yes: ") + toString(votesYes)) + ", vote_no: ") + toString(votesNo)) | |
214 | + | ((((((((((((((((((((((("proposal_id: " + txId) + ", proposal_address: ") + valueOrErrorMessage(proposalAddressStore(txId), "no address")) + ", proposal_status: ") + status) + ", proposal_by: ") + valueOrErrorMessage(getString(this, proposalByStore(txId)), "no proposal")) + ", proposal_height: ") + toString(proposalHeight)) + ", proposal_txheight: ") + toString(inBlockchainHeight)) + ", proposal_votingstart: ") + toString(votingStart)) + ", proposal_votingend: ") + toString(votingEnd)) + ", proposal_power: ") + toString(totalPowerSnap)) + ", vote_yes: ") + toString(votesYes)) + ", vote_no: ") + toString(votesNo)) + ", proposal_quorum: ") + toString(q)) | |
208 | 215 | } | |
209 | 216 | ||
210 | 217 | ||
211 | 218 | func broadcastHeight (txId) = (getIntegerValue(proposalVotingEndStore(txId)) + 1) | |
212 | 219 | ||
213 | 220 | ||
214 | 221 | func rewards (user,votes) = invoke(votingRewardsContract, "countVote", [user, votes], nil) | |
215 | 222 | ||
216 | 223 | ||
217 | 224 | func setResult (txAddress,txId,result) = invoke(votingResultContract, "setResult", [txAddress, txId, result, broadcastHeight(txId)], nil) | |
218 | 225 | ||
219 | 226 | ||
220 | 227 | func setPower (txId) = IntegerEntry(proposalTotalPowerStore(txId), totalVotingPower()) | |
221 | 228 | ||
222 | 229 | ||
223 | 230 | @Callable(i) | |
224 | 231 | func init (config) = [writeConstString(configAddressStore, config)] | |
225 | 232 | ||
226 | 233 | ||
227 | 234 | ||
228 | 235 | @Callable(i) | |
229 | - | func propose (address,txId) = { | |
236 | + | func propose (address,txId,attachments) = { | |
230 | 237 | let checks = opAllowed("governance_propose_tx") | |
231 | 238 | if ((checks == checks)) | |
232 | 239 | then { | |
233 | 240 | let user = toString(i.caller) | |
234 | 241 | let gv = userPower(user) | |
235 | 242 | if ((proposalMinRequired > gv)) | |
236 | 243 | then throw((((("not enough staked power to make proposal." + " Minimum required = ") + toString(proposalMinRequired)) + ", actual: = ") + toString(gv))) | |
237 | 244 | else { | |
238 | 245 | let last = userLastProposeHeight(user) | |
239 | 246 | if (if ((last > -1)) | |
240 | 247 | then ((last + userProposeDelay) > HEIGHT) | |
241 | 248 | else false) | |
242 | 249 | then throw(((("can't propose too often, last proroposal height: " + toString(last)) + ", blocks to wait: ") + toString(((last + userProposeDelay) - HEIGHT)))) | |
243 | 250 | else { | |
244 | 251 | let votingEnds = (HEIGHT + votingEndOffset) | |
245 | 252 | let e = invoke(votingRewardsContract, "votingEnds", [votingEnds], nil) | |
246 | 253 | if ((e == e)) | |
247 | - | then [writeConstInt(proposalHeightStore(txId), HEIGHT), writeConstInt(proposalVotingStartStore(txId), (HEIGHT + votingStartOffset)), writeConstInt(proposalVotingEndStore(txId), votingEnds), writeConstString(proposalByStore(txId), toString(i.caller)), writeInt(userLastProposeHeightStore(user), HEIGHT), writeConstString(proposalAddressStore(txId), address), IntegerEntry(proposalQuorumStore(txId), quorumRatio)] | |
254 | + | then [writeConstInt(proposalHeightStore(txId), HEIGHT), writeConstInt(proposalVotingStartStore(txId), (HEIGHT + votingStartOffset)), writeConstInt(proposalVotingEndStore(txId), votingEnds), writeConstString(proposalByStore(txId), toString(i.caller)), writeInt(userLastProposeHeightStore(user), HEIGHT), writeConstString(proposalAddressStore(txId), address), IntegerEntry(proposalQuorumStore(txId), quorumRatio), writeBinary(proposalAttachmentsStore(txId), attachments)] | |
248 | 255 | else throw("Strict value is not equal to itself.") | |
249 | 256 | } | |
250 | 257 | } | |
258 | + | } | |
259 | + | else throw("Strict value is not equal to itself.") | |
260 | + | } | |
261 | + | ||
262 | + | ||
263 | + | ||
264 | + | @Callable(i) | |
265 | + | func editAttachments (txId,attachments) = { | |
266 | + | let checks = if (opAllowed("governance_edit_attachments")) | |
267 | + | then proposalBeforeVoting(txId) | |
268 | + | else false | |
269 | + | if ((checks == checks)) | |
270 | + | then { | |
271 | + | let user = toString(i.caller) | |
272 | + | let by = valueOrErrorMessage(getString(this, proposalByStore(txId)), "proposal doesn't exist") | |
273 | + | if ((by != user)) | |
274 | + | then throw("only owner can edit proposal attachments") | |
275 | + | else [writeBinary(proposalAttachmentsStore(txId), attachments)] | |
251 | 276 | } | |
252 | 277 | else throw("Strict value is not equal to itself.") | |
253 | 278 | } | |
254 | 279 | ||
255 | 280 | ||
256 | 281 | ||
257 | 282 | @Callable(i) | |
258 | 283 | func voteYes (txId) = { | |
259 | 284 | let checks = if (opAllowed("governance_vote_tx")) | |
260 | 285 | then proposalOnVoting(txId) | |
261 | 286 | else false | |
262 | 287 | if ((checks == checks)) | |
263 | 288 | then { | |
264 | 289 | let user = toString(i.caller) | |
265 | 290 | if ((userNo(user, txId) > 0)) | |
266 | 291 | then throw("already voted against, please retract your vote first") | |
267 | 292 | else { | |
268 | 293 | let yesDelta = (userShares(user) - userYes(user, txId)) | |
269 | 294 | let restake = invoke(stakingContract, "restakeFor", [user], nil) | |
270 | 295 | if ((restake == restake)) | |
271 | 296 | then { | |
272 | 297 | let txAddress = valueOrErrorMessage(getString(proposalAddressStore(txId)), "proposal address not found") | |
273 | 298 | let result = canBroadcast(txId, yesDelta, 0) | |
274 | 299 | let s = setResult(txAddress, txId, result) | |
275 | 300 | if ((s == s)) | |
276 | 301 | then { | |
277 | 302 | let r = rewards(user, yesDelta) | |
278 | 303 | if ((r == r)) | |
279 | 304 | then [setPower(txId), changeBy(proposalUserYesStore(user, txId), yesDelta), changeBy(proposalTotalYesStore(txId), yesDelta)] | |
280 | 305 | else throw("Strict value is not equal to itself.") | |
281 | 306 | } | |
282 | 307 | else throw("Strict value is not equal to itself.") | |
283 | 308 | } | |
284 | 309 | else throw("Strict value is not equal to itself.") | |
285 | 310 | } | |
286 | 311 | } | |
287 | 312 | else throw("Strict value is not equal to itself.") | |
288 | 313 | } | |
289 | 314 | ||
290 | 315 | ||
291 | 316 | ||
292 | 317 | @Callable(i) | |
293 | 318 | func voteNo (txId) = { | |
294 | 319 | let checks = if (opAllowed("governance_vote_tx")) | |
295 | 320 | then proposalOnVoting(txId) | |
296 | 321 | else false | |
297 | 322 | if ((checks == checks)) | |
298 | 323 | then { | |
299 | 324 | let user = toString(i.caller) | |
300 | 325 | if ((userYes(user, txId) > 0)) | |
301 | 326 | then throw("already voted for, please retract your vote first") | |
302 | 327 | else { | |
303 | 328 | let noDelta = (userShares(user) - userNo(user, txId)) | |
304 | 329 | let restake = invoke(stakingContract, "restakeFor", [user], nil) | |
305 | 330 | if ((restake == restake)) | |
306 | 331 | then { | |
307 | 332 | let txAddress = valueOrErrorMessage(getString(proposalAddressStore(txId)), "proposal address not found") | |
308 | 333 | let result = canBroadcast(txId, 0, noDelta) | |
309 | 334 | let s = setResult(txAddress, txId, result) | |
310 | 335 | if ((s == s)) | |
311 | 336 | then { | |
312 | 337 | let r = rewards(user, noDelta) | |
313 | 338 | if ((r == r)) | |
314 | 339 | then [setPower(txId), changeBy(proposalUserNoStore(user, txId), noDelta), changeBy(proposalTotalNoStore(txId), noDelta)] | |
315 | 340 | else throw("Strict value is not equal to itself.") | |
316 | 341 | } | |
317 | 342 | else throw("Strict value is not equal to itself.") | |
318 | 343 | } | |
319 | 344 | else throw("Strict value is not equal to itself.") | |
320 | 345 | } | |
321 | 346 | } | |
322 | 347 | else throw("Strict value is not equal to itself.") | |
323 | 348 | } | |
324 | 349 | ||
325 | 350 | ||
326 | 351 | ||
327 | 352 | @Callable(i) | |
328 | 353 | func retract (txId) = { | |
329 | 354 | let checks = if (opAllowed("governance_retract_vote")) | |
330 | 355 | then proposalOnVoting(txId) | |
331 | 356 | else false | |
332 | 357 | if ((checks == checks)) | |
333 | 358 | then { | |
334 | 359 | let user = toString(i.caller) | |
335 | 360 | let yes = userYes(user, txId) | |
336 | 361 | let no = userNo(user, txId) | |
337 | 362 | let txAddress = valueOrErrorMessage(getString(proposalAddressStore(txId)), "proposal address not found") | |
338 | 363 | let result = canBroadcast(txId, -(yes), -(no)) | |
339 | 364 | let s = setResult(txAddress, txId, result) | |
340 | 365 | if ((s == s)) | |
341 | 366 | then { | |
342 | 367 | let r = rewards(user, (-(yes) - no)) | |
343 | 368 | if ((r == r)) | |
344 | 369 | then [changeBy(proposalTotalYesStore(txId), -(yes)), changeBy(proposalTotalNoStore(txId), -(no)), DeleteEntry(proposalUserYesStore(user, txId)), DeleteEntry(proposalUserNoStore(user, txId))] | |
345 | 370 | else throw("Strict value is not equal to itself.") | |
346 | 371 | } | |
347 | 372 | else throw("Strict value is not equal to itself.") | |
348 | 373 | } | |
349 | 374 | else throw("Strict value is not equal to itself.") | |
350 | 375 | } | |
351 | 376 | ||
352 | 377 | ||
353 | 378 | ||
354 | 379 | @Callable(i) | |
355 | 380 | func retractProposal (txId) = { | |
356 | 381 | let checks = if (opAllowed("governance_retract_proposal_tx")) | |
357 | 382 | then proposalBeforeVoting(txId) | |
358 | 383 | else false | |
359 | 384 | if ((checks == checks)) | |
360 | 385 | then { | |
361 | 386 | let by = valueOrErrorMessage(getString(this, proposalByStore(txId)), "proposal doesn't exist") | |
362 | 387 | let user = toString(i.caller) | |
363 | 388 | if ((by != user)) | |
364 | 389 | then throw("only owner can retract proposal") | |
365 | 390 | else [DeleteEntry(proposalHeightStore(txId)), DeleteEntry(proposalVotingStartStore(txId)), DeleteEntry(proposalVotingEndStore(txId)), DeleteEntry(proposalByStore(txId)), DeleteEntry(proposalTotalPowerStore(txId)), DeleteEntry(proposalTotalYesStore(txId)), DeleteEntry(proposalTotalNoStore(txId)), DeleteEntry(proposalUserYesStore(user, txId)), DeleteEntry(proposalUserNoStore(user, txId)), DeleteEntry(userLastProposeHeightStore(user)), DeleteEntry(proposalAddressStore(txId))] | |
366 | 391 | } | |
367 | 392 | else throw("Strict value is not equal to itself.") | |
368 | 393 | } | |
369 | 394 | ||
370 | 395 |
github/deemru/w8io/3ef1775 66.57 ms ◑