tx · 6DaPD16Yqps9GjwdXMDWTy14yvGCJztqcJJ1qbG8WrFb 3NA3yH1QryPynpwGhEYR3W3LSneJK73rWeL: -0.00900000 Waves 2022.08.10 15:26 [2178343] smart account 3NA3yH1QryPynpwGhEYR3W3LSneJK73rWeL > SELF 0.00000000 Waves
{ "type": 13, "id": "6DaPD16Yqps9GjwdXMDWTy14yvGCJztqcJJ1qbG8WrFb", "fee": 900000, "feeAssetId": null, "timestamp": 1660134381298, "version": 2, "chainId": 84, "sender": "3NA3yH1QryPynpwGhEYR3W3LSneJK73rWeL", "senderPublicKey": "6Ji8AyKFQegAeGHgCr6CYZgm3xxVSbQ9A884zpfzxS77", "proofs": [ "5qvJQhaMNnXWABJ2R5Vonyij4eqXqeUs8qvKjZ9S2CZh7iFBtoW1vKZW5R5PFr4LG9qUA5WYczqR4hTWxYTzXV2W" ], "script": "base64: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c3QgYmUgZ3JlYXRlciB0aGVuIHRocmVzaG9sZCAJAAGkAAAAAQUAAAAUc3Rha2VBbW91bnRUaHJlc2hvbGQICQABkQAAAAIFAAAACHBheW1lbnRzAAAAAAAAAAAAAAAABmFtb3VudAEAAAAWZ2V0Q3VycmVudExvY2tlZEFtb3VudAAAAAEAAAAEdXNlcgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzCQEAAAATa2V5X1VzZXJTdGFrZWRUb3RhbAAAAAEFAAAABHVzZXIAAAAAAAAAAAABAAAABXN0YWtlAAAABAAAAANpbnYAAAAKcmV3YXJkVHlwZQAAAApkYXlzVG9Mb2NrAAAAC2JlbmVmaWNpYXJ5BAAAAAljYWxsZXJTdHIJAAQlAAAAAQgFAAAAA2ludgAAAAZjYWxsZXIEAAAACXBtdEFtb3VudAkBAAAAFGV4dHJhY3RQYXltZW50QW1vdW50AAAAAQgFAAAAA2ludgAAAAhwYXltZW50cwQAAAAaYmVnaW5uaW5nT2ZOZXhEYXlUaW1lc3RhbXAJAABlAAAAAgkAAGQAAAACBQAAABBjdXJyZW50VGltZXN0YW1wBQAAAAdob3VyczI0CQAAagAAAAIFAAAAEGN1cnJlbnRUaW1lc3RhbXAFAAAAB2hvdXJzMjQEAAAAEmxvY2tVbnRpbFRpbWVzdGFtcAkAAGQAAAACBQAAABpiZWdpbm5pbmdPZk5leERheVRpbWVzdGFtcAkAAGgAAAACBQAAAApkYXlzVG9Mb2NrBQAAAAdob3VyczI0BAAAAApzdGFraW5nS2V5CQEAAAAPa2V5X1VzZXJTdGFraW5nAAAAAgUAAAAJY2FsbGVyU3RyCQACWAAAAAEIBQAAAANpbnYAAAANdHJhbnNhY3Rpb25JZAQAAAAMc3Rha2luZ1ZhbHVlCQAEuQAAAAIJAARMAAAAAgUAAAAGQUNUSVZFCQAETAAAAAIJAAGkAAAAAQUAAAAJcG10QW1vdW50CQAETAAAAAIFAAAACnJld2FyZFR5cGUJAARMAAAAAgkAAaQAAAABBQAAAApkYXlzVG9Mb2NrCQAETAAAAAIJAAGkAAAAAQUAAAAQY3VycmVudFRpbWVzdGFtcAkABEwAAAACCQABpAAAAAEFAAAAEmxvY2tVbnRpbFRpbWVzdGFtcAUAAAADbmlsAgAAAAEsAwkAAAAAAAACCAUAAAADaW52AAAADXRyYW5zYWN0aW9uSWQFAAAADWxhc3RTdGFrZVR4SWQJAAACAAAAAQIAAAA5VGhlcmUgaXMgb25seSBvbmUgc3Rha2luZyBwZXIgdHJhbnNhY3Rpb24gYWxsb3dlZCBmb3Igbm93AwkBAAAACWlzRGVmaW5lZAAAAAEJAAQdAAAAAgUAAAAEdGhpcwUAAAAKc3Rha2luZ0tleQkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgIAAAAJU3Rha2luZyAnBQAAAApzdGFraW5nS2V5AgAAABAnIGFscmVhZHkgZXhpc3RzAwkBAAAAASEAAAABCQEAAAAPY29udGFpbnNFbGVtZW50AAAAAgUAAAAYcG9zc2libGVUb2tlbnNGb3JSZXdhcmRzBQAAAApyZXdhcmRUeXBlCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACAgAAABlVbnN1cHBvcnRlZCByZXdhcmQgdHlwZSAnBQAAAApyZXdhcmRUeXBlAgAAAAEnAwkBAAAAASEAAAABCQEAAAAPY29udGFpbnNFbGVtZW50AAAAAgUAAAARbG9ja1BlcmlvZHNJbkRheXMFAAAACmRheXNUb0xvY2sJAAACAAAAAQkAASwAAAACCQABLAAAAAICAAAAG1Vuc3VwcG9ydGVkIG51bWJlciBvZiBkYXlzIAkAAaQAAAABBQAAAApkYXlzVG9Mb2NrAgAAAAggdG8gbWluZQkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAAApzdGFraW5nS2V5BQAAAAxzdGFraW5nVmFsdWUJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABNrZXlfVXNlclN0YWtlZFRvdGFsAAAAAQkABCUAAAABCAUAAAADaW52AAAABmNhbGxlcgkAAGQAAAACCQEAAAAWZ2V0Q3VycmVudExvY2tlZEFtb3VudAAAAAEJAAQlAAAAAQgFAAAAA2ludgAAAAZjYWxsZXIFAAAACXBtdEFtb3VudAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAPa2V5X1N0YWtlZFRvdGFsCQAAZAAAAAIFAAAAC3N0YWtlZFRvdGFsBQAAAAlwbXRBbW91bnQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAARa2V5X0xhc3RTdGFrZVR4SWQJAAJYAAAAAQgFAAAAA2ludgAAAA10cmFuc2FjdGlvbklkBQAAAANuaWwAAAAFAAAAA2ludgEAAAAEaW5pdAAAAAEAAAATaGFzaHJhdGVUb2tlbklzc3VlcgQAAAAGaXNzdWVyCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQUAAAATaGFzaHJhdGVUb2tlbklzc3VlcgkAASwAAAACCQABLAAAAAICAAAAHENhbid0IHBhcnNlIGlzc3VlciBhZGRyZXNzICcFAAAAE2hhc2hyYXRlVG9rZW5Jc3N1ZXICAAAAAScEAAAACmFzc2V0SWRTdHIJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAZpc3N1ZXIFAAAAEmtleV9Jc3N1ZXJfQXNzZXRJZAkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAASQ2FuJ3QgZmluZCBlbnRyeSAnBQAAABJrZXlfSXNzdWVyX0Fzc2V0SWQCAAAADScgYXQgYWRkcmVzcyAFAAAAE2hhc2hyYXRlVG9rZW5Jc3N1ZXIEAAAACm5ld0Fzc2V0SWQICQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAPsAAAAAQkAAlkAAAABBQAAAAphc3NldElkU3RyCQABLAAAAAIJAAEsAAAAAgIAAAASQ2FuJ3QgZmluZCBhc3NldCAnBQAAAAphc3NldElkU3RyAgAAAAEnAAAAAmlkAwkBAAAAAiE9AAAAAggFAAAAA2ludgAAAAZjYWxsZXIFAAAABHRoaXMJAAACAAAAAQIAAAArT25seSB0aGUgREFwcCBpdHNlbGYgY2FuIGNhbGwgdGhpcyBmdW5jdGlvbgMFAAAACmlzREFwcEluaXQJAAACAAAAAQIAAAAUREFwcCBpcyBhbHJlYWR5IGluaXQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAATa2V5X0hhc2hyYXRlVG9rZW5JZAkAAlgAAAABBQAAAApuZXdBc3NldElkCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAA9rZXlfU3Rha2VkVG90YWwAAAAAAAAAAAAFAAAAA25pbAAAAANpbnYBAAAADHNldFByb21vREFwcAAAAAEAAAAHYWRkcmVzcwMJAQAAAAlpc0RlZmluZWQAAAABCQAEHQAAAAIFAAAABHRoaXMFAAAADWtleV9Qcm9tb0RBcHAJAAACAAAAAQIAAAAnUHJvbW8gREFwcCBhZGRyZXNzIGlzIGFscmVhZHkgc3BlY2lmaWVkCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADWtleV9Qcm9tb0RBcHAJAAQlAAAAAQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEJgAAAAEFAAAAB2FkZHJlc3MJAAEsAAAAAgkAASwAAAACAgAAAA1DYW4ndCBwYXJzZSAnBQAAAAdhZGRyZXNzAgAAAAwnIGFzIGFkZHJlc3MFAAAAA25pbAAAAANpbnYBAAAABGxvY2sAAAACAAAACnJld2FyZFR5cGUAAAAKZGF5c1RvTG9jawkBAAAABXN0YWtlAAAABAUAAAADaW52BQAAAApyZXdhcmRUeXBlBQAAAApkYXlzVG9Mb2NrCAUAAAADaW52AAAABmNhbGxlcgAAAANpbnYBAAAABmxvY2tCeQAAAAMAAAALYmVuZWZpY2lhcnkAAAAKcmV3YXJkVHlwZQAAAApkYXlzVG9Mb2NrCQEAAAAFc3Rha2UAAAAEBQAAAANpbnYFAAAACnJld2FyZFR5cGUFAAAACmRheXNUb0xvY2sJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABCYAAAABBQAAAAtiZW5lZmljaWFyeQkAASwAAAACCQABLAAAAAICAAAAGUNhbid0IHBhcnNlIGJlbmVmZWNpYXJ5ICcFAAAAC2JlbmVmaWNpYXJ5AgAAAAwnIGFzIGFkZHJlc3MAAAADaW52AQAAAAZ1bmxvY2sAAAACAAAABHVzZXIAAAAHc3Rha2luZwQAAAALdXNlckFkZHJlc3MJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABCYAAAABBQAAAAR1c2VyCQABLAAAAAIJAAEsAAAAAgIAAAAaQ2FuJ3QgcGFyc2UgdXNlciBhZGRyZXNzICcFAAAABHVzZXICAAAAAScKAQAAAA5leHRyYWN0U3Rha2luZwAAAAIAAAADYWNjAAAABHR4SWQEAAAACnBhcmFtZXRlcnMEAAAAA3ZhbAkABLUAAAACCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwkBAAAAD2tleV9Vc2VyU3Rha2luZwAAAAIFAAAABHVzZXIFAAAABHR4SWQJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAACFN0YWtpbmcgBQAAAAR0eElkAgAAABggZG9lc24ndCBleGlzdCBmb3IgdXNlciAFAAAABHVzZXICAAAAASwDCQEAAAACIT0AAAACCQABkAAAAAEFAAAAA3ZhbAAAAAAAAAAABgkAAAIAAAABCQABLAAAAAICAAAAIkNhbid0IHBhcnNlIHBhcmFtZXRlcnMgb2Ygc3Rha2luZyAFAAAABHR4SWQDCQEAAAACIT0AAAACCQABkQAAAAIFAAAAA3ZhbAAAAAAAAAAAAAUAAAAGQUNUSVZFCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACAgAAAAlzdGFraW5nICcFAAAABHR4SWQCAAAAFScgaXMgYWxyZWFkeSB1bmxvY2tlZAUAAAADdmFsBAAAAAskdDA1ODM3NTkyNQkABRQAAAACCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAGRAAAAAgUAAAAKcGFyYW1ldGVycwAAAAAAAAAAAQkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAACnBhcmFtZXRlcnMAAAAAAAAAAAUEAAAABmFtb3VudAgFAAAACyR0MDU4Mzc1OTI1AAAAAl8xBAAAAAlsb2NrVW50aWwIBQAAAAskdDA1ODM3NTkyNQAAAAJfMgMJAABmAAAAAgUAAAAJbG9ja1VudGlsBQAAABBjdXJyZW50VGltZXN0YW1wCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAG1VuYWJsZSB0byB3aXRoZHJhdyBzdGFraW5nIAUAAAAEdHhJZAIAAAAiIGJlY2F1c2UgaXQgaXMgc3RpbGwgbG9ja2VkIHVudGlsIAkAAaQAAAABBQAAAAlsb2NrVW50aWwJAAUUAAAAAgkABE0AAAACCAUAAAADYWNjAAAAAl8xCQEAAAALU3RyaW5nRW50cnkAAAACCQABLAAAAAIJAAEsAAAAAgUAAAAEdXNlcgIAAAABXwUAAAAEdHhJZAkABLkAAAACCQAETAAAAAIFAAAACEZJTklTSEVECQAETAAAAAIJAAGRAAAAAgUAAAAKcGFyYW1ldGVycwAAAAAAAAAAAQkABEwAAAACCQABkQAAAAIFAAAACnBhcmFtZXRlcnMAAAAAAAAAAAIJAARMAAAAAgkAAZEAAAACBQAAAApwYXJhbWV0ZXJzAAAAAAAAAAADCQAETAAAAAIJAAGRAAAAAgUAAAAKcGFyYW1ldGVycwAAAAAAAAAABAkABEwAAAACCQABkQAAAAIFAAAACnBhcmFtZXRlcnMAAAAAAAAAAAUFAAAAA25pbAIAAAABLAkAAGQAAAACCAUAAAADYWNjAAAAAl8yBQAAAAZhbW91bnQEAAAACyR0MDYzMTc2Mzk1CgAAAAACJGwFAAAAB3N0YWtpbmcKAAAAAAIkcwkAAZAAAAABBQAAAAIkbAoAAAAABSRhY2MwCQAFFAAAAAIFAAAAA25pbAAAAAAAAAAAAAoBAAAABSRmMF8xAAAAAgAAAAIkYQAAAAIkaQMJAABnAAAAAgUAAAACJGkFAAAAAiRzBQAAAAIkYQkBAAAADmV4dHJhY3RTdGFraW5nAAAAAgUAAAACJGEJAAGRAAAAAgUAAAACJGwFAAAAAiRpCgEAAAAFJGYwXzIAAAACAAAAAiRhAAAAAiRpAwkAAGcAAAACBQAAAAIkaQUAAAACJHMFAAAAAiRhCQAAAgAAAAECAAAAFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEAAAAFJGYwXzIAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACCQEAAAAFJGYwXzEAAAACBQAAAAUkYWNjMAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAgAAAAAAAAAAAwAAAAAAAAAABAAAAAAAAAAABQAAAAAAAAAABgAAAAAAAAAABwAAAAAAAAAACAAAAAAAAAAACQAAAAAAAAAACgQAAAALdW5zdGFrZUxpc3QIBQAAAAskdDA2MzE3NjM5NQAAAAJfMQQAAAANdG90YWxVbnN0YWtlZAgFAAAACyR0MDYzMTc2Mzk1AAAAAl8yBAAAAAx1c2VyVG90YWxLZXkJAQAAABNrZXlfVXNlclN0YWtlZFRvdGFsAAAAAQUAAAAEdXNlcgQAAAAJdXNlclRvdGFsCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAADHVzZXJUb3RhbEtleQAAAAAAAAAAAAQAAAAOdXNlclRvdGFsQWZ0ZXIJAABlAAAAAgUAAAAJdXNlclRvdGFsBQAAAA10b3RhbFVuc3Rha2VkAwkBAAAAAiE9AAAAAgkAAZAAAAABCAUAAAADaW52AAAACHBheW1lbnRzAAAAAAAAAAAACQAAAgAAAAECAAAALVRoZXJlIHNob3VsZCBiZSBubyBwYXltZW50cyBmb3IgdGhpcyBmdW5jdGlvbgMDCQEAAAACIT0AAAACCAUAAAADaW52AAAABmNhbGxlcgUAAAAEdGhpcwkBAAAAAiE9AAAAAgUAAAALdXNlckFkZHJlc3MIBQAAAANpbnYAAAAGY2FsbGVyBwkAAAIAAAABAgAAAExPbmx5IHVzZXJzIHRoZW1zZWx2ZXMgY2FuIHdpdGhkcmF3IHRoZWlyIHVubG9ja2VkIHN0YWtpbmcsIG9yIGFkbWluIGZvciB0aGVtAwkAAAAAAAACBQAAAAt1c2VyQWRkcmVzcwUAAAAJcHJvbW9EQXBwCQAAAgAAAAECAAAANVByb21vIHN0YWtpbmcgY2FuIGJlIHVubG9ja2VkIG9ubHkgYnkgUHJvbW8gREFwcCBvbmx5AwMDCQAAZgAAAAIAAAAAAAAAAAAFAAAACXVzZXJUb3RhbAYJAABmAAAAAgAAAAAAAAAAAAUAAAANdG90YWxVbnN0YWtlZAYJAABmAAAAAgAAAAAAAAAAAAUAAAAOdXNlclRvdGFsQWZ0ZXIJAAACAAAAAQIAAAAPbmVnYXRpdmUgcmVzdWx0CQAETgAAAAIFAAAAC3Vuc3Rha2VMaXN0CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAA9rZXlfU3Rha2VkVG90YWwJAABlAAAAAgUAAAALc3Rha2VkVG90YWwFAAAADXRvdGFsVW5zdGFrZWQJAARMAAAAAgMJAABmAAAAAgUAAAAOdXNlclRvdGFsQWZ0ZXIAAAAAAAAAAAAJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAAx1c2VyVG90YWxLZXkFAAAADnVzZXJUb3RhbEFmdGVyCQEAAAALRGVsZXRlRW50cnkAAAABBQAAAAx1c2VyVG90YWxLZXkJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAALdXNlckFkZHJlc3MFAAAADXRvdGFsVW5zdGFrZWQFAAAAD2hhc2hyYXRlVG9rZW5JZAUAAAADbmlsAAAAAJNOosM=", "height": 2178343, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: HA7xiL7ndmW9mkk1AxofddnJsBGtt4jgkurKJZjXnusb Next: 9qjQ7prN1uN8zFBAFA3cmehN8bies5ynw7cTvFZpSYzj Diff:
Old | New | Differences | |
---|---|---|---|
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let stakeAmountThreshold = 1 | |
5 | 5 | ||
6 | - | let lockPeriodsInDays = [1, 10, 30, 90 | |
6 | + | let lockPeriodsInDays = [1, 10, 30, 90] | |
7 | 7 | ||
8 | - | let possibleTokensForRewards = ["REDSmb", " | |
8 | + | let possibleTokensForRewards = ["REDSmb", "BTC"] | |
9 | 9 | ||
10 | 10 | let hours24 = 86400000 | |
11 | 11 | ||
13 | 13 | ||
14 | 14 | let currentTimestamp = lastBlock.timestamp | |
15 | 15 | ||
16 | - | let | |
16 | + | let key_HashrateTokenId = "hashrateTokenId" | |
17 | 17 | ||
18 | - | let | |
18 | + | let key_StakedTotal = "staked_total" | |
19 | 19 | ||
20 | - | let keyTotal = "staked_total" | |
21 | - | ||
22 | - | func keyStaked (address) = address | |
20 | + | func key_UserStaking (address,txId) = ((address + "_staking_") + txId) | |
23 | 21 | ||
24 | 22 | ||
25 | - | ||
23 | + | func key_UserStakedTotal (address) = (address + "_total") | |
26 | 24 | ||
27 | - | let assetId = fromBase58String(getStringValue(this, keyAssetId)) | |
28 | 25 | ||
29 | - | let totalStaked = valueOrErrorMessage(getInteger(this, keyTotal), (("Can't read field '" + keyTotal) + "'")) | |
26 | + | let key_LastStakeTxId = "last_stake_tx_id" | |
27 | + | ||
28 | + | let key_PromoDApp = "promo_dapp" | |
29 | + | ||
30 | + | let key_Issuer_AssetId = "assetId" | |
31 | + | ||
32 | + | let isDAppInit = if (!(isDataStorageUntouched(this))) | |
33 | + | then true | |
34 | + | else isDefined(getString(this, key_HashrateTokenId)) | |
35 | + | ||
36 | + | let hashrateTokenId = fromBase58String(getStringValue(this, key_HashrateTokenId)) | |
37 | + | ||
38 | + | let stakedTotal = valueOrErrorMessage(getInteger(this, key_StakedTotal), (("Can't read field '" + key_StakedTotal) + "'")) | |
39 | + | ||
40 | + | let lastStakeTxId = fromBase58String(valueOrErrorMessage(getString(this, key_LastStakeTxId), (("Can't read field '" + key_LastStakeTxId) + "'"))) | |
41 | + | ||
42 | + | let promoDApp = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, key_PromoDApp), (("Can't read field '" + key_PromoDApp) + "'"))), "Can't parse promo DApp address") | |
43 | + | ||
44 | + | let ACTIVE = "1" | |
45 | + | ||
46 | + | let FINISHED = "0" | |
30 | 47 | ||
31 | 48 | func extractPaymentAmount (payments) = if ((size(payments) != 1)) | |
32 | 49 | then throw("Single payment required") | |
33 | - | else if ((payments[0].assetId != | |
50 | + | else if ((payments[0].assetId != hashrateTokenId)) | |
34 | 51 | then throw("Only REDSmb token is accepted") | |
35 | 52 | else if ((stakeAmountThreshold > payments[0].amount)) | |
36 | 53 | then throw(("Payment amount must be greater then threshold " + toString(stakeAmountThreshold))) | |
37 | 54 | else payments[0].amount | |
38 | 55 | ||
39 | 56 | ||
40 | - | func getCurrentStakedAmount (user) = valueOrElse(getInteger(this, keyStaked(user)), 0) | |
57 | + | func getCurrentLockedAmount (user) = valueOrElse(getInteger(this, key_UserStakedTotal(user)), 0) | |
58 | + | ||
59 | + | ||
60 | + | func stake (inv,rewardType,daysToLock,beneficiary) = { | |
61 | + | let callerStr = toString(inv.caller) | |
62 | + | let pmtAmount = extractPaymentAmount(inv.payments) | |
63 | + | let beginningOfNexDayTimestamp = ((currentTimestamp + hours24) - (currentTimestamp % hours24)) | |
64 | + | let lockUntilTimestamp = (beginningOfNexDayTimestamp + (daysToLock * hours24)) | |
65 | + | let stakingKey = key_UserStaking(callerStr, toBase58String(inv.transactionId)) | |
66 | + | let stakingValue = makeString([ACTIVE, toString(pmtAmount), rewardType, toString(daysToLock), toString(currentTimestamp), toString(lockUntilTimestamp)], ",") | |
67 | + | if ((inv.transactionId == lastStakeTxId)) | |
68 | + | then throw("There is only one staking per transaction allowed for now") | |
69 | + | else if (isDefined(getString(this, stakingKey))) | |
70 | + | then throw((("Staking '" + stakingKey) + "' already exists")) | |
71 | + | else if (!(containsElement(possibleTokensForRewards, rewardType))) | |
72 | + | then throw((("Unsupported reward type '" + rewardType) + "'")) | |
73 | + | else if (!(containsElement(lockPeriodsInDays, daysToLock))) | |
74 | + | then throw((("Unsupported number of days " + toString(daysToLock)) + " to mine")) | |
75 | + | else [StringEntry(stakingKey, stakingValue), IntegerEntry(key_UserStakedTotal(toString(inv.caller)), (getCurrentLockedAmount(toString(inv.caller)) + pmtAmount)), IntegerEntry(key_StakedTotal, (stakedTotal + pmtAmount)), StringEntry(key_LastStakeTxId, toBase58String(inv.transactionId))] | |
76 | + | } | |
41 | 77 | ||
42 | 78 | ||
43 | 79 | @Callable(inv) | |
44 | - | func init (hashrateAssetId) = { | |
45 | - | let newAssetId = valueOrErrorMessage(assetInfo(fromBase58String(hashrateAssetId)), "Can't find asset").id | |
46 | - | if (isInit) | |
47 | - | then throw("DApp is already init") | |
48 | - | else [BooleanEntry(keyInit, true), StringEntry("assetId", toBase58String(newAssetId)), IntegerEntry(keyTotal, 0)] | |
80 | + | func init (hashrateTokenIssuer) = { | |
81 | + | let issuer = valueOrErrorMessage(addressFromString(hashrateTokenIssuer), (("Can't parse issuer address '" + hashrateTokenIssuer) + "'")) | |
82 | + | let assetIdStr = valueOrErrorMessage(getString(issuer, key_Issuer_AssetId), ((("Can't find entry '" + key_Issuer_AssetId) + "' at address ") + hashrateTokenIssuer)) | |
83 | + | let newAssetId = valueOrErrorMessage(assetInfo(fromBase58String(assetIdStr)), (("Can't find asset '" + assetIdStr) + "'")).id | |
84 | + | if ((inv.caller != this)) | |
85 | + | then throw("Only the DApp itself can call this function") | |
86 | + | else if (isDAppInit) | |
87 | + | then throw("DApp is already init") | |
88 | + | else [StringEntry(key_HashrateTokenId, toBase58String(newAssetId)), IntegerEntry(key_StakedTotal, 0)] | |
49 | 89 | } | |
50 | 90 | ||
51 | 91 | ||
52 | 92 | ||
53 | 93 | @Callable(inv) | |
54 | - | func stake (forRewardIn,daysToMine) = { | |
55 | - | let callerStr = toString(inv.caller) | |
56 | - | let pmtAmount = extractPaymentAmount(inv.payments) | |
57 | - | let beginningOfNexDayTimestamp = ((currentTimestamp + hours24) - (currentTimestamp % hours24)) | |
58 | - | let lockUntilTimestamp = (beginningOfNexDayTimestamp + (daysToMine * hours24)) | |
59 | - | let stakingKey = ((callerStr + "_staking_") + toBase58String(inv.transactionId)) | |
60 | - | let stakingValue = makeString([toString(pmtAmount), forRewardIn, toString(daysToMine), toString(currentTimestamp), toString(lockUntilTimestamp)], ",") | |
61 | - | let userTotalKey = (callerStr + "_lockedTotal") | |
62 | - | if (isDefined(getString(this, stakingKey))) | |
63 | - | then throw((("Staking '" + stakingKey) + "' already exists")) | |
64 | - | else if (!(containsElement(lockPeriodsInDays, daysToMine))) | |
65 | - | then throw((("Unsupported number of days " + toString(daysToMine)) + " to mine")) | |
66 | - | else if (!(containsElement(possibleTokensForRewards, forRewardIn))) | |
67 | - | then throw((("Unsupported reward type '" + forRewardIn) + "'")) | |
68 | - | else [StringEntry(stakingKey, stakingValue), IntegerEntry(userTotalKey, (valueOrElse(getInteger(this, userTotalKey), 0) + pmtAmount)), IntegerEntry(keyTotal, (totalStaked + pmtAmount))] | |
69 | - | } | |
94 | + | func setPromoDApp (address) = if (isDefined(getString(this, key_PromoDApp))) | |
95 | + | then throw("Promo DApp address is already specified") | |
96 | + | else [StringEntry(key_PromoDApp, toString(valueOrErrorMessage(addressFromString(address), (("Can't parse '" + address) + "' as address"))))] | |
70 | 97 | ||
71 | 98 | ||
72 | 99 | ||
73 | 100 | @Callable(inv) | |
74 | - | func withdraw (user,staking) = { | |
101 | + | func lock (rewardType,daysToLock) = stake(inv, rewardType, daysToLock, inv.caller) | |
102 | + | ||
103 | + | ||
104 | + | ||
105 | + | @Callable(inv) | |
106 | + | func lockBy (beneficiary,rewardType,daysToLock) = stake(inv, rewardType, daysToLock, valueOrErrorMessage(addressFromString(beneficiary), (("Can't parse benefeciary '" + beneficiary) + "' as address"))) | |
107 | + | ||
108 | + | ||
109 | + | ||
110 | + | @Callable(inv) | |
111 | + | func unlock (user,staking) = { | |
75 | 112 | let userAddress = valueOrErrorMessage(addressFromString(user), (("Can't parse user address '" + user) + "'")) | |
76 | 113 | func extractStaking (acc,txId) = { | |
77 | 114 | let parameters = { | |
78 | - | let val = split(valueOrErrorMessage(getString(this, | |
79 | - | if ((size(val) != | |
115 | + | let val = split(valueOrErrorMessage(getString(this, key_UserStaking(user, txId)), ((("Staking " + txId) + " doesn't exist for user ") + user)), ",") | |
116 | + | if ((size(val) != 6)) | |
80 | 117 | then throw(("Can't parse parameters of staking " + txId)) | |
81 | - | else val | |
118 | + | else if ((val[0] != ACTIVE)) | |
119 | + | then throw((("staking '" + txId) + "' is already unlocked")) | |
120 | + | else val | |
82 | 121 | } | |
83 | - | let $ | |
84 | - | let amount = $ | |
85 | - | let lockUntil = $ | |
122 | + | let $t058375925 = $Tuple2(parseIntValue(parameters[1]), parseIntValue(parameters[5])) | |
123 | + | let amount = $t058375925._1 | |
124 | + | let lockUntil = $t058375925._2 | |
86 | 125 | if ((lockUntil > currentTimestamp)) | |
87 | 126 | then throw(((("Unable to withdraw staking " + txId) + " because it is still locked until ") + toString(lockUntil))) | |
88 | - | else $Tuple2((acc._1 :+ | |
127 | + | else $Tuple2((acc._1 :+ StringEntry(((user + "_") + txId), makeString([FINISHED, parameters[1], parameters[2], parameters[3], parameters[4], parameters[5]], ","))), (acc._2 + amount)) | |
89 | 128 | } | |
90 | 129 | ||
91 | - | let $ | |
130 | + | let $t063176395 = { | |
92 | 131 | let $l = staking | |
93 | 132 | let $s = size($l) | |
94 | 133 | let $acc0 = $Tuple2(nil, 0) | |
102 | 141 | ||
103 | 142 | $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) | |
104 | 143 | } | |
105 | - | let unstakeList = $ | |
106 | - | let totalUnstaked = $ | |
107 | - | let userTotalKey = ( | |
144 | + | let unstakeList = $t063176395._1 | |
145 | + | let totalUnstaked = $t063176395._2 | |
146 | + | let userTotalKey = key_UserStakedTotal(user) | |
108 | 147 | let userTotal = valueOrElse(getInteger(this, userTotalKey), 0) | |
109 | 148 | let userTotalAfter = (userTotal - totalUnstaked) | |
110 | 149 | if ((size(inv.payments) != 0)) | |
113 | 152 | then (userAddress != inv.caller) | |
114 | 153 | else false) | |
115 | 154 | then throw("Only users themselves can withdraw their unlocked staking, or admin for them") | |
116 | - | else if (if (if ((0 > userTotal)) | |
117 | - | then true | |
118 | - | else (0 > totalUnstaked)) | |
119 | - | then true | |
120 | - | else (0 > userTotalAfter)) | |
121 | - | then throw("negative result") | |
122 | - | else (unstakeList ++ [IntegerEntry(keyTotal, (totalStaked - totalUnstaked)), if ((userTotalAfter > 0)) | |
123 | - | then IntegerEntry(userTotalKey, (userTotal - totalUnstaked)) | |
124 | - | else DeleteEntry(userTotalKey), ScriptTransfer(userAddress, totalUnstaked, assetId)]) | |
155 | + | else if ((userAddress == promoDApp)) | |
156 | + | then throw("Promo staking can be unlocked only by Promo DApp only") | |
157 | + | else if (if (if ((0 > userTotal)) | |
158 | + | then true | |
159 | + | else (0 > totalUnstaked)) | |
160 | + | then true | |
161 | + | else (0 > userTotalAfter)) | |
162 | + | then throw("negative result") | |
163 | + | else (unstakeList ++ [IntegerEntry(key_StakedTotal, (stakedTotal - totalUnstaked)), if ((userTotalAfter > 0)) | |
164 | + | then IntegerEntry(userTotalKey, userTotalAfter) | |
165 | + | else DeleteEntry(userTotalKey), ScriptTransfer(userAddress, totalUnstaked, hashrateTokenId)]) | |
125 | 166 | } | |
126 | 167 | ||
127 | 168 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let stakeAmountThreshold = 1 | |
5 | 5 | ||
6 | - | let lockPeriodsInDays = [1, 10, 30, 90 | |
6 | + | let lockPeriodsInDays = [1, 10, 30, 90] | |
7 | 7 | ||
8 | - | let possibleTokensForRewards = ["REDSmb", " | |
8 | + | let possibleTokensForRewards = ["REDSmb", "BTC"] | |
9 | 9 | ||
10 | 10 | let hours24 = 86400000 | |
11 | 11 | ||
12 | 12 | let apr8of2022 = 1649376000000 | |
13 | 13 | ||
14 | 14 | let currentTimestamp = lastBlock.timestamp | |
15 | 15 | ||
16 | - | let | |
16 | + | let key_HashrateTokenId = "hashrateTokenId" | |
17 | 17 | ||
18 | - | let | |
18 | + | let key_StakedTotal = "staked_total" | |
19 | 19 | ||
20 | - | let keyTotal = "staked_total" | |
21 | - | ||
22 | - | func keyStaked (address) = address | |
20 | + | func key_UserStaking (address,txId) = ((address + "_staking_") + txId) | |
23 | 21 | ||
24 | 22 | ||
25 | - | ||
23 | + | func key_UserStakedTotal (address) = (address + "_total") | |
26 | 24 | ||
27 | - | let assetId = fromBase58String(getStringValue(this, keyAssetId)) | |
28 | 25 | ||
29 | - | let totalStaked = valueOrErrorMessage(getInteger(this, keyTotal), (("Can't read field '" + keyTotal) + "'")) | |
26 | + | let key_LastStakeTxId = "last_stake_tx_id" | |
27 | + | ||
28 | + | let key_PromoDApp = "promo_dapp" | |
29 | + | ||
30 | + | let key_Issuer_AssetId = "assetId" | |
31 | + | ||
32 | + | let isDAppInit = if (!(isDataStorageUntouched(this))) | |
33 | + | then true | |
34 | + | else isDefined(getString(this, key_HashrateTokenId)) | |
35 | + | ||
36 | + | let hashrateTokenId = fromBase58String(getStringValue(this, key_HashrateTokenId)) | |
37 | + | ||
38 | + | let stakedTotal = valueOrErrorMessage(getInteger(this, key_StakedTotal), (("Can't read field '" + key_StakedTotal) + "'")) | |
39 | + | ||
40 | + | let lastStakeTxId = fromBase58String(valueOrErrorMessage(getString(this, key_LastStakeTxId), (("Can't read field '" + key_LastStakeTxId) + "'"))) | |
41 | + | ||
42 | + | let promoDApp = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, key_PromoDApp), (("Can't read field '" + key_PromoDApp) + "'"))), "Can't parse promo DApp address") | |
43 | + | ||
44 | + | let ACTIVE = "1" | |
45 | + | ||
46 | + | let FINISHED = "0" | |
30 | 47 | ||
31 | 48 | func extractPaymentAmount (payments) = if ((size(payments) != 1)) | |
32 | 49 | then throw("Single payment required") | |
33 | - | else if ((payments[0].assetId != | |
50 | + | else if ((payments[0].assetId != hashrateTokenId)) | |
34 | 51 | then throw("Only REDSmb token is accepted") | |
35 | 52 | else if ((stakeAmountThreshold > payments[0].amount)) | |
36 | 53 | then throw(("Payment amount must be greater then threshold " + toString(stakeAmountThreshold))) | |
37 | 54 | else payments[0].amount | |
38 | 55 | ||
39 | 56 | ||
40 | - | func getCurrentStakedAmount (user) = valueOrElse(getInteger(this, keyStaked(user)), 0) | |
57 | + | func getCurrentLockedAmount (user) = valueOrElse(getInteger(this, key_UserStakedTotal(user)), 0) | |
58 | + | ||
59 | + | ||
60 | + | func stake (inv,rewardType,daysToLock,beneficiary) = { | |
61 | + | let callerStr = toString(inv.caller) | |
62 | + | let pmtAmount = extractPaymentAmount(inv.payments) | |
63 | + | let beginningOfNexDayTimestamp = ((currentTimestamp + hours24) - (currentTimestamp % hours24)) | |
64 | + | let lockUntilTimestamp = (beginningOfNexDayTimestamp + (daysToLock * hours24)) | |
65 | + | let stakingKey = key_UserStaking(callerStr, toBase58String(inv.transactionId)) | |
66 | + | let stakingValue = makeString([ACTIVE, toString(pmtAmount), rewardType, toString(daysToLock), toString(currentTimestamp), toString(lockUntilTimestamp)], ",") | |
67 | + | if ((inv.transactionId == lastStakeTxId)) | |
68 | + | then throw("There is only one staking per transaction allowed for now") | |
69 | + | else if (isDefined(getString(this, stakingKey))) | |
70 | + | then throw((("Staking '" + stakingKey) + "' already exists")) | |
71 | + | else if (!(containsElement(possibleTokensForRewards, rewardType))) | |
72 | + | then throw((("Unsupported reward type '" + rewardType) + "'")) | |
73 | + | else if (!(containsElement(lockPeriodsInDays, daysToLock))) | |
74 | + | then throw((("Unsupported number of days " + toString(daysToLock)) + " to mine")) | |
75 | + | else [StringEntry(stakingKey, stakingValue), IntegerEntry(key_UserStakedTotal(toString(inv.caller)), (getCurrentLockedAmount(toString(inv.caller)) + pmtAmount)), IntegerEntry(key_StakedTotal, (stakedTotal + pmtAmount)), StringEntry(key_LastStakeTxId, toBase58String(inv.transactionId))] | |
76 | + | } | |
41 | 77 | ||
42 | 78 | ||
43 | 79 | @Callable(inv) | |
44 | - | func init (hashrateAssetId) = { | |
45 | - | let newAssetId = valueOrErrorMessage(assetInfo(fromBase58String(hashrateAssetId)), "Can't find asset").id | |
46 | - | if (isInit) | |
47 | - | then throw("DApp is already init") | |
48 | - | else [BooleanEntry(keyInit, true), StringEntry("assetId", toBase58String(newAssetId)), IntegerEntry(keyTotal, 0)] | |
80 | + | func init (hashrateTokenIssuer) = { | |
81 | + | let issuer = valueOrErrorMessage(addressFromString(hashrateTokenIssuer), (("Can't parse issuer address '" + hashrateTokenIssuer) + "'")) | |
82 | + | let assetIdStr = valueOrErrorMessage(getString(issuer, key_Issuer_AssetId), ((("Can't find entry '" + key_Issuer_AssetId) + "' at address ") + hashrateTokenIssuer)) | |
83 | + | let newAssetId = valueOrErrorMessage(assetInfo(fromBase58String(assetIdStr)), (("Can't find asset '" + assetIdStr) + "'")).id | |
84 | + | if ((inv.caller != this)) | |
85 | + | then throw("Only the DApp itself can call this function") | |
86 | + | else if (isDAppInit) | |
87 | + | then throw("DApp is already init") | |
88 | + | else [StringEntry(key_HashrateTokenId, toBase58String(newAssetId)), IntegerEntry(key_StakedTotal, 0)] | |
49 | 89 | } | |
50 | 90 | ||
51 | 91 | ||
52 | 92 | ||
53 | 93 | @Callable(inv) | |
54 | - | func stake (forRewardIn,daysToMine) = { | |
55 | - | let callerStr = toString(inv.caller) | |
56 | - | let pmtAmount = extractPaymentAmount(inv.payments) | |
57 | - | let beginningOfNexDayTimestamp = ((currentTimestamp + hours24) - (currentTimestamp % hours24)) | |
58 | - | let lockUntilTimestamp = (beginningOfNexDayTimestamp + (daysToMine * hours24)) | |
59 | - | let stakingKey = ((callerStr + "_staking_") + toBase58String(inv.transactionId)) | |
60 | - | let stakingValue = makeString([toString(pmtAmount), forRewardIn, toString(daysToMine), toString(currentTimestamp), toString(lockUntilTimestamp)], ",") | |
61 | - | let userTotalKey = (callerStr + "_lockedTotal") | |
62 | - | if (isDefined(getString(this, stakingKey))) | |
63 | - | then throw((("Staking '" + stakingKey) + "' already exists")) | |
64 | - | else if (!(containsElement(lockPeriodsInDays, daysToMine))) | |
65 | - | then throw((("Unsupported number of days " + toString(daysToMine)) + " to mine")) | |
66 | - | else if (!(containsElement(possibleTokensForRewards, forRewardIn))) | |
67 | - | then throw((("Unsupported reward type '" + forRewardIn) + "'")) | |
68 | - | else [StringEntry(stakingKey, stakingValue), IntegerEntry(userTotalKey, (valueOrElse(getInteger(this, userTotalKey), 0) + pmtAmount)), IntegerEntry(keyTotal, (totalStaked + pmtAmount))] | |
69 | - | } | |
94 | + | func setPromoDApp (address) = if (isDefined(getString(this, key_PromoDApp))) | |
95 | + | then throw("Promo DApp address is already specified") | |
96 | + | else [StringEntry(key_PromoDApp, toString(valueOrErrorMessage(addressFromString(address), (("Can't parse '" + address) + "' as address"))))] | |
70 | 97 | ||
71 | 98 | ||
72 | 99 | ||
73 | 100 | @Callable(inv) | |
74 | - | func withdraw (user,staking) = { | |
101 | + | func lock (rewardType,daysToLock) = stake(inv, rewardType, daysToLock, inv.caller) | |
102 | + | ||
103 | + | ||
104 | + | ||
105 | + | @Callable(inv) | |
106 | + | func lockBy (beneficiary,rewardType,daysToLock) = stake(inv, rewardType, daysToLock, valueOrErrorMessage(addressFromString(beneficiary), (("Can't parse benefeciary '" + beneficiary) + "' as address"))) | |
107 | + | ||
108 | + | ||
109 | + | ||
110 | + | @Callable(inv) | |
111 | + | func unlock (user,staking) = { | |
75 | 112 | let userAddress = valueOrErrorMessage(addressFromString(user), (("Can't parse user address '" + user) + "'")) | |
76 | 113 | func extractStaking (acc,txId) = { | |
77 | 114 | let parameters = { | |
78 | - | let val = split(valueOrErrorMessage(getString(this, | |
79 | - | if ((size(val) != | |
115 | + | let val = split(valueOrErrorMessage(getString(this, key_UserStaking(user, txId)), ((("Staking " + txId) + " doesn't exist for user ") + user)), ",") | |
116 | + | if ((size(val) != 6)) | |
80 | 117 | then throw(("Can't parse parameters of staking " + txId)) | |
81 | - | else val | |
118 | + | else if ((val[0] != ACTIVE)) | |
119 | + | then throw((("staking '" + txId) + "' is already unlocked")) | |
120 | + | else val | |
82 | 121 | } | |
83 | - | let $ | |
84 | - | let amount = $ | |
85 | - | let lockUntil = $ | |
122 | + | let $t058375925 = $Tuple2(parseIntValue(parameters[1]), parseIntValue(parameters[5])) | |
123 | + | let amount = $t058375925._1 | |
124 | + | let lockUntil = $t058375925._2 | |
86 | 125 | if ((lockUntil > currentTimestamp)) | |
87 | 126 | then throw(((("Unable to withdraw staking " + txId) + " because it is still locked until ") + toString(lockUntil))) | |
88 | - | else $Tuple2((acc._1 :+ | |
127 | + | else $Tuple2((acc._1 :+ StringEntry(((user + "_") + txId), makeString([FINISHED, parameters[1], parameters[2], parameters[3], parameters[4], parameters[5]], ","))), (acc._2 + amount)) | |
89 | 128 | } | |
90 | 129 | ||
91 | - | let $ | |
130 | + | let $t063176395 = { | |
92 | 131 | let $l = staking | |
93 | 132 | let $s = size($l) | |
94 | 133 | let $acc0 = $Tuple2(nil, 0) | |
95 | 134 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
96 | 135 | then $a | |
97 | 136 | else extractStaking($a, $l[$i]) | |
98 | 137 | ||
99 | 138 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
100 | 139 | then $a | |
101 | 140 | else throw("List size exceeds 10") | |
102 | 141 | ||
103 | 142 | $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) | |
104 | 143 | } | |
105 | - | let unstakeList = $ | |
106 | - | let totalUnstaked = $ | |
107 | - | let userTotalKey = ( | |
144 | + | let unstakeList = $t063176395._1 | |
145 | + | let totalUnstaked = $t063176395._2 | |
146 | + | let userTotalKey = key_UserStakedTotal(user) | |
108 | 147 | let userTotal = valueOrElse(getInteger(this, userTotalKey), 0) | |
109 | 148 | let userTotalAfter = (userTotal - totalUnstaked) | |
110 | 149 | if ((size(inv.payments) != 0)) | |
111 | 150 | then throw("There should be no payments for this function") | |
112 | 151 | else if (if ((inv.caller != this)) | |
113 | 152 | then (userAddress != inv.caller) | |
114 | 153 | else false) | |
115 | 154 | then throw("Only users themselves can withdraw their unlocked staking, or admin for them") | |
116 | - | else if (if (if ((0 > userTotal)) | |
117 | - | then true | |
118 | - | else (0 > totalUnstaked)) | |
119 | - | then true | |
120 | - | else (0 > userTotalAfter)) | |
121 | - | then throw("negative result") | |
122 | - | else (unstakeList ++ [IntegerEntry(keyTotal, (totalStaked - totalUnstaked)), if ((userTotalAfter > 0)) | |
123 | - | then IntegerEntry(userTotalKey, (userTotal - totalUnstaked)) | |
124 | - | else DeleteEntry(userTotalKey), ScriptTransfer(userAddress, totalUnstaked, assetId)]) | |
155 | + | else if ((userAddress == promoDApp)) | |
156 | + | then throw("Promo staking can be unlocked only by Promo DApp only") | |
157 | + | else if (if (if ((0 > userTotal)) | |
158 | + | then true | |
159 | + | else (0 > totalUnstaked)) | |
160 | + | then true | |
161 | + | else (0 > userTotalAfter)) | |
162 | + | then throw("negative result") | |
163 | + | else (unstakeList ++ [IntegerEntry(key_StakedTotal, (stakedTotal - totalUnstaked)), if ((userTotalAfter > 0)) | |
164 | + | then IntegerEntry(userTotalKey, userTotalAfter) | |
165 | + | else DeleteEntry(userTotalKey), ScriptTransfer(userAddress, totalUnstaked, hashrateTokenId)]) | |
125 | 166 | } | |
126 | 167 | ||
127 | 168 |
github/deemru/w8io/873ac7e 67.51 ms ◑