New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cold Staking contract #51

Open
Dexaran opened this Issue Sep 28, 2018 · 52 comments

Comments

Projects
None yet
3 participants
@Dexaran
Copy link
Member

Dexaran commented Sep 28, 2018

@yograterol @RideSolo @yuriy77k

I'd like to discuss the details of further Cold Staking contract implementation here.

At the moment we have 3 proposed variants:

  1. Dexaran's Cold Staking (description)

  2. Yuriy's Cold Staking (description)

  3. RideSolo's Cold Staking (description)

Overview

1. Dexaran's Cold Staking

The first implementation of the Cold Staking protocol. Every action (new staker, reward claim) has a direct impact on the state of the contract which makes the final reward highly unpredictable.

Reward is computed at the moment of the claiming. Contract does not preserve the history of "staking weights". Reward depend on actual contract state and contract balance, thus it is independent of monetary policy. However, reward depends on claiming order (those, who claim their rewards first, earn more).

Advantages: Has a working reference implementation.

Disadvantages: Each staker can affect others. Too unpredictable rewards.

2. Yuriy's Cold Staking

This implementation relies on TotalStakingWeight variable which preserves the info about how much balance should be allocated for stakers who did not claim their rewards yet.

Stakers cannot directly affect each other with their claims. Reward calculation is more predictable, reward only depend on the amount of staking CLO. The reward is independent of monetary policy.

Advantages: Better reward calculation

Requires more testing.

3. RideSolo's Cold Staking

Advanced reward calculation formula.
However, this version is more complex compared to the previous one and it relies on hardcoded block reward variable. Therefore it depends on monetary policy and it will be necessary to update the contract with a hardfork at each monetary policy change. Also, it is not compatible with The First Stake proposal.

Advantages: Better reward calculation

Disadvantages: higher complexity, depend on monetary policy, incompatible with The First Stake

Implementation at Callisto Network

I'm in favor of implementing the (2) Yuriy's Cold Staking version. It can solve all pressing problems and the implementation is not overcomplicated.

I believe that it is necessary to take the following steps:

  1. Deploy the contract at testnet, test it and make a final decision if it is ready or not.

  2. Re-deploy the testnet and launch a testnet cold staking contract that will behave exactly like the final version (automatically receive block rewards, distribute staking rewards).

  3. Perform a security audit.

  4. Launch an official bug bounty.

  5. (optional) Make final changes if necessary. If everything is fine then the contract is ready to be used. Update the whitepaper.

P.S.

I'm open to any suggestions.
Any proposal, feedback, comments, constructive criticism is welcome!

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Sep 28, 2018

@yuriy77k

Observation: the reward slightly exceeds the expected value.

Imagine the following scenario:

  • Block time = 15 seconds

  • Each block adds 120 CLO to staking contract balance

  • Round length = 40 blocks = 600 seconds

Alice and Bob are stakers. Alice is willing to deposit 1000 CLO and Bob is willing to deposit 500 CLO. As the result, the expected reward for Alice is 66,6% of total staking income and the expected reward is 33,3% for Bob.

In this way, Alice expects to receive 0.66666 * 40 * 120 = 3200 CLO per 600 seconds
Bob expects to receive 0.33333 * 40 * 120 = 1600 CLO

1. Alice starts staking with 1000 CLO at block 0 (right after the launch of staking)

Contract state after the transaction:

Timestamp = 0
TotalStakingAmount = 0
CurrentBlockDeposits = 1000
StakingRewardPool = 0
Alice[time] = 0
Alice[amount] = 1000

TotalStakingWeight    = 0

2. Bob starts staking with 500 CLO at block 10 (150 seconds after the launch).

Contract state after the transaction:

Timestamp  = 150
TotalStakingAmount  = 1000
CurrentBlockDeposits = 500
StakingRewardPool  = 1200
Bob[time] = 150
Bob[amount]  = 500

TotalStakingWeight = 150000

3. Alice claims her reward at block 40 (600 seconds).

Contract state at the moment of execution of this code:

Timestamp = 600
TotalStakingAmount = 1500
CurrentBlockDeposits = 0
StakingRewardPool = 4800 = (40 * 120 CLO)
Alice[time] = 0
Alice[amount] = 1000

TotalStakingWeight = 150000 + (450 * 1500) = 825000

_time = 600
_reward = (4800 * 600 * 1000) / 825000 = 3490

Then Alice is paid with 3490 CLO which is slightly higher than the expected amount.

The resulting state of the contract:

Timestamp = 600
TotalStakingAmount = 1500
CurrentBlockDeposits = 0
StakingRewardPool = 4800 - 3490 = 1310
Alice[time] = 600
Alice[amount] = 1000

TotalStakingWeight = 225000 = 825000 - (600 * 1000)

4. Bob claims his reward at block 50 (750 seconds).

