Merge pull request #2103 from 0xProject/feature/contracts-staking/rich-reverts
Staking RichErrors and cleanup
This commit is contained in:
@@ -1748,8 +1748,8 @@ describe('ERC1155Proxy', () => {
|
||||
nftNotOwnerBalance,
|
||||
];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
maxUintValue,
|
||||
valueMultiplier,
|
||||
);
|
||||
@@ -1836,8 +1836,8 @@ describe('ERC1155Proxy', () => {
|
||||
// check balances before transfer
|
||||
const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
spenderInitialFungibleBalance,
|
||||
valuesToTransfer[0].times(valueMultiplier),
|
||||
);
|
||||
|
@@ -173,8 +173,8 @@ describe('ERC1155Token', () => {
|
||||
const tokenToTransfer = fungibleToken;
|
||||
const valueToTransfer = spenderInitialFungibleBalance.plus(1);
|
||||
// create the expected error (a uint256 underflow)
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
spenderInitialFungibleBalance,
|
||||
valueToTransfer,
|
||||
);
|
||||
@@ -349,8 +349,8 @@ describe('ERC1155Token', () => {
|
||||
const tokensToTransfer = [fungibleToken];
|
||||
const valuesToTransfer = [spenderInitialFungibleBalance.plus(1)];
|
||||
// create the expected error (a uint256 underflow)
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
spenderInitialFungibleBalance,
|
||||
valuesToTransfer[0],
|
||||
);
|
||||
|
@@ -139,8 +139,8 @@ blockchainTests('LibFillResults', env => {
|
||||
takerAssetAmount: MAX_UINT256_ROOT,
|
||||
});
|
||||
const takerAssetFilledAmount = MAX_UINT256_ROOT;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
takerAssetFilledAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
@@ -162,8 +162,8 @@ blockchainTests('LibFillResults', env => {
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
makerAssetFilledAmount,
|
||||
order.makerFee,
|
||||
);
|
||||
@@ -180,8 +180,8 @@ blockchainTests('LibFillResults', env => {
|
||||
takerFee: MAX_UINT256_ROOT.times(11),
|
||||
});
|
||||
const takerAssetFilledAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
takerAssetFilledAmount,
|
||||
order.takerFee,
|
||||
);
|
||||
@@ -303,8 +303,8 @@ blockchainTests('LibFillResults', env => {
|
||||
it('reverts if computing `makerAssetFilledAmount` overflows', async () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.makerAssetFilledAmount = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.makerAssetFilledAmount,
|
||||
b.makerAssetFilledAmount,
|
||||
);
|
||||
@@ -314,8 +314,8 @@ blockchainTests('LibFillResults', env => {
|
||||
it('reverts if computing `takerAssetFilledAmount` overflows', async () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.takerAssetFilledAmount = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.takerAssetFilledAmount,
|
||||
b.takerAssetFilledAmount,
|
||||
);
|
||||
@@ -325,8 +325,8 @@ blockchainTests('LibFillResults', env => {
|
||||
it('reverts if computing `makerFeePaid` overflows', async () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.makerFeePaid = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.makerFeePaid,
|
||||
b.makerFeePaid,
|
||||
);
|
||||
@@ -336,8 +336,8 @@ blockchainTests('LibFillResults', env => {
|
||||
it('reverts if computing `takerFeePaid` overflows', async () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.takerFeePaid = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.takerFeePaid,
|
||||
b.takerFeePaid,
|
||||
);
|
||||
|
@@ -71,8 +71,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = ONE_ETHER;
|
||||
const denominator = ZERO_AMOUNT;
|
||||
const target = ONE_ETHER.times(0.01);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero,
|
||||
numerator.times(target),
|
||||
denominator,
|
||||
);
|
||||
@@ -85,8 +85,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -131,8 +131,8 @@ blockchainTests('LibMath', env => {
|
||||
const denominator = ZERO_AMOUNT;
|
||||
const target = ONE_ETHER.times(0.01);
|
||||
// This will actually manifest as a subtraction underflow.
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
denominator,
|
||||
new BigNumber(1),
|
||||
);
|
||||
@@ -145,8 +145,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -210,8 +210,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -275,8 +275,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -341,8 +341,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -407,8 +407,8 @@ blockchainTests('LibMath', env => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
|
@@ -35,8 +35,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts if computing `makerAssetFilledAmount` overflows', () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.makerAssetFilledAmount = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.makerAssetFilledAmount,
|
||||
b.makerAssetFilledAmount,
|
||||
);
|
||||
@@ -46,8 +46,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts if computing `takerAssetFilledAmount` overflows', () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.takerAssetFilledAmount = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.takerAssetFilledAmount,
|
||||
b.takerAssetFilledAmount,
|
||||
);
|
||||
@@ -57,8 +57,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts if computing `makerFeePaid` overflows', () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.makerFeePaid = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.makerFeePaid,
|
||||
b.makerFeePaid,
|
||||
);
|
||||
@@ -68,8 +68,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts if computing `takerFeePaid` overflows', () => {
|
||||
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||
b.takerFeePaid = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a.takerFeePaid,
|
||||
b.takerFeePaid,
|
||||
);
|
||||
@@ -85,8 +85,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = ONE_ETHER;
|
||||
const denominator = ZERO_AMOUNT;
|
||||
const target = ONE_ETHER.times(0.01);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero,
|
||||
numerator.times(target),
|
||||
denominator,
|
||||
);
|
||||
@@ -99,8 +99,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -118,8 +118,8 @@ describe('Reference Functions', () => {
|
||||
const denominator = ZERO_AMOUNT;
|
||||
const target = ONE_ETHER.times(0.01);
|
||||
// This will actually manifest as a subtraction underflow.
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
denominator,
|
||||
new BigNumber(1),
|
||||
);
|
||||
@@ -132,8 +132,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -170,8 +170,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -208,8 +208,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -254,8 +254,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
@@ -300,8 +300,8 @@ describe('Reference Functions', () => {
|
||||
const numerator = MAX_UINT256;
|
||||
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||
const target = MAX_UINT256_ROOT.times(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
numerator,
|
||||
target,
|
||||
);
|
||||
|
@@ -77,8 +77,8 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
makerAssetAmount: constants.MAX_UINT256_ROOT,
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18),
|
||||
});
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
leftOrder.makerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
);
|
||||
@@ -94,8 +94,8 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18),
|
||||
takerAssetAmount: constants.MAX_UINT256_ROOT,
|
||||
});
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
leftOrder.takerAssetAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
);
|
||||
@@ -228,8 +228,8 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
makerFeePaid: constants.ZERO_AMOUNT,
|
||||
takerFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
orderTakerAssetFilledAmount,
|
||||
takerAssetFillAmount,
|
||||
);
|
||||
@@ -357,8 +357,8 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
rightOrder.takerFeeAssetData = leftOrder.takerFeeAssetData;
|
||||
|
||||
// The expected error that should be thrown by the function.
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
matchedFillResults.left.takerFeePaid,
|
||||
matchedFillResults.right.takerFeePaid,
|
||||
);
|
||||
|
@@ -443,8 +443,8 @@ blockchainTests('Isolated fillOrder() tests', env => {
|
||||
takerAssetAmount: MAX_UINT256_ROOT,
|
||||
});
|
||||
const takerAssetFillAmount = MAX_UINT256_ROOT;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
takerAssetFillAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
@@ -464,8 +464,8 @@ blockchainTests('Isolated fillOrder() tests', env => {
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
makerAssetFilledAmount,
|
||||
order.makerFee,
|
||||
);
|
||||
@@ -480,8 +480,8 @@ blockchainTests('Isolated fillOrder() tests', env => {
|
||||
takerFee: MAX_UINT256_ROOT.times(11),
|
||||
});
|
||||
const takerAssetFillAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
takerAssetFillAmount,
|
||||
order.takerFee,
|
||||
);
|
||||
|
@@ -39,8 +39,8 @@ describe('Reference functions', () => {
|
||||
takerAssetAmount: MAX_UINT256_ROOT,
|
||||
});
|
||||
const takerAssetFilledAmount = MAX_UINT256_ROOT;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
takerAssetFilledAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
@@ -60,8 +60,8 @@ describe('Reference functions', () => {
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
makerAssetFilledAmount,
|
||||
order.makerFee,
|
||||
);
|
||||
@@ -76,8 +76,8 @@ describe('Reference functions', () => {
|
||||
takerFee: MAX_UINT256_ROOT.times(11),
|
||||
});
|
||||
const takerAssetFilledAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
takerAssetFilledAmount,
|
||||
order.takerFee,
|
||||
);
|
||||
|
@@ -718,8 +718,8 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
const signatures = _.times(COUNT, i => createOrderSignature(orders[i]));
|
||||
orders[1].takerAssetAmount = MAX_UINT256;
|
||||
const takerAssetFillAmount = MAX_UINT256;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
orders[0].takerAssetAmount,
|
||||
orders[1].takerAssetAmount,
|
||||
);
|
||||
@@ -1031,8 +1031,8 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
const orders = [randomOrder({ takerAssetAmount: MAX_UINT256 })];
|
||||
const signatures = _.times(orders.length, i => createOrderSignature(orders[i]));
|
||||
const makerAssetFillAmount = new BigNumber(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
orders[0].takerAssetAmount,
|
||||
makerAssetFillAmount,
|
||||
);
|
||||
@@ -1044,8 +1044,8 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
const orders = [randomOrder({ makerAssetAmount: constants.ZERO_AMOUNT })];
|
||||
const signatures = _.times(orders.length, i => createOrderSignature(orders[i]));
|
||||
const makerAssetFillAmount = ONE_ETHER;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero,
|
||||
orders[0].takerAssetAmount.times(makerAssetFillAmount),
|
||||
orders[0].makerAssetAmount,
|
||||
);
|
||||
@@ -1066,8 +1066,8 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
];
|
||||
const signatures = _.times(orders.length, i => createOrderSignature(orders[i]));
|
||||
const makerAssetFillAmount = new BigNumber(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
orders[0].makerAssetAmount,
|
||||
orders[1].makerAssetAmount,
|
||||
);
|
||||
|
@@ -41,7 +41,7 @@ If a vulnerability is discovered in the staking contract, operations may be halt
|
||||
|
||||
In this worst-case scenario, state has been irreperably corrupted and the staking contracts must be re-deployed. Users withdraw their funds from the vaults and re-stake under the new system, at will.
|
||||
|
||||
4. Vaults enter "Catostrophic Failure Mode" allowing users to withdraw their ZRX and Rewards.
|
||||
4. Vaults enter "Catastrophic Failure Mode" allowing users to withdraw their ZRX and Rewards.
|
||||
5. A Balance Oracle is deployed for determining the Reward balance of each user. (\*)
|
||||
|
||||

