Merge pull request #2014 from jalextowle/feature/contracts/3.0/utils-unit-tests
Added Unit Tests to Utils
This commit is contained in:
commit
bd42c33daa
@ -46,7 +46,7 @@ describe('Authorizable', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('addAuthorizedAddress', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwner, owner);
|
||||
const tx = authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
@ -60,7 +60,7 @@ describe('Authorizable', () => {
|
||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||
expect(isAuthorized).to.be.true();
|
||||
});
|
||||
it('should throw if owner attempts to authorize a duplicate address', async () => {
|
||||
it('should revert if owner attempts to authorize a duplicate address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
@ -74,7 +74,7 @@ describe('Authorizable', () => {
|
||||
});
|
||||
|
||||
describe('removeAuthorizedAddress', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
@ -100,7 +100,7 @@ describe('Authorizable', () => {
|
||||
expect(isAuthorized).to.be.false();
|
||||
});
|
||||
|
||||
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||
from: owner,
|
||||
@ -111,7 +111,7 @@ describe('Authorizable', () => {
|
||||
});
|
||||
|
||||
describe('removeAuthorizedAddressAtIndex', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
@ -124,7 +124,7 @@ describe('Authorizable', () => {
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should throw if index is >= authorities.length', async () => {
|
||||
it('should revert if index is >= authorities.length', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
@ -138,7 +138,7 @@ describe('Authorizable', () => {
|
||||
RevertReason.IndexOutOfBounds,
|
||||
);
|
||||
});
|
||||
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
||||
const index = new BigNumber(0);
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||
@ -147,7 +147,7 @@ describe('Authorizable', () => {
|
||||
RevertReason.TargetNotAuthorized,
|
||||
);
|
||||
});
|
||||
it('should throw if address at index does not match target', async () => {
|
||||
it('should revert if address at index does not match target', async () => {
|
||||
const address1 = address;
|
||||
const address2 = notOwner;
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
|
@ -166,7 +166,7 @@ describe('ERC1155Token', () => {
|
||||
];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances);
|
||||
});
|
||||
it('should throw if transfer reverts', async () => {
|
||||
it('should revert if transfer reverts', async () => {
|
||||
// setup test parameters
|
||||
const tokenToTransfer = fungibleToken;
|
||||
const valueToTransfer = spenderInitialFungibleBalance.plus(1);
|
||||
@ -187,7 +187,7 @@ describe('ERC1155Token', () => {
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should throw if callback reverts', async () => {
|
||||
it('should revert if callback reverts', async () => {
|
||||
// setup test parameters
|
||||
const tokenToTransfer = fungibleToken;
|
||||
const valueToTransfer = fungibleValueToTransfer;
|
||||
@ -342,7 +342,7 @@ describe('ERC1155Token', () => {
|
||||
];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
|
||||
});
|
||||
it('should throw if transfer reverts', async () => {
|
||||
it('should revert if transfer reverts', async () => {
|
||||
// setup test parameters
|
||||
const tokensToTransfer = [fungibleToken];
|
||||
const valuesToTransfer = [spenderInitialFungibleBalance.plus(1)];
|
||||
@ -363,7 +363,7 @@ describe('ERC1155Token', () => {
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should throw if callback reverts', async () => {
|
||||
it('should revert if callback reverts', async () => {
|
||||
// setup test parameters
|
||||
const tokensToTransfer = [fungibleToken];
|
||||
const valuesToTransfer = [fungibleValueToTransfer];
|
||||
@ -417,7 +417,7 @@ describe('ERC1155Token', () => {
|
||||
];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances);
|
||||
});
|
||||
it('should throw if trying to transfer tokens via safeTransferFrom by an unapproved account', async () => {
|
||||
it('should revert if trying to transfer tokens via safeTransferFrom by an unapproved account', async () => {
|
||||
// check approval not set
|
||||
const isApprovedForAllCheck = await erc1155Wrapper.isApprovedForAllAsync(spender, delegatedSpender);
|
||||
expect(isApprovedForAllCheck).to.be.false();
|
||||
@ -470,7 +470,7 @@ describe('ERC1155Token', () => {
|
||||
];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
|
||||
});
|
||||
it('should throw if trying to transfer tokens via safeBatchTransferFrom by an unapproved account', async () => {
|
||||
it('should revert if trying to transfer tokens via safeBatchTransferFrom by an unapproved account', async () => {
|
||||
// check approval not set
|
||||
const isApprovedForAllCheck = await erc1155Wrapper.isApprovedForAllAsync(spender, delegatedSpender);
|
||||
expect(isApprovedForAllCheck).to.be.false();
|
||||
|
@ -54,7 +54,7 @@ describe('UnlimitedAllowanceToken', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('transfer', () => {
|
||||
it('should throw if owner has insufficient balance', async () => {
|
||||
it('should revert if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await token.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
return expectContractCallFailedAsync(
|
||||
@ -89,7 +89,7 @@ describe('UnlimitedAllowanceToken', () => {
|
||||
});
|
||||
|
||||
describe('transferFrom', () => {
|
||||
it('should throw if owner has insufficient balance', async () => {
|
||||
it('should revert if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await token.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
@ -104,7 +104,7 @@ describe('UnlimitedAllowanceToken', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if spender has insufficient allowance', async () => {
|
||||
it('should revert if spender has insufficient allowance', async () => {
|
||||
const ownerBalance = await token.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = ownerBalance;
|
||||
|
||||
|
@ -45,7 +45,7 @@ describe('EtherToken', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('deposit', () => {
|
||||
it('should throw if caller attempts to deposit more Ether than caller balance', async () => {
|
||||
it('should revert if caller attempts to deposit more Ether than caller balance', async () => {
|
||||
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const ethToDeposit = initEthBalance.plus(1);
|
||||
|
||||
@ -74,7 +74,7 @@ describe('EtherToken', () => {
|
||||
});
|
||||
|
||||
describe('withdraw', () => {
|
||||
it('should throw if caller attempts to withdraw greater than caller balance', async () => {
|
||||
it('should revert if caller attempts to withdraw greater than caller balance', async () => {
|
||||
const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
|
||||
const ethTokensToWithdraw = initEthTokenBalance.plus(1);
|
||||
|
||||
|
@ -17,7 +17,6 @@ pragma experimental ABIEncoderV2;
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/ReentrancyGuard.sol";
|
||||
import "@0x/contracts-utils/contracts/src/RichErrors.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "./interfaces/IAssetProxyDispatcher.sol";
|
||||
|
@ -380,7 +380,7 @@ describe('Exchange core', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw if fully filled', async () => {
|
||||
it('should revert if fully filled', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
|
||||
@ -423,7 +423,7 @@ describe('Exchange core', () => {
|
||||
).to.be.bignumber.equal(signedOrder.takerFee);
|
||||
});
|
||||
|
||||
it('should throw if order is expired', async () => {
|
||||
it('should revert if order is expired', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
@ -742,14 +742,14 @@ describe('Exchange core', () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
});
|
||||
|
||||
it('should throw if not sent by maker', async () => {
|
||||
it('should revert if not sent by maker', async () => {
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedError = new ExchangeRevertErrors.InvalidMakerError(orderHash, takerAddress);
|
||||
const tx = exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if makerAssetAmount is 0', async () => {
|
||||
it('should revert if makerAssetAmount is 0', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: new BigNumber(0),
|
||||
});
|
||||
@ -762,7 +762,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if takerAssetAmount is 0', async () => {
|
||||
it('should revert if takerAssetAmount is 0', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
takerAssetAmount: new BigNumber(0),
|
||||
});
|
||||
@ -800,7 +800,7 @@ describe('Exchange core', () => {
|
||||
expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
|
||||
});
|
||||
|
||||
it('should throw if already cancelled', async () => {
|
||||
it('should revert if already cancelled', async () => {
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Cancelled);
|
||||
@ -808,7 +808,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if order is expired', async () => {
|
||||
it('should revert if order is expired', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
@ -819,7 +819,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if rounding error is greater than 0.1%', async () => {
|
||||
it('should revert if rounding error is greater than 0.1%', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: new BigNumber(1001),
|
||||
takerAssetAmount: new BigNumber(3),
|
||||
@ -936,7 +936,7 @@ describe('Exchange core', () => {
|
||||
});
|
||||
|
||||
describe('Testing Exchange of ERC721 Tokens', () => {
|
||||
it('should throw when maker does not own the token with id makerAssetId', async () => {
|
||||
it('should revert when maker does not own the token with id makerAssetId', async () => {
|
||||
// Construct Exchange parameters
|
||||
const makerAssetId = erc721TakerAssetIds[0];
|
||||
const takerAssetId = erc721TakerAssetIds[1];
|
||||
@ -963,7 +963,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw when taker does not own the token with id takerAssetId', async () => {
|
||||
it('should revert when taker does not own the token with id takerAssetId', async () => {
|
||||
// Construct Exchange parameters
|
||||
const makerAssetId = erc721MakerAssetIds[0];
|
||||
const takerAssetId = erc721MakerAssetIds[1];
|
||||
@ -990,7 +990,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw when makerAssetAmount is greater than 1', async () => {
|
||||
it('should revert when makerAssetAmount is greater than 1', async () => {
|
||||
// Construct Exchange parameters
|
||||
const makerAssetId = erc721MakerAssetIds[0];
|
||||
const takerAssetId = erc721TakerAssetIds[0];
|
||||
@ -1017,7 +1017,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw when takerAssetAmount is greater than 1', async () => {
|
||||
it('should revert when takerAssetAmount is greater than 1', async () => {
|
||||
// Construct Exchange parameters
|
||||
const makerAssetId = erc721MakerAssetIds[0];
|
||||
const takerAssetId = erc721TakerAssetIds[0];
|
||||
@ -1044,7 +1044,7 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw on partial fill', async () => {
|
||||
it('should revert on partial fill', async () => {
|
||||
// Construct Exchange parameters
|
||||
const makerAssetId = erc721MakerAssetIds[0];
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
|
@ -114,7 +114,7 @@ describe('AssetProxyDispatcher', () => {
|
||||
expect(proxyAddress).to.be.equal(erc721Proxy.address);
|
||||
});
|
||||
|
||||
it('should throw if a proxy with the same id is already registered', async () => {
|
||||
it('should revert if a proxy with the same id is already registered', async () => {
|
||||
// Initial registration
|
||||
await assetProxyDispatcher.registerAssetProxy.awaitTransactionSuccessAsync(erc20Proxy.address, {
|
||||
from: owner,
|
||||
@ -134,7 +134,7 @@ describe('AssetProxyDispatcher', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if requesting address is not owner', async () => {
|
||||
it('should revert if requesting address is not owner', async () => {
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwner, owner);
|
||||
const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
|
||||
from: notOwner,
|
||||
@ -250,7 +250,7 @@ describe('AssetProxyDispatcher', () => {
|
||||
expect(newBalances).to.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should throw if dispatching to unregistered proxy', async () => {
|
||||
it('should revert if dispatching to unregistered proxy', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
|
@ -154,7 +154,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw when taker is specified and order is claimed by other', async () => {
|
||||
it('should revert when taker is specified and order is claimed by other', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
@ -165,7 +165,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if makerAssetAmount is 0', async () => {
|
||||
it('should revert if makerAssetAmount is 0', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
@ -177,7 +177,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if takerAssetAmount is 0', async () => {
|
||||
it('should revert if takerAssetAmount is 0', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
@ -189,7 +189,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if takerAssetFillAmount is 0', async () => {
|
||||
it('should revert if takerAssetFillAmount is 0', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero,
|
||||
@ -197,7 +197,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if an order is expired', async () => {
|
||||
it('should revert if an order is expired', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
@ -310,7 +310,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker balance is too low to fill order', async () => {
|
||||
it('should revert if maker balance is too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
makerStateScenario: {
|
||||
@ -321,7 +321,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker balance is too low to fill order', async () => {
|
||||
it('should revert if taker balance is too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerStateScenario: {
|
||||
@ -332,7 +332,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker allowances are too low to fill order', async () => {
|
||||
it('should revert if maker allowances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
makerStateScenario: {
|
||||
@ -343,7 +343,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker allowances are too low to fill order', async () => {
|
||||
it('should revert if taker allowances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerStateScenario: {
|
||||
@ -354,7 +354,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker fee balance is too low to fill order', async () => {
|
||||
it('should revert if maker fee balance is too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
makerStateScenario: {
|
||||
@ -365,7 +365,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker fee balance is too low to fill order', async () => {
|
||||
it('should revert if taker fee balance is too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerStateScenario: {
|
||||
@ -376,7 +376,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker fee allowances are too low to fill order', async () => {
|
||||
it('should revert if maker fee allowances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
makerStateScenario: {
|
||||
@ -387,7 +387,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker fee allowances are too low to fill order', async () => {
|
||||
it('should revert if taker fee allowances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerStateScenario: {
|
||||
|
@ -1286,7 +1286,7 @@ describe('matchOrders', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Should throw if left order is not fillable', async () => {
|
||||
it('Should revert if left order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -1305,7 +1305,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('Should throw if right order is not fillable', async () => {
|
||||
it('Should revert if right order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -1324,7 +1324,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if there is not a positive spread', async () => {
|
||||
it('should revert if there is not a positive spread', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -1342,7 +1342,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
|
||||
it('should revert if the left maker asset is not equal to the right taker asset ', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -1373,7 +1373,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if the right maker asset is not equal to the left taker asset', async () => {
|
||||
it('should revert if the right maker asset is not equal to the left taker asset', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
@ -2416,7 +2416,7 @@ describe('matchOrders', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Should throw if left order is not fillable', async () => {
|
||||
it('Should revert if left order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -2435,7 +2435,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('Should throw if right order is not fillable', async () => {
|
||||
it('Should revert if right order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -2454,7 +2454,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if there is not a positive spread', async () => {
|
||||
it('should revert if there is not a positive spread', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -2472,7 +2472,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
|
||||
it('should revert if the left maker asset is not equal to the right taker asset ', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18),
|
||||
@ -2503,7 +2503,7 @@ describe('matchOrders', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if the right maker asset is not equal to the left taker asset', async () => {
|
||||
it('should revert if the right maker asset is not equal to the left taker asset', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
|
@ -495,7 +495,7 @@ describe('MixinSignatureValidator', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
||||
it('should revert when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
||||
// Set approval of signature validator to false
|
||||
await signatureValidator.setSignatureValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorWallet.address,
|
||||
@ -702,7 +702,7 @@ describe('MixinSignatureValidator', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
||||
it('should revert when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
||||
// Set approval of signature validator to false
|
||||
await signatureValidator.setSignatureValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorWallet.address,
|
||||
|
@ -234,7 +234,7 @@ describe('Exchange wrappers', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if a signedOrder is expired', async () => {
|
||||
it('should revert if a signedOrder is expired', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
@ -245,7 +245,7 @@ describe('Exchange wrappers', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should throw if entire takerAssetFillAmount not filled', async () => {
|
||||
it('should revert if entire takerAssetFillAmount not filled', async () => {
|
||||
const signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
|
||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
|
||||
@ -815,7 +815,7 @@ describe('Exchange wrappers', () => {
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should throw if a single signedOrder does not fill the expected amount', async () => {
|
||||
it('should revert if a single signedOrder does not fill the expected amount', async () => {
|
||||
const takerAssetFillAmounts: BigNumber[] = [];
|
||||
_.forEach(signedOrders, signedOrder => {
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
|
||||
@ -922,7 +922,7 @@ describe('Exchange wrappers', () => {
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should not throw if an order is invalid and fill the remaining orders', async () => {
|
||||
it('should not revert if an order is invalid and fill the remaining orders', async () => {
|
||||
const makerAssetAddress = erc20TokenA.address;
|
||||
const takerAssetAddress = erc20TokenB.address;
|
||||
|
||||
@ -1132,7 +1132,7 @@ describe('Exchange wrappers', () => {
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should throw when a signedOrder does not use the same takerAssetAddress', async () => {
|
||||
it('should revert when a signedOrder does not use the same takerAssetAddress', async () => {
|
||||
signedOrders = [
|
||||
await orderFactory.newSignedOrderAsync(),
|
||||
await orderFactory.newSignedOrderAsync({
|
||||
@ -1510,7 +1510,7 @@ describe('Exchange wrappers', () => {
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should throw when a signedOrder does not use the same makerAssetAddress', async () => {
|
||||
it('should revert when a signedOrder does not use the same makerAssetAddress', async () => {
|
||||
signedOrders = [
|
||||
await orderFactory.newSignedOrderAsync(),
|
||||
await orderFactory.newSignedOrderAsync({
|
||||
|
@ -115,7 +115,7 @@ describe('AssetProxyOwner', () => {
|
||||
expect(isErc20ProxyRegistered).to.equal(true);
|
||||
expect(isErc721ProxyRegistered).to.equal(true);
|
||||
});
|
||||
it('should throw if a null address is included in assetProxyContracts', async () => {
|
||||
it('should revert if a null address is included in assetProxyContracts', async () => {
|
||||
const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
|
||||
return expectContractCreationFailedAsync(
|
||||
(AssetProxyOwnerContract.deployFrom0xArtifactAsync(
|
||||
@ -158,7 +158,7 @@ describe('AssetProxyOwner', () => {
|
||||
});
|
||||
|
||||
describe('registerAssetProxy', () => {
|
||||
it('should throw if not called by multisig', async () => {
|
||||
it('should revert if not called by multisig', async () => {
|
||||
const isRegistered = true;
|
||||
return expectTransactionFailedWithoutReasonAsync(
|
||||
testAssetProxyOwner.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, {
|
||||
@ -338,7 +338,7 @@ describe('AssetProxyOwner', () => {
|
||||
});
|
||||
|
||||
describe('executeRemoveAuthorizedAddressAtIndex', () => {
|
||||
it('should throw without the required confirmations', async () => {
|
||||
it('should revert without the required confirmations', async () => {
|
||||
const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
|
||||
authorized,
|
||||
erc20Index,
|
||||
@ -359,7 +359,7 @@ describe('AssetProxyOwner', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if tx destination is not registered', async () => {
|
||||
it('should revert if tx destination is not registered', async () => {
|
||||
const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
|
||||
authorized,
|
||||
erc721Index,
|
||||
@ -382,7 +382,7 @@ describe('AssetProxyOwner', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if tx data is not for removeAuthorizedAddressAtIndex', async () => {
|
||||
it('should revert if tx data is not for removeAuthorizedAddressAtIndex', async () => {
|
||||
const newAuthorized = owners[1];
|
||||
const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
|
||||
newAuthorized,
|
||||
@ -468,7 +468,7 @@ describe('AssetProxyOwner', () => {
|
||||
expect(isAuthorizedAfter).to.equal(false);
|
||||
});
|
||||
|
||||
it('should throw if already executed', async () => {
|
||||
it('should revert if already executed', async () => {
|
||||
const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
|
||||
authorized,
|
||||
erc20Index,
|
||||
|
@ -241,13 +241,13 @@ describe('MultiSigWalletWithTimeLock', () => {
|
||||
multiSigWrapper = new MultiSigWrapper(multiSig, provider);
|
||||
});
|
||||
|
||||
it('should throw when not called by wallet', async () => {
|
||||
it('should revert when not called by wallet', async () => {
|
||||
return expectTransactionFailedWithoutReasonAsync(
|
||||
multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw without enough confirmations', async () => {
|
||||
it('should revert without enough confirmations', async () => {
|
||||
const destination = multiSig.address;
|
||||
const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
|
||||
const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
|
||||
@ -325,7 +325,7 @@ describe('MultiSigWalletWithTimeLock', () => {
|
||||
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
|
||||
});
|
||||
|
||||
it('should throw if it has enough confirmations but is not past the time lock', async () => {
|
||||
it('should revert if it has enough confirmations but is not past the time lock', async () => {
|
||||
return expectTransactionFailedAsync(
|
||||
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
|
||||
RevertReason.TimeLockIncomplete,
|
||||
|
@ -42,6 +42,7 @@ export const constants = {
|
||||
NUM_ERC1155_FUNGIBLE_TOKENS_MINT: 4,
|
||||
NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT: 4,
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
NULL_BYTES32: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
||||
TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)),
|
||||
INITIAL_ERC20_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18),
|
||||
|
@ -25,6 +25,10 @@
|
||||
{
|
||||
"note": "Updated RichErrors to the library pattern, and implemented RichErrors for all remaining reverts and requires",
|
||||
"pr": 1913
|
||||
},
|
||||
{
|
||||
"note": "Added unit tests for all of the internal functions in the package",
|
||||
"pr": 2014
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -30,11 +30,16 @@
|
||||
"src/LibEIP712.sol",
|
||||
"src/Ownable.sol",
|
||||
"src/ReentrancyGuard.sol",
|
||||
"src/RichErrors.sol",
|
||||
"src/SafeMath.sol",
|
||||
"src/interfaces/IOwnable.sol",
|
||||
"test/TestConstants.sol",
|
||||
"test/TestLibAddress.sol",
|
||||
"test/TestLibAddressArray.sol",
|
||||
"test/TestLibBytes.sol"
|
||||
"test/TestLibBytes.sol",
|
||||
"test/TestLibEIP712.sol",
|
||||
"test/TestLibRichErrors.sol",
|
||||
"test/TestOwnable.sol",
|
||||
"test/TestReentrancyGuard.sol",
|
||||
"test/TestSafeMath.sol"
|
||||
]
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
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.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
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.
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract RichErrors {
|
||||
|
||||
// bytes4(keccak256("Error(string)"))
|
||||
bytes4 internal constant STANDARD_ERROR_SELECTOR =
|
||||
0x08c379a0;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
/// @dev ABI encode a standard, string revert error payload.
|
||||
/// This is the same payload that would be included by a `revert(string)`
|
||||
/// solidity statement. It has the function signature `Error(string)`.
|
||||
/// @param message The error string.
|
||||
/// @return The ABI encoded error.
|
||||
function StandardError(
|
||||
string memory message
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
STANDARD_ERROR_SELECTOR,
|
||||
bytes(message)
|
||||
);
|
||||
}
|
||||
// solhint-enable func-name-mixedcase
|
||||
|
||||
/// @dev Reverts an encoded rich revert reason `errorData`.
|
||||
/// @param errorData ABI encoded error data.
|
||||
function _rrevert(bytes memory errorData)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
assembly {
|
||||
revert(add(errorData, 0x20), mload(errorData))
|
||||
}
|
||||
}
|
||||
}
|
35
contracts/utils/contracts/test/TestLibAddress.sol
Normal file
35
contracts/utils/contracts/test/TestLibAddress.sol
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
|
||||
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 "../src/LibAddress.sol";
|
||||
|
||||
|
||||
contract TestLibAddress {
|
||||
|
||||
using LibAddress for address;
|
||||
|
||||
function externalIsContract(address account)
|
||||
external
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return account.isContract();
|
||||
}
|
||||
}
|
52
contracts/utils/contracts/test/TestLibEIP712.sol
Normal file
52
contracts/utils/contracts/test/TestLibEIP712.sol
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
|
||||
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 "../src/LibEIP712.sol";
|
||||
|
||||
|
||||
contract TestLibEIP712 is
|
||||
LibEIP712
|
||||
{
|
||||
function externalHashEIP712DomainSeperator(
|
||||
string calldata name,
|
||||
string calldata version,
|
||||
uint256 chainid,
|
||||
address verifyingcontractaddress
|
||||
)
|
||||
external
|
||||
pure
|
||||
returns (bytes32)
|
||||
{
|
||||
return _hashEIP712Domain(
|
||||
name,
|
||||
version,
|
||||
chainid,
|
||||
verifyingcontractaddress
|
||||
);
|
||||
}
|
||||
|
||||
function externalHashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)
|
||||
external
|
||||
pure
|
||||
returns (bytes32)
|
||||
{
|
||||
return _hashEIP712Message(eip712DomainHash, hashStruct);
|
||||
}
|
||||
}
|
32
contracts/utils/contracts/test/TestLibRichErrors.sol
Normal file
32
contracts/utils/contracts/test/TestLibRichErrors.sol
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
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 "../src/LibRichErrors.sol";
|
||||
|
||||
|
||||
contract TestLibRichErrors {
|
||||
|
||||
function externalRRevert(bytes calldata errorData)
|
||||
external
|
||||
pure
|
||||
{
|
||||
LibRichErrors._rrevert(errorData);
|
||||
}
|
||||
}
|
16
contracts/utils/contracts/test/TestOwnable.sol
Normal file
16
contracts/utils/contracts/test/TestOwnable.sol
Normal file
@ -0,0 +1,16 @@
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "../src/Ownable.sol";
|
||||
|
||||
|
||||
contract TestOwnable is
|
||||
Ownable
|
||||
{
|
||||
function externalOnlyOwner()
|
||||
external
|
||||
onlyOwner
|
||||
returns (bool)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
67
contracts/utils/contracts/test/TestReentrancyGuard.sol
Normal file
67
contracts/utils/contracts/test/TestReentrancyGuard.sol
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "../src/ReentrancyGuard.sol";
|
||||
|
||||
|
||||
contract TestReentrancyGuard is
|
||||
ReentrancyGuard
|
||||
{
|
||||
uint256 internal counter = 2;
|
||||
|
||||
/// @dev Exposes the nonReentrant modifier publicly.
|
||||
/// @param shouldBeAttacked True if the contract should be attacked.
|
||||
/// @return True if successful.
|
||||
function guarded(bool shouldBeAttacked)
|
||||
external
|
||||
nonReentrant
|
||||
returns (bool)
|
||||
{
|
||||
if (shouldBeAttacked) {
|
||||
return this.exploitive();
|
||||
} else {
|
||||
return this.nonExploitive();
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev This is a function that will reenter the current contract.
|
||||
/// @return True if successful.
|
||||
function exploitive()
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
if (counter > 0) {
|
||||
counter--;
|
||||
this.guarded(true);
|
||||
} else {
|
||||
counter = 2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev This is a function that will not reenter the current contract.
|
||||
/// @return True if successful.
|
||||
function nonExploitive()
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
74
contracts/utils/contracts/test/TestSafeMath.sol
Normal file
74
contracts/utils/contracts/test/TestSafeMath.sol
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
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 "../src/SafeMath.sol";
|
||||
|
||||
|
||||
contract TestSafeMath is
|
||||
SafeMath
|
||||
{
|
||||
function externalSafeMul(uint256 a, uint256 b)
|
||||
external
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return _safeMul(a, b);
|
||||
}
|
||||
|
||||
function externalSafeDiv(uint256 a, uint256 b)
|
||||
external
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return _safeDiv(a, b);
|
||||
}
|
||||
|
||||
function externalSafeSub(uint256 a, uint256 b)
|
||||
external
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return _safeSub(a, b);
|
||||
}
|
||||
|
||||
function externalSafeAdd(uint256 a, uint256 b)
|
||||
external
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return _safeAdd(a, b);
|
||||
}
|
||||
|
||||
function externalMaxUint256(uint256 a, uint256 b)
|
||||
external
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return _max256(a, b);
|
||||
}
|
||||
|
||||
function externalMinUint256(uint256 a, uint256 b)
|
||||
external
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return _min256(a, b);
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(IOwnable|LibAddress|LibBytes|LibEIP712|Ownable|ReentrancyGuard|RichErrors|SafeMath|TestConstants|TestLibAddressArray|TestLibBytes).json",
|
||||
"abis": "./generated-artifacts/@(IOwnable|LibAddress|LibBytes|LibEIP1271|LibEIP712|Ownable|ReentrancyGuard|SafeMath|TestConstants|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestOwnable|TestReentrancyGuard|TestSafeMath).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@ -8,24 +8,36 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
import * as IOwnable from '../generated-artifacts/IOwnable.json';
|
||||
import * as LibAddress from '../generated-artifacts/LibAddress.json';
|
||||
import * as LibBytes from '../generated-artifacts/LibBytes.json';
|
||||
import * as LibEIP1271 from '../generated-artifacts/LibEIP1271.json';
|
||||
import * as LibEIP712 from '../generated-artifacts/LibEIP712.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as ReentrancyGuard from '../generated-artifacts/ReentrancyGuard.json';
|
||||
import * as RichErrors from '../generated-artifacts/RichErrors.json';
|
||||
import * as SafeMath from '../generated-artifacts/SafeMath.json';
|
||||
import * as TestConstants from '../generated-artifacts/TestConstants.json';
|
||||
import * as TestLibAddress from '../generated-artifacts/TestLibAddress.json';
|
||||
import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray.json';
|
||||
import * as TestLibBytes from '../generated-artifacts/TestLibBytes.json';
|
||||
import * as TestLibEIP712 from '../generated-artifacts/TestLibEIP712.json';
|
||||
import * as TestLibRichErrors from '../generated-artifacts/TestLibRichErrors.json';
|
||||
import * as TestOwnable from '../generated-artifacts/TestOwnable.json';
|
||||
import * as TestReentrancyGuard from '../generated-artifacts/TestReentrancyGuard.json';
|
||||
import * as TestSafeMath from '../generated-artifacts/TestSafeMath.json';
|
||||
export const artifacts = {
|
||||
LibAddress: LibAddress as ContractArtifact,
|
||||
LibBytes: LibBytes as ContractArtifact,
|
||||
LibEIP1271: LibEIP1271 as ContractArtifact,
|
||||
LibEIP712: LibEIP712 as ContractArtifact,
|
||||
Ownable: Ownable as ContractArtifact,
|
||||
ReentrancyGuard: ReentrancyGuard as ContractArtifact,
|
||||
RichErrors: RichErrors as ContractArtifact,
|
||||
SafeMath: SafeMath as ContractArtifact,
|
||||
IOwnable: IOwnable as ContractArtifact,
|
||||
TestConstants: TestConstants as ContractArtifact,
|
||||
TestLibAddress: TestLibAddress as ContractArtifact,
|
||||
TestLibAddressArray: TestLibAddressArray as ContractArtifact,
|
||||
TestLibBytes: TestLibBytes as ContractArtifact,
|
||||
TestLibEIP712: TestLibEIP712 as ContractArtifact,
|
||||
TestLibRichErrors: TestLibRichErrors as ContractArtifact,
|
||||
TestOwnable: TestOwnable as ContractArtifact,
|
||||
TestReentrancyGuard: TestReentrancyGuard as ContractArtifact,
|
||||
TestSafeMath: TestSafeMath as ContractArtifact,
|
||||
};
|
||||
|
@ -6,11 +6,17 @@
|
||||
export * from '../generated-wrappers/i_ownable';
|
||||
export * from '../generated-wrappers/lib_address';
|
||||
export * from '../generated-wrappers/lib_bytes';
|
||||
export * from '../generated-wrappers/lib_e_i_p1271';
|
||||
export * from '../generated-wrappers/lib_e_i_p712';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/reentrancy_guard';
|
||||
export * from '../generated-wrappers/rich_errors';
|
||||
export * from '../generated-wrappers/safe_math';
|
||||
export * from '../generated-wrappers/test_constants';
|
||||
export * from '../generated-wrappers/test_lib_address';
|
||||
export * from '../generated-wrappers/test_lib_address_array';
|
||||
export * from '../generated-wrappers/test_lib_bytes';
|
||||
export * from '../generated-wrappers/test_lib_e_i_p712';
|
||||
export * from '../generated-wrappers/test_lib_rich_errors';
|
||||
export * from '../generated-wrappers/test_ownable';
|
||||
export * from '../generated-wrappers/test_reentrancy_guard';
|
||||
export * from '../generated-wrappers/test_safe_math';
|
||||
|
37
contracts/utils/test/lib_address.ts
Normal file
37
contracts/utils/test/lib_address.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { chaiSetup, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { artifacts, TestLibAddressContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('LibAddress', () => {
|
||||
let lib: TestLibAddressContract;
|
||||
let nonContract: string;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
nonContract = (await web3Wrapper.getAvailableAddressesAsync())[0];
|
||||
// Deploy LibAddress
|
||||
lib = await TestLibAddressContract.deployFrom0xArtifactAsync(artifacts.TestLibAddress, provider, txDefaults);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('isContract', () => {
|
||||
it('should return false for a non-contract address', async () => {
|
||||
const isContract = await lib.externalIsContract.callAsync(nonContract);
|
||||
expect(isContract).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true for a non-contract address', async () => {
|
||||
const isContract = await lib.externalIsContract.callAsync(lib.address);
|
||||
expect(isContract).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
111
contracts/utils/test/lib_eip712.ts
Normal file
111
contracts/utils/test/lib_eip712.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { chaiSetup, constants, hexConcat, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { BigNumber, signTypedDataUtils } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestLibEIP712Contract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
/**
|
||||
* Tests a specific instance of EIP712 domain hashing.
|
||||
* @param lib The LibEIP712 contract to call.
|
||||
* @param name The name of the domain.
|
||||
* @param version The version of the domain.
|
||||
* @param chainId The chain id of the domain.
|
||||
* @param verifyingContractAddress The verifying contract address of the domain.
|
||||
*/
|
||||
async function testHashEIP712DomainAsync(
|
||||
lib: TestLibEIP712Contract,
|
||||
name: string,
|
||||
version: string,
|
||||
chainId: number,
|
||||
verifyingContractAddress: string,
|
||||
): Promise<void> {
|
||||
const expectedHash = signTypedDataUtils.generateDomainHash({
|
||||
name,
|
||||
version,
|
||||
chainId,
|
||||
verifyingContractAddress,
|
||||
});
|
||||
const actualHash = await lib.externalHashEIP712DomainSeperator.callAsync(
|
||||
name,
|
||||
version,
|
||||
new BigNumber(chainId),
|
||||
verifyingContractAddress,
|
||||
);
|
||||
expect(actualHash).to.be.eq(hexConcat(expectedHash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a specific instance of EIP712 message hashing.
|
||||
* @param lib The LibEIP712 contract to call.
|
||||
* @param domainHash The hash of the EIP712 domain of this instance.
|
||||
* @param hashStruct The hash of the struct of this instance.
|
||||
*/
|
||||
async function testHashEIP712MessageAsync(
|
||||
lib: TestLibEIP712Contract,
|
||||
domainHash: string,
|
||||
hashStruct: string,
|
||||
): Promise<void> {
|
||||
const input = '0x1901'.concat(
|
||||
domainHash.slice(2, domainHash.length).concat(hashStruct.slice(2, hashStruct.length)),
|
||||
);
|
||||
const expectedHash = '0x'.concat(ethUtil.sha3(input).toString('hex'));
|
||||
const actualHash = await lib.externalHashEIP712Message.callAsync(domainHash, hashStruct);
|
||||
expect(actualHash).to.be.eq(expectedHash);
|
||||
}
|
||||
|
||||
describe('LibEIP712', () => {
|
||||
let lib: TestLibEIP712Contract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
// Deploy LibEIP712
|
||||
lib = await TestLibEIP712Contract.deployFrom0xArtifactAsync(artifacts.TestLibEIP712, provider, txDefaults);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('_hashEIP712Domain', async () => {
|
||||
it('should correctly hash empty input', async () => {
|
||||
await testHashEIP712DomainAsync(lib, '', '', 0, constants.NULL_ADDRESS);
|
||||
});
|
||||
|
||||
it('should correctly hash non-empty input', async () => {
|
||||
await testHashEIP712DomainAsync(lib, '_hashEIP712Domain', '1.0', 62, lib.address);
|
||||
});
|
||||
|
||||
it('should correctly hash non-empty input', async () => {
|
||||
await testHashEIP712DomainAsync(lib, '_hashEIP712Domain', '2.0', 0, lib.address);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_hashEIP712Message', () => {
|
||||
it('should correctly hash empty input', async () => {
|
||||
await testHashEIP712MessageAsync(lib, constants.NULL_BYTES32, constants.NULL_BYTES32);
|
||||
});
|
||||
|
||||
it('should correctly hash non-empty input', async () => {
|
||||
await testHashEIP712MessageAsync(
|
||||
lib,
|
||||
'0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6', // keccak256(abi.encode(1))
|
||||
'0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace', // keccak256(abi.encode(2))
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly hash non-empty input', async () => {
|
||||
await testHashEIP712MessageAsync(
|
||||
lib,
|
||||
'0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace', // keccak256(abi.encode(2))
|
||||
'0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b', // keccak256(abi.encode(3))
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
40
contracts/utils/test/lib_rich_errors.ts
Normal file
40
contracts/utils/test/lib_rich_errors.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { StringRevertError } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestLibRichErrorsContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('LibRichErrors', () => {
|
||||
let lib: TestLibRichErrorsContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
// Deploy SafeMath
|
||||
lib = await TestLibRichErrorsContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLibRichErrors,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('_rrevert', () => {
|
||||
it('should correctly revert the extra bytes', async () => {
|
||||
return expect(lib.externalRRevert.callAsync(constants.NULL_BYTES)).to.revertWith(constants.NULL_BYTES);
|
||||
});
|
||||
|
||||
it('should correctly revert a StringRevertError', async () => {
|
||||
const error = new StringRevertError('foo');
|
||||
return expect(lib.externalRRevert.callAsync(error.encode())).to.revertWith(error);
|
||||
});
|
||||
});
|
||||
});
|
59
contracts/utils/test/ownable.ts
Normal file
59
contracts/utils/test/ownable.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { OwnableRevertErrors } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestOwnableContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('Ownable', () => {
|
||||
let ownable: TestOwnableContract;
|
||||
let owner: string;
|
||||
let nonOwner: string;
|
||||
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = await accounts[0];
|
||||
nonOwner = await accounts[1];
|
||||
await blockchainLifecycle.startAsync();
|
||||
// Deploy Ownable from the owner address
|
||||
txDefaults.from = owner;
|
||||
ownable = await TestOwnableContract.deployFrom0xArtifactAsync(artifacts.TestOwnable, provider, txDefaults);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('onlyOwner', () => {
|
||||
it('should revert if sender is not the owner', async () => {
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
|
||||
return expect(ownable.externalOnlyOwner.callAsync({ from: nonOwner })).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed if sender is the owner', async () => {
|
||||
const isSuccessful = await ownable.externalOnlyOwner.callAsync({ from: owner });
|
||||
expect(isSuccessful).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferOwnership', () => {
|
||||
it('should not transfer ownership if the specified new owner is the zero address', async () => {
|
||||
expect(
|
||||
ownable.transferOwnership.sendTransactionAsync(constants.NULL_ADDRESS, { from: owner }),
|
||||
).to.be.fulfilled('');
|
||||
const updatedOwner = await ownable.owner.callAsync();
|
||||
expect(updatedOwner).to.be.eq(owner);
|
||||
});
|
||||
|
||||
it('should transfer ownership if the specified new owner is not the zero address', async () => {
|
||||
expect(ownable.transferOwnership.sendTransactionAsync(nonOwner, { from: owner })).to.be.fulfilled('');
|
||||
const updatedOwner = await ownable.owner.callAsync();
|
||||
expect(updatedOwner).to.be.eq(nonOwner);
|
||||
});
|
||||
});
|
||||
});
|
41
contracts/utils/test/reentrancy_guard.ts
Normal file
41
contracts/utils/test/reentrancy_guard.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { chaiSetup, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { ReentrancyGuardRevertErrors } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestReentrancyGuardContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('ReentrancyGuard', () => {
|
||||
let guard: TestReentrancyGuardContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
// Deploy TestReentrancyGuard
|
||||
guard = await TestReentrancyGuardContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestReentrancyGuard,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('nonReentrant', () => {
|
||||
it('should revert if reentrancy occurs', async () => {
|
||||
const expectedError = new ReentrancyGuardRevertErrors.IllegalReentrancyError();
|
||||
return expect(guard.guarded.sendTransactionAsync(true)).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed if reentrancy does not occur', async () => {
|
||||
const isSuccessful = await guard.guarded.callAsync(false);
|
||||
expect(isSuccessful).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
171
contracts/utils/test/safe_math.ts
Normal file
171
contracts/utils/test/safe_math.ts
Normal file
@ -0,0 +1,171 @@
|
||||
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestSafeMathContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
function toBigNumber(a: number | string): BigNumber {
|
||||
return new BigNumber(a);
|
||||
}
|
||||
|
||||
describe('SafeMath', () => {
|
||||
let safeMath: TestSafeMathContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
// Deploy SafeMath
|
||||
safeMath = await TestSafeMathContract.deployFrom0xArtifactAsync(artifacts.TestSafeMath, provider, txDefaults);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('_safeMul', () => {
|
||||
it('should return zero if first argument is zero', async () => {
|
||||
const result = await safeMath.externalSafeMul.callAsync(constants.ZERO_AMOUNT, toBigNumber(1));
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should return zero if second argument is zero', async () => {
|
||||
const result = await safeMath.externalSafeMul.callAsync(toBigNumber(1), constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
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,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
return expect(safeMath.externalSafeMul.callAsync(a, b)).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it("should calculate correct value for values that don't overflow", async () => {
|
||||
const result = await safeMath.externalSafeMul.callAsync(toBigNumber(15), toBigNumber(13));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(195));
|
||||
});
|
||||
});
|
||||
|
||||
describe('_safeDiv', () => {
|
||||
it('should return the correct value if both values are the same', async () => {
|
||||
const result = await safeMath.externalSafeDiv.callAsync(toBigNumber(1), toBigNumber(1));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(1));
|
||||
});
|
||||
|
||||
it('should return the correct value if the values are different', async () => {
|
||||
const result = await safeMath.externalSafeDiv.callAsync(toBigNumber(3), toBigNumber(2));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(1));
|
||||
});
|
||||
|
||||
it('should return zero if the numerator is smaller than the denominator', async () => {
|
||||
const result = await safeMath.externalSafeDiv.callAsync(toBigNumber(2), toBigNumber(3));
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should return zero if first argument is zero', async () => {
|
||||
const result = await safeMath.externalSafeDiv.callAsync(constants.ZERO_AMOUNT, toBigNumber(1));
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should revert if second argument is zero', async () => {
|
||||
const errMessage = 'VM Exception while processing transaction: invalid opcode';
|
||||
return expect(safeMath.externalSafeDiv.callAsync(toBigNumber(1), constants.ZERO_AMOUNT)).to.be.rejectedWith(
|
||||
errMessage,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_safeSub', () => {
|
||||
it('should revert if the subtraction underflows', async () => {
|
||||
const a = toBigNumber(0);
|
||||
const b = toBigNumber(1);
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
return expect(safeMath.externalSafeSub.callAsync(a, b)).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should calculate correct value for values that are equal', async () => {
|
||||
const result = await safeMath.externalSafeMul.callAsync(constants.ZERO_AMOUNT, constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should calculate correct value for values that are not equal', async () => {
|
||||
const result = await safeMath.externalSafeSub.callAsync(toBigNumber(15), toBigNumber(13));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(2));
|
||||
});
|
||||
});
|
||||
|
||||
describe('_safeAdd', () => {
|
||||
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,
|
||||
a,
|
||||
b,
|
||||
);
|
||||
return expect(safeMath.externalSafeAdd.callAsync(a, b)).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should calculate correct value if addition does not overflow', async () => {
|
||||
const result = await safeMath.externalSafeAdd.callAsync(toBigNumber(15), toBigNumber(13));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(28));
|
||||
});
|
||||
|
||||
it('should calculate correct value if first argument is zero', async () => {
|
||||
const result = await safeMath.externalSafeAdd.callAsync(constants.ZERO_AMOUNT, toBigNumber(13));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(13));
|
||||
});
|
||||
|
||||
it('should calculate correct value if second argument is zero', async () => {
|
||||
const result = await safeMath.externalSafeAdd.callAsync(toBigNumber(13), constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(13));
|
||||
});
|
||||
});
|
||||
|
||||
describe('_maxUint256', () => {
|
||||
it('should return first argument if it is greater than the second', async () => {
|
||||
const result = await safeMath.externalMaxUint256.callAsync(toBigNumber(13), constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(13));
|
||||
});
|
||||
|
||||
it('should return first argument if it is equal the second', async () => {
|
||||
const result = await safeMath.externalMaxUint256.callAsync(constants.ZERO_AMOUNT, constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should return second argument if it is greater than the first', async () => {
|
||||
const result = await safeMath.externalMaxUint256.callAsync(constants.ZERO_AMOUNT, toBigNumber(13));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(13));
|
||||
});
|
||||
});
|
||||
|
||||
describe('_minUint256', () => {
|
||||
it('should return first argument if it is less than the second', async () => {
|
||||
const result = await safeMath.externalMaxUint256.callAsync(constants.ZERO_AMOUNT, toBigNumber(13));
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(13));
|
||||
});
|
||||
|
||||
it('should return first argument if it is equal the second', async () => {
|
||||
const result = await safeMath.externalMaxUint256.callAsync(constants.ZERO_AMOUNT, constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should return second argument if it is less than the first', async () => {
|
||||
const result = await safeMath.externalMaxUint256.callAsync(toBigNumber(13), constants.ZERO_AMOUNT);
|
||||
expect(result).bignumber.to.be.eq(toBigNumber(13));
|
||||
});
|
||||
});
|
||||
});
|
@ -6,14 +6,20 @@
|
||||
"generated-artifacts/IOwnable.json",
|
||||
"generated-artifacts/LibAddress.json",
|
||||
"generated-artifacts/LibBytes.json",
|
||||
"generated-artifacts/LibEIP1271.json",
|
||||
"generated-artifacts/LibEIP712.json",
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/ReentrancyGuard.json",
|
||||
"generated-artifacts/RichErrors.json",
|
||||
"generated-artifacts/SafeMath.json",
|
||||
"generated-artifacts/TestConstants.json",
|
||||
"generated-artifacts/TestLibAddress.json",
|
||||
"generated-artifacts/TestLibAddressArray.json",
|
||||
"generated-artifacts/TestLibBytes.json"
|
||||
"generated-artifacts/TestLibBytes.json",
|
||||
"generated-artifacts/TestLibEIP712.json",
|
||||
"generated-artifacts/TestLibRichErrors.json",
|
||||
"generated-artifacts/TestOwnable.json",
|
||||
"generated-artifacts/TestReentrancyGuard.json",
|
||||
"generated-artifacts/TestSafeMath.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export enum SafeMathErrorCodes {
|
||||
}
|
||||
|
||||
export class SafeMathError extends RevertError {
|
||||
constructor(error?: SafeMathErrorCodes, a?: BigNumber | number | string, b?: BigNumber | number | string) {
|
||||
constructor(error?: SafeMathErrorCodes, a?: BigNumber, b?: BigNumber) {
|
||||
super('SafeMathError', 'SafeMathError(uint8 error, uint256 a, uint256 b)', {
|
||||
error,
|
||||
a,
|
||||
|
@ -20,6 +20,28 @@ export const signTypedDataUtils = {
|
||||
]),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Generates the hash of a EIP712 Domain with the default schema
|
||||
* @param domain An EIP712 domain with the default schema containing a name, version, chain id,
|
||||
* and verifying address.
|
||||
* @return A buffer that contains the hash of the domain.
|
||||
*/
|
||||
generateDomainHash(domain: EIP712Object): Buffer {
|
||||
return signTypedDataUtils._structHash(
|
||||
'EIP712Domain',
|
||||
domain,
|
||||
// HACK(jalextowle): When we consolidate our testing packages into test-utils, we can use a constant
|
||||
// to eliminate code duplication. At the moment, there isn't a good way to do that because of cyclic-dependencies.
|
||||
{
|
||||
EIP712Domain: [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'version', type: 'string' },
|
||||
{ name: 'chainId', type: 'uint256' },
|
||||
{ name: 'verifyingContractAddress', type: 'address' },
|
||||
],
|
||||
},
|
||||
);
|
||||
},
|
||||
_findDependencies(primaryType: string, types: EIP712Types, found: string[] = []): string[] {
|
||||
if (found.includes(primaryType) || types[primaryType] === undefined) {
|
||||
return found;
|
||||
|
Loading…
x
Reference in New Issue
Block a user