Contract state at the moment of reward calculation:

Timestamp = 750
TotalStakingAmount = 1500
CurrentBlockDeposits = 0
StakingRewardPool = 1310 + (120 * 10) = 2510
Bob[time] = 150
Bob[amount] = 500

TotalStakingWeight = 225000 + (150 * 1500) = 450000

_time = 750
_reward = (2510 * 600 * 500) / 450000 = 1673

As you can see, Bob will receive 1673 CLO which is also slightly more than the expected amount.

I assume that it is a result of the fact that Alice starts staking earlier and it should take some time for the rewards to rebalance. Am I missing something?

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 28, 2018

Hello @Dexaran,
First of all, the proposal was to show an idea about how to handle the cold staking with a different angle so everyone can see that we have other possibility.

I will try to comment and ask some questions about the disadvantages:

  • Higher complexity: mathematical proof can be more complex, but the implementation is simple.
  • Incompatible with the first stake proposal : the proposed code was just to show the formula and how fair it can be. and the code itself can be changed to be compatible with any version of the cold staking.
  • Depend on monetary policy: the proposed formula is depending on the monetary policy, but if the new monetary policy is set now, even if it needs multiple hardforks the reward can be hardcoded following it. and this is in the case if you want a fully decentralized contract, in another case a simple function that can be called externally that set the block reward value following block.number will solve the issue.

@yograterol, can you please let us know about the new monetary policy.

Also another advantage that is not highlighted is the Cold Staking Treasury fund, none of the other proposals include how to distribute the fund in long term.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 28, 2018

I did not see any problem in that example.
Alice get little more reward, because her part in first 40 blocks not 0.6666, but little bit more (she was only holder for 10 blocks).
Bob get little bit more, because rewards pool was not 3200 CLO, but more on his part from first 10 blocks.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 28, 2018

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 28, 2018

@Dexaran @yograterol If you decide to go with @yuriy77k 's proposal, we should discuss the reward dependence to users transactions (withdraw, claim, stake).

The following statement is no true "Stakers can not directly affect each other with their deposits/withdrawals/claims. Reward calculation is more predictable" , check below for more information.

Reward Computation dependent on Staker Actions (Transaction order)

For better understading of the operation, The time of each block is set for 1 second. The following operation will be done by the stakers:

  • Staker 1 stake 100 clo at block 0.
  • Staker 2 stake 100 clo at block 3.
  • Staker 3 stake 5000 clo at block 5.

the reward per block is set to be 100 clo, just for illustrative purpose.

The following table 1 shows the staking reward pool, the stakers weight and the total staking weight following the block number.

Block 0 1 2 3 4 5 6 7
StakingRewardPool 100 200 300 400 500 600 700 800
staker 1 Weight 0 100 200 300 400 500 600 700
staker 2 Weight 0 0 0 0 100 200 300 400
staker 3 Weight 0 0 0 0 0 0 5000 10000
TotalStakingWeight 0 100 200 300 500 700 5900 11100
				Table 1

The following table 2 shows the stakers reward using data of table 1.

Block 0 1 2 3 4 5 6 7
staker 1 reward 0 200 300 400 400 ~428 ~71 ~50
staker 2 reward 0 0 0 0 100 ~171 ~35 ~28
staker 3 reward 0 0 0 0 0 0 ~593 ~720
				Table 2

We can clearly see for example that the reward of staker 1 is dependent to others stakers interaction, and it is the same for every staker.

Another example is the following interactions that are done in order:

  • Staker 3 stake 5000 clo.
  • Staker 1 claim his reward after staker 3 stake.
  • Staker 3 withdraw his stake before the end of the month.
  • Staker 2 claim after staker 3 withdrawal.

What will happen is staker 1 will get a smaller reward compared to staker 2, even if he staked before staker 2.
In production this use cases will happen all the time, since thousands of users will be claiming, withdrawing and staking.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Sep 29, 2018

@RideSolo

First of all, the proposal was to show an idea about how to handle the cold staking with a different angle so everyone can see that we have other possibility.

Completely agree that there is a wide range of possible implementations each with its own advantages and disadvantages. I think that the version that we are going to pick now may be replaced with a better one in future as well.

We are going to implement 5M32 monetary policy but it may change in future as well (whitepaper).

another advantage that is not highlighted is the Cold Staking Treasury fund, none of the other proposals include how to distribute the fund in long term.

I would say that Treasury Fund distribution is intended to be absolutely abstracted from Cold Staking mechanic. I know that this function exists in the Cold Stack contract, but I can not say that this is an advantage, and I can not say that it is necessary for us.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Sep 29, 2018

The following statement is no true "Stakers can not directly affect each other with their deposits/withdrawals/claims. Reward calculation is more predictable"

