moving towards working delegation + timelocks.
This commit is contained in:
@@ -31,88 +31,120 @@ contract Staking is
|
|||||||
MixinPools
|
MixinPools
|
||||||
{
|
{
|
||||||
|
|
||||||
///// STAKING /////
|
///// STAKE /////
|
||||||
|
|
||||||
function stake(uint256 amount)
|
function deposit(address owner, uint256 amount)
|
||||||
external
|
external
|
||||||
returns (uint256 amountOfStakeMinted)
|
|
||||||
{
|
{
|
||||||
amountOfStakeMinted = _stake(amount);
|
_deposit(msg.sender, amount);
|
||||||
return amountOfStakeMinted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function unstake(uint256 amount)
|
function depositAndStake(address owner, uint256 amount)
|
||||||
external
|
external
|
||||||
returns (uint256 amountOfStakeBurned)
|
|
||||||
{
|
{
|
||||||
amountOfStakeBurned = _unstake(amount);
|
_depositAndStake(msg.sender, amount);
|
||||||
return amountOfStakeBurned;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStakeBalance(address owner)
|
function depositAndDelegate(address owner, bytes32 poolId, uint256 amount)
|
||||||
external
|
external
|
||||||
view
|
|
||||||
returns (uint256 balance)
|
|
||||||
{
|
{
|
||||||
balance = _getStakeBalance(owner);
|
_depositAndDelegate(owner, poolId, amount);
|
||||||
return balance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function delegateStake(bytes32 makerId, uint256 amount)
|
function activateStake(address owner, uint256 amount)
|
||||||
external
|
external
|
||||||
returns (uint256 amountOfStakeDelegated)
|
|
||||||
{
|
{
|
||||||
amountOfStakeDelegated = _delegateStake(makerId, amount);
|
_activateStake(msg.sender, amount);
|
||||||
return amountOfStakeDelegated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function undelegateStake(bytes32 makerId, uint256 amount)
|
function activateAndDelegateStake(address owner, uint256 amount)
|
||||||
external
|
external
|
||||||
returns (uint256 amountOfStakeUndelegated)
|
|
||||||
{
|
{
|
||||||
amountOfStakeUndelegated = _undelegateStake(makerId, amount);
|
_activateAndDelegateStake(msg.sender, amount);
|
||||||
return amountOfStakeUndelegated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stakeAndDelegate(bytes32 makerId, uint256 amount)
|
function deactivateAndTimelockStake(address owner, uint256 amount)
|
||||||
external
|
external
|
||||||
returns (uint256 amountOfStakeMintedAndDelegated)
|
|
||||||
{
|
{
|
||||||
amountOfStakeMintedAndDelegated = _stakeAndDelegate(makerId, amount);
|
_deactivateAndTimelockStake(msg.sender, amount);
|
||||||
return amountOfStakeMintedAndDelegated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function undelegateAndUnstake(bytes32 makerId, uint256 amount)
|
function deactivateAndTimelockDelegatedStake(address owner, bytes32 poolId, uint256 amount)
|
||||||
external
|
external
|
||||||
returns (uint256 amountOfStakeUndelegatedAndUnstaked)
|
|
||||||
{
|
{
|
||||||
|
_deactivateAndTimelockDelegatedStake(msg.sender, poolId, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function withdraw(address owner, uint256 amount)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
_withdraw(msg.sender, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
///// STAKE BALANCES /////
|
///// STAKE BALANCES /////
|
||||||
|
|
||||||
function getStakeDelegatedByOwner(address owner, bytes32 makerId)
|
function getTotalStake(address owner)
|
||||||
external
|
external
|
||||||
returns (uint256 balance)
|
view
|
||||||
|
returns (uint256)
|
||||||
{
|
{
|
||||||
balance = _getStakeDelegatedByOwner(owner, makerId);
|
return _getTotalStake(owner);
|
||||||
return balance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTotalStakeDelegatedByOwner(address owner)
|
function getActivatedStake(address owner)
|
||||||
external
|
external
|
||||||
returns (uint256 balance)
|
view
|
||||||
|
returns (uint256)
|
||||||
{
|
{
|
||||||
balance = _getTotalStakeDelegatedByOwner(owner);
|
return _getActivatedStake(owner);
|
||||||
return balance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTotalStakeDelegatedToMaker(bytes32 makerId)
|
function getDeactivatedStake(address owner)
|
||||||
external
|
external
|
||||||
returns (uint256 balance)
|
view
|
||||||
|
returns (uint256)
|
||||||
{
|
{
|
||||||
balance = _getTotalStakeDelegatedToMaker(makerId);
|
return _getDeactivatedStake(owner);
|
||||||
return balance;
|
}
|
||||||
|
|
||||||
|
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 /////
|
///// POOLS /////
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -24,158 +24,204 @@ import "@0x/contracts-utils/contracts/src/SafeMath.sol";
|
|||||||
import "./MixinStorage.sol";
|
import "./MixinStorage.sol";
|
||||||
import "./MixinConstants.sol";
|
import "./MixinConstants.sol";
|
||||||
import "../interfaces/IStakingEvents.sol";
|
import "../interfaces/IStakingEvents.sol";
|
||||||
|
import "./StakingBalances.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinStake is
|
contract MixinStake is
|
||||||
SafeMath,
|
SafeMath,
|
||||||
IStakingEvents,
|
IStakingEvents,
|
||||||
MixinConstants,
|
MixinConstants,
|
||||||
MixinStorage
|
MixinStorage,
|
||||||
|
MixinStakeBalances
|
||||||
{
|
{
|
||||||
using LibZrxToken for uint256;
|
using LibZrxToken for uint256;
|
||||||
|
|
||||||
// default maker id that stake is delegated to
|
function _deposit(address owner, uint256 amount)
|
||||||
bytes32 constant internal NIL_MAKER_ID = 0x0;
|
|
||||||
|
|
||||||
function _stake(uint256 amount)
|
|
||||||
internal
|
internal
|
||||||
returns (uint256)
|
|
||||||
{
|
{
|
||||||
// sanitize input - can only stake whole tokens
|
_mintStake(owner, amount);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _unstake(uint256 amount)
|
function _depositAndStake(address owner, uint256 amount)
|
||||||
internal
|
internal
|
||||||
returns (uint256)
|
|
||||||
{
|
{
|
||||||
// sanitize input - can only stake whole tokens
|
_mintStake(owner, amount);
|
||||||
uint256 amountOfStakeToBurn = amount._roundDownToNearestWholeToken();
|
_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
|
// burn stake
|
||||||
totalStake[msg.sender] = _safeSub(totalStake[msg.sender], amountOfStakeToBurn);
|
_burnStake(owner, amount);
|
||||||
delegatedStake[msg.sender][NIL_MAKER_ID] = _safeSub(delegatedStake[msg.sender][NIL_MAKER_ID], amountOfStakeToBurn);
|
}
|
||||||
|
|
||||||
// withdraw equivalent amount of ZRX from vault
|
///// PRIVATE HELPERS /////
|
||||||
zrxVault.withdrawFrom(msg.sender, amountOfStakeToBurn);
|
|
||||||
|
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 stake event
|
||||||
emit StakeMinted(
|
emit StakeMinted(
|
||||||
msg.sender,
|
owner,
|
||||||
amountOfStakeToBurn
|
amount
|
||||||
);
|
|
||||||
|
|
||||||
// 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]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getTotalStakeDelegatedToMaker(bytes32 makerId)
|
function _burnStake(address owner, uint256 amount)
|
||||||
internal
|
private
|
||||||
returns (uint256)
|
|
||||||
{
|
{
|
||||||
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)
|
function _activateStake(address owner, uint256 amount)
|
||||||
internal
|
private
|
||||||
view
|
|
||||||
returns (uint256)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
99
contracts/staking/contracts/src/core/MixinStakeBalances.sol
Normal file
99
contracts/staking/contracts/src/core/MixinStakeBalances.sol
Normal file
@@ -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];
|
||||||
|
}
|
||||||
|
}
|
@@ -20,31 +20,39 @@ pragma solidity ^0.5.5;
|
|||||||
|
|
||||||
import "../interfaces/IVault.sol";
|
import "../interfaces/IVault.sol";
|
||||||
import "./MixinConstants.sol";
|
import "./MixinConstants.sol";
|
||||||
|
import "../interfaces/IStructs.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinStorage is
|
contract MixinStorage is
|
||||||
|
IStructs,
|
||||||
MixinConstants
|
MixinConstants
|
||||||
{
|
{
|
||||||
|
|
||||||
// address of staking contract
|
// address of staking contract
|
||||||
address stakingContract;
|
address stakingContract;
|
||||||
|
|
||||||
// mapping from Staker to Maker Id to Amount Staked
|
// mapping from Owner to Amount Staked
|
||||||
mapping (address => mapping (bytes32 => uint256)) delegatedStake;
|
mapping (address => uint256) stakeByOwner;
|
||||||
|
|
||||||
// mapping from Staker to Maker Id to Amount Staked
|
// mapping from Owner to Amount of Instactive Stake
|
||||||
mapping (address => uint256) totalStake;
|
mapping (address => uint256) activeStakeByOwner;
|
||||||
|
|
||||||
// mapping from Maker Id to Amount of Delegated Staked
|
// mapping from Owner to Amount Timelocked
|
||||||
mapping (bytes32 => uint256) totalDelegatedStake;
|
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;
|
bytes32 nextPoolId = INITIAL_POOL_ID;
|
||||||
|
|
||||||
struct Pool {
|
// mapping from Pool Id to Pool
|
||||||
address operatorAddress;
|
|
||||||
uint8 operatorShare;
|
|
||||||
}
|
|
||||||
mapping (bytes32 => Pool) poolById;
|
mapping (bytes32 => Pool) poolById;
|
||||||
|
|
||||||
// mapping from Maker Address to Pool Id
|
// mapping from Maker Address to Pool Id
|
||||||
|
@@ -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()
|
||||||
|
}
|
@@ -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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -69,6 +69,7 @@ describe('Staking Core', () => {
|
|||||||
});
|
});
|
||||||
describe('end-to-end tests', () => {
|
describe('end-to-end tests', () => {
|
||||||
it('staking/unstaking', async () => {
|
it('staking/unstaking', async () => {
|
||||||
|
/*
|
||||||
///// 1/3 SETUP TEST PARAMETERS /////
|
///// 1/3 SETUP TEST PARAMETERS /////
|
||||||
const amountToStake = stakingWrapper.toBaseUnitAmount(10);
|
const amountToStake = stakingWrapper.toBaseUnitAmount(10);
|
||||||
const amountToUnstake = stakingWrapper.toBaseUnitAmount(5);
|
const amountToUnstake = stakingWrapper.toBaseUnitAmount(5);
|
||||||
@@ -111,6 +112,7 @@ describe('Staking Core', () => {
|
|||||||
const zrxTokenBalanceOfStakerAfterStaking = await stakingWrapper.getZrxTokenBalance(stakers[0]);
|
const zrxTokenBalanceOfStakerAfterStaking = await stakingWrapper.getZrxTokenBalance(stakers[0]);
|
||||||
expect(zrxTokenBalanceOfStakerAfterStaking).to.be.bignumber.equal(zrxTokenBalanceOfStakerBeforeStaking.minus(amountToStake).plus(amountToUnstake));
|
expect(zrxTokenBalanceOfStakerAfterStaking).to.be.bignumber.equal(zrxTokenBalanceOfStakerBeforeStaking.minus(amountToStake).plus(amountToUnstake));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nth root', async () => {
|
it('nth root', async () => {
|
||||||
|
@@ -115,6 +115,8 @@ export class StakingWrapper {
|
|||||||
const returnValue = await this._web3Wrapper.callAsync(txData);
|
const returnValue = await this._web3Wrapper.callAsync(txData);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public async stake(holder: string, amount: BigNumber): Promise<BigNumber> {
|
public async stake(holder: string, amount: BigNumber): Promise<BigNumber> {
|
||||||
const calldata = this.getStakingContract().stake.getABIEncodedTransactionData(amount);
|
const calldata = this.getStakingContract().stake.getABIEncodedTransactionData(amount);
|
||||||
const txReceipt = await this._executeTransactionAsync(calldata, holder);
|
const txReceipt = await this._executeTransactionAsync(calldata, holder);
|
||||||
@@ -129,11 +131,13 @@ export class StakingWrapper {
|
|||||||
const stakeBurned = (stakeBurnedLog as any).args.amount;
|
const stakeBurned = (stakeBurnedLog as any).args.amount;
|
||||||
return stakeBurned;
|
return stakeBurned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getStakeBalance(holder: string): Promise<BigNumber> {
|
public async getStakeBalance(holder: string): Promise<BigNumber> {
|
||||||
const calldata = this.getStakingContract().getStakeBalance.getABIEncodedTransactionData(holder);
|
const calldata = this.getStakingContract().getStakeBalance.getABIEncodedTransactionData(holder);
|
||||||
const balance = await this._callAsync(calldata, holder);
|
const balance = await this._callAsync(calldata, holder);
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
public async getNextPoolIdAsync(): Promise<string> {
|
public async getNextPoolIdAsync(): Promise<string> {
|
||||||
const calldata = this.getStakingContract().getNextPoolId.getABIEncodedTransactionData();
|
const calldata = this.getStakingContract().getNextPoolId.getABIEncodedTransactionData();
|
||||||
const nextPoolId = await this._callAsync(calldata);
|
const nextPoolId = await this._callAsync(calldata);
|
||||||
|
Reference in New Issue
Block a user