@0x:contracts-staking
Added tests for protocol fees
This commit is contained in:
@@ -99,37 +99,42 @@ contract MixinExchangeFees is
|
||||
payable
|
||||
onlyExchange
|
||||
{
|
||||
// Get the pool id of the maker address, and use this pool id to get the amount
|
||||
// of fees collected during this epoch.
|
||||
bytes32 poolId = getStakingPoolIdOfMaker(makerAddress);
|
||||
uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId];
|
||||
|
||||
if (msg.value == 0) {
|
||||
// Transfer the protocol fee to this address.
|
||||
erc20Proxy.transferFrom(
|
||||
wethAssetData,
|
||||
payerAddress,
|
||||
address(this),
|
||||
protocolFeePaid
|
||||
);
|
||||
|
||||
// Update the amount of protocol fees paid to this pool this epoch.
|
||||
protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch.safeAdd(protocolFeePaid);
|
||||
|
||||
} else if (msg.value == protocolFeePaid) {
|
||||
// Update the amount of protocol fees paid to this pool this epoch.
|
||||
protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch.safeAdd(protocolFeePaid);
|
||||
} else {
|
||||
// If the wrong message value was sent, revert with a rich error.
|
||||
// If the protocol fee payment is invalid, revert with a rich error.
|
||||
if (
|
||||
protocolFeePaid == 0 ||
|
||||
(msg.value != protocolFeePaid && msg.value != 0)
|
||||
) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.InvalidProtocolFeePaymentError(
|
||||
protocolFeePaid,
|
||||
msg.value
|
||||
));
|
||||
}
|
||||
|
||||
// If there were no fees collected prior to this payment, activate the pool that is being paid.
|
||||
if (_feesCollectedThisEpoch == 0) {
|
||||
activePoolsThisEpoch.push(poolId);
|
||||
// Transfer the protocol fee to this address if it should be paid in WETH.
|
||||
if (msg.value == 0) {
|
||||
erc20Proxy.transferFrom(
|
||||
WETH_ASSET_DATA,
|
||||
payerAddress,
|
||||
address(this),
|
||||
protocolFeePaid
|
||||
);
|
||||
}
|
||||
|
||||
// Get the pool id of the maker address.
|
||||
bytes32 poolId = getStakingPoolIdOfMaker(makerAddress);
|
||||
|
||||
// Only attribute the protocol fee payment to a pool if the maker is registered to a pool.
|
||||
if (poolId != NIL_POOL_ID) {
|
||||
// Use the maker pool id to get the amount of fees collected during this epoch in the pool.
|
||||
uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId];
|
||||
|
||||
// Update the amount of protocol fees paid to this pool this epoch.
|
||||
protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch.safeAdd(protocolFeePaid);
|
||||
|
||||
// If there were no fees collected prior to this payment, activate the pool that is being paid.
|
||||
if (_feesCollectedThisEpoch == 0) {
|
||||
activePoolsThisEpoch.push(poolId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +184,18 @@ contract MixinExchangeFees is
|
||||
return protocolFeesThisEpochByPool[poolId];
|
||||
}
|
||||
|
||||
/// @dev Withdraws the entire WETH balance of the contract.
|
||||
function _unwrapWETH()
|
||||
internal
|
||||
{
|
||||
uint256 wethBalance = IEtherToken(WETH_ADDRESS).balanceOf(address(this));
|
||||
|
||||
// Don't withdraw WETH if the WETH balance is zero as a gas optimization.
|
||||
if (wethBalance != 0) {
|
||||
IEtherToken(WETH_ADDRESS).withdraw(wethBalance);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Pays rewards to market making pools that were active this epoch.
|
||||
/// Each pool receives a portion of the fees generated this epoch (see _cobbDouglas) that is
|
||||
/// proportional to (i) the fee volume attributed to their pool over the epoch, and
|
||||
@@ -204,11 +221,12 @@ contract MixinExchangeFees is
|
||||
uint256 finalContractBalance
|
||||
)
|
||||
{
|
||||
// step 1/4 - withdraw the entire wrapper ether balance into this contract.
|
||||
// WETH is unwrapped here to keep `payProtocolFee()` calls relatively cheap.
|
||||
uint256 wethBalance = IEtherToken(WETH_ADDRESS).balanceOf(address(this));
|
||||
IEtherToken(WETH_ADDRESS).withdraw(wethBalance);
|
||||
// step 1/4 - withdraw the entire wrapped ether balance into this contract. WETH
|
||||
// is unwrapped here to keep `payProtocolFee()` calls relatively cheap,
|
||||
// and WETH is only withdrawn if this contract's WETH balance is nonzero.
|
||||
_unwrapWETH();
|
||||
|
||||
// Initialize initial values
|
||||
totalActivePools = activePoolsThisEpoch.length;
|
||||
totalFeesCollected = 0;
|
||||
totalWeightedStake = 0;
|
||||
|
@@ -34,6 +34,8 @@ contract MixinConstants is
|
||||
|
||||
bytes32 constant internal NIL_POOL_ID = 0x0000000000000000000000000000000000000000000000000000000000000000;
|
||||
|
||||
bytes32 constant internal NIL_POOL_ID = 0x0000000000000000000000000000000000000000000000000000000000000000;
|
||||
|
||||
address constant internal NIL_ADDRESS = 0x0000000000000000000000000000000000000000;
|
||||
|
||||
bytes32 constant internal UNKNOWN_STAKING_POOL_ID = 0x0000000000000000000000000000000000000000000000000000000000000000;
|
||||
@@ -46,4 +48,7 @@ contract MixinConstants is
|
||||
|
||||
// The address of the canonical WETH contract -- this will be used as an alternative to ether for paying protocol fees.
|
||||
address constant internal WETH_ADDRESS = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
|
||||
|
||||
// abi.encodeWithSelector(IAssetData(address(0)).ERC20Token.selector, WETH_ADDRESS)
|
||||
bytes constant internal WETH_ASSET_DATA = hex"f47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
|
||||
}
|
||||
|
@@ -37,20 +37,11 @@ contract MixinStorage is
|
||||
constructor()
|
||||
public
|
||||
Ownable()
|
||||
{
|
||||
// Set the erc20 asset proxy data.
|
||||
wethAssetData = abi.encodeWithSelector(
|
||||
IAssetData(address(0)).ERC20Token.selector,
|
||||
WETH_ADDRESS
|
||||
);
|
||||
}
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
|
||||
// 0x ERC20 Proxy
|
||||
IAssetProxy internal erc20Proxy;
|
||||
|
||||
// The asset data that should be sent to transfer weth
|
||||
bytes internal wethAssetData;
|
||||
|
||||
// address of staking contract
|
||||
address internal stakingContract;
|
||||
|
||||
|
41
contracts/staking/contracts/test/TestProtocolFees.sol
Normal file
41
contracts/staking/contracts/test/TestProtocolFees.sol
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/Staking.sol";
|
||||
|
||||
|
||||
contract TestProtocolFees is
|
||||
Staking
|
||||
{
|
||||
function setPoolIdOfMaker(bytes32 poolId, address makerAddress)
|
||||
external
|
||||
{
|
||||
poolIdByMakerAddress[makerAddress] = poolId;
|
||||
}
|
||||
|
||||
function getActivePoolsByEpoch()
|
||||
external
|
||||
view
|
||||
returns (bytes32[] memory)
|
||||
{
|
||||
return activePoolsThisEpoch;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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.9;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/ERC20Proxy.sol";
|
||||
|
||||
|
||||
contract TestProtocolFeesERC20Proxy is
|
||||
ERC20Proxy
|
||||
{
|
||||
event TransferFromCalled(
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
function transferFrom(
|
||||
bytes calldata assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
emit TransferFromCalled(assetData, from, to, amount);
|
||||
}
|
||||
}
|
53
contracts/staking/contracts/test/TestStaking.sol
Normal file
53
contracts/staking/contracts/test/TestStaking.sol
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/Staking.sol";
|
||||
|
||||
|
||||
contract TestStaking is
|
||||
Staking
|
||||
{
|
||||
// Stub out `payProtocolFee` to be the naive payProtocolFee function so that tests will
|
||||
// not fail for WETH protocol fees.
|
||||
function payProtocolFee(
|
||||
address makerAddress,
|
||||
address,
|
||||
uint256
|
||||
)
|
||||
external
|
||||
payable
|
||||
onlyExchange
|
||||
{
|
||||
uint256 amount = msg.value;
|
||||
bytes32 poolId = getStakingPoolIdOfMaker(makerAddress);
|
||||
uint256 _feesCollectedThisEpoch = protocolFeesThisEpochByPool[poolId];
|
||||
protocolFeesThisEpochByPool[poolId] = _feesCollectedThisEpoch.safeAdd(amount);
|
||||
if (_feesCollectedThisEpoch == 0) {
|
||||
activePoolsThisEpoch.push(poolId);
|
||||
}
|
||||
}
|
||||
|
||||
// Stub out `_unwrapWETH` to prevent the calls to `finalizeFees` from failing in tests
|
||||
// that do not relate to protocol fee payments in WETH.
|
||||
function _unwrapWETH()
|
||||
internal
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
}
|
Reference in New Issue
Block a user