Yes, the statement is not correct.
A staker can affect other stakers if he deposits a significant amount of funds in the contract before the others withdraw their rewards. Updated the comment.

What will happen is staker 1 will get a smaller reward compared to staker 2, even if he staked before staker 2.

In production this use cases will happen all the time, since thousands of users will be claiming, withdrawing and staking.

I assume that this is similar to the dispersion of mining rewards.

If a miner_1 will start mining when the network hashrate is 10 Th/s but the network hashrate will grow to 20 Th/s then the reward of miner_1 will be different from his initial expectations.

Hashrate is not constant because the miners come and go out. However, in large and stable networks (such are ETH or ETC), where there are a lot of miners, rewards are fairly predictable, because of a large number of participants (miners in this case) and the effect of unpredictable behavior of each participant is smoothed.

However, I admit that the parallel with the miners may not be accurate, since the stakers and miners are fundamentally different roles in the network.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 29, 2018

@RideSolo

  1. The reward is calculated and paid not for block, but for a month

  2. This situation looks terrible if you look at it as presented (in blocks). But if interpellate it in real situation, we get:
    30 days / 6 = 1 block is equivalent to 5 days
    5000 CLO is about 5 times more then 900 CLO ( TotalStakingWeight).
    So if in Cold Stking doposits only 10% of total amount of CLO, then on 6 block (25 day) the TotalStakingWeight = 10% *5 = 50%, than amount equivalent 5000 must be more then 50% * 5 = 250% of total amount of CLO (which is impossible).

  3. In other side, if use RideSolo's variant, we get following:

Staker 1 stake 100 clo at block 1.
Staker 2 stake 5000 clo at block 4.

Block 0 1 2 3 4 5 6
StakingRewardPool 100 100 100 100 100 100 100
staker 1 Weight 0 100 100 100 100 100 100
staker 2 Weight 0 0 0 0 5000 5000 5000
staker 1 reward 0 100 200 300 ~30 ~304 ~306
staker 2 reward 0 0 0 0 ~98 ~196 ~294
				Table 1

So Staker 1 receive more reward with 100 CLO deposit, as Staker 2 with 5000 CLO deposit, but staking period of Staker 1 just in two times more then Staker 2 period. And what to do with unused StakingRewardPool for block 0?

  1. Another situation which is possible with RideSolo's variant.
Block 0 1 2 3 4 5 6
StakingRewardPool 100 100 100 100 100 100 100
staker 1 Weight 100 100 100 100 100 100 100
staker 2 Weight 0 100 100 100 100 100 100
.... ... ... ... ... ... ... ...
staker 100 Weight 0 100 100 100 100 100 100
staker 1 reward 100 101 102 103 104 105 106
staker 2 reward 0 1 2 3 4 5 6
.... ... ... ... ... ... ... ...
staker 100 reward 0 1 2 3 4 5 6
				Table 2

So Staker 1 get much more rewards then others, who make deposit just on next block.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 29, 2018

A staker can affect other stakers if he deposits a significant amount of funds in the contract before the others withdraw their rewards. Updated the comment.

Supposing a large number of starkers and not only one big staker, is similar since at the end they will have an accumulated weight, which will be a more common issue.

I assume that this is similar to the dispersion of mining rewards.
If a miner_1 will start mining when the network hashrate is 10 Th/s but the network hashrate will grow to 20 Th/s then the reward of miner_1 will be different from his initial expectations.
Hashrate is not constant because the miners come and go out. However, in large and stable networks (such are ETH or ETC), where there are a lot of miners, rewards are fairly predictable, because of a large number of participants (miners in this case) and the effect of unpredictable behavior of each participant is smoothed.

It is not really the same case since miners previous rewards at block i will not be affected by the future hash rate of the network. in the opposite the future TotalStakingWeight will affect the previous reward at any given block or monthly based reward, since users do no stake all at the same time.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 29, 2018

@yuriy77k

1. The reward is calculated and paid not for block, but for a month

Yes I understand this, but the month is not fixed for everyone, stakers can start staking when they want and the StakingRewardPool distribution doesn't take into account the cycles since everyone cycle is different.

2. This situation looks terrible if you look at it as presented (in blocks). But if interpellate it in real situation, 

My point was to show that the reward is dependent on users actions. and as commented earlier you can think of that stakers as thousands of small stakers who comes in the last week of staker 1 monthly round_interval.

3. In other side, if use RideSolo's variant, we get following:

