From 717a19a08e75f1a00eb18f48929f3e20ee71f70b Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 3 Jun 2019 18:31:42 -0700 Subject: [PATCH] moving towards working delegation + timelocks. --- contracts/staking/contracts/src/Staking.sol | 114 ++++--- .../staking/contracts/src/core/MixinEpoch.sol | 33 ++ .../staking/contracts/src/core/MixinStake.sol | 296 ++++++++++-------- .../contracts/src/core/MixinStakeBalances.sol | 99 ++++++ .../contracts/src/core/MixinStorage.sol | 32 +- .../contracts/src/core/MixinTimelock.sol | 49 +++ .../contracts/src/libs/LibTimelock.sol | 99 ++++++ contracts/staking/test/core_test.ts | 2 + .../staking/test/utils/staking_wrapper.ts | 4 + 9 files changed, 550 insertions(+), 178 deletions(-) create mode 100644 contracts/staking/contracts/src/core/MixinStakeBalances.sol diff --git a/contracts/staking/contracts/src/Staking.sol b/contracts/staking/contracts/src/Staking.sol index 3ae3c1ed18..6c81195395 100644 --- a/contracts/staking/contracts/src/Staking.sol +++ b/contracts/staking/contracts/src/Staking.sol @@ -31,88 +31,120 @@ contract Staking is MixinPools { - ///// STAKING ///// + ///// STAKE ///// - function stake(uint256 amount) + function deposit(address owner, uint256 amount) external - returns (uint256 amountOfStakeMinted) { - amountOfStakeMinted = _stake(amount); - return amountOfStakeMinted; + _deposit(msg.sender, amount); } - function unstake(uint256 amount) + function depositAndStake(address owner, uint256 amount) external - returns (uint256 amountOfStakeBurned) { - amountOfStakeBurned = _unstake(amount); - return amountOfStakeBurned; + _depositAndStake(msg.sender, amount); } - function getStakeBalance(address owner) + function depositAndDelegate(address owner, bytes32 poolId, uint256 amount) external - view - returns (uint256 balance) { - balance = _getStakeBalance(owner); - return balance; + _depositAndDelegate(owner, poolId, amount); } - function delegateStake(bytes32 makerId, uint256 amount) + function activateStake(address owner, uint256 amount) external - returns (uint256 amountOfStakeDelegated) { - amountOfStakeDelegated = _delegateStake(makerId, amount); - return amountOfStakeDelegated; + _activateStake(msg.sender, amount); } - function undelegateStake(bytes32 makerId, uint256 amount) + function activateAndDelegateStake(address owner, uint256 amount) external - returns (uint256 amountOfStakeUndelegated) { - amountOfStakeUndelegated = _undelegateStake(makerId, amount); - return amountOfStakeUndelegated; + _activateAndDelegateStake(msg.sender, amount); } - function stakeAndDelegate(bytes32 makerId, uint256 amount) + function deactivateAndTimelockStake(address owner, uint256 amount) external - returns (uint256 amountOfStakeMintedAndDelegated) { - amountOfStakeMintedAndDelegated = _stakeAndDelegate(makerId, amount); - return amountOfStakeMintedAndDelegated; + _deactivateAndTimelockStake(msg.sender, amount); } - function undelegateAndUnstake(bytes32 makerId, uint256 amount) + function deactivateAndTimelockDelegatedStake(address owner, bytes32 poolId, uint256 amount) external - returns (uint256 amountOfStakeUndelegatedAndUnstaked) { - + _deactivateAndTimelockDelegatedStake(msg.sender, poolId, amount); + } + + function withdraw(address owner, uint256 amount) + external + { + _withdraw(msg.sender, amount); } ///// STAKE BALANCES ///// - function getStakeDelegatedByOwner(address owner, bytes32 makerId) + function getTotalStake(address owner) external - returns (uint256 balance) + view + returns (uint256) { - balance = _getStakeDelegatedByOwner(owner, makerId); - return balance; + return _getTotalStake(owner); } - function getTotalStakeDelegatedByOwner(address owner) + function getActivatedStake(address owner) external - returns (uint256 balance) + view + returns (uint256) { - balance = _getTotalStakeDelegatedByOwner(owner); - return balance; + return _getActivatedStake(owner); } - function getTotalStakeDelegatedToMaker(bytes32 makerId) + function getDeactivatedStake(address owner) external - returns (uint256 balance) + view + returns (uint256) { - balance = _getTotalStakeDelegatedToMaker(makerId); - return balance; + return _getDeactivatedStake(owner); + } + + function getWithdrawableStake(address owner) + external + view + returns (uint256) + { + return getWithdrawableStake(owner); + } + + function getTimelockedStake(address owner) + external + view + returns (uint256) + { + return _getTimelockedStake(owner); + } + + function getStakeDelegatedByOwner(address owner) + external + view + returns (uint256) + { + return _getStakeDelegatedByOwner(owner); + } + + function getStakeDelegatedToPoolByOwner(address owner, bytes32 poolId) + internal + view + returns (uint256) + { + return _getStakeDelegatedToPoolByOwner(owner, poolId); + } + + function getStakeDelegatedToPool(bytes32 poolId) + external + view + returns (uint256) + { + return _getStakeDelegatedToPool(poolId); } ///// POOLS ///// diff --git a/contracts/staking/contracts/src/core/MixinEpoch.sol b/contracts/staking/contracts/src/core/MixinEpoch.sol index e69de29bb2..4e226dcaf4 100644 --- a/contracts/staking/contracts/src/core/MixinEpoch.sol +++ b/contracts/staking/contracts/src/core/MixinEpoch.sol @@ -0,0 +1,33 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.5; + +import "@0x/contracts-utils/contracts/src/SafeMath.sol"; +import "./MixinStorage.sol"; + +contract MixinEpoch { + + function _getCurrentTimelockPeriod() + internal + returns (uint64) + { + // @TODO - IMPLEMENT + return 7; + } +} diff --git a/contracts/staking/contracts/src/core/MixinStake.sol b/contracts/staking/contracts/src/core/MixinStake.sol index 1aed7a6edd..3d7b421f93 100644 --- a/contracts/staking/contracts/src/core/MixinStake.sol +++ b/contracts/staking/contracts/src/core/MixinStake.sol @@ -24,158 +24,204 @@ import "@0x/contracts-utils/contracts/src/SafeMath.sol"; import "./MixinStorage.sol"; import "./MixinConstants.sol"; import "../interfaces/IStakingEvents.sol"; +import "./StakingBalances.sol"; contract MixinStake is SafeMath, IStakingEvents, MixinConstants, - MixinStorage + MixinStorage, + MixinStakeBalances { using LibZrxToken for uint256; - // default maker id that stake is delegated to - bytes32 constant internal NIL_MAKER_ID = 0x0; - - function _stake(uint256 amount) + function _deposit(address owner, uint256 amount) internal - returns (uint256) { - // sanitize input - can only stake whole tokens - uint256 amountOfStakeToMint = amount._roundDownToNearestWholeToken(); - - // deposit equivalent amount of ZRX into vault - zrxVault.depositFrom(msg.sender, amountOfStakeToMint); - - // mint stake - totalStake[msg.sender] = _safeAdd(totalStake[msg.sender], amountOfStakeToMint); - delegatedStake[msg.sender][NIL_MAKER_ID] = _safeAdd(delegatedStake[msg.sender][NIL_MAKER_ID], amountOfStakeToMint); - - // emit stake event - emit StakeMinted( - msg.sender, - amountOfStakeToMint - ); - - // return amount of stake minted - return amountOfStakeToMint; + _mintStake(owner, amount); } - function _unstake(uint256 amount) + function _depositAndStake(address owner, uint256 amount) internal - returns (uint256) { - // sanitize input - can only stake whole tokens - uint256 amountOfStakeToBurn = amount._roundDownToNearestWholeToken(); + _mintStake(owner, amount); + _activateStake(owner, amount); + } + + function _depositAndDelegate(address owner, bytes32 poolId, uint256 amount) + internal + { + _depositAndStake(owner, amount); + _delegateStake(owner, poolId, amount); + } + + function _activateStake(address owner, uint256 amount) + internal + { + _syncTimelockedStake(); + + Timelock memory ownerTimelock = timelocksByOwner[owner]; + require( + ownerTimelock.availableBalance >= amount, + "INSUFFICIENT_BALANCE" + ); + ownerTimelock.sub(amount); + timelocksByOwner[owner] = ownerTimelock; + + _activateStake(owner, amount); + } + + function _activateAndDelegateStake(address owner, bytes32 poolId, uint256 amount) + internal + { + _activateStake(owner, amount); + _delegateStake(owner, poolId, amount); + } + + function _deactivateAndTimelockStake(address owner, uint256 amount) + internal + { + Timelock memory ownerTimelock = timelocksByOwner[owner]; + ownerTimelock.add(amount); + timelocksByOwner[owner] = ownerTimelock; + + activeStakeByOwner[owner] = _safeSub(activeStakeByOwner[owner], amount); + } + + function _deactivateAndTimelockDelegatedStake(address owner, bytes32 poolId, uint256 amount) + internal + { + _deactivateStake(owner, amount); + _undelegateStake(owner, poolId, amount); + } + + function _withdraw(address owner, uint256 amount) + internal + { + Timelock memory ownerTimelock = timelocksByOwner[owner]; + require( + ownerTimelock.availableBalance >= amount, + "INSUFFICIENT_BALANCE" + ); + ownerTimelock.sub(amount); + timelocksByOwner[owner] = ownerTimelock; // burn stake - totalStake[msg.sender] = _safeSub(totalStake[msg.sender], amountOfStakeToBurn); - delegatedStake[msg.sender][NIL_MAKER_ID] = _safeSub(delegatedStake[msg.sender][NIL_MAKER_ID], amountOfStakeToBurn); + _burnStake(owner, amount); + } - // withdraw equivalent amount of ZRX from vault - zrxVault.withdrawFrom(msg.sender, amountOfStakeToBurn); + ///// PRIVATE HELPERS ///// + + function _mintStake(address owner, uint256 amount) + private + { + // deposit equivalent amount of ZRX into vault + zrxVault.depositFrom(owner, amount); + + // mint stake + stakeByOwner[owner] = _safeAdd(stakeByOwner[owner], amount); // emit stake event emit StakeMinted( - msg.sender, - amountOfStakeToBurn - ); - - // return amount of stake minted - return amountOfStakeToBurn; - } - - function _delegateStake(bytes32 makerId, uint256 amount) - internal - returns (uint256) - { - require( - _getUndelegatedStake(msg.sender) >= amount, - "INSUFFICIENT_STAKE_BALANCE" - ); - - // change from undelegated to delegated - delegatedStake[msg.sender][NIL_MAKER_ID] = _safeSub(delegatedStake[msg.sender][NIL_MAKER_ID], amount); - delegatedStake[msg.sender][makerId] = _safeAdd(delegatedStake[msg.sender][makerId], amount); - - // Update total stake delegated to `makerId` - totalDelegatedStake[makerId] = _safeAdd(totalDelegatedStake[makerId], amount); - } - - function _undelegateStake(bytes32 makerId, uint256 amount) - internal - returns (uint256) - { - require( - _getStakeDelegatedByOwner(msg.sender, makerId) >= amount, - "INSUFFICIENT_DELEGATED_STAKE_BALANCE" - ); - - // change from delegated to undelegated - delegatedStake[msg.sender][makerId] = _safeSub(delegatedStake[msg.sender][makerId], amount); - delegatedStake[msg.sender][NIL_MAKER_ID] = _safeAdd(delegatedStake[msg.sender][NIL_MAKER_ID], amount); - - // Update total stake delegated to `makerId` - totalDelegatedStake[makerId] = _safeAdd(totalDelegatedStake[makerId], amount); - } - - function _undelegateAllStake(bytes32 makerId) - internal - returns (uint256) - { - address owner = msg.sender; - uint256 delegatedStakeBalance = _getStakeDelegatedByOwner(owner, makerId); - return _undelegateStake(makerId, delegatedStakeBalance); - } - - function _stakeAndDelegate(bytes32 makerId, uint256 amount) - internal - returns (uint256 amountOfStakeDelegated) - { - // mint stake - uint256 amountOfStakeMinted = _stake(amount); - - // delegate stake to maker - amountOfStakeDelegated = _delegateStake(makerId, amountOfStakeMinted); - return amountOfStakeDelegated; - } - - function _getUndelegatedStake(address owner) - internal - returns (uint256) - { - return delegatedStake[owner][NIL_MAKER_ID]; - } - - function _getStakeDelegatedByOwner(address owner, bytes32 makerId) - internal - returns (uint256) - { - return delegatedStake[owner][makerId]; - } - - function _getTotalStakeDelegatedByOwner(address owner) - internal - returns (uint256) - { - return _safeSub( - totalStake[owner], - delegatedStake[owner][NIL_MAKER_ID] + owner, + amount ); } - function _getTotalStakeDelegatedToMaker(bytes32 makerId) - internal - returns (uint256) + function _burnStake(address owner, uint256 amount) + private { - return totalDelegatedStake[makerId]; + // burn stake + stakeByOwner[owner] = _safeSub(stakeByOwner[owner], amount); + + // withdraw equivalent amount of ZRX from vault + zrxVault.withdrawFrom(owner, amount); + + // emit stake event + emit StakeBurned( + owner, + amount + ); } - function _getStakeBalance(address owner) - internal - view - returns (uint256) + function _activateStake(address owner, uint256 amount) + private { - return totalStake[owner]; + activeStakeByOwner[owner] = _safeAdd(activeStakeByOwner[owner], amount); + } + + function _delegateStake(address owner, bytes32 poolId, uint256 amount) + private + { + // increment how much stake the owner has delegated + delegatedStakeByOwner[owner] = _safeAdd(stakeByOwner[owner], amount); + + // increment how much stake the owner has delegated to the input pool + delegatedStakeToPoolByOwner[owner][poolId] = _safeAdd(delegatedStakeToPoolByOwner[owner][poolId], amount); + + // increment how much stake has been delegated to pool + delegatedStakeByPoolId[poolId] = _safeAdd(delegatedStakeByPoolId[poolId], amount); + } + + function _undelegateStake(address owner, bytes32 poolId, uint256 amount) + private + { + // decrement how much stake the owner has delegated + delegatedStakeByOwner[owner] = _safeSub(stakeByOwner[owner], amount); + + // decrement how much stake the owner has delegated to the input pool + delegatedStakeToPoolByOwner[owner][poolId] = _safeSub(delegatedStakeToPoolByOwner[owner][poolId], amount); + + // decrement how much stake has been delegated to pool + delegatedStakeByPoolId[poolId] = _safeSub(delegatedStakeByPoolId[poolId], amount); + } + + // Epoch | lockedAt | total | pending | current | timelock() | withdraw() | available() + // 0 | 0 | 0 | 0 | 0 | | | 0 + // 1 | 1 | 5 | 0 | 0 | +5 | | 0 + // 2 | 1 | 5 | 0 | 0 | | | 0 + // 2 | 2 | 15 | 5 | 0 | +10 | | 0 + // 3 | 2 | 15 | 5 | 0 | | | 5 + // 3 | 3 | 30 | 15 | 5 | +15 | | 5 + // 4 | 3 | 30 | 15 | 5 | | | 15 + // 5 | 3 | 30 | 15 | 5 | | | 30 + // 5 | 5 | 30 | 30 | 30 | +0 * | | 30 + // 6 | 6 | 50 | 30 | 30 | +20 | | 30 + // 6 | 6 | 20 | 0 | 0 | | -30 | 0 + // 7 | 6 | 20 | 0 | 0 | | | 0 + // 8 | 6 | 20 | 0 | 0 | | | 20 + function _timelockStake(address owner, uint256 amount) + private + { + Timelock memory ownerTimelock = _getSynchronizedTimelock(owner, amount); + ownerTimelock.total = _safeAdd(ownerTimelock.total, amount); + timelocksByOwner[owner] = ownerTimelock; + } + + function _syncTimelockedStake(address owner, uint256 amount) + private + { + timelocksByOwner[owner] = _getSynchronizedTimelock(owner, amount); + } + + function _getSynchronizedTimelock(address owner, uint256 amount) + private + returns (Timelock memory ownerTimelock) + { + Timelock memory ownerTimelock = timelocksByOwner[owner]; + uint64 currentTimelockPeriod = getCurrentTimelockPeriod(); + if (currentTimelockPeriod == _safeAdd(ownerTimelock.lockedAt, 1)) { + // shift one period + ownerTimelock.current = ownerTimelock.pending; + ownerTimelock.pending = ownerTimelock.total; + } else if (currentTimelockPeriod > ownerTimelock.lockedAt) { + // shift n periods + ownerTimelock.current = ownerTimelock.total; + ownerTimelock.pending = ownerTimelock.total; + } else { + // do nothing + } + return ownerTimelock; } } diff --git a/contracts/staking/contracts/src/core/MixinStakeBalances.sol b/contracts/staking/contracts/src/core/MixinStakeBalances.sol new file mode 100644 index 0000000000..105e076e41 --- /dev/null +++ b/contracts/staking/contracts/src/core/MixinStakeBalances.sol @@ -0,0 +1,99 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.5; + +import "../interfaces/IVault.sol"; +import "../libs/LibZrxToken.sol"; +import "@0x/contracts-utils/contracts/src/SafeMath.sol"; +import "./MixinStorage.sol"; +import "./MixinConstants.sol"; + + +contract MixinStake is + SafeMath, + MixinConstants, + MixinStorage, +{ + + function _getTotalStake(address owner) + internal + view + returns (uint256) + { + return stakeByOwner[owner]; + } + + function getActivatedStake(address owner) + internal + view + returns (uint256) + { + return activeStakeByOwner[owner]; + } + + function getDeactivatedStake(address owner) + internal + view + returns (uint256) + { + return _safeSub(_getTotalStake(owner), getActivatedStake(owner)); + } + + function getStakeAvailableForActivation() + + function getWithdrawableStake(address owner) + internal + view + returns (uint256) + { + + } + + function getTimelockedStake(address owner) + internal + view + returns (uint256) + { + return timelockedStakeByOwner[owner].total; + } + + function getStakeDelegatedByOwner(address owner) + internal + view + returns (uint256) + { + return delegatedStakeByOwner[owner]; + } + + function getStakeDelegatedToPoolByOwner(address owner, bytes32 poolId) + internal + view + returns (uint256) + { + return delegatedStakeToPoolByOwner[owner][poolId]; + } + + function getStakeDelegatedToPool(bytes32 poolId) + internal + view + returns (uint256) + { + return delegatedStakeByPoolId[poolId]; + } +} diff --git a/contracts/staking/contracts/src/core/MixinStorage.sol b/contracts/staking/contracts/src/core/MixinStorage.sol index a3d85b66ec..6ee9bdbdbd 100644 --- a/contracts/staking/contracts/src/core/MixinStorage.sol +++ b/contracts/staking/contracts/src/core/MixinStorage.sol @@ -20,31 +20,39 @@ pragma solidity ^0.5.5; import "../interfaces/IVault.sol"; import "./MixinConstants.sol"; +import "../interfaces/IStructs.sol"; contract MixinStorage is - MixinConstants + IStructs, + MixinConstants { // address of staking contract address stakingContract; - // mapping from Staker to Maker Id to Amount Staked - mapping (address => mapping (bytes32 => uint256)) delegatedStake; + // mapping from Owner to Amount Staked + mapping (address => uint256) stakeByOwner; - // mapping from Staker to Maker Id to Amount Staked - mapping (address => uint256) totalStake; + // mapping from Owner to Amount of Instactive Stake + mapping (address => uint256) activeStakeByOwner; - // mapping from Maker Id to Amount of Delegated Staked - mapping (bytes32 => uint256) totalDelegatedStake; + // mapping from Owner to Amount Timelocked + mapping (address => Timelock) timelockedStakeByOwner; - // tracking Maker Id + // mapping from Pool Id to Amount Delegated + mapping (bytes32 => uint256) delegatedStakeByPoolId; + + // mapping from Owner to Amount Delegated + mapping (address => uint256) delegatedStakeByOwner; + + // mapping from Owner to Pool Id to Amount Delegated + mapping (address => mapping (bytes32 => uint256)) delegatedStakeToPoolByOwner; + + // tracking Pool Id bytes32 nextPoolId = INITIAL_POOL_ID; - struct Pool { - address operatorAddress; - uint8 operatorShare; - } + // mapping from Pool Id to Pool mapping (bytes32 => Pool) poolById; // mapping from Maker Address to Pool Id diff --git a/contracts/staking/contracts/src/core/MixinTimelock.sol b/contracts/staking/contracts/src/core/MixinTimelock.sol index e69de29bb2..ab9dcb8f79 100644 --- a/contracts/staking/contracts/src/core/MixinTimelock.sol +++ b/contracts/staking/contracts/src/core/MixinTimelock.sol @@ -0,0 +1,49 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.5; + +import "@0x/contracts-utils/contracts/src/SafeMath.sol"; +import "./MixinStorage.sol"; + + +contract MixinStake is + SafeMath, + MixinStorage +{ + + +contract MixinTimelock { + + // Epoch | lockedAt | total | pending | current | timelock() | withdraw() | available() + // 0 | 0 | 0 | 0 | 0 | | | 0 + // 1 | 1 | 5 | 0 | 0 | +5 | | 0 + // 2 | 1 | 5 | 0 | 0 | | | 0 + // 2 | 2 | 15 | 5 | 0 | +10 | | 0 + // 3 | 2 | 15 | 5 | 0 | | | 5 + // 3 | 3 | 30 | 15 | 5 | +15 | | 5 + // 4 | 3 | 30 | 15 | 5 | | | 15 + // 5 | 3 | 30 | 15 | 5 | | | 30 + // 5 | 5 | 30 | 30 | 30 | +0 * | | 30 + // 6 | 6 | 50 | 30 | 30 | +20 | | 30 + // 6 | 6 | 20 | 0 | 0 | | -30 | 0 + // 7 | 6 | 20 | 0 | 0 | | | 0 + // 8 | 6 | 20 | 0 | 0 | | | 20 + + function _timelockStake() +} \ No newline at end of file diff --git a/contracts/staking/contracts/src/libs/LibTimelock.sol b/contracts/staking/contracts/src/libs/LibTimelock.sol index e69de29bb2..6446b7b204 100644 --- a/contracts/staking/contracts/src/libs/LibTimelock.sol +++ b/contracts/staking/contracts/src/libs/LibTimelock.sol @@ -0,0 +1,99 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.5; + +import "../interfaces/IStructs.sol"; +import "@0x/contracts-utils/contracts/src/SafeMath.sol"; + + +contract MixinTimelock is + IStructs, + SafeMath +{ + + // Epoch | lockedAt | total | pending | current | timelock() | withdraw() | available() + // 0 | 0 | 0 | 0 | 0 | | | 0 + // 1 | 1 | 5 | 0 | 0 | +5 | | 0 + // 2 | 1 | 5 | 0 | 0 | | | 0 + // 2 | 2 | 15 | 5 | 0 | +10 | | 0 + // 3 | 2 | 15 | 5 | 0 | | | 5 + // 3 | 3 | 30 | 15 | 5 | +15 | | 5 + // 4 | 3 | 30 | 15 | 5 | | | 15 + // 5 | 3 | 30 | 15 | 5 | | | 30 + // 5 | 5 | 30 | 30 | 30 | +0 * | | 30 + // 6 | 6 | 50 | 30 | 30 | +20 | | 30 + // 6 | 6 | 20 | 0 | 0 | | -30 | 0 + // 7 | 6 | 20 | 0 | 0 | | | 0 + // 8 | 6 | 20 | 0 | 0 | | | 20 + + + function _add(Timelock memory timelock, uint256 amount) + internal + returns (uint256) + { + timelock.total += amount; + } + + function _sub(Timelock memory timelock, uint256 amount) + internal + returns (uint256) + { + + } + + + + function _subTimelockedStake(address owner, uint256 amount) + internal + { + + } + + function _addTimelockedStake(address owner, uint256 amount) + internal + { + timelockedStakeByOwner[owner] = safeAdd(timelockedStakeByOwner[owner], amount); + + // update timelock + uint64 currentTimelockPeriod = _getTimelockPeriod(); + Timelock memory timelock = timelocksByOwner[owner]; + + } + + function _getAvailableTimelockedStake(address owner) + internal + returns (uint256) + { + + } + + function _getPendingTimelockedStake(address owner) + internal + returns (uint256) + { + + } + + function _getTotalTimelockedStake(address owner) + internal + returns (uint256) + { + + } +} \ No newline at end of file diff --git a/contracts/staking/test/core_test.ts b/contracts/staking/test/core_test.ts index 3f60fcb57e..03579a8fda 100644 --- a/contracts/staking/test/core_test.ts +++ b/contracts/staking/test/core_test.ts @@ -69,6 +69,7 @@ describe('Staking Core', () => { }); describe('end-to-end tests', () => { it('staking/unstaking', async () => { + /* ///// 1/3 SETUP TEST PARAMETERS ///// const amountToStake = stakingWrapper.toBaseUnitAmount(10); const amountToUnstake = stakingWrapper.toBaseUnitAmount(5); @@ -111,6 +112,7 @@ describe('Staking Core', () => { const zrxTokenBalanceOfStakerAfterStaking = await stakingWrapper.getZrxTokenBalance(stakers[0]); expect(zrxTokenBalanceOfStakerAfterStaking).to.be.bignumber.equal(zrxTokenBalanceOfStakerBeforeStaking.minus(amountToStake).plus(amountToUnstake)); } + */ }); it('nth root', async () => { diff --git a/contracts/staking/test/utils/staking_wrapper.ts b/contracts/staking/test/utils/staking_wrapper.ts index 566bcebcee..b53d541465 100644 --- a/contracts/staking/test/utils/staking_wrapper.ts +++ b/contracts/staking/test/utils/staking_wrapper.ts @@ -115,6 +115,8 @@ export class StakingWrapper { const returnValue = await this._web3Wrapper.callAsync(txData); return returnValue; } + + /* public async stake(holder: string, amount: BigNumber): Promise { const calldata = this.getStakingContract().stake.getABIEncodedTransactionData(amount); const txReceipt = await this._executeTransactionAsync(calldata, holder); @@ -129,11 +131,13 @@ export class StakingWrapper { const stakeBurned = (stakeBurnedLog as any).args.amount; return stakeBurned; } + public async getStakeBalance(holder: string): Promise { const calldata = this.getStakingContract().getStakeBalance.getABIEncodedTransactionData(holder); const balance = await this._callAsync(calldata, holder); return balance; } + */ public async getNextPoolIdAsync(): Promise { const calldata = this.getStakingContract().getNextPoolId.getABIEncodedTransactionData(); const nextPoolId = await this._callAsync(calldata);