From 28402ff7d89898c8b13bf48f0cf0a56330f0ce53 Mon Sep 17 00:00:00 2001 From: Lawrence Forman Date: Wed, 20 May 2020 14:42:09 -0400 Subject: [PATCH] `@0x/contracts-zero-ex`: Add self-destructing to transformers --- .../errors/LibTransformERC20RichErrors.sol | 30 +++++++ .../src/transformers/FillQuoteTransformer.sol | 14 ++-- .../src/transformers/PayTakerTransformer.sol | 19 ++--- .../src/transformers/Transformer.sol | 80 +++++++++++++++++++ .../src/transformers/WethTransformer.sol | 14 ++-- .../contracts/test/TestDelegateCaller.sol | 37 +++++++++ .../contracts/test/TestTransformerBase.sol | 53 ++++++++++++ .../contracts/test/TestTransformerHost.sol | 2 +- contracts/zero-ex/package.json | 2 +- contracts/zero-ex/test/artifacts.ts | 6 ++ .../transformers/transformer_base_test.ts | 68 ++++++++++++++++ contracts/zero-ex/test/wrappers.ts | 3 + contracts/zero-ex/tsconfig.json | 3 + 13 files changed, 306 insertions(+), 25 deletions(-) create mode 100644 contracts/zero-ex/contracts/src/transformers/Transformer.sol create mode 100644 contracts/zero-ex/contracts/test/TestDelegateCaller.sol create mode 100644 contracts/zero-ex/contracts/test/TestTransformerBase.sol create mode 100644 contracts/zero-ex/test/transformers/transformer_base_test.ts diff --git a/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol index 4ce8f16687..cc1352eac4 100644 --- a/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol +++ b/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol @@ -100,6 +100,36 @@ library LibTransformERC20RichErrors { // Common Transformer errors /////////////////////////////////////////////// + function OnlyCallableByDeployerError( + address caller, + address deployer + ) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("OnlyCallableByDeployerError(address,address)")), + caller, + deployer + ); + } + + function InvalidExecutionContextError( + address actualContext, + address expectedContext + ) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("InvalidExecutionContextError(address,address)")), + actualContext, + expectedContext + ); + } + function InvalidTransformDataError( bytes memory transformData ) diff --git a/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol b/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol index 565be0fb75..39604ce763 100644 --- a/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol @@ -27,13 +27,13 @@ import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol"; import "../errors/LibTransformERC20RichErrors.sol"; import "../vendor/v3/IExchange.sol"; -import "./IERC20Transformer.sol"; +import "./Transformer.sol"; import "./LibERC20Transformer.sol"; /// @dev A transformer that fills an ERC20 market sell/buy quote. contract FillQuoteTransformer is - IERC20Transformer + Transformer { /// @dev Transform data to ABI-encode and pass into `transform()`. struct TransformData { @@ -74,8 +74,6 @@ contract FillQuoteTransformer is /// @dev The Exchange contract. IExchange public immutable exchange; - /// @dev The nonce of the deployer when deploying this contract. - uint256 public immutable deploymentNonce; /// @dev The ERC20Proxy address. address public immutable erc20Proxy; @@ -87,10 +85,12 @@ contract FillQuoteTransformer is /// @dev Create this contract. /// @param exchange_ The Exchange V3 instance. /// @param deploymentNonce_ The nonce of the deployer when deploying this contract. - constructor(IExchange exchange_, uint256 deploymentNonce_) public { + constructor(IExchange exchange_, uint256 deploymentNonce_) + public + Transformer(deploymentNonce_) + { exchange = exchange_; erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID); - deploymentNonce = deploymentNonce_; } /// @dev Sell this contract's entire balance of of `sellToken` in exchange @@ -217,7 +217,7 @@ contract FillQuoteTransformer is ).rrevert(); } } - return LibERC20Transformer.rlpEncodeNonce(deploymentNonce); + return _getRLPEncodedDeploymentNonce(); } /// @dev Try to sell up to `sellAmount` from an order. diff --git a/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol b/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol index e5d59f7c7c..7c09c9ddd4 100644 --- a/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol @@ -24,14 +24,16 @@ import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; import "../errors/LibTransformERC20RichErrors.sol"; -import "./IERC20Transformer.sol"; +import "./Transformer.sol"; import "./LibERC20Transformer.sol"; /// @dev A transformer that transfers tokens to the taker. contract PayTakerTransformer is - IERC20Transformer + Transformer { + // solhint-disable no-empty-blocks + /// @dev Transform data to ABI-encode and pass into `transform()`. struct TransformData { // The tokens to transfer to the taker. @@ -45,14 +47,13 @@ contract PayTakerTransformer is using LibSafeMathV06 for uint256; using LibERC20Transformer for IERC20TokenV06; - /// @dev The nonce of the deployer when deploying this contract. - uint256 public immutable deploymentNonce; - /// @dev Create this contract. /// @param deploymentNonce_ The nonce of the deployer when deploying this contract. - constructor(uint256 deploymentNonce_) public { - deploymentNonce = deploymentNonce_; - } + /// @dev Construct the transformer and store the WETH address in an immutable. + constructor(uint256 deploymentNonce_) + public + Transformer(deploymentNonce_) + {} /// @dev Forwards tokens to the taker. /// @param taker The taker address (caller of `TransformERC20.transformERC20()`). @@ -83,6 +84,6 @@ contract PayTakerTransformer is data.tokens[i].transformerTransfer(taker, amount); } } - return LibERC20Transformer.rlpEncodeNonce(deploymentNonce); + return _getRLPEncodedDeploymentNonce(); } } diff --git a/contracts/zero-ex/contracts/src/transformers/Transformer.sol b/contracts/zero-ex/contracts/src/transformers/Transformer.sol new file mode 100644 index 0000000000..ec9a942d64 --- /dev/null +++ b/contracts/zero-ex/contracts/src/transformers/Transformer.sol @@ -0,0 +1,80 @@ +/* + + Copyright 2020 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.6.5; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; +import "../errors/LibTransformERC20RichErrors.sol"; +import "./IERC20Transformer.sol"; +import "./LibERC20Transformer.sol"; + + +/// @dev Abstract base class for transformers. +abstract contract Transformer is + IERC20Transformer +{ + using LibRichErrorsV06 for bytes; + + /// @dev The address of the deployer. + address public immutable deployer; + /// @dev The nonce of the deployer when deploying this contract. + uint256 public immutable deploymentNonce; + /// @dev The original address of this contract. + address private immutable _implementation; + + /// @dev Create this contract. + /// @param deploymentNonce_ The nonce of the deployer when deploying this contract. + constructor(uint256 deploymentNonce_) public { + deploymentNonce = deploymentNonce_; + deployer = msg.sender; + _implementation = address(this); + } + + /// @dev Destruct this contract. Only callable by the deployer and will not + /// succeed in the context of a delegatecall (from another contract). + /// @param ethRecipient The recipient of ETH held in this contract. + function die(address payable ethRecipient) + external + virtual + { + // Only the deployer can call this. + if (msg.sender != deployer) { + LibTransformERC20RichErrors + .OnlyCallableByDeployerError(msg.sender, deployer) + .rrevert(); + } + // Must be executing our own context. + if (address(this) != _implementation) { + LibTransformERC20RichErrors + .InvalidExecutionContextError(address(this), _implementation) + .rrevert(); + } + selfdestruct(ethRecipient); + } + + /// @dev Get the RLP-encoded deployment nonce of this contract. + /// @return rlpEncodedNonce The RLP-encoded deployment nonce. + function _getRLPEncodedDeploymentNonce() + internal + view + returns (bytes memory rlpEncodedNonce) + { + return LibERC20Transformer.rlpEncodeNonce(deploymentNonce); + } +} diff --git a/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol b/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol index 69e9e4b33b..35678dbf17 100644 --- a/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol @@ -23,13 +23,13 @@ import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol"; import "../errors/LibTransformERC20RichErrors.sol"; -import "./IERC20Transformer.sol"; +import "./Transformer.sol"; import "./LibERC20Transformer.sol"; /// @dev A transformer that wraps or unwraps WETH. contract WethTransformer is - IERC20Transformer + Transformer { /// @dev Transform data to ABI-encode and pass into `transform()`. struct TransformData { @@ -42,8 +42,6 @@ contract WethTransformer is /// @dev The WETH contract address. IEtherTokenV06 public immutable weth; - /// @dev The nonce of the deployer when deploying this contract. - uint256 public immutable deploymentNonce; using LibRichErrorsV06 for bytes; using LibSafeMathV06 for uint256; @@ -53,9 +51,11 @@ contract WethTransformer is /// @param weth_ The weth token. /// @param deploymentNonce_ The nonce of the deployer when deploying this contract. /// @dev Construct the transformer and store the WETH address in an immutable. - constructor(IEtherTokenV06 weth_, uint256 deploymentNonce_) public { + constructor(IEtherTokenV06 weth_, uint256 deploymentNonce_) + public + Transformer(deploymentNonce_) + { weth = weth_; - deploymentNonce = deploymentNonce_; } /// @dev Wraps and unwraps WETH. @@ -91,6 +91,6 @@ contract WethTransformer is weth.withdraw(amount); } } - return LibERC20Transformer.rlpEncodeNonce(deploymentNonce); + return _getRLPEncodedDeploymentNonce(); } } diff --git a/contracts/zero-ex/contracts/test/TestDelegateCaller.sol b/contracts/zero-ex/contracts/test/TestDelegateCaller.sol new file mode 100644 index 0000000000..0fcbf3aef5 --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestDelegateCaller.sol @@ -0,0 +1,37 @@ +/* + + Copyright 2020 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.6.5; +pragma experimental ABIEncoderV2; + + + +contract TestDelegateCaller { + function executeDelegateCall( + address target, + bytes calldata callData + ) + external + { + (bool success, bytes memory resultData) = target.delegatecall(callData); + if (!success) { + assembly { revert(add(resultData, 32), mload(resultData)) } + } + assembly { return(add(resultData, 32), mload(resultData)) } + } +} diff --git a/contracts/zero-ex/contracts/test/TestTransformerBase.sol b/contracts/zero-ex/contracts/test/TestTransformerBase.sol new file mode 100644 index 0000000000..f4ae45e07d --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestTransformerBase.sol @@ -0,0 +1,53 @@ +/* + + Copyright 2020 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.6.5; +pragma experimental ABIEncoderV2; + +import "../src/transformers/Transformer.sol"; + + +contract TestTransformerBase is + Transformer +{ + // solhint-disable no-empty-blocks + constructor(uint256 deploymentNonce_) + public + Transformer(deploymentNonce_) + {} + + function transform( + bytes32, + address payable, + bytes calldata + ) + external + override + returns (bytes memory rlpDeploymentNonce) + { + return hex""; + } + + function getRLPEncodedDeploymentNonce() + external + view + returns (bytes memory) + { + return _getRLPEncodedDeploymentNonce(); + } +} diff --git a/contracts/zero-ex/contracts/test/TestTransformerHost.sol b/contracts/zero-ex/contracts/test/TestTransformerHost.sol index 283dc0e4fe..57344ae885 100644 --- a/contracts/zero-ex/contracts/test/TestTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestTransformerHost.sol @@ -37,7 +37,7 @@ contract TestTransformerHost { bytes calldata data ) external - returns (bytes memory rlpDeploymentNonce) + returns (bytes memory) { (bool success, bytes memory resultData) = address(transformer).delegatecall(abi.encodeWithSelector( diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json index fb07186d3e..d94206f4e9 100644 --- a/contracts/zero-ex/package.json +++ b/contracts/zero-ex/package.json @@ -40,7 +40,7 @@ "config": { "publicInterfaceContracts": "ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20,FillQuoteTransformer,PayTakerTransformer,WethTransformer", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(AllowanceTarget|Bootstrap|FillQuoteTransformer|FixinCommon|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Transformer|IExchange|IFeature|IFlashWallet|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|Ownable|PayTakerTransformer|SimpleFunctionRegistry|TestCallTarget|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|WethTransformer|ZeroEx).json" + "abis": "./test/generated-artifacts/@(AllowanceTarget|Bootstrap|FillQuoteTransformer|FixinCommon|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Transformer|IExchange|IFeature|IFlashWallet|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|Ownable|PayTakerTransformer|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|WethTransformer|ZeroEx).json" }, "repository": { "type": "git", diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index 09476a1d5a..4774071dca 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -43,6 +43,7 @@ import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json'; import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json'; import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json'; +import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCaller.json'; import * as TestFillQuoteTransformerExchange from '../test/generated-artifacts/TestFillQuoteTransformerExchange.json'; import * as TestFillQuoteTransformerHost from '../test/generated-artifacts/TestFillQuoteTransformerHost.json'; import * as TestFullMigration from '../test/generated-artifacts/TestFullMigration.json'; @@ -54,12 +55,14 @@ import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artif import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json'; import * as TestTokenSpender from '../test/generated-artifacts/TestTokenSpender.json'; import * as TestTokenSpenderERC20Token from '../test/generated-artifacts/TestTokenSpenderERC20Token.json'; +import * as TestTransformerBase from '../test/generated-artifacts/TestTransformerBase.json'; import * as TestTransformERC20 from '../test/generated-artifacts/TestTransformERC20.json'; import * as TestTransformerHost from '../test/generated-artifacts/TestTransformerHost.json'; import * as TestWeth from '../test/generated-artifacts/TestWeth.json'; import * as TestWethTransformerHost from '../test/generated-artifacts/TestWethTransformerHost.json'; import * as TestZeroExFeature from '../test/generated-artifacts/TestZeroExFeature.json'; import * as TokenSpender from '../test/generated-artifacts/TokenSpender.json'; +import * as Transformer from '../test/generated-artifacts/Transformer.json'; import * as TransformERC20 from '../test/generated-artifacts/TransformERC20.json'; import * as WethTransformer from '../test/generated-artifacts/WethTransformer.json'; import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json'; @@ -102,10 +105,12 @@ export const artifacts = { IERC20Transformer: IERC20Transformer as ContractArtifact, LibERC20Transformer: LibERC20Transformer as ContractArtifact, PayTakerTransformer: PayTakerTransformer as ContractArtifact, + Transformer: Transformer as ContractArtifact, WethTransformer: WethTransformer as ContractArtifact, IExchange: IExchange as ContractArtifact, ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, TestCallTarget: TestCallTarget as ContractArtifact, + TestDelegateCaller: TestDelegateCaller as ContractArtifact, TestFillQuoteTransformerExchange: TestFillQuoteTransformerExchange as ContractArtifact, TestFillQuoteTransformerHost: TestFillQuoteTransformerHost as ContractArtifact, TestFullMigration: TestFullMigration as ContractArtifact, @@ -118,6 +123,7 @@ export const artifacts = { TestTokenSpender: TestTokenSpender as ContractArtifact, TestTokenSpenderERC20Token: TestTokenSpenderERC20Token as ContractArtifact, TestTransformERC20: TestTransformERC20 as ContractArtifact, + TestTransformerBase: TestTransformerBase as ContractArtifact, TestTransformerHost: TestTransformerHost as ContractArtifact, TestWeth: TestWeth as ContractArtifact, TestWethTransformerHost: TestWethTransformerHost as ContractArtifact, diff --git a/contracts/zero-ex/test/transformers/transformer_base_test.ts b/contracts/zero-ex/test/transformers/transformer_base_test.ts new file mode 100644 index 0000000000..9f8324d74a --- /dev/null +++ b/contracts/zero-ex/test/transformers/transformer_base_test.ts @@ -0,0 +1,68 @@ +import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; +import { BigNumber, ZeroExRevertErrors } from '@0x/utils'; +import * as _ from 'lodash'; + +import { rlpEncodeNonce } from '../../src/nonce_utils'; +import { artifacts } from '../artifacts'; +import { TestDelegateCallerContract, TestTransformerBaseContract } from '../wrappers'; + +blockchainTests.resets('Transformer (base)', env => { + const deploymentNonce = _.random(0, 0xffffffff); + let deployer: string; + let delegateCaller: TestDelegateCallerContract; + let transformer: TestTransformerBaseContract; + + before(async () => { + [deployer] = await env.getAccountAddressesAsync(); + delegateCaller = await TestDelegateCallerContract.deployFrom0xArtifactAsync( + artifacts.TestDelegateCaller, + env.provider, + env.txDefaults, + artifacts, + ); + transformer = await TestTransformerBaseContract.deployFrom0xArtifactAsync( + artifacts.TestTransformerBase, + env.provider, + { + ...env.txDefaults, + from: deployer, + }, + artifacts, + new BigNumber(deploymentNonce), + ); + }); + + describe('_getRLPEncodedDeploymentNonce()', () => { + it('returns the RLP encoded deployment nonce', async () => { + const r = await transformer.getRLPEncodedDeploymentNonce().callAsync(); + expect(r).to.eq(rlpEncodeNonce(deploymentNonce)); + }); + }); + + describe('die()', () => { + it('cannot be called by non-deployer', async () => { + const notDeployer = randomAddress(); + const tx = transformer.die(randomAddress()).callAsync({ from: notDeployer }); + return expect(tx).to.revertWith( + new ZeroExRevertErrors.TransformERC20.OnlyCallableByDeployerError(notDeployer, deployer), + ); + }); + + it('cannot be called outside of its own context', async () => { + const callData = transformer.die(randomAddress()).getABIEncodedTransactionData(); + const tx = delegateCaller.executeDelegateCall(transformer.address, callData).callAsync({ from: deployer }); + return expect(tx).to.revertWith( + new ZeroExRevertErrors.TransformERC20.InvalidExecutionContextError( + delegateCaller.address, + transformer.address, + ), + ); + }); + + it('destroys the transformer', async () => { + await transformer.die(randomAddress()).awaitTransactionSuccessAsync({ from: deployer }); + const code = await env.web3Wrapper.getContractCodeAsync(transformer.address); + return expect(code).to.eq(constants.NULL_BYTES); + }); + }); +}); diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index 140573cfdf..94390b6387 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -42,6 +42,7 @@ export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/pay_taker_transformer'; export * from '../test/generated-wrappers/simple_function_registry'; export * from '../test/generated-wrappers/test_call_target'; +export * from '../test/generated-wrappers/test_delegate_caller'; export * from '../test/generated-wrappers/test_fill_quote_transformer_exchange'; export * from '../test/generated-wrappers/test_fill_quote_transformer_host'; export * from '../test/generated-wrappers/test_full_migration'; @@ -54,6 +55,7 @@ export * from '../test/generated-wrappers/test_simple_function_registry_feature_ export * from '../test/generated-wrappers/test_token_spender'; export * from '../test/generated-wrappers/test_token_spender_erc20_token'; export * from '../test/generated-wrappers/test_transform_erc20'; +export * from '../test/generated-wrappers/test_transformer_base'; export * from '../test/generated-wrappers/test_transformer_host'; export * from '../test/generated-wrappers/test_weth'; export * from '../test/generated-wrappers/test_weth_transformer_host'; @@ -61,5 +63,6 @@ export * from '../test/generated-wrappers/test_zero_ex_feature'; export * from '../test/generated-wrappers/token_spender'; export * from '../test/generated-wrappers/token_spender_puppet'; export * from '../test/generated-wrappers/transform_erc20'; +export * from '../test/generated-wrappers/transformer'; export * from '../test/generated-wrappers/weth_transformer'; export * from '../test/generated-wrappers/zero_ex'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index 288e41bd47..637fe2eece 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -55,6 +55,7 @@ "test/generated-artifacts/PayTakerTransformer.json", "test/generated-artifacts/SimpleFunctionRegistry.json", "test/generated-artifacts/TestCallTarget.json", + "test/generated-artifacts/TestDelegateCaller.json", "test/generated-artifacts/TestFillQuoteTransformerExchange.json", "test/generated-artifacts/TestFillQuoteTransformerHost.json", "test/generated-artifacts/TestFullMigration.json", @@ -67,6 +68,7 @@ "test/generated-artifacts/TestTokenSpender.json", "test/generated-artifacts/TestTokenSpenderERC20Token.json", "test/generated-artifacts/TestTransformERC20.json", + "test/generated-artifacts/TestTransformerBase.json", "test/generated-artifacts/TestTransformerHost.json", "test/generated-artifacts/TestWeth.json", "test/generated-artifacts/TestWethTransformerHost.json", @@ -74,6 +76,7 @@ "test/generated-artifacts/TokenSpender.json", "test/generated-artifacts/TokenSpenderPuppet.json", "test/generated-artifacts/TransformERC20.json", + "test/generated-artifacts/Transformer.json", "test/generated-artifacts/WethTransformer.json", "test/generated-artifacts/ZeroEx.json" ],