Staker 1 stake 100 clo at block 1.
Staker 2 stake 5000 clo at block 4.
........
So Staker 1 receive more reward with 100 CLO deposit, as Staker 2 with 5000 CLO deposit, but staking period of Staker 1 just in two times more then Staker 2 period. And what to do with unused StakingRewardPool for block 0?

  • Yes but, the reward of staker 1 didn't become less than what was expected at any anterior block and same as you pointed out you can see the bigger picture, 1 month worth of block is almost 172800 blocks.

  • The reward distribution is block based, so if he stake for 3 blocks without anyone else staking he will get 300 clo, if staker 2 comes after and put 5000 clo in his stake, staker 1 reward will become 100 x 100/5100 per block.

  • If StakingRewardPool is not distributed it means that there is no stakers at that giving block and you can imagine the odds of that, In the worst case scenario were no one is staking in the whole contract the non distributed reward can be redistributed at anytime at will without need to send it to external address as in the proposal code (was just an example).

1. Another situation which is possible with RideSolo's variant.

..............
So Staker 1 get much more rewards then others, who make deposit just on next block.

He got 100 CLO at the first block since he was the only one staking. it is expected and you can see it as share holders to who you distribute the benefit on every block, or a mining pool with one miner who find a block and no one with who to share with and after if there is 100 staker they will all get a reward proportional to their stake.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 29, 2018

@Dexaran @yuriy77k, correct If I'm wrong but the only way to give a fair reward and independent from any action to everyone is to fix a monthly cycle with a fix reward pool for every month. for example all the starkers will be able to claim after every 30 days since cold staking start.

The main issue of yuriy's proposal is that the cycles for every stakers are different. and they all get a reward from the same reward pool.

To be able to let the stakers stake when they want while keeping an independent reward from users actions and a fair distribution, the smallest unit of time ( block.number ) have to be used as cycle of distribution and not allowing them to take the reward until the month pass. which is basically the main idea of my proposal. and it is the same as a mining pool where the hashrate will be the staker stake and the diff will be the total stake.

@Dexaran please note that I will update my proposal to make it independent from the monetary policy and I will simplify the formula since the monetary policy will be removed, while keeping the same distribution schema of the reward as proposed in the previous version. To remove all the disadvantages of the previous proposal.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 29, 2018

@Dexaran @yuriy77k, I didn't notice before, but yuriy's formula and mine are exactly the same at the only difference that I use a round_interval of 1 block only, and the reward are accumulated to be giving after one month.
I just noticed it after removing the monetary policy dependence.
I just do it in a lower scale since staking time will be 1 block:

  • User staking weight will be his stake since it will be multiplied by 1.
  • The TotalStakingWeight will be the total stake since it will be multiplied by 1.
  • The StakingRewardPool will be the 20% of the mining block reward.

And since it is done in round_interval of one block, the reward dependence is the smallest possible.

Please let me know your opinion.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 29, 2018

I have updated a previous answer

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

My point was to show that the reward is dependent on users actions.

My examples also show that final staker reward dependent on users actions even with RideSolo's formula. The difference is only in calculation methods, but staker would not estimate his final reward in any case.
Therefore, I proposed a comparison with the deviants on shares. The company can work well during the year, and in the last month it incurs large losses, and shareholders will receive less revenue than they expected. And vice versa.
Therefore, companies do not publish monthly or daily income per share, but do it once a year, according to the annual result.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 30, 2018

@yuriy77k

My examples also show that final staker reward dependent on users actions even with RideSolo's formula. The difference is only in calculation methods, but staker would not estimate his final reward in any case.
Therefore, I proposed a comparison with the deviants on shares. The company can work well during the year, and in the last month it incurs large losses, and shareholders will receive less revenue than they expected. And vice versa.
Therefore, companies do not publish monthly or daily income per share, but do it once a year, according to the annual result.

The company give share holders their rewards in a fixed period from day x of the year to day y of the year, Yuriy's proposal set an x(i) and y(i) different for each staker i, the reward dependence comes from the non-fixed round_invetrval start of each user, as pointed out before the only way to avoid the reward dependence is to use the smalest unit of time available on the blockchain (round_interval = 1 block) so the stakers will be free to start staking at any given moment.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

What do you think about calculation staker reward at fixed day / time? For example each 15 day of month. In this case every staker will receive rewards commensurate with his StakerWeight.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

the reward dependence comes from the non-fixed round_invetrval start of each user, as pointed out before the only way to avoid the reward dependence is to use the smalest unit of time available on the blockchain (round_interval = 1 block) so the stakers will be free to start staking at any given moment.

round_invetrval - a) time interval to froze Stakers deposits; b) time interval to calculate Stakers rewards.
In case of "a)" we can not make it = 1 block.

This situation similar to the situation in real life:
Alice goes to work for 5 days, but actually works only 1 hour a day. Bob went to work for 1 day, but worked 8 hours. How to pay the salary?

a) by the days (Alice get more)
b) by the hours (Bob get more)

Both options are permissible, and both options have their advantages and disadvantages.

I think that it is not possible to make an ideal solution, without disadvantages, so we need to take one as a basis and work with it.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

I think that the version that we are going to pick now may be replaced with a better one in future as well.

