tx · GdrRXWwTCaUfpvWwP2nJCwiycPCuXDsJYhrpntDzSEo5 3N4PzCkHU7VTJeNCPpT8w9XZLnjTsi2YMHN: -0.01000000 Waves 2022.04.08 11:33 [1999356] smart account 3N4PzCkHU7VTJeNCPpT8w9XZLnjTsi2YMHN > SELF 0.00000000 Waves
{ "type": 13, "id": "GdrRXWwTCaUfpvWwP2nJCwiycPCuXDsJYhrpntDzSEo5", "fee": 1000000, "feeAssetId": null, "timestamp": 1649406892397, "version": 2, "chainId": 84, "sender": "3N4PzCkHU7VTJeNCPpT8w9XZLnjTsi2YMHN", "senderPublicKey": "2DVVUYkJNWCMHSCPWEXRjF3THHEdc5bVinyp2c4z8nV8", "proofs": [ "SLsB7ShW9MQcdJo4SWafNdpLRg7fVhx4ad6kUjpu8FcQ6JunVxupfYWpu3BHGWa595oPTBoBXZKgk5y6My9n1zL" ], "script": "base64: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", "height": 1999356, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: BtjiSioBKbapZmQ6YQ7Qo9PkFG2XkcuXTPQ2RuRmEY63 Next: none Diff:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let stakeAmountThreshold = 1 | |
5 | + | ||
6 | + | let lockPeriodsInDays = [1, 10, 30, 90, 180] | |
7 | + | ||
8 | + | let possibleTokensForRewards = ["REDSmb", "rBTC"] | |
9 | + | ||
10 | + | let hours24 = 86400000 | |
11 | + | ||
12 | + | let apr8of2022 = 1649376000000 | |
13 | + | ||
14 | + | let currentTimestamp = lastBlock.timestamp | |
15 | + | ||
4 | 16 | let keyInit = "init" | |
5 | 17 | ||
6 | 18 | let keyAssetId = "assetId" | |
19 | 31 | func extractPaymentAmount (payments) = if ((size(payments) != 1)) | |
20 | 32 | then throw("Single payment required") | |
21 | 33 | else if ((payments[0].assetId != assetId)) | |
22 | - | then throw(" | |
23 | - | else if (( | |
24 | - | then throw("Payment amount must be greater then | |
34 | + | then throw("Only REDSmb token is accepted") | |
35 | + | else if ((stakeAmountThreshold > payments[0].amount)) | |
36 | + | then throw(("Payment amount must be greater then threshold " + toString(stakeAmountThreshold))) | |
25 | 37 | else payments[0].amount | |
26 | 38 | ||
27 | 39 | ||
39 | 51 | ||
40 | 52 | ||
41 | 53 | @Callable(inv) | |
42 | - | func | |
54 | + | func createNewStaking (forRewardIn,daysToMine) = { | |
43 | 55 | let callerStr = toString(inv.caller) | |
44 | 56 | let pmtAmount = extractPaymentAmount(inv.payments) | |
45 | - | let currentStakeAmount = getCurrentStakedAmount(callerStr) | |
46 | - | [IntegerEntry(keyStaked(callerStr), (currentStakeAmount + pmtAmount)), IntegerEntry(keyTotal, (totalStaked + pmtAmount))] | |
57 | + | let beginningOfNexDayTimestamp = ((currentTimestamp + hours24) - (currentTimestamp % hours24)) | |
58 | + | let lockUntilTimestamp = (beginningOfNexDayTimestamp + (daysToMine * hours24)) | |
59 | + | let stakingKey = ((callerStr + "_") + toBase58String(inv.transactionId)) | |
60 | + | let stakingValue = makeString([toString(pmtAmount), forRewardIn, toString(daysToMine), toString(currentTimestamp), toString(lockUntilTimestamp)], ",") | |
61 | + | if (isDefined(getString(this, stakingKey))) | |
62 | + | then throw((("Staking '" + stakingKey) + "' already exists")) | |
63 | + | else if (!(containsElement(lockPeriodsInDays, daysToMine))) | |
64 | + | then throw((("Unsupported number of days " + toString(daysToMine)) + " to mine")) | |
65 | + | else if (!(containsElement(possibleTokensForRewards, forRewardIn))) | |
66 | + | then throw((("Unsupported reward type '" + forRewardIn) + "'")) | |
67 | + | else [StringEntry(stakingKey, stakingValue), IntegerEntry(keyTotal, (totalStaked + pmtAmount))] | |
47 | 68 | } | |
48 | 69 | ||
49 | 70 | ||
50 | 71 | ||
51 | 72 | @Callable(inv) | |
52 | - | func withdraw (amount) = { | |
53 | - | let callerStr = toString(inv.caller) | |
54 | - | let stakedByCaller = getCurrentStakedAmount(callerStr) | |
73 | + | func withdraw (user,staking) = { | |
74 | + | let userAddress = valueOrErrorMessage(addressFromString(user), (("Can't parse user address '" + user) + "'")) | |
75 | + | func extractStaking (acc,txId) = { | |
76 | + | let parameters = { | |
77 | + | let val = split(valueOrErrorMessage(getString(this, ((user + "_") + txId)), ((("Staking " + txId) + " doesn't exist for user ") + user)), ",") | |
78 | + | if ((size(val) != 5)) | |
79 | + | then throw(("Can't parse parameters of staking " + txId)) | |
80 | + | else val | |
81 | + | } | |
82 | + | let $t035943682 = $Tuple2(parseIntValue(parameters[0]), parseIntValue(parameters[4])) | |
83 | + | let amount = $t035943682._1 | |
84 | + | let lockUntil = $t035943682._2 | |
85 | + | if ((lockUntil > currentTimestamp)) | |
86 | + | then throw(((("Unable to withdraw staking " + txId) + " because it is still locked until ") + toString(lockUntil))) | |
87 | + | else $Tuple2((acc._1 :+ DeleteEntry(((user + "_") + txId))), (acc._2 + amount)) | |
88 | + | } | |
89 | + | ||
90 | + | let $t039424020 = { | |
91 | + | let $l = staking | |
92 | + | let $s = size($l) | |
93 | + | let $acc0 = $Tuple2(nil, 0) | |
94 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
95 | + | then $a | |
96 | + | else extractStaking($a, $l[$i]) | |
97 | + | ||
98 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
99 | + | then $a | |
100 | + | else throw("List size exceeds 10") | |
101 | + | ||
102 | + | $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) | |
103 | + | } | |
104 | + | let unstakeList = $t039424020._1 | |
105 | + | let totalUnstaked = $t039424020._2 | |
55 | 106 | if ((size(inv.payments) != 0)) | |
56 | 107 | then throw("There should be no payments for this function") | |
57 | - | else if ((0 >= amount)) | |
58 | - | then throw("Amount must be positive") | |
59 | - | else if ((amount > totalStaked)) | |
60 | - | then throw("You cannot withdraw more funds than total staked on the dApp") | |
61 | - | else if ((amount > stakedByCaller)) | |
62 | - | then throw("You don't have enough staked funds available to withdraw") | |
63 | - | else [if ((amount == stakedByCaller)) | |
64 | - | then DeleteEntry(keyStaked(callerStr)) | |
65 | - | else IntegerEntry(keyStaked(callerStr), (stakedByCaller - amount)), IntegerEntry(keyTotal, (totalStaked - amount)), ScriptTransfer(inv.caller, amount, assetId)] | |
108 | + | else if (if ((inv.caller != this)) | |
109 | + | then (userAddress != inv.caller) | |
110 | + | else false) | |
111 | + | then throw("Only users themselves can withdraw their unlocked staking, or admin for them") | |
112 | + | else (unstakeList ++ [IntegerEntry(keyTotal, (totalStaked - totalUnstaked)), ScriptTransfer(userAddress, totalUnstaked, assetId)]) | |
66 | 113 | } | |
67 | 114 | ||
68 | 115 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let stakeAmountThreshold = 1 | |
5 | + | ||
6 | + | let lockPeriodsInDays = [1, 10, 30, 90, 180] | |
7 | + | ||
8 | + | let possibleTokensForRewards = ["REDSmb", "rBTC"] | |
9 | + | ||
10 | + | let hours24 = 86400000 | |
11 | + | ||
12 | + | let apr8of2022 = 1649376000000 | |
13 | + | ||
14 | + | let currentTimestamp = lastBlock.timestamp | |
15 | + | ||
4 | 16 | let keyInit = "init" | |
5 | 17 | ||
6 | 18 | let keyAssetId = "assetId" | |
7 | 19 | ||
8 | 20 | let keyTotal = "staked_total" | |
9 | 21 | ||
10 | 22 | func keyStaked (address) = address | |
11 | 23 | ||
12 | 24 | ||
13 | 25 | let isInit = valueOrElse(getBoolean(this, keyInit), false) | |
14 | 26 | ||
15 | 27 | let assetId = fromBase58String(getStringValue(this, keyAssetId)) | |
16 | 28 | ||
17 | 29 | let totalStaked = valueOrErrorMessage(getInteger(this, keyTotal), (("Can't read field '" + keyTotal) + "'")) | |
18 | 30 | ||
19 | 31 | func extractPaymentAmount (payments) = if ((size(payments) != 1)) | |
20 | 32 | then throw("Single payment required") | |
21 | 33 | else if ((payments[0].assetId != assetId)) | |
22 | - | then throw(" | |
23 | - | else if (( | |
24 | - | then throw("Payment amount must be greater then | |
34 | + | then throw("Only REDSmb token is accepted") | |
35 | + | else if ((stakeAmountThreshold > payments[0].amount)) | |
36 | + | then throw(("Payment amount must be greater then threshold " + toString(stakeAmountThreshold))) | |
25 | 37 | else payments[0].amount | |
26 | 38 | ||
27 | 39 | ||
28 | 40 | func getCurrentStakedAmount (user) = valueOrElse(getInteger(this, keyStaked(user)), 0) | |
29 | 41 | ||
30 | 42 | ||
31 | 43 | @Callable(inv) | |
32 | 44 | func init (hashrateAssetId) = { | |
33 | 45 | let newAssetId = valueOrErrorMessage(assetInfo(fromBase58String(hashrateAssetId)), "Can't find asset").id | |
34 | 46 | if (isInit) | |
35 | 47 | then throw("DApp is already init") | |
36 | 48 | else [BooleanEntry(keyInit, true), StringEntry("assetId", toBase58String(newAssetId)), IntegerEntry(keyTotal, 0)] | |
37 | 49 | } | |
38 | 50 | ||
39 | 51 | ||
40 | 52 | ||
41 | 53 | @Callable(inv) | |
42 | - | func | |
54 | + | func createNewStaking (forRewardIn,daysToMine) = { | |
43 | 55 | let callerStr = toString(inv.caller) | |
44 | 56 | let pmtAmount = extractPaymentAmount(inv.payments) | |
45 | - | let currentStakeAmount = getCurrentStakedAmount(callerStr) | |
46 | - | [IntegerEntry(keyStaked(callerStr), (currentStakeAmount + pmtAmount)), IntegerEntry(keyTotal, (totalStaked + pmtAmount))] | |
57 | + | let beginningOfNexDayTimestamp = ((currentTimestamp + hours24) - (currentTimestamp % hours24)) | |
58 | + | let lockUntilTimestamp = (beginningOfNexDayTimestamp + (daysToMine * hours24)) | |
59 | + | let stakingKey = ((callerStr + "_") + toBase58String(inv.transactionId)) | |
60 | + | let stakingValue = makeString([toString(pmtAmount), forRewardIn, toString(daysToMine), toString(currentTimestamp), toString(lockUntilTimestamp)], ",") | |
61 | + | if (isDefined(getString(this, stakingKey))) | |
62 | + | then throw((("Staking '" + stakingKey) + "' already exists")) | |
63 | + | else if (!(containsElement(lockPeriodsInDays, daysToMine))) | |
64 | + | then throw((("Unsupported number of days " + toString(daysToMine)) + " to mine")) | |
65 | + | else if (!(containsElement(possibleTokensForRewards, forRewardIn))) | |
66 | + | then throw((("Unsupported reward type '" + forRewardIn) + "'")) | |
67 | + | else [StringEntry(stakingKey, stakingValue), IntegerEntry(keyTotal, (totalStaked + pmtAmount))] | |
47 | 68 | } | |
48 | 69 | ||
49 | 70 | ||
50 | 71 | ||
51 | 72 | @Callable(inv) | |
52 | - | func withdraw (amount) = { | |
53 | - | let callerStr = toString(inv.caller) | |
54 | - | let stakedByCaller = getCurrentStakedAmount(callerStr) | |
73 | + | func withdraw (user,staking) = { | |
74 | + | let userAddress = valueOrErrorMessage(addressFromString(user), (("Can't parse user address '" + user) + "'")) | |
75 | + | func extractStaking (acc,txId) = { | |
76 | + | let parameters = { | |
77 | + | let val = split(valueOrErrorMessage(getString(this, ((user + "_") + txId)), ((("Staking " + txId) + " doesn't exist for user ") + user)), ",") | |
78 | + | if ((size(val) != 5)) | |
79 | + | then throw(("Can't parse parameters of staking " + txId)) | |
80 | + | else val | |
81 | + | } | |
82 | + | let $t035943682 = $Tuple2(parseIntValue(parameters[0]), parseIntValue(parameters[4])) | |
83 | + | let amount = $t035943682._1 | |
84 | + | let lockUntil = $t035943682._2 | |
85 | + | if ((lockUntil > currentTimestamp)) | |
86 | + | then throw(((("Unable to withdraw staking " + txId) + " because it is still locked until ") + toString(lockUntil))) | |
87 | + | else $Tuple2((acc._1 :+ DeleteEntry(((user + "_") + txId))), (acc._2 + amount)) | |
88 | + | } | |
89 | + | ||
90 | + | let $t039424020 = { | |
91 | + | let $l = staking | |
92 | + | let $s = size($l) | |
93 | + | let $acc0 = $Tuple2(nil, 0) | |
94 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
95 | + | then $a | |
96 | + | else extractStaking($a, $l[$i]) | |
97 | + | ||
98 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
99 | + | then $a | |
100 | + | else throw("List size exceeds 10") | |
101 | + | ||
102 | + | $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) | |
103 | + | } | |
104 | + | let unstakeList = $t039424020._1 | |
105 | + | let totalUnstaked = $t039424020._2 | |
55 | 106 | if ((size(inv.payments) != 0)) | |
56 | 107 | then throw("There should be no payments for this function") | |
57 | - | else if ((0 >= amount)) | |
58 | - | then throw("Amount must be positive") | |
59 | - | else if ((amount > totalStaked)) | |
60 | - | then throw("You cannot withdraw more funds than total staked on the dApp") | |
61 | - | else if ((amount > stakedByCaller)) | |
62 | - | then throw("You don't have enough staked funds available to withdraw") | |
63 | - | else [if ((amount == stakedByCaller)) | |
64 | - | then DeleteEntry(keyStaked(callerStr)) | |
65 | - | else IntegerEntry(keyStaked(callerStr), (stakedByCaller - amount)), IntegerEntry(keyTotal, (totalStaked - amount)), ScriptTransfer(inv.caller, amount, assetId)] | |
108 | + | else if (if ((inv.caller != this)) | |
109 | + | then (userAddress != inv.caller) | |
110 | + | else false) | |
111 | + | then throw("Only users themselves can withdraw their unlocked staking, or admin for them") | |
112 | + | else (unstakeList ++ [IntegerEntry(keyTotal, (totalStaked - totalUnstaked)), ScriptTransfer(userAddress, totalUnstaked, assetId)]) | |
66 | 113 | } | |
67 | 114 | ||
68 | 115 |
github/deemru/w8io/169f3d6 28.99 ms ◑