This is the report from a security audit performed on Cold-staking by gorbunovperm.
Callisto Cold staking contract.
In total, 4 issues were reported including:
-
0 high severity issue.
-
2 medium severity issues.
-
1 low severity issues.
-
1 minor observations.
1. A staker will lose the deserved reward if he makes an additional deposit before the end of the round.
Round interval is 27 days. Mike makes deposit to coldstaking and after 53 days he made a staking contract replenishment. In this case he will lose reward for 26 days. Reward is paid only for full periods and after that the time of the staking is reset.
Time of staking start is correctly recalculated here but further the time is reset. This is the same as the lose a reward.
For case if need to get reward when making new deposit to stake do add staker weight(for uncompleted round) to staker amount value.
2. Reward depends on StakingRewardPool
value and this is the motivation to manipulate the order of transactions.
Reward depends on StakingRewardPool
value. If one staker will claim his reward, another user with same stake value and staking time but which will call claim
function in next transaction will get less reward. This is essential for stakers with big stakes.
Change StakingRewardPool
one time at block. Do not change it in claim
function.
The round can go faster than 27 days in case of an increase block generation time to over 25 seconds for a long time.
In case when blocktime is more than 25 seconds the Timestamp
will have not "timestamp of the last interaction" value (look at here). This will lead to a distortion of the flow of staking time.
Consider the problem by example:
Block id | Block time, sec | _seconds variable |
now | Timestamp variable |
now - Timestamp = |
Recommendation |
---|---|---|---|---|---|---|
start value | 1539260000 | Mike make a stake. | ||||
1200000 | 35 | 25 | 1539260035 | 1539260025 | 10 | |
1200001 | 35 | 25 | 1539260070 | 1539260050 | 20 | |
1200002 | 35 | 25 | 1539260105 | 1539260075 | 30 | |
... | ... | ... | ... | ... | ... | An hour has passed |
1200103 | 35 | 25 | 1539263640 | 1539262600 | 1040 | Passed 1 hour of real time, but the contract "thinks" that 43 minutes have passed. |
I don't know whether a continuous change in the block generation time by a value greater than 25 seconds is possible. But if it is possible then the time inside the contract will differ from the real time. What will affect the reward.
staker[msg.sender].time
is not reset after withdrawal process. Only variable staker[msg.sender].amount
is reset.
-
Result of
staker_info
function may be misleading because after withdrawalamount
will be zero, buttime
will have stake timestamp value. -
This is just a reminder for developers.
staker[msg.sender].time
variable should always used withstaker[msg.sender].amount > 0
condition.
This contract has some issues that should be fixed.