Replace Cold Staking contract is not trivial task. Will need to keep all customers address, amount of deposits and time of deposits... and others values...

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 30, 2018

What do you think about calculation staker reward at fixed day / time? For example each 15 day of month. In this case every staker will receive rewards commensurate with his StakerWeight.

I do think that it will be the most fair solution, but some issues can be raised:

  • Monthly network congestion, since all stakers will be claiming their rewards at the same period.
  • And of course, what will be the repercusions on the coin price if a certain % of this claims will be sold.

round_invetrval - a) time interval to froze Stakers deposits; b) time interval to calculate Stakers rewards.
In case of "a)" we can not make it = 1 block.

Yes, I agree with you. how ever what I proposed is a round_interval=1 block to distribute the block reward (20% of the mining block reward) and a waiting time equal to 1 month to freeze the reward, where the reward is the total reward of every block.

I think that it is not possible to make an ideal solution, without disadvantages, so we need to take one as a basis and work with it.

I agree with you, I will update my proposal and the code in few hours, to remove to disadvantages pointed out by Dexaran so we can decide, the reward schema will stay the same.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

Monthly network congestion, since all stakers will be claiming their rewards at the same period.

we can fix RewardPool on selected day, and staker can claim his reward on any day after (before next month Payouts day). All unclaimed rewards will be add to next month RewardPool, And Staker, who did not calim his rewards until next Payouts day, may claim new rewards which will calculate from new RewardPool (and may be lower then was on previous month).

And of course, what will be the repercusions on the coin price if a certain % of this claims will be sold.

This is true for any schema of payouts.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 30, 2018

we can fix RewardPool on selected day, and staker can claim his reward on any day after (before next month Payouts day) of the first

By not fixing a selected day, the stakers claim will be more distributed. this is part dexaran staking protocol.

And of course, what will be the repercusions on the coin price if a certain % of this claims will be sold.

This is true for any schema of payouts.

It is not true, since if the day is not fixed the claims will be more distributed. if there is any sell volume coming from the claim rewards the volume will be more distributed.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

if the day is not fixed the claims will be more distributed. if there is any sell volume coming from the claim rewards the volume will be more distributed.

an x(i) and y(i) different for each staker i, the reward dependence comes from the non-fixed round_invetrval start of each user

so not fixed date - bad, fixed day - bad... :-)
As I said, there is no an ideal solution.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 30, 2018

if the day is not fixed the claims will be more distributed. if there is any sell volume coming from the claim rewards the volume will be more distributed.

an x(i) and y(i) different for each staker i, the reward dependence comes from the non-fixed round_invetrval start of each user

so not fixed date - bad, fixed day - bad... :-)

My proposal solve this issue, the date is not fixed and in the same time the reward is independent.
since as explained, I proposed a round_interval=1 block to distribute the block reward (20% of the mining block reward) and a waiting time equal to 1 month to freeze the reward, where the reward is the total reward of every block that is given to user on every block.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Sep 30, 2018

My proposal solve this issue, the date is not fixed and in the same time the reward in independent.
since as explained 'I proposed is a round_interval=1 block to distribute the block reward (20% of the mining block reward) and a waiting time equal to 1 month to freeze the reward, where the reward is the total reward of every block.'

  1. How you get block reward (20% of the mining block reward)?

  2. If staker claim his rewards after 40 days, he get rewards amount for 30 or 40 days?

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 30, 2018

1. How you get block reward?

I have updated the proposal, the contract is completely independent from the monetary policy adopted or any future or changes through a planned or not planned hard fork. as I said i will share it soon.

2. If staker claim his rewards after 40 days, he get rewards amount for 30 or 40 days?

if a staker stake at time X and claim after 40 days. he will get a reward of 40 days. and his lastClaim time will be set to X+40days, which will be a good enhancement that will push the claims to be distributed through the time.

So the next possible claim of that user will be X+40 days + 30 days.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Sep 30, 2018

@Dexaran @yuriy77k , Please note that I have updated the proposal (below is the links to the code and the proposal)

Advantages:

  • Better reward calculation.
  • Independent reward from users actions or transactions.
  • Stakers can stake extra amount even after that they started staking (can be discussed), this feature will stop them from creating new address to stake more. Every time when user stake more the reward won't be given to him until 30 days from his last stake day which will make them wait more to be able to withdraw the reward, if he doesn't wait and withdraw his stake the reward will be redistributed.

Disadvantages:
The disadvantages highlighted by Dexaran have been removed

  • Complexity: as shown here Yuriy's proposal formula and mine are almost the same.
  • Dependence to monetary policy: Independent.
  • Compatiblity with The First Stake: Compatible.
@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 1, 2018

Replace Cold Staking contract is not a trivial task. Will need to keep all customers address, amount of deposits and time of deposits... and others values...

