Cleaned up staking pool mixin

This commit is contained in:
Greg Hysen 2019-06-27 15:49:10 -07:00
parent 829533d501
commit ab3246cc71
9 changed files with 355 additions and 264 deletions

View File

@ -25,7 +25,7 @@ import "./core/MixinRewardVault.sol";
import "./core/MixinScheduler.sol"; import "./core/MixinScheduler.sol";
import "./core/MixinStakeBalances.sol"; import "./core/MixinStakeBalances.sol";
import "./core/MixinStake.sol"; import "./core/MixinStake.sol";
import "./core/MixinPools.sol"; import "./core/MixinStakingPool.sol";
import "./core/MixinExchangeFees.sol"; import "./core/MixinExchangeFees.sol";
import "./core/MixinRewards.sol"; import "./core/MixinRewards.sol";
@ -40,7 +40,7 @@ contract Staking is
MixinZrxVault, MixinZrxVault,
MixinExchangeManager, MixinExchangeManager,
MixinStakeBalances, MixinStakeBalances,
MixinPools, MixinStakingPool,
MixinRewards, MixinRewards,
MixinStake, MixinStake,
MixinExchangeFees MixinExchangeFees

View File

@ -25,7 +25,7 @@ import "../immutable/MixinConstants.sol";
import "../interfaces/IStakingEvents.sol"; import "../interfaces/IStakingEvents.sol";
import "./MixinStakeBalances.sol"; import "./MixinStakeBalances.sol";
import "./MixinScheduler.sol"; import "./MixinScheduler.sol";
import "./MixinPools.sol"; import "./MixinStakingPool.sol";
import "./MixinExchangeManager.sol"; import "./MixinExchangeManager.sol";
import "./MixinRewardVault.sol"; import "./MixinRewardVault.sol";
import "../interfaces/IStructs.sol"; import "../interfaces/IStructs.sol";
@ -39,14 +39,14 @@ contract MixinExchangeFees is
MixinRewardVault, MixinRewardVault,
MixinExchangeManager, MixinExchangeManager,
MixinStakeBalances, MixinStakeBalances,
MixinPools MixinStakingPool
{ {
using LibSafeMath for uint256; using LibSafeMath for uint256;
/// @dev This mixin contains the logic for 0x protocol fees. /// @dev This mixin contains the logic for 0x protocol fees.
/// Protocol fees are sent by 0x exchanges every time there is a trade. /// Protocol fees are sent by 0x exchanges every time there is a trade.
/// If the maker has associated their address with a pool (see MixinPools.sol), then /// If the maker has associated their address with a pool (see MixinStakingPool.sol), then
/// the fee will be attributed to their pool. At the end of an epoch the maker and /// the fee will be attributed to their pool. At the end of an epoch the maker and
/// their pool will receive a rebate that is proportional to (i) the fee volume attributed /// their pool will receive a rebate that is proportional to (i) the fee volume attributed
/// to their pool over the epoch, and (ii) the amount of stake provided by the maker and /// to their pool over the epoch, and (ii) the amount of stake provided by the maker and
@ -63,7 +63,7 @@ contract MixinExchangeFees is
onlyExchange onlyExchange
{ {
uint256 amount = msg.value; uint256 amount = msg.value;
bytes32 poolId = getMakerPoolId(makerAddress); bytes32 poolId = getPoolIdOfMaker(makerAddress);
uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId]; uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId];
protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch._add(amount); protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch._add(amount);
if (_feesCollectedThisEpoch == 0) { if (_feesCollectedThisEpoch == 0) {

View File

@ -1,243 +0,0 @@
/*
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;
pragma experimental ABIEncoderV2;
import "../libs/LibSafeMath.sol";
import "../libs/LibSignatureValidator.sol";
import "../libs/LibEIP712Hash.sol";
import "../interfaces/IStructs.sol";
import "../interfaces/IStakingEvents.sol";
import "../immutable/MixinConstants.sol";
import "../immutable/MixinStorage.sol";
import "./MixinRewardVault.sol";
contract MixinPools is
IStakingEvents,
MixinConstants,
MixinStorage,
MixinRewardVault
{
using LibSafeMath for uint256;
/// @dev This mixin contains logic for pools.
/// A "pool" can be delegated to by any number of stakers.
/// A market maker can create a pool
modifier onlyPoolOperator(bytes32 poolId) {
require(
msg.sender == getPoolOperator(poolId),
"ONLY_CALLABLE_BY_POOL_OPERATOR"
);
_;
}
function createPool(uint8 operatorShare)
external
returns (bytes32 poolId)
{
address payable operatorAddress = msg.sender;
poolId = nextPoolId;
nextPoolId = _computeNextPoolId(poolId);
//
IStructs.Pool memory pool = IStructs.Pool({
operatorAddress: operatorAddress,
operatorShare: operatorShare
});
poolById[poolId] = pool;
// create pool in reward vault
_createPoolInRewardVault(poolId, operatorShare);
//
emit PoolCreated(poolId, operatorAddress, operatorShare);
return poolId;
}
function addMakerToPool(
bytes32 poolId,
address makerAddress,
bytes calldata makerSignature
)
external
onlyPoolOperator(poolId)
{
require(
isValidMakerSignature(poolId, makerAddress, makerSignature),
"INVALID_MAKER_SIGNATURE"
);
_recordMaker(poolId, makerAddress);
}
function removeMakerFromPool(
bytes32 poolId,
address makerAddress
)
external
onlyPoolOperator(poolId)
{
_unrecordMaker(poolId, makerAddress);
}
function getNextPoolId()
public
returns (bytes32)
{
return nextPoolId;
}
function isValidMakerSignature(bytes32 poolId, address makerAddress, bytes memory makerSignature)
public
view
returns (bool isValid)
{
bytes32 approvalHash = getStakingPoolApprovalMessageHash(poolId, makerAddress);
isValid = LibSignatureValidator._isValidSignature(approvalHash, makerAddress, makerSignature);
return isValid;
}
function getStakingPoolApprovalMessageHash(bytes32 poolId, address makerAddress)
public
view
returns (bytes32 approvalHash)
{
IStructs.StakingPoolApproval memory approval = IStructs.StakingPoolApproval({
poolId: poolId,
makerAddress: makerAddress
});
// Hash approval message and check signer address
address verifierAddress = address(this);
approvalHash = LibEIP712Hash._hashStakingPoolApprovalMessage(approval, CHAIN_ID, verifierAddress);
return approvalHash;
}
function getMakerPoolId(address makerAddress)
public
view
returns (bytes32)
{
return poolIdByMakerAddress[makerAddress];
}
function getPoolOperator(bytes32 poolId)
public
view
returns (address operatorAddress)
{
operatorAddress = poolById[poolId].operatorAddress;
}
function isMakerRegistered(address makerAddress)
public
view
returns (bool)
{
return getMakerPoolId(makerAddress) != NIL_MAKER_ID;
}
function getMakerAddressesForPool(bytes32 poolId)
public
view
returns (address[] memory _makerAddressesByPoolId)
{
//
address[] storage makerAddressesByPoolIdPtr = makerAddressesByPoolId[poolId];
uint256 makerAddressesByPoolIdLength = makerAddressesByPoolIdPtr.length;
//
_makerAddressesByPoolId = new address[](makerAddressesByPoolIdLength);
for (uint i = 0; i < makerAddressesByPoolIdLength; ++i) {
_makerAddressesByPoolId[i] = makerAddressesByPoolIdPtr[i];
}
return _makerAddressesByPoolId;
}
function _getPool(bytes32 poolId)
internal
view
returns (IStructs.Pool memory pool)
{
pool = poolById[poolId];
return pool;
}
function _computeNextPoolId(bytes32 poolId)
internal
pure
returns (bytes32)
{
return bytes32(uint256(poolId)._add(POOL_ID_INCREMENT_AMOUNT));
}
function _recordMaker(
bytes32 poolId,
address makerAddress
)
private
{
require(
!isMakerRegistered(makerAddress),
"MAKER_ADDRESS_ALREADY_REGISTERED"
);
poolIdByMakerAddress[makerAddress] = poolId;
makerAddressesByPoolId[poolId].push(makerAddress);
}
function _unrecordMaker(
bytes32 poolId,
address makerAddress
)
private
{
require(
getMakerPoolId(makerAddress) == poolId,
"MAKER_ADDRESS_NOT_REGISTERED"
);
//
address[] storage makerAddressesByPoolIdPtr = makerAddressesByPoolId[poolId];
uint256 makerAddressesByPoolIdLength = makerAddressesByPoolIdPtr.length;
//
uint indexOfMakerAddress = 0;
for (; indexOfMakerAddress < makerAddressesByPoolIdLength; ++indexOfMakerAddress) {
if (makerAddressesByPoolIdPtr[indexOfMakerAddress] == makerAddress) {
break;
}
}
//
makerAddressesByPoolIdPtr[indexOfMakerAddress] = makerAddressesByPoolIdPtr[makerAddressesByPoolIdLength - 1];
makerAddressesByPoolIdPtr[indexOfMakerAddress] = NIL_ADDRESS;
makerAddressesByPoolIdPtr.length -= 1;
//
poolIdByMakerAddress[makerAddress] = NIL_MAKER_ID;
}
}

View File

@ -24,7 +24,7 @@ import "../immutable/MixinStorage.sol";
import "../immutable/MixinConstants.sol"; import "../immutable/MixinConstants.sol";
import "./MixinStakeBalances.sol"; import "./MixinStakeBalances.sol";
import "./MixinRewardVault.sol"; import "./MixinRewardVault.sol";
import "./MixinPools.sol"; import "./MixinStakingPool.sol";
contract MixinRewards is contract MixinRewards is
@ -32,12 +32,12 @@ contract MixinRewards is
MixinStorage, MixinStorage,
MixinRewardVault, MixinRewardVault,
MixinStakeBalances, MixinStakeBalances,
MixinPools MixinStakingPool
{ {
using LibSafeMath for uint256; using LibSafeMath for uint256;
/// @dev This mixin contains logic for rewards /// @dev This mixin contains logic for managing the reward pool
function withdrawOperatorReward(bytes32 poolId, uint256 amount) function withdrawOperatorReward(bytes32 poolId, uint256 amount)
external external

View File

@ -0,0 +1,334 @@
/*
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;
pragma experimental ABIEncoderV2;
import "../libs/LibSafeMath.sol";
import "../libs/LibSignatureValidator.sol";
import "../libs/LibEIP712Hash.sol";
import "../interfaces/IStructs.sol";
import "../interfaces/IStakingEvents.sol";
import "../immutable/MixinConstants.sol";
import "../immutable/MixinStorage.sol";
import "./MixinRewardVault.sol";
contract MixinStakingPool is
IStakingEvents,
MixinConstants,
MixinStorage,
MixinRewardVault
{
using LibSafeMath for uint256;
/// @dev This mixin contains logic for staking pools.
/// A pool has a single operator and any number of delegators (members).
/// Any staker can create a pool, although at present it is only beneficial
/// for market makers to create staking pools. A market maker *must* create a
/// pool in order to receive fee-based rewards at the end of each epoch (see MixinExchangeFees).
/// Moreover, creating a staking pool leverages the delegated stake within the pool,
/// which is counted towards a maker's total stake when computing rewards. A market maker
/// can register any number of makerAddresses with their pool, and can incentivize delegators
/// to join their pool by specifying a fixed percentage of their fee-based rewards to be split amonst
/// the members of their pool. Any rewards set aside for members of the pool is divided based on
/// how much stake each member delegated.
///
/// Terminology:
/// "Pool Id" - A unique id generated by this contract and assigned to each pool when it is created.
/// "Pool Operator" - The creator and operator of the pool.
/// "Pool Members" - Members of the pool who opted-in by delegating to the pool.
/// "Market Makers" - Market makers on the 0x protocol.
///
/// How-To for Market Makers:
/// 1. Create a pool, specifying what percentage of rewards kept for yourself.
/// The remaining is divided among members of your pool.
/// 2. Add the addresses that you use to market make on 0x.
/// 3. Leverage the staking power of others by convincing them to delegate to your pool.
/// @dev Asserts that the sender is the operator of the input pool.
/// @param poolId Pool sender must be operator of.
modifier onlyPoolOperator(bytes32 poolId) {
require(
msg.sender == getPoolOperator(poolId),
"ONLY_CALLABLE_BY_POOL_OPERATOR"
);
_;
}
/// @dev Asserts that the sender is the operator of the input pool or the input maker.
/// @param poolId Pool sender must be operator of.
/// @param makerAddress Address of a maker in the pool.
modifier onlyPoolOperatorOrMaker(bytes32 poolId, address makerAddress) {
require(
msg.sender == getPoolOperator(poolId) || msg.sender == makerAddress,
"ONLY_CALLABLE_BY_POOL_OPERATOR_OR_MAKER"
);
_;
}
/// @dev Create a new staking pool. The sender will be the operator of this pool.
/// Note that an operator must be payable.
/// @param operatorShare The percentage of any rewards owned by the operator.
/// @return poolId The unique pool id generated for this pool.
function createPool(uint8 operatorShare)
external
returns (bytes32 poolId)
{
// note that an operator must be payable
address payable operatorAddress = msg.sender;
// assign pool id and generate next id
poolId = nextPoolId;
nextPoolId = _computeNextPoolId(poolId);
// store metadata about this pool
IStructs.Pool memory pool = IStructs.Pool({
operatorAddress: operatorAddress,
operatorShare: operatorShare
});
poolById[poolId] = pool;
// register pool in reward vault
_createPoolInRewardVault(poolId, operatorShare);
// notify
emit PoolCreated(poolId, operatorAddress, operatorShare);
return poolId;
}
/// @dev Adds a maker to a staking pool. Note that this is only callable by the pool operator.
/// @param poolId Unique id of pool.
/// @param makerAddress Address of maker.
/// @param makerSignature Signature proving that maker has agreed to join the pool.
function addMakerToPool(
bytes32 poolId,
address makerAddress,
bytes calldata makerSignature
)
external
onlyPoolOperator(poolId)
{
// sanity check - did maker agree to join this pool?
require(
isValidMakerSignature(poolId, makerAddress, makerSignature),
"INVALID_MAKER_SIGNATURE"
);
// maker has agreed, record their address
_recordMaker(poolId, makerAddress);
}
/// @dev Adds a maker to a staking pool. Note that this is only callable by the pool operator or maker.
/// Note also that the maker does not have to *agree* to leave the pool; this action is
/// at the sole discretion of the pool operator.
/// @param poolId Unique id of pool.
/// @param makerAddress Address of maker.
function removeMakerFromPool(
bytes32 poolId,
address makerAddress
)
onlyPoolOperatorOrMaker(poolId, makerAddress)
external
{
_unrecordMaker(poolId, makerAddress);
}
/// @dev Returns true iff the input signature is valid; meaning that the maker agrees to
/// be added to the pool.
/// @param poolId Unique id of pool the maker wishes to join.
/// @param makerAddress Address of maker.
/// @param makerSignature Signature of the maker.
/// @return isValid True iff the maker agrees to be added to the pool.
function isValidMakerSignature(bytes32 poolId, address makerAddress, bytes memory makerSignature)
public
view
returns (bool isValid)
{
bytes32 approvalHash = getStakingPoolApprovalMessageHash(poolId, makerAddress);
isValid = LibSignatureValidator._isValidSignature(approvalHash, makerAddress, makerSignature);
return isValid;
}
/// @dev Returns the approval message hash - this is what a maker must sign in order to
/// be added to a pool.
/// @param poolId Unique id of pool the maker wishes to join.
/// @param makerAddress Address of maker.
/// @return approvalHash Hash of message the maker must sign.
function getStakingPoolApprovalMessageHash(bytes32 poolId, address makerAddress)
public
view
returns (bytes32 approvalHash)
{
IStructs.StakingPoolApproval memory approval = IStructs.StakingPoolApproval({
poolId: poolId,
makerAddress: makerAddress
});
// hash approval message and check signer address
address verifierAddress = address(this);
approvalHash = LibEIP712Hash._hashStakingPoolApprovalMessage(approval, CHAIN_ID, verifierAddress);
return approvalHash;
}
/// @dev Returns the pool id of an input maker.
function getPoolIdOfMaker(address makerAddress)
public
view
returns (bytes32)
{
return poolIdByMakerAddress[makerAddress];
}
/// @dev Returns true iff the maker is assigned to a staking pool.
/// @param makerAddress Address of maker
/// @return True iff assigned.
function isMakerAssignedToPool(address makerAddress)
public
view
returns (bool)
{
return getPoolIdOfMaker(makerAddress) != NIL_MAKER_ID;
}
/// @dev Returns the makers for a given pool.
/// @param poolId Unique id of pool.
/// @return _makerAddressesByPoolId Makers for pool.
function getMakersForPool(bytes32 poolId)
public
view
returns (address[] memory _makerAddressesByPoolId)
{
// Load pointer to addresses of makers
address[] storage makerAddressesByPoolIdPtr = makerAddressesByPoolId[poolId];
uint256 makerAddressesByPoolIdLength = makerAddressesByPoolIdPtr.length;
// Construct list of makers
_makerAddressesByPoolId = new address[](makerAddressesByPoolIdLength);
for (uint i = 0; i < makerAddressesByPoolIdLength; ++i) {
_makerAddressesByPoolId[i] = makerAddressesByPoolIdPtr[i];
}
return _makerAddressesByPoolId;
}
/// @dev Returns the unique id that will be assigned to the next pool that is created.
/// @return Pool id.
function getNextPoolId()
public
view
returns (bytes32)
{
return nextPoolId;
}
/// @dev Returns the pool operator
/// @param poolId Unique id of pool
/// @return operatorAddress Operator of the pool
function getPoolOperator(bytes32 poolId)
public
view
returns (address operatorAddress)
{
operatorAddress = poolById[poolId].operatorAddress;
}
/// @dev Convenience function for loading information on a pool.
/// @param poolId Unique id of pool.
/// @return pool Pool info.
function _getPool(bytes32 poolId)
internal
view
returns (IStructs.Pool memory pool)
{
pool = poolById[poolId];
return pool;
}
/// @dev Computes the unique id that comes after the input pool id.
/// @param poolId Unique id of pool.
/// @return Next pool id after input pool.
function _computeNextPoolId(bytes32 poolId)
internal
pure
returns (bytes32)
{
return bytes32(uint256(poolId)._add(POOL_ID_INCREMENT_AMOUNT));
}
/// @dev Records a maker for a pool.
/// @param poolId Unique id of pool.
/// @param makerAddress Address of maker.
function _recordMaker(
bytes32 poolId,
address makerAddress
)
private
{
require(
!isMakerAssignedToPool(makerAddress),
"MAKER_ADDRESS_ALREADY_REGISTERED"
);
poolIdByMakerAddress[makerAddress] = poolId;
makerAddressesByPoolId[poolId].push(makerAddress);
}
/// @dev Unrecords a maker for a pool.
/// @param poolId Unique id of pool.
/// @param makerAddress Address of maker.
function _unrecordMaker(
bytes32 poolId,
address makerAddress
)
private
{
require(
getPoolIdOfMaker(makerAddress) == poolId,
"MAKER_ADDRESS_NOT_REGISTERED"
);
// load list of makers for the input pool.
address[] storage makerAddressesByPoolIdPtr = makerAddressesByPoolId[poolId];
uint256 makerAddressesByPoolIdLength = makerAddressesByPoolIdPtr.length;
// find index of maker to remove.
uint indexOfMakerAddress = 0;
for (; indexOfMakerAddress < makerAddressesByPoolIdLength; ++indexOfMakerAddress) {
if (makerAddressesByPoolIdPtr[indexOfMakerAddress] == makerAddress) {
break;
}
}
// remove the maker from the list of makers for this pool.
// (i) move maker at end of list to the slot occupied by the maker to remove, then
// (ii) zero out the slot at the end of the list and decrement the length.
uint256 indexOfLastMakerAddress = makerAddressesByPoolIdLength - 1;
if (indexOfMakerAddress != indexOfLastMakerAddress) {
makerAddressesByPoolIdPtr[indexOfMakerAddress] = makerAddressesByPoolIdPtr[indexOfLastMakerAddress];
}
makerAddressesByPoolIdPtr[indexOfLastMakerAddress] = NIL_ADDRESS;
makerAddressesByPoolIdPtr.length -= 1;
// reset the pool id assigned to the maker.
poolIdByMakerAddress[makerAddress] = NIL_MAKER_ID;
}
}

View File

@ -50,10 +50,10 @@ export class PoolOperatorActor extends BaseActor {
} }
await txReceiptPromise; await txReceiptPromise;
// check the pool id of the maker // check the pool id of the maker
const poolIdOfMaker = await this._stakingWrapper.getMakerPoolIdAsync(makerAddress); const poolIdOfMaker = await this._stakingWrapper.getPoolIdOfMakerAsync(makerAddress);
expect(poolIdOfMaker, 'pool id of maker').to.be.equal(poolId); expect(poolIdOfMaker, 'pool id of maker').to.be.equal(poolId);
// check the list of makers for the pool // check the list of makers for the pool
const makerAddressesForPool = await this._stakingWrapper.getMakerAddressesForPoolAsync(poolId); const makerAddressesForPool = await this._stakingWrapper.getMakersForPoolAsync(poolId);
expect(makerAddressesForPool, 'maker addresses for pool').to.include(makerAddress); expect(makerAddressesForPool, 'maker addresses for pool').to.include(makerAddress);
} }
public async removeMakerFromPoolAsync( public async removeMakerFromPoolAsync(
@ -69,10 +69,10 @@ export class PoolOperatorActor extends BaseActor {
} }
await txReceiptPromise; await txReceiptPromise;
// check the pool id of the maker // check the pool id of the maker
const poolIdOfMakerAfterRemoving = await this._stakingWrapper.getMakerPoolIdAsync(makerAddress); const poolIdOfMakerAfterRemoving = await this._stakingWrapper.getPoolIdOfMakerAsync(makerAddress);
expect(poolIdOfMakerAfterRemoving, 'pool id of maker').to.be.equal(stakingConstants.NIL_POOL_ID); expect(poolIdOfMakerAfterRemoving, 'pool id of maker').to.be.equal(stakingConstants.NIL_POOL_ID);
// check the list of makers for the pool // check the list of makers for the pool
const makerAddressesForPoolAfterRemoving = await this._stakingWrapper.getMakerAddressesForPoolAsync(poolId); const makerAddressesForPoolAfterRemoving = await this._stakingWrapper.getMakersForPoolAsync(poolId);
expect(makerAddressesForPoolAfterRemoving, 'maker addresses for pool').to.not.include(makerAddress); expect(makerAddressesForPoolAfterRemoving, 'maker addresses for pool').to.not.include(makerAddress);
} }
} }

View File

@ -118,8 +118,7 @@ describe('Staking Pool Management', () => {
// remove maker from pool // remove maker from pool
await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[0]); await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[0]);
await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[1]); await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[1]);
// @TODO - this fails with `RuntimeError: VM Exception while processing transaction: revert` on Ganache await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[2]);
// await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[2]);
}); });
it('Should fail to add the same maker twice', async () => { it('Should fail to add the same maker twice', async () => {
// test parameters // test parameters
@ -260,7 +259,7 @@ describe('Staking Pool Management', () => {
// try to remove the maker address from an address other than the operator // try to remove the maker address from an address other than the operator
await expectTransactionFailedAsync( await expectTransactionFailedAsync(
stakingWrapper.removeMakerFromPoolAsync(poolId, makerAddress, notOperatorAddress), stakingWrapper.removeMakerFromPoolAsync(poolId, makerAddress, notOperatorAddress),
RevertReason.OnlyCallableByPoolOperator, RevertReason.OnlyCallableByPoolOperatorOrMaker,
); );
}); });
}); });

View File

@ -349,15 +349,15 @@ export class StakingWrapper {
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress); const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
return txReceipt; return txReceipt;
} }
public async getMakerPoolIdAsync(makerAddress: string): Promise<string> { public async getPoolIdOfMakerAsync(makerAddress: string): Promise<string> {
const calldata = this.getStakingContract().getMakerPoolId.getABIEncodedTransactionData(makerAddress); const calldata = this.getStakingContract().getPoolIdOfMaker.getABIEncodedTransactionData(makerAddress);
const poolId = await this._callAsync(calldata); const poolId = await this._callAsync(calldata);
return poolId; return poolId;
} }
public async getMakerAddressesForPoolAsync(poolId: string): Promise<string[]> { public async getMakersForPoolAsync(poolId: string): Promise<string[]> {
const calldata = this.getStakingContract().getMakerAddressesForPool.getABIEncodedTransactionData(poolId); const calldata = this.getStakingContract().getMakersForPool.getABIEncodedTransactionData(poolId);
const returndata = await this._callAsync(calldata); const returndata = await this._callAsync(calldata);
const makerAddresses = this.getStakingContract().getMakerAddressesForPool.getABIDecodedReturnData(returndata); const makerAddresses = this.getStakingContract().getMakersForPool.getABIDecodedReturnData(returndata);
return makerAddresses; return makerAddresses;
} }
public async isValidMakerSignatureAsync( public async isValidMakerSignatureAsync(

View File

@ -342,6 +342,7 @@ export enum RevertReason {
TransfersSuccessful = 'TRANSFERS_SUCCESSFUL', TransfersSuccessful = 'TRANSFERS_SUCCESSFUL',
// Staking // Staking
OnlyCallableByPoolOperator = 'ONLY_CALLABLE_BY_POOL_OPERATOR', OnlyCallableByPoolOperator = 'ONLY_CALLABLE_BY_POOL_OPERATOR',
OnlyCallableByPoolOperatorOrMaker = 'ONLY_CALLABLE_BY_POOL_OPERATOR_OR_MAKER',
MakerAddressAlreadyRegistered = 'MAKER_ADDRESS_ALREADY_REGISTERED', MakerAddressAlreadyRegistered = 'MAKER_ADDRESS_ALREADY_REGISTERED',
MakerAddressNotRegistered = 'MAKER_ADDRESS_NOT_REGISTERED', MakerAddressNotRegistered = 'MAKER_ADDRESS_NOT_REGISTERED',
OnlyCallableByExchange = 'ONLY_CALLABLE_BY_EXCHANGE', OnlyCallableByExchange = 'ONLY_CALLABLE_BY_EXCHANGE',