@0x:contracts-exchange Added the MixinStakingManager contract

This commit is contained in:
Alex Towle 2019-08-21 14:46:35 -07:00
parent 365cb161cf
commit 415af90ae7
10 changed files with 276 additions and 3 deletions

View File

@ -28,13 +28,15 @@ import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol";
import "./interfaces/IExchangeCore.sol";
import "./MixinAssetProxyDispatcher.sol";
import "./MixinSignatureValidator.sol";
import "./MixinStakingManager.sol";
contract MixinExchangeCore is
LibEIP712ExchangeDomain,
IExchangeCore,
MixinAssetProxyDispatcher,
MixinSignatureValidator
MixinSignatureValidator,
MixinStakingManager
{
using LibOrder for LibOrder.Order;
using LibSafeMath for uint256;

View File

@ -0,0 +1,67 @@
/*
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-utils/contracts/src/Ownable.sol";
import "./interfaces/IStakingManager.sol";
contract MixinStakingManager is
IStakingManager,
Ownable
{
// The protocol fee multiplier -- the owner can update this field.
uint256 public protocolFeeMultiplier;
// The address of the registered staking contract -- the owner can update this field.
address public staking;
// The address of the wrapped ether contract -- the owner can update this field.
address public weth;
/// @dev Allows the owner to update the protocol fee multiplier.
/// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier.
function updateProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier)
external
onlyOwner()
{
emit UpdatedProtocolFeeMultiplier(protocolFeeMultiplier, updatedProtocolFeeMultiplier);
protocolFeeMultiplier = updatedProtocolFeeMultiplier;
}
/// @dev Allows the owner to update the staking address.
/// @param updatedStaking The updated staking contract address.
function updateStakingAddress(address updatedStaking)
external
onlyOwner()
{
emit UpdatedStakingAddress(staking, updatedStaking);
staking = updatedStaking;
}
/// @dev Allows the owner to update the WETH address.
/// @param updatedWeth The updated WETH contract address.
function updateWethAddress(address updatedWeth)
external
onlyOwner()
{
emit UpdatedWethAddress(weth, updatedWeth);
weth = updatedWeth;
}
}

View File

@ -0,0 +1,47 @@
/*
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;
contract IStakingManager {
// Logs updates to the protocol fee multiplier.
event UpdatedProtocolFeeMultiplier(uint256 oldProtocolFeeMultiplier, uint256 updatedProtocolFeeMultiplier);
// Logs updates to the staking address.
event UpdatedStakingAddress(address oldStaking, address updatedStaking);
// Logs updates to the weth address.
event UpdatedWethAddress(address oldWeth, address updatedWeth);
/// @dev Allows the owner to update the protocol fee multiplier.
/// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier.
function updateProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier)
external;
/// @dev Allows the owner to update the staking address.
/// @param updatedStaking The updated staking contract address.
function updateStakingAddress(address updatedStaking)
external;
/// @dev Allows the owner to update the WETH address.
/// @param updatedWeth The updated WETH contract address.
function updateWethAddress(address updatedWeth)
external;
}

View File

@ -35,7 +35,7 @@
"compile:truffle": "truffle compile"
},
"config": {
"abis": "./generated-artifacts/@(Exchange|ExchangeWrapper|IAssetProxy|IAssetProxyDispatcher|IEIP1271Wallet|IExchange|IExchangeCore|IMatchOrders|ISignatureValidator|ITransactions|ITransferSimulator|IWallet|IWrapperFunctions|IsolatedExchange|LibExchangeRichErrorDecoder|MixinAssetProxyDispatcher|MixinExchangeCore|MixinMatchOrders|MixinSignatureValidator|MixinTransactions|MixinTransferSimulator|MixinWrapperFunctions|ReentrancyTester|TestAssetProxyDispatcher|TestExchangeInternals|TestLibExchangeRichErrorDecoder|TestSignatureValidator|TestTransactions|TestValidatorWallet|TestWrapperFunctions|Whitelist).json",
"abis": "./generated-artifacts/@(Exchange|ExchangeWrapper|IAssetProxy|IAssetProxyDispatcher|IEIP1271Wallet|IExchange|IExchangeCore|IMatchOrders|ISignatureValidator|IStakingManager|ITransactions|ITransferSimulator|IWallet|IWrapperFunctions|IsolatedExchange|LibExchangeRichErrorDecoder|MixinAssetProxyDispatcher|MixinExchangeCore|MixinMatchOrders|MixinSignatureValidator|MixinStakingManager|MixinTransactions|MixinTransferSimulator|MixinWrapperFunctions|ReentrancyTester|TestAssetProxyDispatcher|TestExchangeInternals|TestLibExchangeRichErrorDecoder|TestSignatureValidator|TestTransactions|TestValidatorWallet|TestWrapperFunctions|Whitelist).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {

View File

@ -14,16 +14,18 @@ import * as IExchange from '../generated-artifacts/IExchange.json';
import * as IExchangeCore from '../generated-artifacts/IExchangeCore.json';
import * as IMatchOrders from '../generated-artifacts/IMatchOrders.json';
import * as ISignatureValidator from '../generated-artifacts/ISignatureValidator.json';
import * as IsolatedExchange from '../generated-artifacts/IsolatedExchange.json';
import * as IStakingManager from '../generated-artifacts/IStakingManager.json';
import * as ITransactions from '../generated-artifacts/ITransactions.json';
import * as ITransferSimulator from '../generated-artifacts/ITransferSimulator.json';
import * as IWallet from '../generated-artifacts/IWallet.json';
import * as IWrapperFunctions from '../generated-artifacts/IWrapperFunctions.json';
import * as IsolatedExchange from '../generated-artifacts/IsolatedExchange.json';
import * as LibExchangeRichErrorDecoder from '../generated-artifacts/LibExchangeRichErrorDecoder.json';
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinExchangeCore from '../generated-artifacts/MixinExchangeCore.json';
import * as MixinMatchOrders from '../generated-artifacts/MixinMatchOrders.json';
import * as MixinSignatureValidator from '../generated-artifacts/MixinSignatureValidator.json';
import * as MixinStakingManager from '../generated-artifacts/MixinStakingManager.json';
import * as MixinTransactions from '../generated-artifacts/MixinTransactions.json';
import * as MixinTransferSimulator from '../generated-artifacts/MixinTransferSimulator.json';
import * as MixinWrapperFunctions from '../generated-artifacts/MixinWrapperFunctions.json';
@ -44,6 +46,7 @@ export const artifacts = {
MixinExchangeCore: MixinExchangeCore as ContractArtifact,
MixinMatchOrders: MixinMatchOrders as ContractArtifact,
MixinSignatureValidator: MixinSignatureValidator as ContractArtifact,
MixinStakingManager: MixinStakingManager as ContractArtifact,
MixinTransactions: MixinTransactions as ContractArtifact,
MixinTransferSimulator: MixinTransferSimulator as ContractArtifact,
MixinWrapperFunctions: MixinWrapperFunctions as ContractArtifact,
@ -54,6 +57,7 @@ export const artifacts = {
IExchangeCore: IExchangeCore as ContractArtifact,
IMatchOrders: IMatchOrders as ContractArtifact,
ISignatureValidator: ISignatureValidator as ContractArtifact,
IStakingManager: IStakingManager as ContractArtifact,
ITransactions: ITransactions as ContractArtifact,
ITransferSimulator: ITransferSimulator as ContractArtifact,
IWallet: IWallet as ContractArtifact,

View File

@ -12,6 +12,7 @@ export * from '../generated-wrappers/i_exchange';
export * from '../generated-wrappers/i_exchange_core';
export * from '../generated-wrappers/i_match_orders';
export * from '../generated-wrappers/i_signature_validator';
export * from '../generated-wrappers/i_staking_manager';
export * from '../generated-wrappers/i_transactions';
export * from '../generated-wrappers/i_transfer_simulator';
export * from '../generated-wrappers/i_wallet';
@ -22,6 +23,7 @@ export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../generated-wrappers/mixin_exchange_core';
export * from '../generated-wrappers/mixin_match_orders';
export * from '../generated-wrappers/mixin_signature_validator';
export * from '../generated-wrappers/mixin_staking_manager';
export * from '../generated-wrappers/mixin_transactions';
export * from '../generated-wrappers/mixin_transfer_simulator';
export * from '../generated-wrappers/mixin_wrapper_functions';

View File

@ -0,0 +1,143 @@
import { blockchainTests, constants, expect, LogDecoder } from '@0x/contracts-test-utils';
import { BigNumber, OwnableRevertErrors } from '@0x/utils';
import { LogWithDecodedArgs } from 'ethereum-types';
import {
artifacts,
ExchangeContract,
ExchangeUpdatedProtocolFeeMultiplierEventArgs,
ExchangeUpdatedStakingAddressEventArgs,
ExchangeUpdatedWethAddressEventArgs,
} from '../src';
blockchainTests.resets('MixinStakingManager', env => {
let accounts: string[];
let exchange: ExchangeContract;
let logDecoder: LogDecoder;
let nonOwner: string;
let owner: string;
let staking: string;
let weth: string;
// The protocolFeeMultiplier that will be used to test the update functions.
const protocolFeeMultiplier = new BigNumber(15000);
before(async () => {
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
owner = accounts[0];
nonOwner = accounts[1];
staking = accounts[2];
weth = accounts[3];
// Update the from address of the txDefaults. This is the address that will become the owner.
env.txDefaults.from = owner;
// Deploy the exchange contract.
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange,
env.provider,
env.txDefaults,
{},
new BigNumber(1337),
);
// Configure the log decoder
logDecoder = new LogDecoder(env.web3Wrapper, artifacts);
});
blockchainTests.resets('updateProtocolFeeMultiplier', () => {
it('should revert if msg.sender != owner', async () => {
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
// Ensure that the transaction reverts with the expected rich error.
const tx = exchange.updateStakingAddress.sendTransactionAsync(staking, {
from: nonOwner,
});
return expect(tx).to.revertWith(expectedError);
});
it('should succeed and emit an UpdatedProtocolFeeMultiplier event if msg.sender == owner', async () => {
// Call the `updateProtocolFeeMultiplier()` function and get the receipt.
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
await exchange.updateProtocolFeeMultiplier.sendTransactionAsync(protocolFeeMultiplier, {
from: owner,
}),
);
// Verify that the staking address was actually updated to the correct address.
const updated = await exchange.protocolFeeMultiplier.callAsync();
expect(updated).bignumber.to.be.eq(protocolFeeMultiplier);
// Ensure that the correct `UpdatedStakingAddress` event was logged.
// tslint:disable:no-unnecessary-type-assertion
const updatedEvent = receipt.logs[0] as LogWithDecodedArgs<ExchangeUpdatedProtocolFeeMultiplierEventArgs>;
expect(updatedEvent.event).to.be.eq('UpdatedProtocolFeeMultiplier');
expect(updatedEvent.args.oldProtocolFeeMultiplier).bignumber.to.be.eq(constants.ZERO_AMOUNT);
expect(updatedEvent.args.updatedProtocolFeeMultiplier).bignumber.to.be.eq(protocolFeeMultiplier);
});
});
blockchainTests.resets('updateStakingAddress', () => {
it('should revert if msg.sender != owner', async () => {
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
// Ensure that the transaction reverts with the expected rich error.
const tx = exchange.updateStakingAddress.sendTransactionAsync(staking, {
from: nonOwner,
});
return expect(tx).to.revertWith(expectedError);
});
it('should succeed and emit an UpdatedStakingAddress event if msg.sender == owner', async () => {
// Call the `updateStakingAddress()` function and get the receipt.
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
await exchange.updateStakingAddress.sendTransactionAsync(staking, {
from: owner,
}),
);
// Verify that the staking address was actually updated to the correct address.
const updated = await exchange.staking.callAsync();
expect(updated).to.be.eq(staking);
// Ensure that the correct `UpdatedStakingAddress` event was logged.
// tslint:disable:no-unnecessary-type-assertion
const updatedEvent = receipt.logs[0] as LogWithDecodedArgs<ExchangeUpdatedStakingAddressEventArgs>;
expect(updatedEvent.event).to.be.eq('UpdatedStakingAddress');
expect(updatedEvent.args.oldStaking).to.be.eq(constants.NULL_ADDRESS);
expect(updatedEvent.args.updatedStaking).to.be.eq(staking);
});
});
blockchainTests.resets('updateWethAddress', () => {
it('should revert if msg.sender != owner', async () => {
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
// Ensure that the transaction reverts with the expected rich error.
const tx = exchange.updateWethAddress.sendTransactionAsync(weth, {
from: nonOwner,
});
return expect(tx).to.revertWith(expectedError);
});
it('should succeed and emit an UpdatedStakingAddress event if msg.sender == owner', async () => {
// Call the `updateWethAddress()` function and get the receipt.
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
await exchange.updateWethAddress.sendTransactionAsync(weth, {
from: owner,
}),
);
// Verify that the staking address was actually updated to the correct address.
const updated = await exchange.weth.callAsync();
expect(updated).to.be.eq(weth);
// Ensure that the correct `UpdatedStakingAddress` event was logged.
// tslint:disable:no-unnecessary-type-assertion
const updatedEvent = receipt.logs[0] as LogWithDecodedArgs<ExchangeUpdatedWethAddressEventArgs>;
expect(updatedEvent.event).to.be.eq('UpdatedWethAddress');
expect(updatedEvent.args.oldWeth).to.be.eq(constants.NULL_ADDRESS);
expect(updatedEvent.args.updatedWeth).to.be.eq(weth);
});
});
});

View File

@ -9,6 +9,9 @@ export const constants = {
ExchangeFunctionName.RegisterAssetProxy,
ExchangeFunctionName.SimulateDispatchTransferFromCalls,
ExchangeFunctionName.TransferOwnership,
ExchangeFunctionName.UpdateProtocolFeeMultiplier,
ExchangeFunctionName.UpdateStakingAddress,
ExchangeFunctionName.UpdateWethAddress,
],
SINGLE_FILL_FN_NAMES: [
ExchangeFunctionName.FillOrder,

View File

@ -32,4 +32,7 @@ export enum ExchangeFunctionName {
SetSignatureValidatorApproval = 'setSignatureValidatorApproval',
SimulateDispatchTransferFromCalls = 'simulateDispatchTransferFromCalls',
TransferOwnership = 'transferOwnership',
UpdateProtocolFeeMultiplier = 'updateProtocolFeeMultiplier',
UpdateStakingAddress = 'updateStakingAddress',
UpdateWethAddress = 'updateWethAddress',
}

View File

@ -12,6 +12,7 @@
"generated-artifacts/IExchangeCore.json",
"generated-artifacts/IMatchOrders.json",
"generated-artifacts/ISignatureValidator.json",
"generated-artifacts/IStakingManager.json",
"generated-artifacts/ITransactions.json",
"generated-artifacts/ITransferSimulator.json",
"generated-artifacts/IWallet.json",
@ -22,6 +23,7 @@
"generated-artifacts/MixinExchangeCore.json",
"generated-artifacts/MixinMatchOrders.json",
"generated-artifacts/MixinSignatureValidator.json",
"generated-artifacts/MixinStakingManager.json",
"generated-artifacts/MixinTransactions.json",
"generated-artifacts/MixinTransferSimulator.json",
"generated-artifacts/MixinWrapperFunctions.json",