No, if we replace contract at the protocol level.

  1. At HardFork1 the cold staking contract is deployed at address 0xaaaaaaaaaaaa and 20% of block reward is going to address 0xaaaaaaaaaaaa

  2. We decided to replace the contract. We deploy a new cold staking contract at address 0xbbbbbbbbbb.

  3. At HardFork2 we change the address, which receives 20% of the block reward, from 0xaaaaaaaaaaaa to 0xbbbbbbbbbb. Thus, the new contract starts to receive income. Then users withdraw the remaining balance of the old contract until it will be equal to 0. New stakers continue staking with a new contract at address 0xbbbbbbbbbb.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 1, 2018

@RideSolo

Please note that I have updated the proposal

Reviewing...

What do you think about calculation staker reward at fixed day / time? For example each 15 day of month. In this case every staker will receive rewards commensurate with his StakerWeight.

I do think that it will be the most fair solution, but some issues can be raised:

  • Monthly network congestion, since all stakers will be claiming their rewards at the same period.
  • And of course, what will be the repercusions on the coin price if a certain % of this claims will be sold.

Honestly, I don't think that this is a problem.
A good opportunity to buy the dip attracts the attention of traders (thus increasing the adoption, network effect, liquidity and potential community of bagholders), that is rather good than bad, in long-term. It is necessary that the time intervals were large enough (for example a month) that the price could recover.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Oct 1, 2018

Honestly, I don't think that this is a problem.
A good opportunity to buy the dip attracts the attention of traders (thus increasing the adoption, network effect, liquidity and potential community of bagholders), that is rather good than bad, in long-term. It is necessary that the time intervals were large enough (for example a month) that the price could recover.

I got your point and it is true, but how about the network congestion we don't know the future usage of the cold staking contract or the adoption of Callisto cryptocurrency by the crypto community.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 1, 2018

@RideSolo please explain what do you mean by "network congestion". Is it a sell pressure or a network stress caused by large quantities of claim-transactions?

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Oct 1, 2018

@Dexaran "large quantities of claim-transactions", since after each 15th of every month all the users will be able to withdraw their reward.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 1, 2018

Yes, this issue still stands and it is the disadvantage of having a fixed pay day.

Currently, the supply of CLO is 668M. Assuming that 70% of total CLOs are engaged in cold staking, Callisto bandwidth is 15 tx/s and an approximate amount of each stakers deposit is 1000 CLO, it will require 9 hours to process all claim transactions.

In reality it will cause periodic increases in gas fees.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Oct 1, 2018

  1. At HardFork2 we change the address, which receives 20% of the block reward, from 0xaaaaaaaaaaaa to 0xbbbbbbbbbb. Thus, the new contract starts to receive income. Then users withdraw the remaining balance of the old contract until it will be equal to 0. New stakers continue staking with a new contract at address 0xbbbbbbbbbb.

But users need to wait for complete 30 days after deposit (claim reward) before they can withdraw. So money will be frozen, but without getting reward.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Oct 3, 2018

@Dexaran the proposed cold staking contract was updated, @yuriy77k highlighted an error in the intervalReward computation.

RideSolo/Cold-staking@4ace8b5

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Oct 4, 2018

@Dexaran added functions freeze and withdraw_rewards.
To complete CS contract, please, clarify following:

  1. Do we allow staker to withdraw deposit before 30 days? (propose: No)

  2. When staker claim reward after 40 days, he got reward for 30 (10 days left on his account and he can claim next time at least after 20 days) or 40 days? (purpose: 30 days. It will stimulate staker to hold longer.)

  3. Set max_delay to 1 year or more? (propose: 2 years. The 1 year is very common interval.)

  4. Do we need the function claim_and_withdraw ? The function withdraw_stake also claim rewards, if possible. (propose: remove claim_and_withdraw)

  5. Do we need function reinvest which add all staker's reward to his deposit? (propose: yes, it will stimulate staker to hold longer.)

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 4, 2018

@yuriy77k

Applied some changes yuriy77k/Cold-staking#1 .

Do we allow staker to withdraw deposit before 30 days? (propose: No)

No. We shouldn't allow stakers to claim before 30 days.

When staker claim reward after 40 days, he got reward for 30 or 40 days? (propose: 30 days. It will stimulate staker to hold longer.)

30 days.

Set max_delay to 1 year or more? (propose: 2 years. The 1 year is very common interval.)

Let's set it to 2 years then.

Do we need the function claim_and_withdraw ?

This function was necessary in my version of the contract. Now it is not necessary because withdraw_stake claims reward automatically in this version. We can get rid of claim_and_withdraw.

Do we need function reinvest which add all staker's reward to his deposit?

It is nice to have, however we can upgrade the contract in the future. Let's make the first version as simple as possible.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Oct 4, 2018

>> Do we need function reinvest which add all staker's reward to his deposit?