|
||||
|
@@ -18,8 +18,10 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibSafeMath.sol";
|
||||
import "../libs/LibFeeMath.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../immutable/MixinStorage.sol";
|
||||
import "../immutable/MixinConstants.sol";
|
||||
import "../interfaces/IStakingEvents.sol";
|
||||
@@ -33,7 +35,7 @@ import "./MixinExchangeManager.sol";
|
||||
|
||||
/// @dev This mixin contains the logic for 0x protocol fees.
|
||||
/// Protocol fees are sent by 0x exchanges every time there is a trade.
|
||||
/// If the maker has associated their address with a pool (see MixinStakingPool.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
|
||||
/// 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
|
||||
@@ -121,7 +123,7 @@ contract MixinExchangeFees is
|
||||
|
||||
/// @dev Pays rewards to market making pools that were active this epoch.
|
||||
/// Each pool receives a portion of the fees generated this epoch (see LibFeeMath) that is
|
||||
/// proportional to (i) the fee volume attributed to their pool over the epoch, and
|
||||
/// proportional to (i) the fee volume attributed to their pool over the epoch, and
|
||||
/// (ii) the amount of stake provided by the maker and their delegators. Rebates are paid
|
||||
/// into the Reward Vault (see MixinStakingPoolRewardVault) where they can be withdraw by makers and
|
||||
/// the members of their pool. There will be a small amount of ETH leftover in this contract
|
||||
@@ -223,10 +225,14 @@ contract MixinExchangeFees is
|
||||
activePoolsThisEpoch.length = 0;
|
||||
|
||||
// step 3/3 send total payout to vault
|
||||
require(
|
||||
totalRewardsPaid <= initialContractBalance,
|
||||
"MISCALCULATED_REWARDS"
|
||||
);
|
||||
|
||||
// Sanity check rewards calculation
|
||||
if (totalRewardsPaid > initialContractBalance) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.MiscalculatedRewardsError(
|
||||
totalRewardsPaid,
|
||||
initialContractBalance
|
||||
));
|
||||
}
|
||||
if (totalRewardsPaid > 0) {
|
||||
_depositIntoStakingPoolRewardVault(totalRewardsPaid);
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../interfaces/IStakingEvents.sol";
|
||||
import "../immutable/MixinConstants.sol";
|
||||
import "../immutable/MixinStorage.sol";
|
||||
@@ -38,10 +40,11 @@ contract MixinExchangeManager is
|
||||
|
||||
/// @dev Asserts that the call is coming from a valid exchange.
|
||||
modifier onlyExchange() {
|
||||
require(
|
||||
isValidExchangeAddress(msg.sender),
|
||||
"ONLY_CALLABLE_BY_EXCHANGE"
|
||||
);
|
||||
if (!isValidExchangeAddress(msg.sender)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByExchangeError(
|
||||
msg.sender
|
||||
));
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -51,10 +54,11 @@ contract MixinExchangeManager is
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
!validExchanges[addr],
|
||||
"EXCHANGE_ADDRESS_ALREADY_REGISTERED"
|
||||
);
|
||||
if (validExchanges[addr]) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.ExchangeAddressAlreadyRegisteredError(
|
||||
addr
|
||||
));
|
||||
}
|
||||
validExchanges[addr] = true;
|
||||
emit ExchangeAdded(addr);
|
||||
}
|
||||
@@ -65,10 +69,11 @@ contract MixinExchangeManager is
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
validExchanges[addr],
|
||||
"EXCHANGE_ADDRESS_NOT_REGISTERED"
|
||||
);
|
||||
if (!validExchanges[addr]) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.ExchangeAddressNotRegisteredError(
|
||||
addr
|
||||
));
|
||||
}
|
||||
validExchanges[addr] = false;
|
||||
emit ExchangeRemoved(addr);
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ pragma solidity ^0.5.9;
|
||||
/// @dev This vault manages staking pool rewards.
|
||||
/// Rewards can be deposited and withdraw by the staking contract.
|
||||
/// There is a "Catastrophic Failure Mode" that, when invoked, only
|
||||
/// allows withdrawals to be made. Once this vault is in catostrophic
|
||||
/// allows withdrawals to be made. Once this vault is in catastrophic
|
||||
/// failure mode, it cannot be returned to normal mode; this prevents
|
||||
/// corruption of related state in the staking contract.
|
||||
interface IStakingPoolRewardVault {
|
||||
|
@@ -27,7 +27,7 @@ pragma solidity ^0.5.9;
|
||||
/// Vaults should only be set to Catastrophic Failure Mode iff there is
|
||||
/// non-recoverable corruption of the staking contracts. If there is a
|
||||
/// recoverable flaw/bug/vulnerability, simply detach the staking contract
|
||||
/// by setting its address to `address(0)`. Once in Catostrophic Failure Mode,
|
||||
/// by setting its address to `address(0)`. Once in Catastrophic Failure Mode,
|
||||
/// a vault cannot be reset to normal mode; this prevents corruption of related
|
||||
/// state in the staking contract.
|
||||
interface IVaultCore {
|
||||
@@ -38,9 +38,9 @@ interface IVaultCore {
|
||||
address stakingContractAddress
|
||||
);
|
||||
|
||||
/// @dev Emitted when the Staking contract is put into Catostrophic Failure Mode
|
||||
/// @dev Emitted when the Staking contract is put into Catastrophic Failure Mode
|
||||
/// @param sender Address of sender (`msg.sender`)
|
||||
event InCatostrophicFailureMode(
|
||||
event InCatastrophicFailureMode(
|
||||
address sender
|
||||
);
|
||||
|
||||
@@ -50,9 +50,9 @@ interface IVaultCore {
|
||||
function setStakingContract(address payable _stakingContractAddress)
|
||||
external;
|
||||
|
||||
/// @dev Vault enters into Catostrophic Failure Mode.
|
||||
/// @dev Vault enters into Catastrophic Failure Mode.
|
||||
/// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! ***
|
||||
/// Note that only the contract owner can call this function.
|
||||
function enterCatostrophicFailure()
|
||||
function enterCatastrophicFailure()
|
||||
external;
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ pragma solidity ^0.5.9;
|
||||
/// When a user mints stake, their Zrx Tokens are deposited into this vault.
|
||||
/// Similarly, when they burn stake, their Zrx Tokens are withdrawn from this vault.
|
||||
/// There is a "Catastrophic Failure Mode" that, when invoked, only
|
||||
/// allows withdrawals to be made. Once this vault is in catostrophic
|
||||
/// allows withdrawals to be made. Once this vault is in catastrophic
|
||||
/// failure mode, it cannot be returned to normal mode; this prevents
|
||||
/// corruption of related state in the staking contract.
|
||||
interface IZrxVault {
|
||||
@@ -62,21 +62,21 @@ interface IZrxVault {
|
||||
|
||||
/// @dev Sets the ERC20 proxy.
|
||||
/// Note that only the contract owner can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param erc20ProxyAddress Address of the 0x ERC20 Proxy.
|
||||
function setErc20Proxy(address erc20ProxyAddress)
|
||||
external;
|
||||
|
||||
/// @dev Sets the Zrx Asset Data.
|
||||
/// Note that only the contract owner can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param _zrxAssetData Zrx asset data for the ERC20 Proxy.
|
||||
function setZrxAssetData(bytes calldata _zrxAssetData)
|
||||
external;
|
||||
|
||||
/// @dev Deposit an `amount` of Zrx Tokens from `owner` into the vault.
|
||||
/// Note that only the Staking contract can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param owner of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens to deposit.
|
||||
function depositFrom(address owner, uint256 amount)
|
||||
@@ -84,14 +84,14 @@ interface IZrxVault {
|
||||
|
||||
/// @dev Withdraw an `amount` of Zrx Tokens to `owner` from the vault.
|
||||
/// Note that only the Staking contract can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param owner of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens to withdraw.
|
||||
function withdrawFrom(address owner, uint256 amount)
|
||||
external;
|
||||
|
||||
/// @dev Withdraw ALL Zrx Tokens to `owner` from the vault.
|
||||
/// Note that this can only be called when *in* Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *in* Catastrophic Failure mode.
|
||||
/// @param owner of Zrx Tokens.
|
||||
function withdrawAllFrom(address owner)
|
||||
external
|
||||
|
@@ -18,27 +18,42 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMathRichErrors.sol";
|
||||
|
||||
|
||||
library LibSafeMath {
|
||||
|
||||
uint256 constant internal MAX_UINT_96 = 79228162514264337593543950335; // 2**96-1
|
||||
|
||||
uint256 constant internal MAX_UINT_64 = 18446744073709551615; // 2**64-1
|
||||
|
||||
/// @dev Returns the addition of two unsigned integers, reverting on overflow.
|
||||
/// Note that this reverts on overflow.
|
||||
function _add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
uint256 c = a + b;
|
||||
require(c >= a, "OVERFLOW");
|
||||
if (c < a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// @dev Returns the subtraction of two unsigned integers.
|
||||
/// Note that this reverts on underflow.
|
||||
function _sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
require(b <= a, "UNDEROVERFLOW");
|
||||
uint256 c = a - b;
|
||||
if (b > a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
uint256 c = a - b;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -53,7 +68,13 @@ library LibSafeMath {
|
||||
}
|
||||
|
||||
uint256 c = a * b;
|
||||
require(c / a == b, "SafeMath: multiplication overflow");
|
||||
if (c / a != b) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -61,7 +82,14 @@ library LibSafeMath {
|
||||
/// @dev Returns the integer division of two unsigned integers.
|
||||
/// Note that this reverts on division by zero. The result is rounded towards zero.
|
||||
function _div(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
require(b > 0, "DIVISION_BY_ZERO");
|
||||
if (b == 0) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
uint256 c = a / b;
|
||||
return c;
|
||||
}
|
||||
@@ -73,10 +101,12 @@ library LibSafeMath {
|
||||
pure
|
||||
returns (uint96)
|
||||
{
|
||||
require(
|
||||
a <= MAX_UINT_96,
|
||||
"VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96"
|
||||
);
|
||||
if (a > MAX_UINT_96) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256DowncastError(
|
||||
LibSafeMathRichErrors.DowncastErrorCodes.VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96,
|
||||
a
|
||||
));
|
||||
}
|
||||
return uint96(a);
|
||||
}
|
||||
|
||||
@@ -87,10 +117,12 @@ library LibSafeMath {
|
||||
pure
|
||||
returns (uint64)
|
||||
{
|
||||
require(
|
||||
a <= MAX_UINT_64,
|
||||
"VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64"
|
||||
);
|
||||
if (a > MAX_UINT_64) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256DowncastError(
|
||||
LibSafeMathRichErrors.DowncastErrorCodes.VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64,
|
||||
a
|
||||
));
|
||||
}
|
||||
return uint64(a);
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,9 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMathRichErrors.sol";
|
||||
|
||||
|
||||
library LibSafeMath64 {
|
||||
|
||||
@@ -25,16 +28,29 @@ library LibSafeMath64 {
|
||||
/// Note that this reverts on overflow.
|
||||
function _add(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
uint64 c = a + b;
|
||||
require(c >= a, "OVERFLOW");
|
||||
if (c < a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint64BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// @dev Returns the subtraction of two unsigned integers.
|
||||
/// Note that this reverts on underflow.
|
||||
function _sub(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
require(b <= a, "UNDEROVERFLOW");
|
||||
uint64 c = a - b;
|
||||
if (b > a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint64BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
uint64 c = a - b;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -49,7 +65,13 @@ library LibSafeMath64 {
|
||||
}
|
||||
|
||||
uint64 c = a * b;
|
||||
require(c / a == b, "SafeMath: multiplication overflow");
|
||||
if (c / a != b) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint64BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -57,7 +79,14 @@ library LibSafeMath64 {
|
||||
/// @dev Returns the integer division of two unsigned integers.
|
||||
/// Note that this reverts on division by zero. The result is rounded towards zero.
|
||||
function _div(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
require(b > 0, "DIVISION_BY_ZERO");
|
||||
if (b == 0) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint64BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
uint64 c = a / b;
|
||||
return c;
|
||||
}
|
||||
|
@@ -18,6 +18,9 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMathRichErrors.sol";
|
||||
|
||||
|
||||
library LibSafeMath96 {
|
||||
|
||||
@@ -25,16 +28,29 @@ library LibSafeMath96 {
|
||||
/// Note that this reverts on overflow.
|
||||
function _add(uint96 a, uint96 b) internal pure returns (uint96) {
|
||||
uint96 c = a + b;
|
||||
require(c >= a, "OVERFLOW");
|
||||
if (c < a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint96BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// @dev Returns the subtraction of two unsigned integers.
|
||||
/// Note that this reverts on underflow.
|
||||
function _sub(uint96 a, uint96 b) internal pure returns (uint96) {
|
||||
require(b <= a, "UNDEROVERFLOW");
|
||||
uint96 c = a - b;
|
||||
if (b > a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint96BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
uint96 c = a - b;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -49,7 +65,13 @@ library LibSafeMath96 {
|
||||
}
|
||||
|
||||
uint96 c = a * b;
|
||||
require(c / a == b, "SafeMath: multiplication overflow");
|
||||
if (c / a != b) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint96BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -57,7 +79,14 @@ library LibSafeMath96 {
|
||||
/// @dev Returns the integer division of two unsigned integers.
|
||||
/// Note that this reverts on division by zero. The result is rounded towards zero.
|
||||
function _div(uint96 a, uint96 b) internal pure returns (uint96) {
|
||||
require(b > 0, "DIVISION_BY_ZERO");
|
||||
if (b == 0) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint96BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
|
||||
a,
|
||||
b
|
||||
));
|
||||
}
|
||||
|
||||
uint96 c = a / b;
|
||||
return c;
|
||||
}
|
||||
|
@@ -14,12 +14,14 @@
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../interfaces/IStructs.sol";
|
||||
import "../interfaces/IWallet.sol";
|
||||
|
||||
|
||||
library LibSignatureValidator {
|
||||
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
// bytes4(keccak256("isValidSignature(bytes,bytes)")
|
||||
@@ -39,19 +41,19 @@ library LibSignatureValidator {
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
require(
|
||||
signature.length > 0,
|
||||
"LENGTH_GREATER_THAN_0_REQUIRED"
|
||||
);
|
||||
if (signature.length == 0) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureLengthGreaterThan0RequiredError());
|
||||
}
|
||||
|
||||
// Pop last byte off of signature byte array.
|
||||
uint8 signatureTypeRaw = uint8(signature.popLastByte());
|
||||
|
||||
// Ensure signature is supported
|
||||
require(
|
||||
signatureTypeRaw < uint8(IStructs.SignatureType.NSignatureTypes),
|
||||
"SIGNATURE_UNSUPPORTED"
|
||||
);
|
||||
if (signatureTypeRaw >= uint8(IStructs.SignatureType.NSignatureTypes)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureUnsupportedError(
|
||||
signature
|
||||
));
|
||||
}
|
||||
|
||||
IStructs.SignatureType signatureType = IStructs.SignatureType(signatureTypeRaw);
|
||||
|
||||
@@ -67,26 +69,30 @@ library LibSignatureValidator {
|
||||
// it an explicit option. This aids testing and analysis. It is
|
||||
// also the initialization value for the enum type.
|
||||
if (signatureType == IStructs.SignatureType.Illegal) {
|
||||
revert("SIGNATURE_ILLEGAL");
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureIllegalError(
|
||||
signature
|
||||
));
|
||||
|
||||
// Always invalid signature.
|
||||
// Like Illegal, this is always implicitly available and therefore
|
||||
// offered explicitly. It can be implicitly created by providing
|
||||
// a correctly formatted but incorrect signature.
|
||||
} else if (signatureType == IStructs.SignatureType.Invalid) {
|
||||
require(
|
||||
signature.length == 0,
|
||||
"LENGTH_0_REQUIRED"
|
||||
);
|
||||
if (signature.length > 0) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureLength0RequiredError(
|
||||
signature
|
||||
));
|
||||
}
|
||||
isValid = false;
|
||||
return isValid;
|
||||
|
||||
// Signature using EIP712
|
||||
} else if (signatureType == IStructs.SignatureType.EIP712) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
"LENGTH_65_REQUIRED"
|
||||
);
|
||||
if (signature.length != 65) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureLength65RequiredError(
|
||||
signature
|
||||
));
|
||||
}
|
||||
v = uint8(signature[0]);
|
||||
r = signature.readBytes32(1);
|
||||
s = signature.readBytes32(33);
|
||||
@@ -101,10 +107,11 @@ library LibSignatureValidator {
|
||||
|
||||
// Signed using web3.eth_sign
|
||||
} else if (signatureType == IStructs.SignatureType.EthSign) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
"LENGTH_65_REQUIRED"
|
||||
);
|
||||
if (signature.length != 65) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureLength65RequiredError(
|
||||
signature
|
||||
));
|
||||
}
|
||||
v = uint8(signature[0]);
|
||||
r = signature.readBytes32(1);
|
||||
s = signature.readBytes32(33);
|
||||
@@ -136,7 +143,9 @@ library LibSignatureValidator {
|
||||
// that we currently support. In this case returning false
|
||||
// may lead the caller to incorrectly believe that the
|
||||
// signature was invalid.)
|
||||
revert("SIGNATURE_UNSUPPORTED");
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.SignatureUnsupportedError(
|
||||
signature
|
||||
));
|
||||
}
|
||||
|
||||
/// @dev Verifies signature using logic defined by Wallet contract.
|
||||
@@ -169,10 +178,12 @@ library LibSignatureValidator {
|
||||
(bool success, bytes memory result) = walletAddress.staticcall(callData);
|
||||
|
||||
// Sanity check call and extract the magic value
|
||||
require(
|
||||
success,
|
||||
"WALLET_ERROR"
|
||||
);
|
||||
if (!success) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.WalletError(
|
||||
walletAddress,
|
||||
result
|
||||
));
|
||||
}
|
||||
bytes4 magicValue = result.readBytes4(0);
|
||||
|
||||
isValid = (magicValue == EIP1271_MAGIC_VALUE);
|
||||
|
446
contracts/staking/contracts/src/libs/LibStakingRichErrors.sol
Normal file
446
contracts/staking/contracts/src/libs/LibStakingRichErrors.sol
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
|
||||
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/LibRichErrors.sol";
|
||||
|
||||
|
||||
library LibStakingRichErrors {
|
||||
// bytes4(keccak256("MiscalculatedRewardsError(uint256,uint256)"))
|
||||
bytes4 internal constant MISCALCULATED_REWARDS_ERROR_SELECTOR =
|
||||
0xf7806c4e;
|
||||
|
||||
// bytes4(keccak256("OnlyCallableByExchangeError(address)"))
|
||||
bytes4 internal constant ONLY_CALLABLE_BY_EXCHANGE_ERROR_SELECTOR =
|
||||
0xb56d2df0;
|
||||
|
||||
// bytes4(keccak256("ExchangeAddressAlreadyRegisteredError(address)"))
|
||||
bytes4 internal constant EXCHANGE_ADDRESS_ALREADY_REGISTERED_ERROR_SELECTOR =
|
||||
0xc87a78b7;
|
||||
|
||||
// bytes4(keccak256("ExchangeAddressNotRegisteredError(address)"))
|
||||
bytes4 internal constant EXCHANGE_ADDRESS_NOT_REGISTERED_ERROR_SELECTOR =
|
||||
0x7dc025b0;
|
||||
|
||||
// bytes4(keccak256("SignatureLengthGreaterThan0RequiredError()"))
|
||||
bytes internal constant SIGNATURE_LENGTH_GREATER_THAN_0_REQUIRED_ERROR =
|
||||
hex"2dcb01d9";
|
||||
|
||||
// bytes4(keccak256("SignatureUnsupportedError(bytes)"))
|
||||
bytes4 internal constant SIGNATURE_UNSUPPORTED_ERROR_SELECTOR =
|
||||
0xffca2a70;
|
||||
|
||||
// bytes4(keccak256("SignatureIllegalError(bytes)"))
|
||||
bytes4 internal constant SIGNATURE_ILLEGAL_ERROR_SELECTOR =
|
||||
0x4a95093c;
|
||||
|
||||
// bytes4(keccak256("SignatureLength0RequiredError(bytes)"))
|
||||
bytes4 internal constant SIGNATURE_LENGTH_0_REQUIRED_ERROR_SELECTOR =
|
||||
0xcbcd59a2;
|
||||
|
||||
// bytes4(keccak256("SignatureLength65RequiredError(bytes)"))
|
||||
bytes4 internal constant SIGNATURE_LENGTH_65_REQUIRED_ERROR_SELECTOR =
|
||||
0x091d7ab9;
|
||||
|
||||
// bytes4(keccak256("WalletError(address,bytes)"))
|
||||
bytes4 internal constant WALLET_ERROR_SELECTOR =
|
||||
0x0cfc935d;
|
||||
|
||||
// bytes4(keccak256("InsufficientBalanceError(uint256,uint256)"))
|
||||
bytes4 internal constant INSUFFICIENT_BALANCE_ERROR_SELECTOR =
|
||||
0x84c8b7c9;
|
||||
|
||||
// bytes4(keccak256("OnlyCallableByPoolOperatorError(address,address)"))
|
||||
bytes4 internal constant ONLY_CALLABLE_BY_POOL_OPERATOR_ERROR_SELECTOR =
|
||||
0x6cfa0c22;
|
||||
|
||||
// bytes4(keccak256("OnlyCallableByPoolOperatorOrMakerError(address,address,address)"))
|
||||
bytes4 internal constant ONLY_CALLABLE_BY_POOL_OPERATOR_OR_MAKER_ERROR_SELECTOR =
|
||||
0x7d9e1c10;
|
||||
|
||||
// bytes4(keccak256("InvalidMakerSignatureError(bytes32,address,bytes)"))
|
||||
bytes4 internal constant INVALID_MAKER_SIGNATURE_ERROR_SELECTOR =
|
||||
0x726b89c8;
|
||||
|
||||
// bytes4(keccak256("MakerAddressAlreadyRegisteredError(address)"))
|
||||
bytes4 internal constant MAKER_ADDRESS_ALREADY_REGISTERED_ERROR_SELECTOR =
|
||||
0x5a3971da;
|
||||
|
||||
// bytes4(keccak256("MakerAddressNotRegisteredError(address,bytes32,bytes32)"))
|
||||
bytes4 internal constant MAKER_ADDRESS_NOT_REGISTERED_ERROR_SELECTOR =
|
||||
0x12ab07e8;
|
||||
|
||||
// bytes4(keccak256("WithdrawAmountExceedsMemberBalanceError(uint256,uint256)"))
|
||||
bytes4 internal constant WITHDRAW_AMOUNT_EXCEEDS_MEMBER_BALANCE_ERROR_SELECTOR =
|
||||
0xfc9c065f;
|
||||
|
||||
// bytes4(keccak256("BlockTimestampTooLowError(uint64,uint64)"))
|
||||
bytes4 internal constant BLOCK_TIMESTAMP_TOO_LOW_ERROR_SELECTOR =
|
||||
0x887225f7;
|
||||
|
||||
// bytes4(keccak256("OnlyCallableByStakingContractError(address)"))
|
||||
bytes4 internal constant ONLY_CALLABLE_BY_STAKING_CONTRACT_ERROR_SELECTOR =
|
||||
0xca1d07a2;
|
||||
|
||||
// bytes4(keccak256("OnlyCallableIfInCatastrophicFailureError()"))
|
||||
bytes internal constant ONLY_CALLABLE_IF_IN_CATASTROPHIC_FAILURE_ERROR =
|
||||
hex"3ef081cc";
|
||||
|
||||
// bytes4(keccak256("OnlyCallableIfNotInCatastrophicFailureError()"))
|
||||
bytes internal constant ONLY_CALLABLE_IF_NOT_IN_CATASTROPHIC_FAILURE_ERROR =
|
||||
hex"7dd020ce";
|
||||
|
||||
// bytes4(keccak256("AmountExceedsBalanceOfPoolError(uint256,uint96)"))
|
||||
bytes4 internal constant AMOUNT_EXCEEDS_BALANCE_OF_POOL_ERROR_SELECTOR =
|
||||
0x4c5c09dd;
|
||||
|
||||
// bytes4(keccak256("OperatorShareMustBeBetween0And100Error(bytes32,uint8)"))
|
||||
bytes4 internal constant OPERATOR_SHARE_MUST_BE_BETWEEN_0_AND_100_ERROR_SELECTOR =
|
||||
0xde447684;
|
||||
|
||||
// bytes4(keccak256("PoolAlreadyExistsError(bytes32)"))
|
||||
bytes4 internal constant POOL_ALREADY_EXISTS_ERROR_SELECTOR =
|
||||
0x2a5e4dcf;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function MiscalculatedRewardsError(
|
||||
uint256 totalRewardsPaid,
|
||||
uint256 initialContractBalance
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
MISCALCULATED_REWARDS_ERROR_SELECTOR,
|
||||
totalRewardsPaid,
|
||||
initialContractBalance
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyCallableByExchangeError(
|
||||
address senderAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ONLY_CALLABLE_BY_EXCHANGE_ERROR_SELECTOR,
|
||||
senderAddress
|
||||
);
|
||||
}
|
||||
|
||||
function ExchangeAddressAlreadyRegisteredError(
|
||||
address exchangeAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
EXCHANGE_ADDRESS_ALREADY_REGISTERED_ERROR_SELECTOR,
|
||||
exchangeAddress
|
||||
);
|
||||
}
|
||||
|
||||
function ExchangeAddressNotRegisteredError(
|
||||
address exchangeAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
EXCHANGE_ADDRESS_NOT_REGISTERED_ERROR_SELECTOR,
|
||||
exchangeAddress
|
||||
);
|
||||
}
|
||||
|
||||
function SignatureLengthGreaterThan0RequiredError()
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return SIGNATURE_LENGTH_GREATER_THAN_0_REQUIRED_ERROR;
|
||||
}
|
||||
|
||||
function SignatureUnsupportedError(
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
SIGNATURE_UNSUPPORTED_ERROR_SELECTOR,
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
function SignatureIllegalError(
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
SIGNATURE_ILLEGAL_ERROR_SELECTOR,
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
function SignatureLength0RequiredError(
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
SIGNATURE_LENGTH_0_REQUIRED_ERROR_SELECTOR,
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
function SignatureLength65RequiredError(
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
SIGNATURE_LENGTH_65_REQUIRED_ERROR_SELECTOR,
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
function WalletError(
|
||||
address walletAddress,
|
||||
bytes memory errorData
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
WALLET_ERROR_SELECTOR,
|
||||
walletAddress,
|
||||
errorData
|
||||
);
|
||||
}
|
||||
|
||||
function InsufficientBalanceError(
|
||||
uint256 amount,
|
||||
uint256 balance
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INSUFFICIENT_BALANCE_ERROR_SELECTOR,
|
||||
amount,
|
||||
balance
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyCallableByPoolOperatorError(
|
||||
address senderAddress,
|
||||
address poolOperatorAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ONLY_CALLABLE_BY_POOL_OPERATOR_ERROR_SELECTOR,
|
||||
senderAddress,
|
||||
poolOperatorAddress
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyCallableByPoolOperatorOrMakerError(
|
||||
address senderAddress,
|
||||
address poolOperatorAddress,
|
||||
address makerAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ONLY_CALLABLE_BY_POOL_OPERATOR_OR_MAKER_ERROR_SELECTOR,
|
||||
senderAddress,
|
||||
poolOperatorAddress,
|
||||
makerAddress
|
||||
);
|
||||
}
|
||||
|
||||
function InvalidMakerSignatureError(
|
||||
bytes32 poolId,
|
||||
address makerAddress,
|
||||
bytes memory makerSignature
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INVALID_MAKER_SIGNATURE_ERROR_SELECTOR,
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerSignature
|
||||
);
|
||||
}
|
||||
|
||||
function MakerAddressAlreadyRegisteredError(
|
||||
address makerAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
MAKER_ADDRESS_ALREADY_REGISTERED_ERROR_SELECTOR,
|
||||
makerAddress
|
||||
);
|
||||
}
|
||||
|
||||
function MakerAddressNotRegisteredError(
|
||||
address makerAddress,
|
||||
bytes32 makerPoolId,
|
||||
bytes32 poolId
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
MAKER_ADDRESS_NOT_REGISTERED_ERROR_SELECTOR,
|
||||
makerAddress,
|
||||
makerPoolId,
|
||||
poolId
|
||||
);
|
||||
}
|
||||
|
||||
function WithdrawAmountExceedsMemberBalanceError(
|
||||
uint256 withdrawAmount,
|
||||
uint256 balance
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
WITHDRAW_AMOUNT_EXCEEDS_MEMBER_BALANCE_ERROR_SELECTOR,
|
||||
withdrawAmount,
|
||||
balance
|
||||
);
|
||||
}
|
||||
|
||||
function BlockTimestampTooLowError(
|
||||
uint64 epochEndTime,
|
||||
uint64 currentBlockTimestamp
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
BLOCK_TIMESTAMP_TOO_LOW_ERROR_SELECTOR,
|
||||
epochEndTime,
|
||||
currentBlockTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyCallableByStakingContractError(
|
||||
address senderAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ONLY_CALLABLE_BY_STAKING_CONTRACT_ERROR_SELECTOR,
|
||||
senderAddress
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyCallableIfInCatastrophicFailureError()
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return ONLY_CALLABLE_IF_IN_CATASTROPHIC_FAILURE_ERROR;
|
||||
}
|
||||
|
||||
function OnlyCallableIfNotInCatastrophicFailureError()
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return ONLY_CALLABLE_IF_NOT_IN_CATASTROPHIC_FAILURE_ERROR;
|
||||
}
|
||||
|
||||
function AmountExceedsBalanceOfPoolError(
|
||||
uint256 amount,
|
||||
uint96 poolBalance
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
AMOUNT_EXCEEDS_BALANCE_OF_POOL_ERROR_SELECTOR,
|
||||
amount,
|
||||
poolBalance
|
||||
);
|
||||
}
|
||||
|
||||
function OperatorShareMustBeBetween0And100Error(
|
||||
bytes32 poolId,
|
||||
uint8 poolOperatorShare
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
OPERATOR_SHARE_MUST_BE_BETWEEN_0_AND_100_ERROR_SELECTOR,
|
||||
poolId,
|
||||
poolOperatorShare
|
||||
);
|
||||
}
|
||||
|
||||
function PoolAlreadyExistsError(
|
||||
bytes32 poolId
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
POOL_ALREADY_EXISTS_ERROR_SELECTOR,
|
||||
poolId
|
||||
);
|
||||
}
|
||||
}
|
@@ -18,6 +18,8 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../libs/LibSafeMath.sol";
|
||||
import "../libs/LibRewardMath.sol";
|
||||
import "../immutable/MixinConstants.sol";
|
||||
@@ -62,7 +64,7 @@ import "./MixinTimeLockedStake.sol";
|
||||
///
|
||||
/// -- Valid State Transtions --
|
||||
/// Activated -> Deactivated & TimeLocked
|
||||
///
|
||||
///
|
||||
/// Activated & Delegated -> Deactivated & TimeLocked
|
||||
///
|
||||
/// Deactivated & TimeLocked -> Deactivated & Withdrawable
|
||||
@@ -117,10 +119,13 @@ contract MixinStake is
|
||||
{
|
||||
address owner = msg.sender;
|
||||
_syncTimeLockedStake(owner);
|
||||
require(
|
||||
amount <= getDeactivatedStake(owner),
|
||||
"INSUFFICIENT_BALANCE"
|
||||
);
|
||||
if (amount > getDeactivatedStake(owner)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.InsufficientBalanceError(
|
||||
amount,
|
||||
getDeactivatedStake(owner)
|
||||
));
|
||||
}
|
||||
|
||||
_burnStake(owner, amount);
|
||||
}
|
||||
|
||||
@@ -131,10 +136,13 @@ contract MixinStake is
|
||||
{
|
||||
address owner = msg.sender;
|
||||
_syncTimeLockedStake(owner);
|
||||
require(
|
||||
amount <= getActivatableStake(owner),
|
||||
"INSUFFICIENT_BALANCE"
|
||||
);
|
||||
if (amount > getActivatableStake(owner)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.InsufficientBalanceError(
|
||||
amount,
|
||||
getActivatableStake(owner)
|
||||
));
|
||||
}
|
||||
|
||||
activatedStakeByOwner[owner] = activatedStakeByOwner[owner]._add(amount);
|
||||
totalActivatedStake = totalActivatedStake._add(amount);
|
||||
}
|
||||
@@ -146,10 +154,13 @@ contract MixinStake is
|
||||
{
|
||||
address owner = msg.sender;
|
||||
_syncTimeLockedStake(owner);
|
||||
require(
|
||||
amount <= getActivatedStake(owner),
|
||||
"INSUFFICIENT_BALANCE"
|
||||
);
|
||||
if (amount > getActivatedStake(owner)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.InsufficientBalanceError(
|
||||
amount,
|
||||
getActivatedStake(owner)
|
||||
));
|
||||
}
|
||||
|
||||
activatedStakeByOwner[owner] = activatedStakeByOwner[owner]._sub(amount);
|
||||
totalActivatedStake = totalActivatedStake._sub(amount);
|
||||
_timeLockStake(owner, amount);
|
||||
|
@@ -19,6 +19,8 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../libs/LibSafeMath.sol";
|
||||
import "../libs/LibSignatureValidator.sol";
|
||||
import "../libs/LibEIP712Hash.sol";
|
||||
@@ -32,7 +34,7 @@ import "./MixinStakingPoolRewardVault.sol";
|
||||
/// @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
|
||||
/// 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
|
||||
@@ -66,10 +68,13 @@ contract MixinStakingPool is
|
||||
/// @dev Asserts that the sender is the operator of the input pool.
|
||||
/// @param poolId Pool sender must be operator of.
|
||||
modifier onlyStakingPoolOperator(bytes32 poolId) {
|
||||
require(
|
||||
msg.sender == getStakingPoolOperator(poolId),
|
||||
"ONLY_CALLABLE_BY_POOL_OPERATOR"
|
||||
);
|
||||
address poolOperator = getStakingPoolOperator(poolId);
|
||||
if (msg.sender != poolOperator) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByPoolOperatorError(
|
||||
msg.sender,
|
||||
poolOperator
|
||||
));
|
||||
}
|
||||
|
||||
_;
|
||||
}
|
||||
@@ -78,10 +83,16 @@ contract MixinStakingPool is
|
||||
/// @param poolId Pool sender must be operator of.
|
||||
/// @param makerAddress Address of a maker in the pool.
|
||||
modifier onlyStakingPoolOperatorOrMaker(bytes32 poolId, address makerAddress) {
|
||||
require(
|
||||
msg.sender == getStakingPoolOperator(poolId) || msg.sender == makerAddress,
|
||||
"ONLY_CALLABLE_BY_POOL_OPERATOR_OR_MAKER"
|
||||
);
|
||||
address poolOperator = getStakingPoolOperator(poolId);
|
||||
if (msg.sender != poolOperator && msg.sender != makerAddress) {
|
||||
LibRichErrors.rrevert(
|
||||
LibStakingRichErrors.OnlyCallableByPoolOperatorOrMakerError(
|
||||
msg.sender,
|
||||
poolOperator,
|
||||
makerAddress
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
_;
|
||||
}
|
||||
@@ -129,14 +140,19 @@ contract MixinStakingPool is
|
||||
onlyStakingPoolOperator(poolId)
|
||||
{
|
||||
// sanity check - did maker agree to join this pool?
|
||||
require(
|
||||
isValidMakerSignature(poolId, makerAddress, makerSignature),
|
||||
"INVALID_MAKER_SIGNATURE"
|
||||
);
|
||||
require(
|
||||
!isMakerAssignedToStakingPool(makerAddress),
|
||||
"MAKER_ADDRESS_ALREADY_REGISTERED"
|
||||
);
|
||||
if (!isValidMakerSignature(poolId, makerAddress, makerSignature)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.InvalidMakerSignatureError(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerSignature
|
||||
));
|
||||
}
|
||||
if (isMakerAssignedToStakingPool(makerAddress)) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.MakerAddressAlreadyRegisteredError(
|
||||
makerAddress
|
||||
));
|
||||
}
|
||||
|
||||
poolIdByMakerAddress[makerAddress] = poolId;
|
||||
makerAddressesByPoolId[poolId].push(makerAddress);
|
||||
|
||||
@@ -159,10 +175,14 @@ contract MixinStakingPool is
|
||||
external
|
||||
onlyStakingPoolOperatorOrMaker(poolId, makerAddress)
|
||||
{
|
||||
require(
|
||||
getStakingPoolIdOfMaker(makerAddress) == poolId,
|
||||
"MAKER_ADDRESS_NOT_REGISTERED"
|
||||
);
|
||||
bytes32 makerPoolId = getStakingPoolIdOfMaker(makerAddress);
|
||||
if (makerPoolId != poolId) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.MakerAddressNotRegisteredError(
|
||||
makerAddress,
|
||||
makerPoolId,
|
||||
poolId
|
||||
));
|
||||
}
|
||||
|
||||
// load list of makers for the input pool.
|
||||
address[] storage makerAddressesByPoolIdPtr = makerAddressesByPoolId[poolId];
|
||||
|
@@ -18,6 +18,8 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../libs/LibSafeMath.sol";
|
||||
import "../libs/LibRewardMath.sol";
|
||||
import "../immutable/MixinStorage.sol";
|
||||
@@ -39,7 +41,7 @@ import "./MixinStakingPool.sol";
|
||||
/// is currently at the end of each epoch. Additionally, each member has an associated "Shadow Balance" which is updated only
|
||||
/// when a member delegates/undelegates stake to the pool, along with a "Total Shadow Balance" that represents the cumulative
|
||||
/// Shadow Balances of all members in a pool.
|
||||
///
|
||||
///
|
||||
/// -- Member Balances --
|
||||
/// Terminology:
|
||||
/// Real Balance - The reward balance in ETH of a member.
|
||||
@@ -52,11 +54,11 @@ import "./MixinStakingPool.sol";
|
||||
/// member delegates stake, we *increase* their Shadow Balance and the Total Shadow Balance of the pool.
|
||||
///
|
||||
/// 2. When a member withdraws a portion of their reward, their realized balance increases but their ownership
|
||||
/// within the pool remains unchanged. Thus, we simultaneously *decrease* their Real Balance and
|
||||
/// within the pool remains unchanged. Thus, we simultaneously *decrease* their Real Balance and
|
||||
/// *increase* their Shadow Balance by the amount withdrawn. The cumulative balance decrease and increase, respectively.
|
||||
///
|
||||
/// 3. When a member undelegates, the portion of their reward that corresponds to that stake is also withdrawn. Thus,
|
||||
/// their realized balance *increases* while their ownership of the pool *decreases*. To reflect this, we
|
||||
/// their realized balance *increases* while their ownership of the pool *decreases*. To reflect this, we
|
||||
/// decrease their Shadow Balance, the Total Shadow Balance, their Real Balance, and the Total Real Balance.
|
||||
contract MixinStakingPoolRewards is
|
||||
IStakingEvents,
|
||||
@@ -108,10 +110,12 @@ contract MixinStakingPoolRewards is
|
||||
// sanity checks
|
||||
address payable member = msg.sender;
|
||||
uint256 memberBalance = computeRewardBalanceOfStakingPoolMember(poolId, member);
|
||||
require(
|
||||
amount <= memberBalance,
|
||||
"INVALID_AMOUNT"
|
||||
);
|
||||
if (amount > memberBalance) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.WithdrawAmountExceedsMemberBalanceError(
|
||||
amount,
|
||||
memberBalance
|
||||
));
|
||||
}
|
||||
|
||||
// update shadow rewards
|
||||
shadowRewardsInPoolByOwner[member][poolId] = shadowRewardsInPoolByOwner[member][poolId]._add(amount);
|
||||
@@ -178,7 +182,7 @@ contract MixinStakingPoolRewards is
|
||||
|
||||
/// @dev Returns the shadow balance of a specific member of a staking pool.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param member The member of the pool.
|
||||
/// @param member The member of the pool.
|
||||
/// @return Balance.
|
||||
function getShadowBalanceOfStakingPoolMember(bytes32 poolId, address member)
|
||||
public
|
||||
@@ -201,7 +205,7 @@ contract MixinStakingPoolRewards is
|
||||
|
||||
/// @dev Computes the reward balance in ETH of a specific member of a pool.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param member The member of the pool.
|
||||
/// @param member The member of the pool.
|
||||
/// @return Balance.
|
||||
function computeRewardBalanceOfStakingPoolMember(bytes32 poolId, address member)
|
||||
public
|
||||
@@ -223,7 +227,7 @@ contract MixinStakingPoolRewards is
|
||||
/// with the total shadow balance of the pool. This ensures that
|
||||
/// any rewards belonging to existing members will not be diluted.
|
||||
/// @param poolId Unique Id of pool to join.
|
||||
/// @param member The member to join.
|
||||
/// @param member The member to join.
|
||||
/// @param amountOfStakeToDelegate The stake to be delegated by `member` upon joining.
|
||||
/// @param totalStakeDelegatedToPool The amount of stake currently delegated to the pool.
|
||||
/// This does not include `amountOfStakeToDelegate`.
|
||||
@@ -256,7 +260,7 @@ contract MixinStakingPoolRewards is
|
||||
/// with the total shadow balance of the pool. This ensures that
|
||||
/// any rewards belonging to co-members will not be inflated.
|
||||
/// @param poolId Unique Id of pool to leave.
|
||||
/// @param member The member to leave.
|
||||
/// @param member The member to leave.
|
||||
/// @param amountOfStakeToUndelegate The stake to be undelegated by `member` upon leaving.
|
||||
/// @param totalStakeDelegatedToPoolByMember The amount of stake currently delegated to the pool by the member.
|
||||
/// This includes `amountOfStakeToUndelegate`.
|
||||
|
@@ -18,6 +18,8 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../libs/LibSafeMath.sol";
|
||||
import "../libs/LibSafeMath64.sol";
|
||||
import "../immutable/MixinConstants.sol";
|
||||
@@ -75,7 +77,7 @@ contract MixinScheduler is
|
||||
}
|
||||
|
||||
/// @dev Returns the earliest end time in seconds of this epoch.
|
||||
/// The next epoch can begin once this time is reached.
|
||||
/// The next epoch can begin once this time is reached.
|
||||
/// Epoch period = [startTimeInSeconds..endTimeInSeconds)
|
||||
/// @return Time in seconds.
|
||||
function getCurrentEpochEarliestEndTimeInSeconds()
|
||||
@@ -140,17 +142,20 @@ contract MixinScheduler is
|
||||
uint64 currentBlockTimestamp = block.timestamp._downcastToUint64();
|
||||
|
||||
// validate that we can increment the current epoch
|
||||
require(
|
||||
getCurrentEpochEarliestEndTimeInSeconds() <= currentBlockTimestamp,
|
||||
"BLOCK_TIMESTAMP_TOO_LOW"
|
||||
);
|
||||
uint64 epochEndTime = getCurrentEpochEarliestEndTimeInSeconds();
|
||||
if (epochEndTime > currentBlockTimestamp) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.BlockTimestampTooLowError(
|
||||
epochEndTime,
|
||||
currentBlockTimestamp
|
||||
));
|
||||
}
|
||||
|
||||
// incremment epoch
|
||||
uint64 nextEpoch = currentEpoch._add(1);
|
||||
currentEpoch = nextEpoch;
|
||||
currentEpochStartTimeInSeconds = currentBlockTimestamp;
|
||||
uint64 earliestEndTimeInSeconds = currentEpochStartTimeInSeconds._add(getEpochDurationInSeconds());
|
||||
|
||||
|
||||
// notify of epoch change
|
||||
emit EpochChanged(
|
||||
currentEpoch,
|
||||
@@ -163,7 +168,7 @@ contract MixinScheduler is
|
||||
currentTimeLockPeriod = currentTimeLockPeriod._add(1);
|
||||
currentTimeLockPeriodStartEpoch = currentEpoch;
|
||||
uint64 endEpoch = currentEpoch._add(getTimeLockDurationInEpochs());
|
||||
|
||||
|
||||
// notify
|
||||
emit TimeLockPeriodChanged(
|
||||
currentTimeLockPeriod,
|
||||
|
@@ -19,6 +19,8 @@
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "../interfaces/IVaultCore.sol";
|
||||
|
||||
|
||||
@@ -30,7 +32,7 @@ import "../interfaces/IVaultCore.sol";
|
||||
/// Vaults should only be set to Catastrophic Failure Mode iff there is
|
||||
/// non-recoverable corruption of the staking contracts. If there is a
|
||||
/// recoverable flaw/bug/vulnerability, simply detach the staking contract
|
||||
/// by setting its address to `address(0)`. Once in Catostrophic Failure Mode,
|
||||
/// by setting its address to `address(0)`. Once in Catastrophic Failure Mode,
|
||||
/// a vault cannot be reset to normal mode; this prevents corruption of related
|
||||
/// state in the staking contract.
|
||||
contract MixinVaultCore is
|
||||
@@ -41,39 +43,38 @@ contract MixinVaultCore is
|
||||
// Address of staking contract
|
||||
address payable internal stakingContractAddress;
|
||||
|
||||
// True iff vault has been set to Catostrophic Failure Mode
|
||||
bool internal isInCatostrophicFailure;
|
||||
// True iff vault has been set to Catastrophic Failure Mode
|
||||
bool internal isInCatastrophicFailure;
|
||||
|
||||
/// @dev Constructor.
|
||||
constructor() public {
|
||||
stakingContractAddress = 0x0000000000000000000000000000000000000000;
|
||||
isInCatostrophicFailure = false;
|
||||
isInCatastrophicFailure = false;
|
||||
}
|
||||
|
||||
/// @dev Asserts that the sender (`msg.sender`) is the staking contract.
|
||||
modifier onlyStakingContract {
|
||||
require(
|
||||
msg.sender == stakingContractAddress,
|
||||
"ONLY_CALLABLE_BY_STAKING_CONTRACT"
|
||||
);
|
||||
if (msg.sender != stakingContractAddress) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByStakingContractError(
|
||||
msg.sender
|
||||
));
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Asserts that this contract *is in* Catostrophic Failure Mode.
|
||||
modifier onlyInCatostrophicFailure {
|
||||
require(
|
||||
isInCatostrophicFailure,
|
||||
"ONLY_CALLABLE_IN_CATOSTROPHIC_FAILURE"
|
||||
);
|
||||
/// @dev Asserts that this contract *is in* Catastrophic Failure Mode.
|
||||
modifier onlyInCatastrophicFailure {
|
||||
if (!isInCatastrophicFailure) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableIfInCatastrophicFailureError());
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Asserts that this contract *is not in* Catostrophic Failure Mode.
|
||||
modifier onlyNotInCatostrophicFailure {
|
||||
require(
|
||||
!isInCatostrophicFailure,
|
||||
"ONLY_CALLABLE_NOT_IN_CATOSTROPHIC_FAILURE"
|
||||
);
|
||||
/// @dev Asserts that this contract *is not in* Catastrophic Failure Mode.
|
||||
modifier onlyNotInCatastrophicFailure {
|
||||
if (isInCatastrophicFailure) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableIfNotInCatastrophicFailureError());
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
@@ -88,14 +89,14 @@ contract MixinVaultCore is
|
||||
emit StakingContractChanged(stakingContractAddress);
|
||||
}
|
||||
|
||||
/// @dev Vault enters into Catostrophic Failure Mode.
|
||||
/// @dev Vault enters into Catastrophic Failure Mode.
|
||||
/// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! ***
|
||||
/// Note that only the contract owner can call this function.
|
||||
function enterCatostrophicFailure()
|
||||
function enterCatastrophicFailure()
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
isInCatostrophicFailure = true;
|
||||
emit InCatostrophicFailureMode(msg.sender);
|
||||
isInCatastrophicFailure = true;
|
||||
emit InCatastrophicFailureMode(msg.sender);
|
||||
}
|
||||
}
|
||||
|
@@ -18,8 +18,10 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "../libs/LibSafeMath.sol";
|
||||
import "../libs/LibSafeMath96.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "./MixinVaultCore.sol";
|
||||
import "../interfaces/IStakingPoolRewardVault.sol";
|
||||
import "../immutable/MixinConstants.sol";
|
||||
@@ -28,7 +30,7 @@ import "../immutable/MixinConstants.sol";
|
||||
/// @dev This vault manages staking pool rewards.
|
||||
/// Rewards can be deposited and withdraw by the staking contract.
|
||||
/// There is a "Catastrophic Failure Mode" that, when invoked, only
|
||||
/// allows withdrawals to be made. Once this vault is in catostrophic
|
||||
/// allows withdrawals to be made. Once this vault is in catastrophic
|
||||
/// failure mode, it cannot be returned to normal mode; this prevents
|
||||
/// corruption of related state in the staking contract.
|
||||
///
|
||||
@@ -53,7 +55,7 @@ contract StakingPoolRewardVault is
|
||||
external
|
||||
payable
|
||||
onlyStakingContract
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
emit RewardDeposited(UNKNOWN_STAKING_POOL_ID, msg.value);
|
||||
}
|
||||
@@ -66,7 +68,7 @@ contract StakingPoolRewardVault is
|
||||
external
|
||||
payable
|
||||
onlyStakingContract
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
// update balance of pool
|
||||
uint256 amount = msg.value;
|
||||
@@ -87,7 +89,7 @@ contract StakingPoolRewardVault is
|
||||
function recordDepositFor(bytes32 poolId, uint256 amount)
|
||||
external
|
||||
onlyStakingContract
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
// update balance of pool
|
||||
Balance memory balance = balanceByPoolId[poolId];
|
||||
@@ -105,11 +107,13 @@ contract StakingPoolRewardVault is
|
||||
onlyStakingContract
|
||||
{
|
||||
// sanity check - sufficient balance?
|
||||
require(
|
||||
amount <= balanceByPoolId[poolId].operatorBalance,
|
||||
"AMOUNT_EXCEEDS_BALANCE_OF_POOL"
|
||||
);
|
||||
|
||||
if (amount > balanceByPoolId[poolId].operatorBalance) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.AmountExceedsBalanceOfPoolError(
|
||||
amount,
|
||||
balanceByPoolId[poolId].operatorBalance
|
||||
));
|
||||
}
|
||||
|
||||
// update balance and transfer `amount` in ETH to staking contract
|
||||
balanceByPoolId[poolId].operatorBalance -= amount._downcastToUint96();
|
||||
stakingContractAddress.transfer(amount);
|
||||
@@ -128,10 +132,12 @@ contract StakingPoolRewardVault is
|
||||
onlyStakingContract
|
||||
{
|
||||
// sanity check - sufficient balance?
|
||||
require(
|
||||
amount <= balanceByPoolId[poolId].membersBalance,
|
||||
"AMOUNT_EXCEEDS_BALANCE_OF_POOL"
|
||||
);
|
||||
if (amount > balanceByPoolId[poolId].membersBalance) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.AmountExceedsBalanceOfPoolError(
|
||||
amount,
|
||||
balanceByPoolId[poolId].membersBalance
|
||||
));
|
||||
}
|
||||
|
||||
// update balance and transfer `amount` in ETH to staking contract
|
||||
balanceByPoolId[poolId].membersBalance -= amount._downcastToUint96();
|
||||
@@ -149,20 +155,23 @@ contract StakingPoolRewardVault is
|
||||
function registerStakingPool(bytes32 poolId, uint8 poolOperatorShare)
|
||||
external
|
||||
onlyStakingContract
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
// operator share must be a valid percentage
|
||||
require(
|
||||
poolOperatorShare <= 100,
|
||||
"OPERATOR_SHARE_MUST_BE_BETWEEN_0_AND_100"
|
||||
);
|
||||
if (poolOperatorShare > 100) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.OperatorShareMustBeBetween0And100Error(
|
||||
poolId,
|
||||
poolOperatorShare
|
||||
));
|
||||
}
|
||||
|
||||
// pool must not exist
|
||||
Balance memory balance = balanceByPoolId[poolId];
|
||||
require(
|
||||
!balance.initialized,
|
||||
"POOL_ALREADY_EXISTS"
|
||||
);
|
||||
if (balance.initialized) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.PoolAlreadyExistsError(
|
||||
poolId
|
||||
));
|
||||
}
|
||||
|
||||
// set initial balance
|
||||
balance.initialized = true;
|
||||
|
@@ -29,7 +29,7 @@ import "./MixinVaultCore.sol";
|
||||
/// When a user mints stake, their Zrx Tokens are deposited into this vault.
|
||||
/// Similarly, when they burn stake, their Zrx Tokens are withdrawn from this vault.
|
||||
/// There is a "Catastrophic Failure Mode" that, when invoked, only
|
||||
/// allows withdrawals to be made. Once this vault is in catostrophic
|
||||
/// allows withdrawals to be made. Once this vault is in catastrophic
|
||||
/// failure mode, it cannot be returned to normal mode; this prevents
|
||||
/// corruption of related state in the staking contract.
|
||||
contract ZrxVault is
|
||||
@@ -70,12 +70,12 @@ contract ZrxVault is
|
||||
|
||||
/// @dev Sets the ERC20 proxy.
|
||||
/// Note that only the contract owner can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param erc20ProxyAddress Address of the 0x ERC20 Proxy.
|
||||
function setErc20Proxy(address erc20ProxyAddress)
|
||||
external
|
||||
onlyOwner
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
erc20Proxy = IAssetProxy(erc20ProxyAddress);
|
||||
emit Erc20ProxyChanged(erc20ProxyAddress);
|
||||
@@ -83,12 +83,12 @@ contract ZrxVault is
|
||||
|
||||
/// @dev Sets the Zrx Asset Data.
|
||||
/// Note that only the contract owner can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param _zrxAssetData Zrx asset data for the ERC20 Proxy.
|
||||
function setZrxAssetData(bytes calldata _zrxAssetData)
|
||||
external
|
||||
onlyOwner
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
zrxAssetData = _zrxAssetData;
|
||||
emit ZrxAssetDataChanged(_zrxAssetData);
|
||||
@@ -96,13 +96,13 @@ contract ZrxVault is
|
||||
|
||||
/// @dev Deposit an `amount` of Zrx Tokens from `owner` into the vault.
|
||||
/// Note that only the Staking contract can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param owner of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens to deposit.
|
||||
function depositFrom(address owner, uint256 amount)
|
||||
external
|
||||
onlyStakingContract
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
// update balance
|
||||
balances[owner] = balances[owner]._add(amount);
|
||||
@@ -121,23 +121,23 @@ contract ZrxVault is
|
||||
|
||||
/// @dev Withdraw an `amount` of Zrx Tokens to `owner` from the vault.
|
||||
/// Note that only the Staking contract can call this.
|
||||
/// Note that this can only be called when *not* in Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param owner of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens to withdraw.
|
||||
function withdrawFrom(address owner, uint256 amount)
|
||||
external
|
||||
onlyStakingContract
|
||||
onlyNotInCatostrophicFailure
|
||||
onlyNotInCatastrophicFailure
|
||||
{
|
||||
_withdrawFrom(owner, amount);
|
||||
}
|
||||
|
||||
/// @dev Withdraw ALL Zrx Tokens to `owner` from the vault.
|
||||
/// Note that this can only be called when *in* Catostrophic Failure mode.
|
||||
/// Note that this can only be called when *in* Catastrophic Failure mode.
|
||||
/// @param owner of Zrx Tokens.
|
||||
function withdrawAllFrom(address owner)
|
||||
external
|
||||
onlyInCatostrophicFailure
|
||||
onlyInCatastrophicFailure
|
||||
returns (uint256)
|
||||
{
|
||||
// get total balance
|
||||
|
@@ -36,7 +36,7 @@
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingPoolRewardVault|IStakingProxy|IStructs|IVaultCore|IWallet|IZrxVault|LibEIP712Hash|LibFeeMath|LibFeeMathTest|LibRewardMath|LibSafeMath|LibSafeMath64|LibSafeMath96|LibSignatureValidator|MixinConstants|MixinDelegatedStake|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinOwnable|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakingPool|MixinStakingPoolRewardVault|MixinStakingPoolRewards|MixinStorage|MixinTimeLockedStake|MixinVaultCore|MixinZrxVault|Staking|StakingPoolRewardVault|StakingProxy|ZrxVault).json",
|
||||
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingPoolRewardVault|IStakingProxy|IStructs|IVaultCore|IWallet|IZrxVault|LibEIP712Hash|LibFeeMath|LibFeeMathTest|LibRewardMath|LibSafeMath|LibSafeMath64|LibSafeMath96|LibSignatureValidator|LibStakingRichErrors|MixinConstants|MixinDelegatedStake|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinOwnable|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakingPool|MixinStakingPoolRewardVault|MixinStakingPoolRewards|MixinStorage|MixinTimeLockedStake|MixinVaultCore|MixinZrxVault|Staking|StakingPoolRewardVault|StakingProxy|ZrxVault).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@@ -21,6 +21,7 @@ import * as LibSafeMath from '../generated-artifacts/LibSafeMath.json';
|
||||
import * as LibSafeMath64 from '../generated-artifacts/LibSafeMath64.json';
|
||||
import * as LibSafeMath96 from '../generated-artifacts/LibSafeMath96.json';
|
||||
import * as LibSignatureValidator from '../generated-artifacts/LibSignatureValidator.json';
|
||||
import * as LibStakingRichErrors from '../generated-artifacts/LibStakingRichErrors.json';
|
||||
import * as MixinConstants from '../generated-artifacts/MixinConstants.json';
|
||||
import * as MixinDelegatedStake from '../generated-artifacts/MixinDelegatedStake.json';
|
||||
import * as MixinDeploymentConstants from '../generated-artifacts/MixinDeploymentConstants.json';
|
||||
@@ -64,6 +65,7 @@ export const artifacts = {
|
||||
LibSafeMath64: LibSafeMath64 as ContractArtifact,
|
||||
LibSafeMath96: LibSafeMath96 as ContractArtifact,
|
||||
LibSignatureValidator: LibSignatureValidator as ContractArtifact,
|
||||
LibStakingRichErrors: LibStakingRichErrors as ContractArtifact,
|
||||
MixinDelegatedStake: MixinDelegatedStake as ContractArtifact,
|
||||
MixinStake: MixinStake as ContractArtifact,
|
||||
MixinStakeBalances: MixinStakeBalances as ContractArtifact,
|
||||
|
@@ -19,6 +19,7 @@ export * from '../generated-wrappers/lib_safe_math';
|
||||
export * from '../generated-wrappers/lib_safe_math64';
|
||||
export * from '../generated-wrappers/lib_safe_math96';
|
||||
export * from '../generated-wrappers/lib_signature_validator';
|
||||
export * from '../generated-wrappers/lib_staking_rich_errors';
|
||||
export * from '../generated-wrappers/mixin_constants';
|
||||
export * from '../generated-wrappers/mixin_delegated_stake';
|
||||
export * from '../generated-wrappers/mixin_deployment_constants';
|
||||
|
@@ -1,7 +1,5 @@
|
||||
import { expectTransactionFailedAsync } from '@0x/contracts-test-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { expect } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, RevertError } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { StakingWrapper } from '../utils/staking_wrapper';
|
||||
@@ -9,8 +7,6 @@ import { DelegatorBalances, StakerBalances } from '../utils/types';
|
||||
|
||||
import { StakerActor } from './staker_actor';
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
export class DelegatorActor extends StakerActor {
|
||||
constructor(owner: string, stakingWrapper: StakingWrapper) {
|
||||
super(owner, stakingWrapper);
|
||||
@@ -18,7 +14,7 @@ export class DelegatorActor extends StakerActor {
|
||||
public async depositZrxAndDelegateToStakingPoolAsync(
|
||||
poolId: string,
|
||||
amount: BigNumber,
|
||||
revertReason?: RevertReason,
|
||||
revertError?: RevertError,
|
||||
): Promise<void> {
|
||||
// query init balances
|
||||
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
|
||||
@@ -29,8 +25,8 @@ export class DelegatorActor extends StakerActor {
|
||||
poolId,
|
||||
amount,
|
||||
);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
@@ -54,14 +50,14 @@ export class DelegatorActor extends StakerActor {
|
||||
public async activateAndDelegateStakeAsync(
|
||||
poolId: string,
|
||||
amount: BigNumber,
|
||||
revertReason?: RevertReason,
|
||||
revertError?: RevertError,
|
||||
): Promise<void> {
|
||||
// query init balances
|
||||
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
|
||||
// activate and delegate
|
||||
const txReceiptPromise = this._stakingWrapper.activateAndDelegateStakeAsync(this._owner, poolId, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
@@ -89,7 +85,7 @@ export class DelegatorActor extends StakerActor {
|
||||
public async deactivateAndTimeLockDelegatedStakeAsync(
|
||||
poolId: string,
|
||||
amount: BigNumber,
|
||||
revertReason?: RevertReason,
|
||||
revertError?: RevertError,
|
||||
): Promise<void> {
|
||||
// query init balances
|
||||
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
|
||||
@@ -99,8 +95,8 @@ export class DelegatorActor extends StakerActor {
|
||||
poolId,
|
||||
amount,
|
||||
);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { expectTransactionFailedAsync } from '@0x/contracts-test-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import * as chai from 'chai';
|
||||
import { expect } from '@0x/contracts-test-utils';
|
||||
import { RevertError } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants as stakingConstants } from '../utils/constants';
|
||||
@@ -8,20 +7,18 @@ import { StakingWrapper } from '../utils/staking_wrapper';
|
||||
|
||||
import { BaseActor } from './base_actor';
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
export class PoolOperatorActor extends BaseActor {
|
||||
constructor(owner: string, stakingWrapper: StakingWrapper) {
|
||||
super(owner, stakingWrapper);
|
||||
}
|
||||
|
||||
public async createStakingPoolAsync(operatorShare: number, revertReason?: RevertReason): Promise<string> {
|
||||
public async createStakingPoolAsync(operatorShare: number, revertError?: RevertError): Promise<string> {
|
||||
// query next pool id
|
||||
const nextPoolId = await this._stakingWrapper.getNextStakingPoolIdAsync();
|
||||
// create pool
|
||||
const poolIdPromise = this._stakingWrapper.createStakingPoolAsync(this._owner, operatorShare);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(poolIdPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(poolIdPromise).to.revertWith(revertError);
|
||||
return '';
|
||||
}
|
||||
const poolId = await poolIdPromise;
|
||||
@@ -33,7 +30,7 @@ export class PoolOperatorActor extends BaseActor {
|
||||
poolId: string,
|
||||
makerAddress: string,
|
||||
makerSignature: string,
|
||||
revertReason?: RevertReason,
|
||||
revertError?: RevertError,
|
||||
): Promise<void> {
|
||||
// add maker
|
||||
const txReceiptPromise = this._stakingWrapper.addMakerToStakingPoolAsync(
|
||||
@@ -42,8 +39,8 @@ export class PoolOperatorActor extends BaseActor {
|
||||
makerSignature,
|
||||
this._owner,
|
||||
);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
@@ -57,7 +54,7 @@ export class PoolOperatorActor extends BaseActor {
|
||||
public async removeMakerFromStakingPoolAsync(
|
||||
poolId: string,
|
||||
makerAddress: string,
|
||||
revertReason?: RevertReason,
|
||||
revertError?: RevertError,
|
||||
): Promise<void> {
|
||||
// remove maker
|
||||
const txReceiptPromise = this._stakingWrapper.removeMakerFromStakingPoolAsync(
|
||||
@@ -65,8 +62,8 @@ export class PoolOperatorActor extends BaseActor {
|
||||
makerAddress,
|
||||
this._owner,
|
||||
);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
import { expectTransactionFailedAsync } from '@0x/contracts-test-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { expect } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, RevertError } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { StakingWrapper } from '../utils/staking_wrapper';
|
||||
@@ -9,24 +7,22 @@ import { StakerBalances } from '../utils/types';
|
||||
|
||||
import { BaseActor } from './base_actor';
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
export class StakerActor extends BaseActor {
|
||||
constructor(owner: string, stakingWrapper: StakingWrapper) {
|
||||
super(owner, stakingWrapper);
|
||||
}
|
||||
public async depositZrxAndMintDeactivatedStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
public async depositZrxAndMintDeactivatedStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
|
||||
await this._stakingWrapper.depositZrxAndMintDeactivatedStakeAsync(this._owner, amount);
|
||||
throw new Error('Checks Unimplemented');
|
||||
}
|
||||
public async depositZrxAndMintActivatedStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
public async depositZrxAndMintActivatedStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
|
||||
// query init balances
|
||||
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
|
||||
const initStakerBalances = await this.getBalancesAsync();
|
||||
// deposit stake
|
||||
const txReceiptPromise = this._stakingWrapper.depositZrxAndMintActivatedStakeAsync(this._owner, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
@@ -42,13 +38,13 @@ export class StakerActor extends BaseActor {
|
||||
const finalZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
|
||||
expect(finalZrxBalanceOfVault).to.be.bignumber.equal(initZrxBalanceOfVault.plus(amount));
|
||||
}
|
||||
public async activateStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
public async activateStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
|
||||
// query init balances
|
||||
const initStakerBalances = await this.getBalancesAsync();
|
||||
// activate stake
|
||||
const txReceiptPromise = this._stakingWrapper.activateStakeAsync(this._owner, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
@@ -61,13 +57,13 @@ export class StakerActor extends BaseActor {
|
||||
expectedStakerBalances.deactivatedStakeBalance = initStakerBalances.deactivatedStakeBalance.minus(amount);
|
||||
await this.assertBalancesAsync(expectedStakerBalances);
|
||||
}
|
||||
public async deactivateAndTimeLockStakeAsync(amount: BigNumber, revertReason?: RevertReason): Promise<void> {
|
||||
public async deactivateAndTimeLockStakeAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
|
||||
// query init balances
|
||||
const initStakerBalances = await this.getBalancesAsync();
|
||||
// deactivate and timeLock stake
|
||||
const txReceiptPromise = this._stakingWrapper.deactivateAndTimeLockStakeAsync(this._owner, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
@@ -79,17 +75,14 @@ export class StakerActor extends BaseActor {
|
||||
expectedStakerBalances.deactivatedStakeBalance = initStakerBalances.deactivatedStakeBalance.plus(amount);
|
||||
await this.assertBalancesAsync(expectedStakerBalances);
|
||||
}
|
||||
public async burnDeactivatedStakeAndWithdrawZrxAsync(
|
||||
amount: BigNumber,
|
||||
revertReason?: RevertReason,
|
||||
): Promise<void> {
|
||||
public async burnDeactivatedStakeAndWithdrawZrxAsync(amount: BigNumber, revertError?: RevertError): Promise<void> {
|
||||
// query init balances
|
||||
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVaultAsync();
|
||||
const initStakerBalances = await this.getBalancesAsync();
|
||||
// withdraw stake
|
||||
const txReceiptPromise = this._stakingWrapper.burnDeactivatedStakeAndWithdrawZrxAsync(this._owner, amount);
|
||||
if (revertReason !== undefined) {
|
||||
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
|
||||
if (revertError !== undefined) {
|
||||
await expect(txReceiptPromise).to.revertWith(revertError);
|
||||
return;
|
||||
}
|
||||
await txReceiptPromise;
|
||||
|
@@ -1,19 +1,14 @@
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { StakingWrapper } from './utils/staking_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Exchange Integrations', () => {
|
||||
blockchainTests('Exchange Integrations', env => {
|
||||
// constants
|
||||
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
||||
// tokens & addresses
|
||||
@@ -26,34 +21,22 @@ describe('Exchange Integrations', () => {
|
||||
let stakingWrapper: StakingWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
// tests
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// create accounts
|
||||
accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
exchange = accounts[1];
|
||||
// deploy erc20 proxy
|
||||
erc20Wrapper = new ERC20Wrapper(provider, accounts, owner);
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
||||
erc20ProxyContract = await erc20Wrapper.deployProxyAsync();
|
||||
// deploy zrx token
|
||||
[zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, ZRX_TOKEN_DECIMALS);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
// deploy staking contracts
|
||||
stakingWrapper = new StakingWrapper(provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
stakingWrapper = new StakingWrapper(env.provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
await stakingWrapper.deployAndConfigureContractsAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Exchange Tracking in Staking Contract', () => {
|
||||
blockchainTests.resets('Exchange Tracking in Staking Contract', () => {
|
||||
it('basic exchange tracking', async () => {
|
||||
// 1 try querying an invalid addresses
|
||||
const invalidAddress = '0x0000000000000000000000000000000000000001';
|
||||
@@ -64,19 +47,17 @@ describe('Exchange Integrations', () => {
|
||||
const isValidAddressValid = await stakingWrapper.isValidExchangeAddressAsync(exchange);
|
||||
expect(isValidAddressValid).to.be.true();
|
||||
// 3 try adding valid address again
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.addExchangeAddressAsync(exchange),
|
||||
RevertReason.ExchangeAddressAlreadyRegistered,
|
||||
);
|
||||
let revertError = new StakingRevertErrors.ExchangeAddressAlreadyRegisteredError(exchange);
|
||||
let tx = stakingWrapper.addExchangeAddressAsync(exchange);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
// 4 remove valid address
|
||||
await stakingWrapper.removeExchangeAddressAsync(exchange);
|
||||
const isValidAddressStillValid = await stakingWrapper.isValidExchangeAddressAsync(exchange);
|
||||
expect(isValidAddressStillValid).to.be.false();
|
||||
// 5 try removing valid address again
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.removeExchangeAddressAsync(exchange),
|
||||
RevertReason.ExchangeAddressNotRegistered,
|
||||
);
|
||||
revertError = new StakingRevertErrors.ExchangeAddressNotRegisteredError(exchange);
|
||||
tx = stakingWrapper.removeExchangeAddressAsync(exchange);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
// @todo should not be able to add / remove an exchange if not contract owner.
|
||||
});
|
||||
});
|
||||
|
@@ -1,10 +1,8 @@
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -13,11 +11,8 @@ import { PoolOperatorActor } from './actors/pool_operator_actor';
|
||||
import { constants as stakingConstants } from './utils/constants';
|
||||
import { StakingWrapper } from './utils/staking_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Staking Pool Management', () => {
|
||||
blockchainTests('Staking Pool Management', env => {
|
||||
// constants
|
||||
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
||||
// tokens & addresses
|
||||
@@ -30,34 +25,22 @@ describe('Staking Pool Management', () => {
|
||||
let stakingWrapper: StakingWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
// tests
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// create accounts
|
||||
accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
users = accounts.slice(1);
|
||||
// deploy erc20 proxy
|
||||
erc20Wrapper = new ERC20Wrapper(provider, accounts, owner);
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
||||
erc20ProxyContract = await erc20Wrapper.deployProxyAsync();
|
||||
// deploy zrx token
|
||||
[zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, ZRX_TOKEN_DECIMALS);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
// deploy staking contracts
|
||||
stakingWrapper = new StakingWrapper(provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
stakingWrapper = new StakingWrapper(env.provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
await stakingWrapper.deployAndConfigureContractsAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Staking Pool Management', () => {
|
||||
blockchainTests.resets('Staking Pool Management', () => {
|
||||
it('Should successfully create a pool', async () => {
|
||||
// test parameters
|
||||
const operatorAddress = users[0];
|
||||
@@ -128,13 +111,9 @@ describe('Staking Pool Management', () => {
|
||||
// add maker to pool
|
||||
const makerApproval = maker.signApprovalForStakingPool(poolId);
|
||||
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature);
|
||||
const revertError = new StakingRevertErrors.MakerAddressAlreadyRegisteredError(makerAddress);
|
||||
// add same maker to pool again
|
||||
await poolOperator.addMakerToStakingPoolAsync(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerApproval.signature,
|
||||
RevertReason.MakerAddressAlreadyRegistered,
|
||||
);
|
||||
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature, revertError);
|
||||
});
|
||||
it('Should fail to remove a maker that does not exist', async () => {
|
||||
// test parameters
|
||||
@@ -145,12 +124,13 @@ describe('Staking Pool Management', () => {
|
||||
// create pool
|
||||
const poolId = await poolOperator.createStakingPoolAsync(operatorShare);
|
||||
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
||||
// remove non-existent maker from pool
|
||||
await poolOperator.removeMakerFromStakingPoolAsync(
|
||||
poolId,
|
||||
const revertError = new StakingRevertErrors.MakerAddressNotRegisteredError(
|
||||
makerAddress,
|
||||
RevertReason.MakerAddressNotRegistered,
|
||||
stakingConstants.NIL_POOL_ID,
|
||||
poolId,
|
||||
);
|
||||
// remove non-existent maker from pool
|
||||
await poolOperator.removeMakerFromStakingPoolAsync(poolId, makerAddress, revertError);
|
||||
});
|
||||
it('Should fail to add a maker who signed with the wrong private key', async () => {
|
||||
// test parameters
|
||||
@@ -165,14 +145,14 @@ describe('Staking Pool Management', () => {
|
||||
// create pool
|
||||
const poolId = await poolOperator.createStakingPoolAsync(operatorShare);
|
||||
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
||||
// add maker to pool
|
||||
// add maker to poolxx
|
||||
const makerApproval = maker.signApprovalForStakingPool(poolId);
|
||||
await poolOperator.addMakerToStakingPoolAsync(
|
||||
const revertError = new StakingRevertErrors.InvalidMakerSignatureError(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerApproval.signature,
|
||||
RevertReason.InvalidMakerSignature,
|
||||
);
|
||||
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature, revertError);
|
||||
});
|
||||
it('Should fail to add a maker who signed with the wrong staking contract address', async () => {
|
||||
// test parameters
|
||||
@@ -188,12 +168,12 @@ describe('Staking Pool Management', () => {
|
||||
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
||||
// add maker to pool
|
||||
const makerApproval = maker.signApprovalForStakingPool(poolId);
|
||||
await poolOperator.addMakerToStakingPoolAsync(
|
||||
const revertError = new StakingRevertErrors.InvalidMakerSignatureError(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerApproval.signature,
|
||||
RevertReason.InvalidMakerSignature,
|
||||
);
|
||||
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature, revertError);
|
||||
});
|
||||
it('Should fail to add a maker who signed with the wrong chain id', async () => {
|
||||
// test parameters
|
||||
@@ -216,12 +196,12 @@ describe('Staking Pool Management', () => {
|
||||
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
||||
// add maker to pool
|
||||
const makerApproval = maker.signApprovalForStakingPool(poolId);
|
||||
await poolOperator.addMakerToStakingPoolAsync(
|
||||
const revertError = new StakingRevertErrors.InvalidMakerSignatureError(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerApproval.signature,
|
||||
RevertReason.InvalidMakerSignature,
|
||||
);
|
||||
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature, revertError);
|
||||
});
|
||||
it('Should fail to add a maker when called by someone other than the pool operator', async () => {
|
||||
// test parameters
|
||||
@@ -236,15 +216,17 @@ describe('Staking Pool Management', () => {
|
||||
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
||||
// add maker to pool
|
||||
const makerApproval = maker.signApprovalForStakingPool(poolId);
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.addMakerToStakingPoolAsync(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerApproval.signature,
|
||||
notOperatorAddress,
|
||||
),
|
||||
RevertReason.OnlyCallableByPoolOperator,
|
||||
const revertError = new StakingRevertErrors.OnlyCallableByPoolOperatorError(
|
||||
notOperatorAddress,
|
||||
operatorAddress,
|
||||
);
|
||||
const tx = stakingWrapper.addMakerToStakingPoolAsync(
|
||||
poolId,
|
||||
makerAddress,
|
||||
makerApproval.signature,
|
||||
notOperatorAddress,
|
||||
);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
});
|
||||
it('Should fail to remove a maker when called by someone other than the pool operator', async () => {
|
||||
// test parameters
|
||||
@@ -261,10 +243,13 @@ describe('Staking Pool Management', () => {
|
||||
const makerApproval = maker.signApprovalForStakingPool(poolId);
|
||||
await poolOperator.addMakerToStakingPoolAsync(poolId, makerAddress, makerApproval.signature);
|
||||
// try to remove the maker address from an address other than the operator
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.removeMakerFromStakingPoolAsync(poolId, makerAddress, notOperatorAddress),
|
||||
RevertReason.OnlyCallableByPoolOperatorOrMaker,
|
||||
const revertError = new StakingRevertErrors.OnlyCallableByPoolOperatorOrMakerError(
|
||||
notOperatorAddress,
|
||||
operatorAddress,
|
||||
makerAddress,
|
||||
);
|
||||
const tx = stakingWrapper.removeMakerFromStakingPoolAsync(poolId, makerAddress, notOperatorAddress);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,17 +1,14 @@
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { Simulation } from './utils/Simulation';
|
||||
import { StakingWrapper } from './utils/staking_wrapper';
|
||||
chaiSetup.configure();
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('End-To-End Simulations', () => {
|
||||
blockchainTests('End-To-End Simulations', env => {
|
||||
// constants
|
||||
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
||||
// tokens & addresses
|
||||
@@ -25,37 +22,25 @@ describe('End-To-End Simulations', () => {
|
||||
let stakingWrapper: StakingWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
// tests
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// create accounts
|
||||
accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
exchange = accounts[1];
|
||||
users = accounts.slice(2);
|
||||
users = [...users, ...users]; // @TODO figure out how to get more addresses from `web3Wrapper`
|
||||
|
||||
// deploy erc20 proxy
|
||||
erc20Wrapper = new ERC20Wrapper(provider, accounts, owner);
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
||||
erc20ProxyContract = await erc20Wrapper.deployProxyAsync();
|
||||
// deploy zrx token
|
||||
[zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, ZRX_TOKEN_DECIMALS);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
// deploy staking contracts
|
||||
stakingWrapper = new StakingWrapper(provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
stakingWrapper = new StakingWrapper(env.provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
await stakingWrapper.deployAndConfigureContractsAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Simulations', () => {
|
||||
blockchainTests.resets('Simulations', () => {
|
||||
it('Should successfully simulate (no delegators / no shadow balances)', async () => {
|
||||
// @TODO - get computations more accurate
|
||||
const simulationParams = {
|
||||
@@ -348,10 +333,9 @@ describe('End-To-End Simulations', () => {
|
||||
it('Should not be able to record a protocol fee from an unknown exchange', async () => {
|
||||
const makerAddress = users[1];
|
||||
const protocolFee = new BigNumber(1);
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.payProtocolFeeAsync(makerAddress, protocolFee, owner),
|
||||
RevertReason.OnlyCallableByExchange,
|
||||
);
|
||||
const revertError = new StakingRevertErrors.OnlyCallableByExchangeError(owner);
|
||||
const tx = stakingWrapper.payProtocolFeeAsync(makerAddress, protocolFee, owner);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -10,10 +9,8 @@ import { DelegatorActor } from './actors/delegator_actor';
|
||||
import { StakerActor } from './actors/staker_actor';
|
||||
import { StakingWrapper } from './utils/staking_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Staking & Delegating', () => {
|
||||
blockchainTests('Staking & Delegating', env => {
|
||||
// constants
|
||||
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
||||
// tokens & addresses
|
||||
@@ -26,34 +23,22 @@ describe('Staking & Delegating', () => {
|
||||
let stakingWrapper: StakingWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
// tests
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// create accounts
|
||||
accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
stakers = accounts.slice(2, 5);
|
||||
// deploy erc20 proxy
|
||||
erc20Wrapper = new ERC20Wrapper(provider, accounts, owner);
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
||||
erc20ProxyContract = await erc20Wrapper.deployProxyAsync();
|
||||
// deploy zrx token
|
||||
[zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, ZRX_TOKEN_DECIMALS);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
// deploy staking contracts
|
||||
stakingWrapper = new StakingWrapper(provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
stakingWrapper = new StakingWrapper(env.provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
await stakingWrapper.deployAndConfigureContractsAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Staking', () => {
|
||||
blockchainTests.resets('Staking', () => {
|
||||
it('basic staking/unstaking', async () => {
|
||||
// setup test parameters
|
||||
const amountToStake = StakingWrapper.toBaseUnitAmount(10);
|
||||
@@ -66,9 +51,10 @@ describe('Staking & Delegating', () => {
|
||||
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.
|
||||
await staker.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
|
||||
const revertError = new StakingRevertErrors.InsufficientBalanceError(amountToReactivate, 0);
|
||||
await staker.activateStakeAsync(amountToReactivate, revertError);
|
||||
await staker.skipToNextTimeLockPeriodAsync();
|
||||
await staker.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
|
||||
await staker.activateStakeAsync(amountToReactivate, revertError);
|
||||
await staker.skipToNextTimeLockPeriodAsync();
|
||||
// this forces the internal state to update; it is not necessary to activate stake, but
|
||||
// allows us to check that state is updated correctly after a timeLock period rolls over.
|
||||
@@ -79,7 +65,7 @@ describe('Staking & Delegating', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delegating', () => {
|
||||
blockchainTests.resets('Delegating', () => {
|
||||
it('basic delegating/undelegating', async () => {
|
||||
// setup test parameters
|
||||
const amountToDelegate = StakingWrapper.toBaseUnitAmount(10);
|
||||
@@ -95,9 +81,10 @@ describe('Staking & Delegating', () => {
|
||||
await delegator.deactivateAndTimeLockDelegatedStakeAsync(poolId, amountToDeactivate);
|
||||
// note - we cannot re-activate this timeLocked stake until at least one full timeLock period has passed.
|
||||
// attempting to do so should revert.
|
||||
await delegator.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
|
||||
const revertError = new StakingRevertErrors.InsufficientBalanceError(amountToReactivate, 0);
|
||||
await delegator.activateStakeAsync(amountToReactivate, revertError);
|
||||
await delegator.skipToNextTimeLockPeriodAsync();
|
||||
await delegator.activateStakeAsync(amountToReactivate, RevertReason.InsufficientBalance);
|
||||
await delegator.activateStakeAsync(amountToReactivate, revertError);
|
||||
await delegator.skipToNextTimeLockPeriodAsync();
|
||||
// this forces the internal state to update; it is not necessary to activate stake, but
|
||||
// allows us to check that state is updated correctly after a timeLock period rolls over.
|
||||
|
@@ -660,7 +660,7 @@ export class StakingWrapper {
|
||||
public async rewardVaultEnterCatastrophicFailureModeAsync(
|
||||
zeroExMultisigAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingPoolRewardVaultContract().enterCatostrophicFailure.getABIEncodedTransactionData();
|
||||
const calldata = this.getStakingPoolRewardVaultContract().enterCatastrophicFailure.getABIEncodedTransactionData();
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, zeroExMultisigAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
|
@@ -1,17 +1,14 @@
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { chaiSetup, expectTransactionFailedAsync, provider, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { StakingWrapper } from './utils/staking_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Staking Vaults', () => {
|
||||
blockchainTests('Staking Vaults', env => {
|
||||
// constants
|
||||
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
||||
// tokens & addresses
|
||||
@@ -24,34 +21,22 @@ describe('Staking Vaults', () => {
|
||||
let stakingWrapper: StakingWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
// tests
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// create accounts
|
||||
accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
users = accounts.slice(1);
|
||||
// deploy erc20 proxy
|
||||
erc20Wrapper = new ERC20Wrapper(provider, accounts, owner);
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
||||
erc20ProxyContract = await erc20Wrapper.deployProxyAsync();
|
||||
// deploy zrx token
|
||||
[zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, ZRX_TOKEN_DECIMALS);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
// deploy staking contracts
|
||||
stakingWrapper = new StakingWrapper(provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
stakingWrapper = new StakingWrapper(env.provider, owner, erc20ProxyContract, zrxTokenContract, accounts);
|
||||
await stakingWrapper.deployAndConfigureContractsAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Reward Vault', () => {
|
||||
blockchainTests.resets('Reward Vault', () => {
|
||||
it.skip('basic management', async () => {
|
||||
// 1 setup test parameters
|
||||
const poolOperator = users[0];
|
||||
@@ -62,15 +47,13 @@ describe('Staking Vaults', () => {
|
||||
// create pool in vault
|
||||
await stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, stakingContractAddress);
|
||||
// should fail to create pool if it already exists
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, stakingContractAddress),
|
||||
RevertReason.PoolAlreadyExists,
|
||||
);
|
||||
let revertError = new StakingRevertErrors.PoolAlreadyExistsError(poolId);
|
||||
let tx = stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, stakingContractAddress);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
// should fail to create a pool from an address other than the staking contract
|
||||
await expectTransactionFailedAsync(
|
||||
stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, notStakingContractAddress),
|
||||
RevertReason.OnlyCallableByStakingContract,
|
||||
);
|
||||
revertError = new StakingRevertErrors.OnlyCallableByStakingContractError(notStakingContractAddress);
|
||||
tx = stakingWrapper.rewardVaultRegisterPoolAsync(poolId, operatorShare, notStakingContractAddress);
|
||||
await expect(tx).to.revertWith(revertError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"generated-artifacts/LibSafeMath64.json",
|
||||
"generated-artifacts/LibSafeMath96.json",
|
||||
"generated-artifacts/LibSignatureValidator.json",
|
||||
"generated-artifacts/LibStakingRichErrors.json",
|
||||
"generated-artifacts/MixinConstants.json",
|
||||
"generated-artifacts/MixinDelegatedStake.json",
|
||||
"generated-artifacts/MixinDeploymentConstants.json",
|
||||
|
@@ -164,7 +164,7 @@ function defineBlockchainSuite<T>(
|
||||
const env = BlockchainTestsEnvironmentSingleton.create();
|
||||
return describeCall(description, function(this: ISuiteCallbackContext): void {
|
||||
before(async () => env.blockchainLifecycle.startAsync());
|
||||
before(async () => env.blockchainLifecycle.revertAsync());
|
||||
after(async () => env.blockchainLifecycle.revertAsync());
|
||||
callback.call(this, env);
|
||||
});
|
||||
}
|
||||
|
@@ -16,8 +16,8 @@ library LibSafeMath {
|
||||
}
|
||||
uint256 c = a * b;
|
||||
if (c / a != b) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_MULTIPLICATION_OVERFLOW,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
@@ -31,8 +31,8 @@ library LibSafeMath {
|
||||
returns (uint256)
|
||||
{
|
||||
if (b == 0) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_DIVISION_BY_ZERO,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
|
||||
a,
|
||||
b
|
||||
));
|
||||
@@ -47,8 +47,8 @@ library LibSafeMath {
|
||||
returns (uint256)
|
||||
{
|
||||
if (b > a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_SUBTRACTION_UNDERFLOW,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
@@ -63,8 +63,8 @@ library LibSafeMath {
|
||||
{
|
||||
uint256 c = a + b;
|
||||
if (c < a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_ADDITION_OVERFLOW,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
|
@@ -3,20 +3,37 @@ pragma solidity ^0.5.9;
|
||||
|
||||
library LibSafeMathRichErrors {
|
||||
|
||||
// bytes4(keccak256("SafeMathError(uint8,uint256,uint256)"))
|
||||
bytes4 internal constant SAFE_MATH_ERROR =
|
||||
0x35a51a70;
|
||||
// bytes4(keccak256("Uint256BinOpError(uint8,uint256,uint256)"))
|
||||
bytes4 internal constant UINT256_BINOP_ERROR_SELECTOR =
|
||||
0xe946c1bb;
|
||||
|
||||
enum SafeMathErrorCodes {
|
||||
UINT256_ADDITION_OVERFLOW,
|
||||
UINT256_MULTIPLICATION_OVERFLOW,
|
||||
UINT256_SUBTRACTION_UNDERFLOW,
|
||||
UINT256_DIVISION_BY_ZERO
|
||||
// bytes4(keccak256("Uint96BinOpError(uint8,uint96,uint96)"))
|
||||
bytes4 internal constant UINT96_BINOP_ERROR_SELECTOR =
|
||||
0xe486a353;
|
||||
|
||||
// bytes4(keccak256("Uint64BinOpError(uint8,uint64,uint64)"))
|
||||
bytes4 internal constant UINT64_BINOP_ERROR_SELECTOR =
|
||||
0x67e71b32;
|
||||
|
||||
// bytes4(keccak256("Uint256DowncastError(uint8,uint256)"))
|
||||
bytes4 internal constant UINT256_DOWNCAST_ERROR_SELECTOR =
|
||||
0xc996af7b;
|
||||
|
||||
enum BinOpErrorCodes {
|
||||
ADDITION_OVERFLOW,
|
||||
MULTIPLICATION_OVERFLOW,
|
||||
SUBTRACTION_UNDERFLOW,
|
||||
DIVISION_BY_ZERO
|
||||
}
|
||||
|
||||
enum DowncastErrorCodes {
|
||||
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64,
|
||||
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96
|
||||
}
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function SafeMathError(
|
||||
SafeMathErrorCodes errorCode,
|
||||
function Uint256BinOpError(
|
||||
BinOpErrorCodes errorCode,
|
||||
uint256 a,
|
||||
uint256 b
|
||||
)
|
||||
@@ -25,10 +42,59 @@ library LibSafeMathRichErrors {
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
SAFE_MATH_ERROR,
|
||||
UINT256_BINOP_ERROR_SELECTOR,
|
||||
errorCode,
|
||||
a,
|
||||
b
|
||||
);
|
||||
}
|
||||
|
||||
function Uint96BinOpError(
|
||||
BinOpErrorCodes errorCode,
|
||||
uint96 a,
|
||||
uint96 b
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
UINT96_BINOP_ERROR_SELECTOR,
|
||||
errorCode,
|
||||
a,
|
||||
b
|
||||
);
|
||||
}
|
||||
|
||||
function Uint64BinOpError(
|
||||
BinOpErrorCodes errorCode,
|
||||
uint64 a,
|
||||
uint64 b
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
UINT64_BINOP_ERROR_SELECTOR,
|
||||
errorCode,
|
||||
a,
|
||||
b
|
||||
);
|
||||
}
|
||||
|
||||
function Uint256DowncastError(
|
||||
DowncastErrorCodes errorCode,
|
||||
uint256 a
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
UINT256_DOWNCAST_ERROR_SELECTOR,
|
||||
errorCode,
|
||||
a
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -16,8 +16,8 @@ contract SafeMath {
|
||||
}
|
||||
uint256 c = a * b;
|
||||
if (c / a != b) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_MULTIPLICATION_OVERFLOW,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
@@ -31,8 +31,8 @@ contract SafeMath {
|
||||
returns (uint256)
|
||||
{
|
||||
if (b == 0) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_DIVISION_BY_ZERO,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
|
||||
a,
|
||||
b
|
||||
));
|
||||
@@ -47,8 +47,8 @@ contract SafeMath {
|
||||
returns (uint256)
|
||||
{
|
||||
if (b > a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_SUBTRACTION_UNDERFLOW,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
@@ -63,8 +63,8 @@ contract SafeMath {
|
||||
{
|
||||
uint256 c = a + b;
|
||||
if (c < a) {
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.SafeMathError(
|
||||
LibSafeMathRichErrors.SafeMathErrorCodes.UINT256_ADDITION_OVERFLOW,
|
||||
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
|
||||
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
|
||||
a,
|
||||
b
|
||||
));
|
||||
|
@@ -8,11 +8,7 @@ const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||
export function safeAdd(a: BigNumber, b: BigNumber): BigNumber {
|
||||
const r = a.plus(b);
|
||||
if (r.isGreaterThan(MAX_UINT256)) {
|
||||
throw new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
throw new SafeMathRevertErrors.Uint256BinOpError(SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, a, b);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -23,8 +19,8 @@ export function safeAdd(a: BigNumber, b: BigNumber): BigNumber {
|
||||
export function safeSub(a: BigNumber, b: BigNumber): BigNumber {
|
||||
const r = a.minus(b);
|
||||
if (r.isLessThan(0)) {
|
||||
throw new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
throw new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -38,8 +34,8 @@ export function safeSub(a: BigNumber, b: BigNumber): BigNumber {
|
||||
export function safeMul(a: BigNumber, b: BigNumber): BigNumber {
|
||||
const r = a.times(b);
|
||||
if (r.isGreaterThan(MAX_UINT256)) {
|
||||
throw new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
throw new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -52,11 +48,7 @@ export function safeMul(a: BigNumber, b: BigNumber): BigNumber {
|
||||
*/
|
||||
export function safeDiv(a: BigNumber, b: BigNumber): BigNumber {
|
||||
if (b.isEqualTo(0)) {
|
||||
throw new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
throw new SafeMathRevertErrors.Uint256BinOpError(SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero, a, b);
|
||||
}
|
||||
return a.dividedToIntegerBy(b);
|
||||
}
|
||||
|
@@ -21,8 +21,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts on overflow', () => {
|
||||
const a = MAX_UINT256.dividedToIntegerBy(2);
|
||||
const b = MAX_UINT256.dividedToIntegerBy(2).plus(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -41,8 +41,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts on underflow', () => {
|
||||
const a = MAX_UINT256.dividedToIntegerBy(2);
|
||||
const b = MAX_UINT256.dividedToIntegerBy(2).plus(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -61,8 +61,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts on overflow', () => {
|
||||
const a = MAX_UINT256.dividedToIntegerBy(2);
|
||||
const b = MAX_UINT256.dividedToIntegerBy(2).plus(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -81,8 +81,8 @@ describe('Reference Functions', () => {
|
||||
it('reverts if denominator is zero', () => {
|
||||
const a = MAX_UINT256.dividedToIntegerBy(2);
|
||||
const b = ZERO_AMOUNT;
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
|
@@ -45,8 +45,8 @@ blockchainTests('SafeMath', env => {
|
||||
it('should revert if the multiplication overflows', async () => {
|
||||
const a = toBigNumber('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'); // The largest uint256 number
|
||||
const b = toBigNumber(2);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -91,8 +91,8 @@ blockchainTests('SafeMath', env => {
|
||||
it('should revert if second argument is zero', async () => {
|
||||
const a = toBigNumber(1);
|
||||
const b = toBigNumber(0);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -112,8 +112,8 @@ blockchainTests('SafeMath', env => {
|
||||
it('should revert if the subtraction underflows', async () => {
|
||||
const a = toBigNumber(0);
|
||||
const b = toBigNumber(1);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
@@ -143,8 +143,8 @@ blockchainTests('SafeMath', env => {
|
||||
it('should revert if the addition overflows', async () => {
|
||||
const a = toBigNumber('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'); // The largest uint256 number
|
||||
const b = toBigNumber(1);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
|
Reference in New Issue
Block a user