Documented MixinStake.sol
This commit is contained in:
@@ -44,33 +44,90 @@ contract MixinStake is
|
||||
MixinTimelockedStake
|
||||
{
|
||||
|
||||
/// @dev This mixin contains logic for managing ZRX tokens and Stake.
|
||||
/// Stake is minted when ZRX is deposited and burned when ZRX is withdrawn.
|
||||
/// Stake can exist in one of many states:
|
||||
/// 1. Activated
|
||||
/// 2. Activated & Delegated
|
||||
/// 3. Deactivated & Timelocked
|
||||
/// 4. Deactivated & Withdrawable
|
||||
///
|
||||
/// -- State Definitions --
|
||||
/// Activated Stake
|
||||
/// Stake in this state can be used as a utility within the 0x ecosystem.
|
||||
/// For example, it carries weight when computing fee-based rewards (see MixinExchangeFees).
|
||||
/// In the future, it may be used to participate in the 0x governance system.
|
||||
///
|
||||
/// Activated & Delegated Stake
|
||||
/// Stake in this state also serves as a utility that is shared between the delegator and delegate.
|
||||
/// For example, if delegated to a staking pool then it carries weight when computing fee-based rewards for
|
||||
/// the staking pool; however, in this case, delegated stake carries less weight that regular stake (see MixinStakingPool).
|
||||
///
|
||||
/// Deactivated & Timelocked Stake
|
||||
/// Stake in this state cannot be used as a utility within the 0x ecosystem.
|
||||
/// Stake is timelocked when it moves out of activated states (Activated / Activated & Delagated).
|
||||
/// By limiting the portability of stake, we mitigate undesirable behavior such as switching staking pools
|
||||
/// in the middle of an epoch.
|
||||
///
|
||||
/// Deactivated & Withdrawable
|
||||
/// Stake in this state cannot be used as a utility with in the 0x ecosystem.
|
||||
/// This stake can, however, be burned and withdrawn as Zrx tokens.
|
||||
/// ----------------------------
|
||||
///
|
||||
/// -- Valid State Transtions --
|
||||
/// Activated -> Deactivated & Timelocked
|
||||
///
|
||||
/// Activated & Delegated -> Deactivated & Timelocked
|
||||
///
|
||||
/// Deactivated & Timelocked -> Deactivated & Withdrawable
|
||||
///
|
||||
/// Deactivated & Withdrawable -> Activated
|
||||
/// Deactivated & Withdrawable -> Activated & Delegated
|
||||
/// Deactivated & Withdrawable -> Deactivated & Withdrawable
|
||||
/// ----------------------------
|
||||
///
|
||||
/// Freshly minted stake is in the "Deactvated & Withdrawable" State, so it can
|
||||
/// either be activated, delegated or withdrawn.
|
||||
/// See MixinDelegatedStake and MixinTimelockedStake for more on respective state transitions.
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
function deposit(uint256 amount)
|
||||
/// @dev Deposit Zrx. This mints stake for the sender that is in the "Deactivated & Withdrawable" state.
|
||||
/// @param amount of Zrx to deposit / Stake to mint.
|
||||
function depositZrxAndMintDeactivatedStake(uint256 amount)
|
||||
external
|
||||
{
|
||||
_mintStake(msg.sender, amount);
|
||||
}
|
||||
|
||||
function depositAndStake(uint256 amount)
|
||||
/// @dev Deposit Zrx and mint stake in the activated stake.
|
||||
/// This is a convenience function, and can be used in-place of
|
||||
/// calling `depositZrxAndMintDeactivatedStake` and `activateStake`.
|
||||
/// This mints stake for the sender that is in the "Activated" state.
|
||||
/// @param amount of Zrx to deposit / Stake to mint.
|
||||
function depositZrxAndMintActivatedStake(uint256 amount)
|
||||
external
|
||||
{
|
||||
_mintStake(msg.sender, amount);
|
||||
activateStake(amount);
|
||||
}
|
||||
|
||||
function withdraw(uint256 amount)
|
||||
/// @dev Burns deactivated stake and withdraws the corresponding amount of Zrx.
|
||||
/// @param amount of Stake to burn / Zrx to withdraw
|
||||
function burnDeactivatedStakeAndWithdrawZrx(uint256 amount)
|
||||
external
|
||||
{
|
||||
address owner = msg.sender;
|
||||
_syncTimelockedStake(owner);
|
||||
require(
|
||||
getDeactivatedStake(owner) >= amount,
|
||||
amount <= getDeactivatedStake(owner),
|
||||
"INSUFFICIENT_BALANCE"
|
||||
);
|
||||
_burnStake(owner, amount);
|
||||
}
|
||||
|
||||
/// @dev Activates stake that is presently in the Deactivated & Withdrawable state.
|
||||
/// @param amount of Stake to activate.
|
||||
function activateStake(uint256 amount)
|
||||
public
|
||||
{
|
||||
@@ -84,6 +141,8 @@ contract MixinStake is
|
||||
totalActivatedStake = totalActivatedStake._add(amount);
|
||||
}
|
||||
|
||||
/// @dev Deactivate & Timelock stake that is currently in the Activated state.
|
||||
/// @param amount of Stake to deactivate and timelock.
|
||||
function deactivateAndTimelockStake(uint256 amount)
|
||||
public
|
||||
{
|
||||
@@ -98,7 +157,9 @@ contract MixinStake is
|
||||
_timelockStake(owner, amount);
|
||||
}
|
||||
|
||||
|
||||
/// @dev Mints Stake in the Deactivated & Withdrawable state.
|
||||
/// @param owner to mint Stake for.
|
||||
/// @param amount of Stake to mint.
|
||||
function _mintStake(address owner, uint256 amount)
|
||||
internal
|
||||
{
|
||||
@@ -115,6 +176,9 @@ contract MixinStake is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Burns Stake in the Deactivated & Withdrawable state.
|
||||
/// @param owner to mint Stake for.
|
||||
/// @param amount of Stake to mint.
|
||||
function _burnStake(address owner, uint256 amount)
|
||||
internal
|
||||
{
|
||||
|
@@ -17,16 +17,16 @@ export class StakerActor extends BaseActor {
|
||||
constructor(owner: string, stakingWrapper: StakingWrapper) {
|
||||
super(owner, stakingWrapper);
|
||||
}
|
||||
public async depositAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
await this._stakingWrapper.depositAsync(this._owner, amount);
|
||||
public async depositZrxAndMintDeactivatedStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
await this._stakingWrapper.depositZrxAndMintDeactivatedStakeAsync(this._owner, amount);
|
||||
throw new Error('Checks Unimplemented');
|
||||
}
|
||||
public async depositAndStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
public async depositZrxAndMintActivatedStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
// query init balances
|
||||
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
|
||||
const initStakerBalances = await this.getBalancesAsync();
|
||||
// deposit stake
|
||||
const txReceiptPromise = this._stakingWrapper.depositAndStakeAsync(this._owner, amount);
|
||||
const txReceiptPromise = this._stakingWrapper.depositZrxAndMintActivatedStakeAsync(this._owner, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
return;
|
||||
@@ -81,12 +81,12 @@ export class StakerActor extends BaseActor {
|
||||
expectedStakerBalances.deactivatedStakeBalance = initStakerBalances.deactivatedStakeBalance.plus(amount);
|
||||
await this.assertBalancesAsync(expectedStakerBalances);
|
||||
}
|
||||
public async withdrawAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
public async burnDeactivatedStakeAndWithdrawZrxAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
// query init balances
|
||||
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
|
||||
const initStakerBalances = await this.getBalancesAsync();
|
||||
// withdraw stake
|
||||
const txReceiptPromise = this._stakingWrapper.withdrawAsync(this._owner, amount);
|
||||
const txReceiptPromise = this._stakingWrapper.burnDeactivatedStakeAndWithdrawZrxAsync(this._owner, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
return;
|
||||
|
@@ -66,7 +66,7 @@ describe('Staking & Delegating', () => {
|
||||
const amountToWithdraw = StakingWrapper.toBaseUnitAmount(1.5);
|
||||
// run test - this actor will validate its own state
|
||||
const staker = new StakerActor(stakers[0], stakingWrapper);
|
||||
await staker.depositAndStakeAsync(amountToStake);
|
||||
await staker.depositZrxAndMintActivatedStakeAsync(amountToStake);
|
||||
await staker.deactivateAndTimelockStakeAsync(amountToDeactivate);
|
||||
// note - we cannot re-activate this timelocked stake until at least one full timelock period has passed.
|
||||
// attempting to do so should revert.
|
||||
@@ -79,7 +79,7 @@ describe('Staking & Delegating', () => {
|
||||
await staker.forceTimelockSyncAsync();
|
||||
// now we can activate stake
|
||||
await staker.activateStakeAsync(amountToReactivate);
|
||||
await staker.withdrawAsync(amountToWithdraw);
|
||||
await staker.burnDeactivatedStakeAndWithdrawZrxAsync(amountToWithdraw);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('Staking & Delegating', () => {
|
||||
await delegator.forceTimelockSyncAsync();
|
||||
// now we can activate stake
|
||||
await delegator.activateAndDelegateStakeAsync(poolId, amountToReactivate);
|
||||
await delegator.withdrawAsync(amountToWithdraw);
|
||||
await delegator.burnDeactivatedStakeAndWithdrawZrxAsync(amountToWithdraw);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -131,7 +131,7 @@ export class Simulation {
|
||||
this._poolOperatorsAsDelegators.push(poolOperatorAsDelegator);
|
||||
// add stake to the operator's pool
|
||||
const amountOfStake = p.stakeByPoolOperator[i];
|
||||
await poolOperatorAsDelegator.depositAndStakeAsync(amountOfStake);
|
||||
await poolOperatorAsDelegator.depositZrxAndMintActivatedStakeAsync(amountOfStake);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -180,13 +180,13 @@ export class StakingWrapper {
|
||||
return balance;
|
||||
}
|
||||
///// STAKE /////
|
||||
public async depositAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().deposit.getABIEncodedTransactionData(amount);
|
||||
public async depositZrxAndMintDeactivatedStakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().depositZrxAndMintDeactivatedStake.getABIEncodedTransactionData(amount);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner);
|
||||
return txReceipt;
|
||||
}
|
||||
public async depositAndStakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().depositAndStake.getABIEncodedTransactionData(amount);
|
||||
public async depositZrxAndMintActivatedStakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().depositZrxAndMintActivatedStake.getABIEncodedTransactionData(amount);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner);
|
||||
return txReceipt;
|
||||
}
|
||||
@@ -236,8 +236,8 @@ export class StakingWrapper {
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner, new BigNumber(0), true);
|
||||
return txReceipt;
|
||||
}
|
||||
public async withdrawAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().withdraw.getABIEncodedTransactionData(amount);
|
||||
public async burnDeactivatedStakeAndWithdrawZrxAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().burnDeactivatedStakeAndWithdrawZrx.getABIEncodedTransactionData(amount);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner);
|
||||
return txReceipt;
|
||||
}
|
||||
|
Reference in New Issue
Block a user