It is nice to have, however we can upgrade the contract in the future. Let's make the first version as simple as possible.

I already implement reinvest function and it will not rise contract complexity too much. However upgrade the contract in the future may cause more inconvenience for stakers.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 4, 2018

I already implement reinvest function and it will not rise contract complexity too much.

Yes, I saw the code.
Each line introduces a new place for a bug to exist, even when each individual line is incredibly simple. Even when I fully understand the purpose of the new code, I know lurking in each line could be a subtle but important bug.

As we know, writing bug-free code is almost impossible. Let's recall the 80:20 rule as well. I'd like to cite this: In summary, there is no doubt that focusing on the 20% of the features that give you 80% of the value will maximize the investment in software development and improve overall user satisfaction ... Therefore, reducing scope and not doing 100% of the features and functions is not only a valid strategy, but a prudent one.

The main idea is that we don't need 100% ideal smart-contract code right now, we need a perfectly working one. It may only contain 70% - 80% of the "nice to have" features but it must be error-free. The cost of a single bug is too high.

It is better to have a working contract with some inconveniences and limited functionality than have a complicated and convenient but hacked contract.

Again, we are not developing an ideal implementation of the Cold Staking contract. We are developing the very first and experimental implementation which will be updated in the future.

I think that it must be as simple as possible.

However upgrade the contract in the future may cause more inconvenience for stakers.

We will upgrade contract in the future. I think that everything will be fair if we announce the upgrading of the contract and let stakers know about it. They all will be in absolutely the same situation.

Anyways, the inconvenience that you pointed out make no sense compared to the disastrous consequences of a single bug in the contract.

Let me remind about TheDAO hack. Parity Multisig hack 1 and Parity Multisig hack 2 that I witnessed.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Oct 4, 2018

Anyways, the inconvenience that you pointed out make no sense compared to the disastrous consequences of a single bug in the contract.

I would agree with you if it be completely different function code, but code of reinvest is almost copy-paste from claim function + start_staking function. So if reinvest contain bug the above functions will also contain bug. And no risk to get new bug.
Anyway its only a few strings of code, so you, RideSolo, and other auditors can check it independently.

I see an additional benefit from this feature in that it allows to more evenly distribute stakers requests for rewards. If we assume that the majority of users will make a deposit on the day the CS is launched (in order to get the maximum profit), requests for rewards will also be made in one day in order to minimize losses. And using this function, the staker can reinvest the reward on any day without losing an incomplete period.

Maybe you have other reason don't add reinvest?

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 4, 2018

The result of the execution of reinvest() function is exactly the same as if a user withdrawn his staking reward and then deposited the withdrawal amount back with the second transaction.

At the other hand, there were multiple protocol-related bugs (see fallback function behavior for example). If we were just developing a smarе-contract and there was an error that is not related to our code, then we would report it and say that this is an error of the Ethereum protocol. Its not our problem.
In our case we are responsible for ANY error that may occur.

Evaluating the "risk VS reward" ratio of having some extra functions I can conclude that we must schedule them for the next release (HF2).

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 4, 2018

I tend to agree that my approach may cause a bit of inconvenience for the users, but it is normal for the very first release of the protocol.
It may also increase the number of transactions on the network, but I doubt that CLO will suffer serious bandwidth issues during the next half of the year.

Again, it is better to have a very primitive but working contract, than start with advanced hacked version.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 4, 2018

I would suggest moving forward and make a decision on final values for constant variables (staking_threshold, round_interval, max_delay and so on).

After that, we should update the contract so that it will be ready for use without any changes. We will perform a security audit and a bug bounty on the version of the contract that will not undergo any changes prior to deployment.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 4, 2018

1. staking_threshold

We have the following statement at the Whitepaper: Minimal amount: No minimal threshold.

I don't see any serious reason to change this. I think that it should be 0.
However, we need to keep the staking_threshold implementation at the contract because it is intended to be reusable. I'd like to propose Cold Staking protocol for ETC as well. If it will be decided to apply any minimum threshold for some reason, then it will be easier to do this with our current implementation.

2. round_interval

I'm proposing 27 days.

Our initial implementation assumes ~1 month of locking time. Traders often make their decisions based on charts and candle closures. Therefore, it is better for them to have their coins available when the time to make a decision will come. That's why I'm proposing 27 days interval.

If you deposit your funds at the beginning of a month then you will have the opportunity to claim it back right before the closure of the (1) week candle and (2) month candle at the same time.

candle_close

3. max_delay

If you think that 2 years is a reasonable length then I have no objections. Let's use 2 years.

4. DateStartStaking

I'm proposing 1541980800.

12 November 2018 @ 12:00am (UTC). The staking will be auto-enabled a day after the HF1.

@yuriy77k

This comment has been minimized.

Copy link
Member

