diff --git a/contracts/asset-proxy/test/authorizable.ts b/contracts/asset-proxy/test/authorizable.ts index ee2eff5884..57cd4abf73 100644 --- a/contracts/asset-proxy/test/authorizable.ts +++ b/contracts/asset-proxy/test/authorizable.ts @@ -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( diff --git a/contracts/erc1155/test/erc1155_token.ts b/contracts/erc1155/test/erc1155_token.ts index aa57e590b5..29315c065d 100644 --- a/contracts/erc1155/test/erc1155_token.ts +++ b/contracts/erc1155/test/erc1155_token.ts @@ -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(); diff --git a/contracts/erc20/test/unlimited_allowance_token.ts b/contracts/erc20/test/unlimited_allowance_token.ts index f0b8e53a46..e31507d7ab 100644 --- a/contracts/erc20/test/unlimited_allowance_token.ts +++ b/contracts/erc20/test/unlimited_allowance_token.ts @@ -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; diff --git a/contracts/erc20/test/weth9.ts b/contracts/erc20/test/weth9.ts index 6a3948e2c3..444a8c3ef6 100644 --- a/contracts/erc20/test/weth9.ts +++ b/contracts/erc20/test/weth9.ts @@ -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); diff --git a/contracts/exchange/contracts/src/MixinMatchOrders.sol b/contracts/exchange/contracts/src/MixinMatchOrders.sol index c3954e62a3..04ddb08a9b 100644 --- a/contracts/exchange/contracts/src/MixinMatchOrders.sol +++ b/contracts/exchange/contracts/src/MixinMatchOrders.sol @@ -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"; diff --git a/contracts/exchange/test/core.ts b/contracts/exchange/test/core.ts index fbcdda23e5..2d5069592e 100644 --- a/contracts/exchange/test/core.ts +++ b/contracts/exchange/test/core.ts @@ -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({ diff --git a/contracts/exchange/test/dispatcher.ts b/contracts/exchange/test/dispatcher.ts index befb88d601..c547d44f17 100644 --- a/contracts/exchange/test/dispatcher.ts +++ b/contracts/exchange/test/dispatcher.ts @@ -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 diff --git a/contracts/exchange/test/fill_order.ts b/contracts/exchange/test/fill_order.ts index 6ce16af5b4..34ddafdff2 100644 --- a/contracts/exchange/test/fill_order.ts +++ b/contracts/exchange/test/fill_order.ts @@ -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: { diff --git a/contracts/exchange/test/match_orders.ts b/contracts/exchange/test/match_orders.ts index 1e200778ce..74edbd9acd 100644 --- a/contracts/exchange/test/match_orders.ts +++ b/contracts/exchange/test/match_orders.ts @@ -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), diff --git a/contracts/exchange/test/signature_validator.ts b/contracts/exchange/test/signature_validator.ts index 6bc75c06c0..ba5b84822d 100644 --- a/contracts/exchange/test/signature_validator.ts +++ b/contracts/exchange/test/signature_validator.ts @@ -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, diff --git a/contracts/exchange/test/wrapper.ts b/contracts/exchange/test/wrapper.ts index be30975aef..4d48862012 100644 --- a/contracts/exchange/test/wrapper.ts +++ b/contracts/exchange/test/wrapper.ts @@ -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({ diff --git a/contracts/multisig/test/asset_proxy_owner.ts b/contracts/multisig/test/asset_proxy_owner.ts index 62081554be..729449e144 100644 --- a/contracts/multisig/test/asset_proxy_owner.ts +++ b/contracts/multisig/test/asset_proxy_owner.ts @@ -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, diff --git a/contracts/multisig/test/multi_sig_with_time_lock.ts b/contracts/multisig/test/multi_sig_with_time_lock.ts index 9596271514..cd6c6b3571 100644 --- a/contracts/multisig/test/multi_sig_with_time_lock.ts +++ b/contracts/multisig/test/multi_sig_with_time_lock.ts @@ -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, diff --git a/contracts/test-utils/src/constants.ts b/contracts/test-utils/src/constants.ts index 83ea993ed8..3ec8ff987d 100644 --- a/contracts/test-utils/src/constants.ts +++ b/contracts/test-utils/src/constants.ts @@ -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), diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index 1f8c882eb8..b457e5c0f3 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -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 } ] }, diff --git a/contracts/utils/compiler.json b/contracts/utils/compiler.json index 600011d083..c1de9dcb0e 100644 --- a/contracts/utils/compiler.json +++ b/contracts/utils/compiler.json @@ -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" ] } diff --git a/contracts/utils/contracts/src/LibAddress.sol b/contracts/utils/contracts/src/LibAddress.sol index cd89e23cbd..cd0d41792e 100644 --- a/contracts/utils/contracts/src/LibAddress.sol +++ b/contracts/utils/contracts/src/LibAddress.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. diff --git a/contracts/utils/contracts/src/LibEIP712.sol b/contracts/utils/contracts/src/LibEIP712.sol index 62a1f38dfb..32ca6ff117 100644 --- a/contracts/utils/contracts/src/LibEIP712.sol +++ b/contracts/utils/contracts/src/LibEIP712.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. diff --git a/contracts/utils/contracts/src/RichErrors.sol b/contracts/utils/contracts/src/RichErrors.sol deleted file mode 100644 index ebba8b7d4f..0000000000 --- a/contracts/utils/contracts/src/RichErrors.sol +++ /dev/null @@ -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)) - } - } -} diff --git a/contracts/utils/contracts/test/TestLibAddress.sol b/contracts/utils/contracts/test/TestLibAddress.sol new file mode 100644 index 0000000000..642ae2b99e --- /dev/null +++ b/contracts/utils/contracts/test/TestLibAddress.sol @@ -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(); + } +} diff --git a/contracts/utils/contracts/test/TestLibEIP712.sol b/contracts/utils/contracts/test/TestLibEIP712.sol new file mode 100644 index 0000000000..807651e5b3 --- /dev/null +++ b/contracts/utils/contracts/test/TestLibEIP712.sol @@ -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); + } +} diff --git a/contracts/utils/contracts/test/TestLibRichErrors.sol b/contracts/utils/contracts/test/TestLibRichErrors.sol new file mode 100644 index 0000000000..fe0909c18a --- /dev/null +++ b/contracts/utils/contracts/test/TestLibRichErrors.sol @@ -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); + } +} diff --git a/contracts/utils/contracts/test/TestOwnable.sol b/contracts/utils/contracts/test/TestOwnable.sol new file mode 100644 index 0000000000..a62d3c713d --- /dev/null +++ b/contracts/utils/contracts/test/TestOwnable.sol @@ -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; + } +} diff --git a/contracts/utils/contracts/test/TestReentrancyGuard.sol b/contracts/utils/contracts/test/TestReentrancyGuard.sol new file mode 100644 index 0000000000..7a878fd072 --- /dev/null +++ b/contracts/utils/contracts/test/TestReentrancyGuard.sol @@ -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; + } +} diff --git a/contracts/utils/contracts/test/TestSafeMath.sol b/contracts/utils/contracts/test/TestSafeMath.sol new file mode 100644 index 0000000000..36670e13af --- /dev/null +++ b/contracts/utils/contracts/test/TestSafeMath.sol @@ -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); + } +} diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 36c46f76e0..55aa8618ab 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -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": { diff --git a/contracts/utils/src/artifacts.ts b/contracts/utils/src/artifacts.ts index 2b82dbd63f..52d1002075 100644 --- a/contracts/utils/src/artifacts.ts +++ b/contracts/utils/src/artifacts.ts @@ -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, }; diff --git a/contracts/utils/src/wrappers.ts b/contracts/utils/src/wrappers.ts index 94aab4f426..3caa25b828 100644 --- a/contracts/utils/src/wrappers.ts +++ b/contracts/utils/src/wrappers.ts @@ -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'; diff --git a/contracts/utils/test/lib_address.ts b/contracts/utils/test/lib_address.ts new file mode 100644 index 0000000000..a6a53c2252 --- /dev/null +++ b/contracts/utils/test/lib_address.ts @@ -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(); + }); + }); +}); diff --git a/contracts/utils/test/lib_eip712.ts b/contracts/utils/test/lib_eip712.ts new file mode 100644 index 0000000000..a2a0b7218a --- /dev/null +++ b/contracts/utils/test/lib_eip712.ts @@ -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 { + 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 { + 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)) + ); + }); + }); +}); diff --git a/contracts/utils/test/lib_rich_errors.ts b/contracts/utils/test/lib_rich_errors.ts new file mode 100644 index 0000000000..df3e60b910 --- /dev/null +++ b/contracts/utils/test/lib_rich_errors.ts @@ -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); + }); + }); +}); diff --git a/contracts/utils/test/ownable.ts b/contracts/utils/test/ownable.ts new file mode 100644 index 0000000000..e204a48d3e --- /dev/null +++ b/contracts/utils/test/ownable.ts @@ -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); + }); + }); +}); diff --git a/contracts/utils/test/reentrancy_guard.ts b/contracts/utils/test/reentrancy_guard.ts new file mode 100644 index 0000000000..270c9eab84 --- /dev/null +++ b/contracts/utils/test/reentrancy_guard.ts @@ -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(); + }); + }); +}); diff --git a/contracts/utils/test/safe_math.ts b/contracts/utils/test/safe_math.ts new file mode 100644 index 0000000000..51ac43662b --- /dev/null +++ b/contracts/utils/test/safe_math.ts @@ -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)); + }); + }); +}); diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json index 962e961380..3e74470d85 100644 --- a/contracts/utils/tsconfig.json +++ b/contracts/utils/tsconfig.json @@ -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"] } diff --git a/packages/utils/src/safe_math_revert_errors.ts b/packages/utils/src/safe_math_revert_errors.ts index e91f90ef40..897123f8da 100644 --- a/packages/utils/src/safe_math_revert_errors.ts +++ b/packages/utils/src/safe_math_revert_errors.ts @@ -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, diff --git a/packages/utils/src/sign_typed_data_utils.ts b/packages/utils/src/sign_typed_data_utils.ts index 001509c899..b9b9502a84 100644 --- a/packages/utils/src/sign_typed_data_utils.ts +++ b/packages/utils/src/sign_typed_data_utils.ts @@ -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;