yuriy77k commented Oct 5, 2018

The result of the execution of reinvest() function is exactly the same as if a user withdrawn his staking reward and then deposited the withdrawal amount back with the second transaction.

Not exactly. If staker hold 40 days and withdraw his deposit - he received reward only for 30 days (round_interval) and lose reward for 10 days. But reinvest() add full reward for 40 days to staker deposit (and begin new round), so it will be more profitable for users and stimulate it keep staking longer time.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Oct 5, 2018

@yuriy77k @Dexaran, I just want to highlight something with the current proposal.
The stakers should be pushed to claim their reward otherwise if we suppose a positive growth of the total staked amount, if a user wait two months for example to claim, his two months reward will be less that if he claims twice (the first and second month). To resume the issue, the formula is not linear.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 6, 2018

@yuriy77k

reinvest() add full reward for 40 days to staker deposit (and begin new round)

Yes, it is a bit more convenient for stakers.
If you re-stake each month or use the second account then it will still work properly.

I fully agree that the reinvest() function is a useful feature, but it is not of critical importance for us right now. That is why it is better to implement it after we make sure that the very basic version works properly.

it will be more profitable for users and stimulate it keep staking longer time.

Honestly, I don't see how it incentivizes users to stake longer. Staking longer is not more profitable compared to the "withdraw & use another account" method.
I agree that it is a bit inconvenient but not critical. As the side effect, it can increase the number of transactions and active addresses of the Callisto network, but I don't think that it is a big problem.

@RideSolo

if a user wait two months for example to claim, his two months reward will be less that if he claims twice

I would say yes. We need to provide a description and highlight how the staking works. The description should be pinned somewhere so that everyone can find it easily.

Dexaran added a commit to EthereumCommonwealth/Cold-staking that referenced this issue Oct 6, 2018

Final variables applied.
Applied final constant variables for the contract according to EthereumCommonwealth/Roadmap#51 (comment)
@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 6, 2018

@yuriy77k @RideSolo

I've implemented the final changes.

This contract will be deployed at the CLO mainnet "as-is" and it will be enabled after HF1: https://github.com/EthereumCommonwealth/Cold-staking/blob/master/ColdStaking.sol

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 6, 2018

Final implementation pattern.

  1. Security audit of the Cold Staking contract.
  2. Bug bounty.
  3. Contract will be compiled and deployed at Callisto Mainnet before the hardfork date.
  4. At 11th November, the hardfork №1 changes will be enabled. Contract will start to receive 20% of block rewards. Staking will not be enabled instantly.
  5. At 12th November 0:0 UTC the staking will become available.

Contract will be deployed at Callisto Testnet soon.

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 6, 2018

Conclusion.

I've reviewed both Yuriy's and RideSolo's versions of the Cold Staking.
RideSolo's version seems to be of arguable higher complexity. I think that for the first launch, the main focus is to show that everything works as intended. Also, Callisto is an experimental project and both versions of the Staking Protocol could be a part of this experiment.

As the result, I've decided that the best option is to implement Yuriy's version at HF1 and test the RideSolo's version at this time. After that, the RideSolo's version of ColdStaking will be implemented at HF2.

In this way we will have the opportunity to test and compare both versions properly. However, I'd like to highlight that the most important aspect for the first implementation (HF1) is to ensure that everything works properly without a single bug.We must avoid such accidents like TheDAO hack by any costs.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Oct 6, 2018

I've reviewed both Yuriy's and RideSolo's versions of the Cold Staking.
RideSolo's version seems to be of arguable higher complexity. I think that for the first launch, the main focus is to show that everything works as intended. Also, Callisto is an experimental project and both versions of the Staking Protocol could be a part of this experiment.

The most important for me was to show the inconvenients of yuriy's proposal, so everyone will know what to expect, and we all know that any possible idea has inconvenient and advantages.

As the result, I've decided that the best option is to implement Yuriy's version at HF1 and test the RideSolo's version at this time. After that, the RideSolo's version of ColdStaking will be implemented at HF2.

Personally I will keep the repository up to date until then.

In this way we will have the opportunity to test and compare both versions properly. However, I'd like to highlight that the most important aspect for the first implementation (HF1) is to ensure that everything works properly without a single bug.We must avoid such accidents like TheDAO hack by any costs.

I agree with your vision.

@RideSolo

This comment has been minimized.

Copy link

RideSolo commented Oct 7, 2018

@Dexaran I do think that it is better to set the withdrawal address to the actual Callisto Staking Reserve Address, it has less activity and our community will be able to check the withdrawn amount easily (of course I hope that it will be the last possible scenario).

@Dexaran

This comment has been minimized.

Copy link
Member

Dexaran commented Oct 7, 2018

I do think that it is better to set the withdrawal address to the actual Callisto Staking Reserve

Sounds reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment