diff --git a/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol index 2cee9e18b7..ea6789ea15 100644 --- a/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol +++ b/contracts/zero-ex/contracts/src/errors/LibTransformERC20RichErrors.sol @@ -70,31 +70,20 @@ library LibTransformERC20RichErrors { ); } - function UnauthorizedTransformerError( + function TransformerFailedError( address transformer, - bytes memory rlpNonce + bytes memory transformerData, + bytes memory resultData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( - bytes4(keccak256("UnauthorizedTransformerError(address,bytes)")), + bytes4(keccak256("TransformerFailedError(address,bytes,bytes)")), transformer, - rlpNonce - ); - } - - function InvalidRLPNonceError( - bytes memory rlpNonce - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("InvalidRLPNonceError(bytes)")), - rlpNonce + transformerData, + resultData ); } diff --git a/contracts/zero-ex/contracts/src/external/AllowanceTarget.sol b/contracts/zero-ex/contracts/src/external/AllowanceTarget.sol index 7675376c67..176eebd293 100644 --- a/contracts/zero-ex/contracts/src/external/AllowanceTarget.sol +++ b/contracts/zero-ex/contracts/src/external/AllowanceTarget.sol @@ -42,7 +42,6 @@ contract AllowanceTarget is bytes calldata callData ) external - payable override onlyAuthorized returns (bytes memory resultData) diff --git a/contracts/zero-ex/contracts/src/external/IAllowanceTarget.sol b/contracts/zero-ex/contracts/src/external/IAllowanceTarget.sol index 1f84fff3da..d4c533745c 100644 --- a/contracts/zero-ex/contracts/src/external/IAllowanceTarget.sol +++ b/contracts/zero-ex/contracts/src/external/IAllowanceTarget.sol @@ -35,6 +35,5 @@ interface IAllowanceTarget is bytes calldata callData ) external - payable returns (bytes memory resultData); } diff --git a/contracts/zero-ex/contracts/src/features/ITransformERC20.sol b/contracts/zero-ex/contracts/src/features/ITransformERC20.sol index e2259be51a..c60fdb4690 100644 --- a/contracts/zero-ex/contracts/src/features/ITransformERC20.sol +++ b/contracts/zero-ex/contracts/src/features/ITransformERC20.sol @@ -29,9 +29,10 @@ interface ITransformERC20 { /// @dev Defines a transformation to run in `transformERC20()`. struct Transformation { - // The transformation handler. - // Can receive the entire balance of `tokens`. - IERC20Transformer transformer; + // The deployment nonce for the transformer. + // The address of the transformer contract will be derived from this + // value. + uint32 deploymentNonce; // Arbitrary data to pass to the transformer. bytes data; } @@ -52,6 +53,15 @@ interface ITransformERC20 { uint256 outputTokenAmount ); + /// @dev Raised when `setTransformerDeployer()` is called. + /// @param transformerDeployer The new deployer address. + event TransformerDeployerUpdated(address transformerDeployer); + + /// @dev Replace the allowed deployer for transformers. + /// Only callable by the owner. + function setTransformerDeployer(address transformerDeployer) + external; + /// @dev Deploy a new flash wallet instance and replace the current one with it. /// Useful if we somehow break the current wallet instance. /// Anyone can call this. diff --git a/contracts/zero-ex/contracts/src/features/TransformERC20.sol b/contracts/zero-ex/contracts/src/features/TransformERC20.sol index 3a736a8c00..1e76cd5414 100644 --- a/contracts/zero-ex/contracts/src/features/TransformERC20.sol +++ b/contracts/zero-ex/contracts/src/features/TransformERC20.sol @@ -44,13 +44,19 @@ contract TransformERC20 is FixinCommon { + /// @dev Stack vars for `_transformERC20Private()`. + struct TransformERC20PrivateState { + IFlashWallet wallet; + address transformerDeployer; + uint256 takerOutputTokenBalanceBefore; + uint256 takerOutputTokenBalanceAfter; + } + // solhint-disable /// @dev Name of this feature. string public constant override FEATURE_NAME = "TransformERC20"; /// @dev Version of this feature. uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0); - /// @dev The trusted deployer for all transformers. - address public immutable transformDeployer; /// @dev The implementation address of this feature. address private immutable _implementation; // solhint-enable @@ -58,37 +64,51 @@ contract TransformERC20 is using LibSafeMathV06 for uint256; using LibRichErrorsV06 for bytes; - constructor(address trustedDeployer_) public { + constructor() public { _implementation = address(this); - transformDeployer = trustedDeployer_; } /// @dev Initialize and register this feature. /// Should be delegatecalled by `Migrate.migrate()`. - function migrate() external returns (bytes4 success) { + /// @param transformerDeployer The trusted deployer for transformers. + function migrate(address transformerDeployer) external returns (bytes4 success) { ISimpleFunctionRegistry(address(this)) .extend(this.getTransformerDeployer.selector, _implementation); ISimpleFunctionRegistry(address(this)) .extend(this.createTransformWallet.selector, _implementation); ISimpleFunctionRegistry(address(this)) .extend(this.getTransformWallet.selector, _implementation); + ISimpleFunctionRegistry(address(this)) + .extend(this.setTransformerDeployer.selector, _implementation); ISimpleFunctionRegistry(address(this)) .extend(this.transformERC20.selector, _implementation); ISimpleFunctionRegistry(address(this)) .extend(this._transformERC20.selector, _implementation); createTransformWallet(); + LibTransformERC20Storage.getStorage().transformerDeployer = transformerDeployer; return LibMigrate.MIGRATE_SUCCESS; } + /// @dev Replace the allowed deployer for transformers. + /// Only callable by the owner. + function setTransformerDeployer(address transformerDeployer) + external + override + onlyOwner + { + LibTransformERC20Storage.getStorage().transformerDeployer = transformerDeployer; + emit TransformerDeployerUpdated(transformerDeployer); + } + /// @dev Return the allowed deployer for transformers. /// @return deployer The transform deployer address. function getTransformerDeployer() - external + public override view returns (address deployer) { - return transformDeployer; + return LibTransformERC20Storage.getStorage().transformerDeployer; } /// @dev Deploy a new wallet instance and replace the current one with it. @@ -209,8 +229,7 @@ contract TransformERC20 is uint256 minOutputTokenAmount, Transformation[] memory transformations ) - public - payable + private returns (uint256 outputTokenAmount) { // If the input token amount is -1, transform the taker's entire @@ -220,31 +239,44 @@ contract TransformERC20 is .getSpendableERC20BalanceOf(inputToken, taker); } - IFlashWallet wallet = getTransformWallet(); + TransformERC20PrivateState memory state; + state.wallet = getTransformWallet(); + state.transformerDeployer = getTransformerDeployer(); // Remember the initial output token balance of the taker. - uint256 takerOutputTokenBalanceBefore = + state.takerOutputTokenBalanceBefore = LibERC20Transformer.getTokenBalanceOf(outputToken, taker); // Pull input tokens from the taker to the wallet and transfer attached ETH. - _transferInputTokensAndAttachedEth(inputToken, taker, address(wallet), inputTokenAmount); + _transferInputTokensAndAttachedEth( + inputToken, + taker, + address(state.wallet), + inputTokenAmount + ); // Perform transformations. for (uint256 i = 0; i < transformations.length; ++i) { - _executeTransformation(wallet, transformations[i], taker, callDataHash); + _executeTransformation( + state.wallet, + transformations[i], + state.transformerDeployer, + taker, + callDataHash + ); } // Compute how much output token has been transferred to the taker. - uint256 takerOutputTokenBalanceAfter = + state.takerOutputTokenBalanceAfter = LibERC20Transformer.getTokenBalanceOf(outputToken, taker); - if (takerOutputTokenBalanceAfter > takerOutputTokenBalanceBefore) { - outputTokenAmount = takerOutputTokenBalanceAfter.safeSub( - takerOutputTokenBalanceBefore + if (state.takerOutputTokenBalanceAfter > state.takerOutputTokenBalanceBefore) { + outputTokenAmount = state.takerOutputTokenBalanceAfter.safeSub( + state.takerOutputTokenBalanceBefore ); - } else if (takerOutputTokenBalanceAfter < takerOutputTokenBalanceBefore) { + } else if (state.takerOutputTokenBalanceAfter < state.takerOutputTokenBalanceBefore) { LibTransformERC20RichErrors.NegativeTransformERC20OutputError( address(outputToken), - takerOutputTokenBalanceBefore - takerOutputTokenBalanceAfter + state.takerOutputTokenBalanceBefore - state.takerOutputTokenBalanceAfter ).rrevert(); } // Ensure enough output token has been sent to the taker. @@ -316,20 +348,27 @@ contract TransformERC20 is /// @dev Executs a transformer in the context of `wallet`. /// @param wallet The wallet instance. /// @param transformation The transformation. + /// @param transformerDeployer The address of the transformer deployer. /// @param taker The taker address. /// @param callDataHash Hash of the calldata. function _executeTransformation( IFlashWallet wallet, Transformation memory transformation, + address transformerDeployer, address payable taker, bytes32 callDataHash ) private { + // Derive the transformer address from the deployment nonce. + address payable transformer = LibERC20Transformer.getDeployedAddress( + transformerDeployer, + transformation.deploymentNonce + ); // Call `transformer.transform()` as the wallet. bytes memory resultData = wallet.executeDelegateCall( - // Call target. - address(uint160(address(transformation.transformer))), + // The call target. + transformer, // Call data. abi.encodeWithSelector( IERC20Transformer.transform.selector, @@ -338,39 +377,15 @@ contract TransformERC20 is transformation.data ) ); - // Ensure the transformer returned its valid rlp-encoded deployment nonce. - bytes memory rlpNonce = resultData.length == 0 - ? new bytes(0) - : abi.decode(resultData, (bytes)); - if (_getExpectedDeployment(rlpNonce) != address(transformation.transformer)) { - LibTransformERC20RichErrors.UnauthorizedTransformerError( - address(transformation.transformer), - rlpNonce + // Ensure the transformer returned the magic bytes. + if (resultData.length != 32 || + abi.decode(resultData, (bytes4)) != LibERC20Transformer.TRANSFORMER_SUCCESS + ) { + LibTransformERC20RichErrors.TransformerFailedError( + transformer, + transformation.data, + resultData ).rrevert(); } } - - /// @dev Compute the expected deployment address by `transformDeployer` at - /// the nonce given by `rlpNonce`. - /// @param rlpNonce The RLP-encoded nonce that - /// the deployer had when deploying a contract. - /// @return deploymentAddress The deployment address. - function _getExpectedDeployment(bytes memory rlpNonce) - private - view - returns (address deploymentAddress) - { - // See https://github.com/ethereum/wiki/wiki/RLP for RLP encoding rules. - // The RLP-encoded nonce may be prefixed with a length byte. - // We only support nonces up to 32-bits. - if (rlpNonce.length == 0 || rlpNonce.length > 5) { - LibTransformERC20RichErrors.InvalidRLPNonceError(rlpNonce).rrevert(); - } - return address(uint160(uint256(keccak256(abi.encodePacked( - byte(uint8(0xC0 + 21 + rlpNonce.length)), - byte(uint8(0x80 + 20)), - transformDeployer, - rlpNonce - ))))); - } } diff --git a/contracts/zero-ex/contracts/src/migrations/FullMigration.sol b/contracts/zero-ex/contracts/src/migrations/FullMigration.sol index 2c54950324..b1a0e2246d 100644 --- a/contracts/zero-ex/contracts/src/migrations/FullMigration.sol +++ b/contracts/zero-ex/contracts/src/migrations/FullMigration.sol @@ -40,6 +40,11 @@ contract FullMigration { TransformERC20 transformERC20; } + /// @dev Parameters needed to initialize features. + struct MigrateOpts { + address transformerDeployer; + } + /// @dev The allowed caller of `deploy()`. address public immutable deployer; /// @dev The initial migration contract. @@ -62,9 +67,11 @@ contract FullMigration { /// @param owner The owner of the contract. /// @param features Features to add to the proxy. /// @return zeroEx The deployed and configured `ZeroEx` contract. + /// @param migrateOpts Parameters needed to initialize features. function deploy( address payable owner, - Features memory features + Features memory features, + MigrateOpts memory migrateOpts ) public returns (ZeroEx zeroEx) @@ -81,7 +88,7 @@ contract FullMigration { ); // Add features. - _addFeatures(zeroEx, owner, features); + _addFeatures(zeroEx, owner, features, migrateOpts); // Transfer ownership to the real owner. IOwnable(address(zeroEx)).transferOwnership(owner); @@ -106,10 +113,12 @@ contract FullMigration { /// @param zeroEx The bootstrapped ZeroEx contract. /// @param owner The ultimate owner of the ZeroEx contract. /// @param features Features to add to the proxy. + /// @param migrateOpts Parameters needed to initialize features. function _addFeatures( ZeroEx zeroEx, address owner, - Features memory features + Features memory features, + MigrateOpts memory migrateOpts ) private { @@ -138,7 +147,8 @@ contract FullMigration { ownable.migrate( address(features.transformERC20), abi.encodeWithSelector( - TransformERC20.migrate.selector + TransformERC20.migrate.selector, + migrateOpts.transformerDeployer ), address(this) ); diff --git a/contracts/zero-ex/contracts/src/storage/LibTransformERC20Storage.sol b/contracts/zero-ex/contracts/src/storage/LibTransformERC20Storage.sol index 2049d60077..78740b171b 100644 --- a/contracts/zero-ex/contracts/src/storage/LibTransformERC20Storage.sol +++ b/contracts/zero-ex/contracts/src/storage/LibTransformERC20Storage.sol @@ -30,6 +30,8 @@ library LibTransformERC20Storage { struct Storage { // The current wallet instance. IFlashWallet wallet; + // The transformer deployer address. + address transformerDeployer; } /// @dev Get the storage bucket for this contract. diff --git a/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol b/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol index eb7af401f3..383b0e2d02 100644 --- a/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol @@ -93,10 +93,9 @@ 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_) + constructor(IExchange exchange_) public - Transformer(deploymentNonce_) + Transformer() { exchange = exchange_; erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID); @@ -106,9 +105,7 @@ contract FillQuoteTransformer is /// for `buyToken` by filling `orders`. Protocol fees should be attached /// to this call. `buyToken` and excess ETH will be transferred back to the caller. /// @param data_ ABI-encoded `TransformData`. - /// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer - /// when this transformer was deployed. This is used to verify that - /// this transformer was deployed by a trusted contract. + /// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`). function transform( bytes32, // callDataHash, address payable, // taker, @@ -116,7 +113,7 @@ contract FillQuoteTransformer is ) external override - returns (bytes memory rlpDeploymentNonce) + returns (bytes4 success) { TransformData memory data = abi.decode(data_, (TransformData)); @@ -231,7 +228,7 @@ contract FillQuoteTransformer is ).rrevert(); } } - return _getRLPEncodedDeploymentNonce(); + return LibERC20Transformer.TRANSFORMER_SUCCESS; } /// @dev Try to sell up to `sellAmount` from an order. diff --git a/contracts/zero-ex/contracts/src/transformers/IERC20Transformer.sol b/contracts/zero-ex/contracts/src/transformers/IERC20Transformer.sol index 217ca41355..40fd9387c0 100644 --- a/contracts/zero-ex/contracts/src/transformers/IERC20Transformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/IERC20Transformer.sol @@ -30,14 +30,12 @@ interface IERC20Transformer { /// @param callDataHash The hash of the `TransformERC20.transformERC20()` calldata. /// @param taker The taker address (caller of `TransformERC20.transformERC20()`). /// @param data Arbitrary data to pass to the transformer. - /// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer - /// when this transformer was deployed. This is used to verify that - /// this transformer was deployed by a trusted contract. + /// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`). function transform( bytes32 callDataHash, address payable taker, bytes calldata data ) external - returns (bytes memory rlpDeploymentNonce); + returns (bytes4 success); } diff --git a/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol b/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol index fe768b34ad..a06194c2d2 100644 --- a/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol @@ -29,6 +29,9 @@ library LibERC20Transformer { /// @dev ETH pseudo-token address. address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + /// @dev Return value indicating success in `IERC20Transformer.transform()`. + /// This is just `keccak256('TRANSFORMER_SUCCESS')`. + bytes4 constant internal TRANSFORMER_SUCCESS = 0x13c9929e; /// @dev Transfer ERC20 tokens and ETH. /// @param token An ERC20 or the ETH pseudo-token address (`ETH_TOKEN_ADDRESS`). @@ -68,17 +71,21 @@ library LibERC20Transformer { view returns (uint256 tokenBalance) { - return isTokenETH(token) ? owner.balance : token.balanceOf(owner); + if (isTokenETH(token)) { + return owner.balance + } + return token.balanceOf(owner); } /// @dev RLP-encode a 32-bit or less account nonce. /// @param nonce A positive integer in the range 0 <= nonce < 2^32. /// @return rlpNonce The RLP encoding. - function rlpEncodeNonce(uint256 nonce) + function rlpEncodeNonce(uint32 nonce) internal pure returns (bytes memory rlpNonce) { + // See https://github.com/ethereum/wiki/wiki/RLP for RLP encoding rules. if (nonce == 0) { rlpNonce = new bytes(1); rlpNonce[0] = 0x80; @@ -100,15 +107,36 @@ library LibERC20Transformer { rlpNonce[1] = byte(uint8((nonce & 0xFF0000) >> 16)); rlpNonce[2] = byte(uint8((nonce & 0xFF00) >> 8)); rlpNonce[3] = byte(uint8(nonce)); - } else if (nonce <= 0xFFFFFFFF) { + } else { rlpNonce = new bytes(5); rlpNonce[0] = 0x84; rlpNonce[1] = byte(uint8((nonce & 0xFF000000) >> 24)); rlpNonce[2] = byte(uint8((nonce & 0xFF0000) >> 16)); rlpNonce[3] = byte(uint8((nonce & 0xFF00) >> 8)); rlpNonce[4] = byte(uint8(nonce)); - } else { - revert("LibERC20Transformer/INVALID_ENCODE_NONCE"); } } + + /// @dev Compute the expected deployment address by `deployer` at + /// the nonce given by `deploymentNonce`. + /// @param deployer The address of the deployer. + /// @param deploymentNonce The nonce that the deployer had when deploying + /// a contract. + /// @return deploymentAddress The deployment address. + function getDeployedAddress(address deployer, uint32 deploymentNonce) + internal + pure + returns (address payable deploymentAddress) + { + // The address of if a deployed contract is the lower 20 bytes of the + // hash of the RLP-encoded deployer's account address + account nonce. + // See: https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed + bytes memory rlpNonce = rlpEncodeNonce(deploymentNonce); + return address(uint160(uint256(keccak256(abi.encodePacked( + byte(uint8(0xC0 + 21 + rlpNonce.length)), + byte(uint8(0x80 + 20)), + deployer, + rlpNonce + ))))); + } } diff --git a/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol b/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol index 53de743e77..4b03759ab1 100644 --- a/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol @@ -50,18 +50,15 @@ contract PayTakerTransformer is uint256 private constant MAX_UINT256 = uint256(-1); /// @dev Create this contract. - /// @param deploymentNonce_ The nonce of the deployer when deploying this contract. - constructor(uint256 deploymentNonce_) + constructor() public - Transformer(deploymentNonce_) + Transformer() {} /// @dev Forwards tokens to the taker. /// @param taker The taker address (caller of `TransformERC20.transformERC20()`). /// @param data_ ABI-encoded `TransformData`, indicating which tokens to transfer. - /// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer - /// when this transformer was deployed. This is used to verify that - /// this transformer was deployed by a trusted contract. + /// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`). function transform( bytes32, // callDataHash, address payable taker, @@ -69,7 +66,7 @@ contract PayTakerTransformer is ) external override - returns (bytes memory rlpDeploymentNonce) + returns (bytes4 success) { TransformData memory data = abi.decode(data_, (TransformData)); @@ -85,6 +82,6 @@ contract PayTakerTransformer is data.tokens[i].transformerTransfer(taker, amount); } } - return _getRLPEncodedDeploymentNonce(); + return LibERC20Transformer.TRANSFORMER_SUCCESS; } } diff --git a/contracts/zero-ex/contracts/src/transformers/Transformer.sol b/contracts/zero-ex/contracts/src/transformers/Transformer.sol index ec9a942d64..855745e32b 100644 --- a/contracts/zero-ex/contracts/src/transformers/Transformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/Transformer.sol @@ -22,7 +22,6 @@ 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. @@ -33,15 +32,11 @@ abstract contract Transformer is /// @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_; + constructor() public { deployer = msg.sender; _implementation = address(this); } @@ -67,14 +62,4 @@ abstract contract Transformer is } 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 bba2d6440e..503712cfd9 100644 --- a/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol @@ -51,19 +51,16 @@ contract WethTransformer is /// @dev Construct the transformer and store the WETH address in an immutable. /// @param weth_ The weth token. - /// @param deploymentNonce_ The nonce of the deployer when deploying this contract. - constructor(IEtherTokenV06 weth_, uint256 deploymentNonce_) + constructor(IEtherTokenV06 weth_) public - Transformer(deploymentNonce_) + Transformer() { weth = weth_; } /// @dev Wraps and unwraps WETH. /// @param data_ ABI-encoded `TransformData`, indicating which token to wrap/umwrap. - /// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer - /// when this transformer was deployed. This is used to verify that - /// this transformer was deployed by a trusted contract. + /// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`). function transform( bytes32, // callDataHash, address payable, // taker, @@ -71,7 +68,7 @@ contract WethTransformer is ) external override - returns (bytes memory rlpDeploymentNonce) + returns (bytes4 success) { TransformData memory data = abi.decode(data_, (TransformData)); if (!data.token.isTokenETH() && data.token != weth) { @@ -95,6 +92,6 @@ contract WethTransformer is weth.withdraw(amount); } } - return _getRLPEncodedDeploymentNonce(); + return LibERC20Transformer.TRANSFORMER_SUCCESS; } } diff --git a/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol b/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol index 3f9c196bd8..6b85acd2f5 100644 --- a/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol @@ -35,12 +35,11 @@ contract TestFillQuoteTransformerHost is ) external payable - returns (bytes memory rlpDeploymentNonce) { if (inputTokenAmount != 0) { inputToken.mint(address(this), inputTokenAmount); } // Have to make this call externally because transformers aren't payable. - return this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); + this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); } } diff --git a/contracts/zero-ex/contracts/test/TestMintTokenERC20Transformer.sol b/contracts/zero-ex/contracts/test/TestMintTokenERC20Transformer.sol index 6ff386f45e..2bd2463b64 100644 --- a/contracts/zero-ex/contracts/test/TestMintTokenERC20Transformer.sol +++ b/contracts/zero-ex/contracts/test/TestMintTokenERC20Transformer.sol @@ -34,7 +34,6 @@ contract TestMintTokenERC20Transformer is uint256 burnAmount; uint256 mintAmount; uint256 feeAmount; - bytes deploymentNonce; } event MintTransform( @@ -54,7 +53,7 @@ contract TestMintTokenERC20Transformer is ) external override - returns (bytes memory rlpDeploymentNonce) + returns (bytes4 success) { TransformData memory data = abi.decode(data_, (TransformData)); emit MintTransform( @@ -79,6 +78,6 @@ contract TestMintTokenERC20Transformer is // Burn fees from output. data.outputToken.burn(taker, data.feeAmount); } - return data.deploymentNonce; + return LibERC20Transformer.TRANSFORMER_SUCCESS; } } diff --git a/contracts/zero-ex/contracts/test/TestTransformERC20.sol b/contracts/zero-ex/contracts/test/TestTransformERC20.sol index f7549cb1e4..0e133d81d1 100644 --- a/contracts/zero-ex/contracts/test/TestTransformERC20.sol +++ b/contracts/zero-ex/contracts/test/TestTransformERC20.sol @@ -26,8 +26,8 @@ contract TestTransformERC20 is TransformERC20 { // solhint-disable no-empty-blocks - constructor(address trustedDeployer) - TransformERC20(trustedDeployer) + constructor() + TransformERC20() public {} diff --git a/contracts/zero-ex/contracts/test/TestTransformerBase.sol b/contracts/zero-ex/contracts/test/TestTransformerBase.sol index f4ae45e07d..d08151d3b4 100644 --- a/contracts/zero-ex/contracts/test/TestTransformerBase.sol +++ b/contracts/zero-ex/contracts/test/TestTransformerBase.sol @@ -20,17 +20,12 @@ pragma solidity ^0.6.5; pragma experimental ABIEncoderV2; import "../src/transformers/Transformer.sol"; +import "../src/transformers/LibERC20Transformer.sol"; contract TestTransformerBase is Transformer { - // solhint-disable no-empty-blocks - constructor(uint256 deploymentNonce_) - public - Transformer(deploymentNonce_) - {} - function transform( bytes32, address payable, @@ -38,16 +33,8 @@ contract TestTransformerBase is ) external override - returns (bytes memory rlpDeploymentNonce) + returns (bytes4 success) { - return hex""; - } - - function getRLPEncodedDeploymentNonce() - external - view - returns (bytes memory) - { - return _getRLPEncodedDeploymentNonce(); + return LibERC20Transformer.TRANSFORMER_SUCCESS; } } diff --git a/contracts/zero-ex/contracts/test/TestTransformerHost.sol b/contracts/zero-ex/contracts/test/TestTransformerHost.sol index 57344ae885..587b837de9 100644 --- a/contracts/zero-ex/contracts/test/TestTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestTransformerHost.sol @@ -37,19 +37,21 @@ contract TestTransformerHost { bytes calldata data ) external - returns (bytes memory) { - (bool success, bytes memory resultData) = + (bool _success, bytes memory resultData) = address(transformer).delegatecall(abi.encodeWithSelector( transformer.transform.selector, callDataHash, taker, data )); - if (!success) { + if (!_success) { resultData.rrevert(); } - assembly { return(add(resultData, 32), mload(resultData)) } + require( + abi.decode(resultData, (bytes4)) == LibERC20Transformer.TRANSFORMER_SUCCESS, + "TestTransformerHost/INVALID_TRANSFORMER_RESULT" + ); } // solhint-disable diff --git a/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol b/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol index fbadc6a9dd..3c0fd83999 100644 --- a/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol @@ -43,12 +43,11 @@ contract TestWethTransformerHost is ) external payable - returns (bytes memory rlpDeploymentNonce) { if (wethAmount != 0) { _weth.deposit{value: wethAmount}(); } // Have to make this call externally because transformers aren't payable. - return this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); + this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); } } diff --git a/contracts/zero-ex/test/features/transform_erc20_test.ts b/contracts/zero-ex/test/features/transform_erc20_test.ts index 82bb3aee90..77a18a7f9b 100644 --- a/contracts/zero-ex/test/features/transform_erc20_test.ts +++ b/contracts/zero-ex/test/features/transform_erc20_test.ts @@ -8,10 +8,9 @@ import { randomAddress, verifyEventsFromLogs, } from '@0x/contracts-test-utils'; -import { AbiEncoder, hexUtils, ZeroExRevertErrors } from '@0x/utils'; +import { AbiEncoder, hexUtils, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils'; import { ETH_TOKEN_ADDRESS } from '../../src/constants'; -import { getRLPEncodedAccountNonceAsync } from '../../src/nonce_utils'; import { artifacts } from '../artifacts'; import { abis } from '../utils/abis'; import { fullMigrateAsync } from '../utils/migration'; @@ -27,6 +26,7 @@ import { } from '../wrappers'; blockchainTests.resets('TransformERC20 feature', env => { + let owner: string; let taker: string; let transformerDeployer: string; let zeroEx: ZeroExContract; @@ -35,17 +35,21 @@ blockchainTests.resets('TransformERC20 feature', env => { let allowanceTarget: string; before(async () => { - let owner; [owner, taker, transformerDeployer] = await env.getAccountAddressesAsync(); - zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, { - transformERC20: await TransformERC20Contract.deployFrom0xArtifactAsync( - artifacts.TestTransformERC20, - env.provider, - env.txDefaults, - artifacts, - transformerDeployer, - ), - }); + zeroEx = await fullMigrateAsync( + owner, + env.provider, + env.txDefaults, + { + transformERC20: await TransformERC20Contract.deployFrom0xArtifactAsync( + artifacts.TestTransformERC20, + env.provider, + env.txDefaults, + artifacts, + ), + }, + { transformerDeployer }, + ); feature = new TransformERC20Contract(zeroEx.address, env.provider, env.txDefaults, abis); wallet = new FlashWalletContract(await feature.getTransformWallet().callAsync(), env.provider, env.txDefaults); allowanceTarget = await new ITokenSpenderContract(zeroEx.address, env.provider, env.txDefaults) @@ -53,7 +57,7 @@ blockchainTests.resets('TransformERC20 feature', env => { .callAsync(); }); - const { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } = constants; + const { MAX_UINT256, ZERO_AMOUNT } = constants; describe('wallets', () => { it('createTransformWallet() replaces the current wallet', async () => { @@ -64,11 +68,39 @@ blockchainTests.resets('TransformERC20 feature', env => { }); }); + describe('transformer deployer', () => { + it('`getTransformerDeployer()` returns the transformer deployer', async () => { + const actualDeployer = await feature.getTransformerDeployer().callAsync(); + expect(actualDeployer).to.eq(transformerDeployer); + }); + + it('owner can set the transformer deployer with `setTransformerDeployer()`', async () => { + const newDeployer = randomAddress(); + const receipt = await feature + .setTransformerDeployer(newDeployer) + .awaitTransactionSuccessAsync({ from: owner }); + verifyEventsFromLogs( + receipt.logs, + [{ transformerDeployer: newDeployer }], + TransformERC20Events.TransformerDeployerUpdated, + ); + const actualDeployer = await feature.getTransformerDeployer().callAsync(); + expect(actualDeployer).to.eq(newDeployer); + }); + + it('non-owner cannot set the transformer deployer with `setTransformerDeployer()`', async () => { + const newDeployer = randomAddress(); + const notOwner = randomAddress(); + const tx = feature.setTransformerDeployer(newDeployer).callAsync({ from: notOwner }); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner, owner)); + }); + }); + describe('_transformERC20()', () => { let inputToken: TestMintableERC20TokenContract; let outputToken: TestMintableERC20TokenContract; let mintTransformer: TestMintTokenERC20TransformerContract; - let rlpNonce: string; + let transformerNonce: number; before(async () => { inputToken = await TestMintableERC20TokenContract.deployFrom0xArtifactAsync( @@ -83,7 +115,7 @@ blockchainTests.resets('TransformERC20 feature', env => { env.txDefaults, artifacts, ); - rlpNonce = await getRLPEncodedAccountNonceAsync(env.web3Wrapper, transformerDeployer); + transformerNonce = await env.web3Wrapper.getAccountNonceAsync(transformerDeployer); mintTransformer = await TestMintTokenERC20TransformerContract.deployFrom0xArtifactAsync( artifacts.TestMintTokenERC20Transformer, env.provider, @@ -97,7 +129,7 @@ blockchainTests.resets('TransformERC20 feature', env => { }); interface Transformation { - transformer: string; + deploymentNonce: number; data: string; } @@ -111,7 +143,6 @@ blockchainTests.resets('TransformERC20 feature', env => { { name: 'burnAmount', type: 'uint256' }, { name: 'mintAmount', type: 'uint256' }, { name: 'feeAmount', type: 'uint256' }, - { name: 'deploymentNonce', type: 'bytes' }, ], }, ]); @@ -124,21 +155,21 @@ blockchainTests.resets('TransformERC20 feature', env => { inputTokenBurnAmunt: Numberish; outputTokenMintAmount: Numberish; outputTokenFeeAmount: Numberish; - rlpNonce: string; + deploymentNonce: number; }> = {}, ): Transformation { const _opts = { - rlpNonce, outputTokenAddress: outputToken.address, inputTokenAddress: inputToken.address, inputTokenBurnAmunt: ZERO_AMOUNT, outputTokenMintAmount: ZERO_AMOUNT, outputTokenFeeAmount: ZERO_AMOUNT, transformer: mintTransformer.address, + deploymentNonce: transformerNonce, ...opts, }; return { - transformer: _opts.transformer, + deploymentNonce: _opts.deploymentNonce, data: transformDataEncoder.encode([ { inputToken: _opts.inputTokenAddress, @@ -146,7 +177,6 @@ blockchainTests.resets('TransformERC20 feature', env => { burnAmount: _opts.inputTokenBurnAmunt, mintAmount: _opts.outputTokenMintAmount, feeAmount: _opts.outputTokenFeeAmount, - deploymentNonce: _opts.rlpNonce, }, ]), }; @@ -443,7 +473,7 @@ blockchainTests.resets('TransformERC20 feature', env => { ); }); - it('fails with third-party transformer', async () => { + it('fails with invalid transformer nonce', async () => { const startingOutputTokenBalance = getRandomInteger(0, '100e18'); const startingInputTokenBalance = getRandomInteger(2, '100e18'); await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync(); @@ -452,32 +482,7 @@ blockchainTests.resets('TransformERC20 feature', env => { const minOutputTokenAmount = getRandomInteger(2, '1e18'); const callValue = getRandomInteger(1, '1e18'); const callDataHash = hexUtils.random(); - const transformations = [createMintTokenTransformation({ transformer: randomAddress() })]; - const tx = feature - ._transformERC20( - callDataHash, - taker, - inputToken.address, - outputToken.address, - inputTokenAmount, - minOutputTokenAmount, - transformations, - ) - .awaitTransactionSuccessAsync({ value: callValue }); - return expect(tx).to.revertWith(new ZeroExRevertErrors.TransformERC20.InvalidRLPNonceError(NULL_BYTES)); - }); - - it('fails with incorrect transformer RLP nonce', async () => { - const startingOutputTokenBalance = getRandomInteger(0, '100e18'); - const startingInputTokenBalance = getRandomInteger(2, '100e18'); - await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync(); - await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync(); - const inputTokenAmount = getRandomPortion(startingInputTokenBalance); - const minOutputTokenAmount = getRandomInteger(2, '1e18'); - const callValue = getRandomInteger(1, '1e18'); - const callDataHash = hexUtils.random(); - const badRlpNonce = '0x00'; - const transformations = [createMintTokenTransformation({ rlpNonce: badRlpNonce })]; + const transformations = [createMintTokenTransformation({ deploymentNonce: 1337 })]; const tx = feature ._transformERC20( callDataHash, @@ -490,36 +495,12 @@ blockchainTests.resets('TransformERC20 feature', env => { ) .awaitTransactionSuccessAsync({ value: callValue }); return expect(tx).to.revertWith( - new ZeroExRevertErrors.TransformERC20.UnauthorizedTransformerError( - transformations[0].transformer, - badRlpNonce, + new ZeroExRevertErrors.TransformERC20.TransformerFailedError( + undefined, + transformations[0].data, + constants.NULL_BYTES, ), ); }); - - it('fails with invalid transformer RLP nonce', async () => { - const startingOutputTokenBalance = getRandomInteger(0, '100e18'); - const startingInputTokenBalance = getRandomInteger(2, '100e18'); - await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync(); - await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync(); - const inputTokenAmount = getRandomPortion(startingInputTokenBalance); - const minOutputTokenAmount = getRandomInteger(2, '1e18'); - const callValue = getRandomInteger(1, '1e18'); - const callDataHash = hexUtils.random(); - const badRlpNonce = '0x010203040506'; - const transformations = [createMintTokenTransformation({ rlpNonce: badRlpNonce })]; - const tx = feature - ._transformERC20( - callDataHash, - taker, - inputToken.address, - outputToken.address, - inputTokenAmount, - minOutputTokenAmount, - transformations, - ) - .awaitTransactionSuccessAsync({ value: callValue }); - return expect(tx).to.revertWith(new ZeroExRevertErrors.TransformERC20.InvalidRLPNonceError(badRlpNonce)); - }); }); }); diff --git a/contracts/zero-ex/test/full_migration_test.ts b/contracts/zero-ex/test/full_migration_test.ts index a95474de6c..b45b7d9a5c 100644 --- a/contracts/zero-ex/test/full_migration_test.ts +++ b/contracts/zero-ex/test/full_migration_test.ts @@ -23,6 +23,7 @@ blockchainTests.resets('Full migration', env => { let zeroEx: ZeroExContract; let features: FullFeatures; let migrator: TestFullMigrationContract; + const transformerDeployer = randomAddress(); before(async () => { [owner] = await env.getAccountAddressesAsync(); @@ -34,7 +35,7 @@ blockchainTests.resets('Full migration', env => { artifacts, env.txDefaults.from as string, ); - const deployCall = migrator.deploy(owner, toFeatureAdddresses(features)); + const deployCall = migrator.deploy(owner, toFeatureAdddresses(features), { transformerDeployer }); zeroEx = new ZeroExContract(await deployCall.callAsync(), env.provider, env.txDefaults); await deployCall.awaitTransactionSuccessAsync(); }); @@ -52,7 +53,9 @@ blockchainTests.resets('Full migration', env => { it('Non-deployer cannot call deploy()', async () => { const notDeployer = randomAddress(); - const tx = migrator.deploy(owner, toFeatureAdddresses(features)).callAsync({ from: notDeployer }); + const tx = migrator + .deploy(owner, toFeatureAdddresses(features), { transformerDeployer }) + .callAsync({ from: notDeployer }); return expect(tx).to.revertWith('FullMigration/INVALID_SENDER'); }); @@ -63,7 +66,13 @@ blockchainTests.resets('Full migration', env => { }, TransformERC20: { contractType: ITransformERC20Contract, - fns: ['transformERC20', '_transformERC20', 'createTransformWallet', 'getTransformWallet'], + fns: [ + 'transformERC20', + '_transformERC20', + 'createTransformWallet', + 'getTransformWallet', + 'setTransformerDeployer', + ], }, }; @@ -162,4 +171,16 @@ blockchainTests.resets('Full migration', env => { return expect(allowanceTarget.authorized(zeroEx.address).callAsync()).to.become(true); }); }); + + describe('TransformERC20', () => { + let feature: ITransformERC20Contract; + + before(async () => { + feature = new ITransformERC20Contract(zeroEx.address, env.provider, env.txDefaults); + }); + + it('has the correct transformer deployer', async () => { + return expect(feature.getTransformerDeployer().callAsync()).to.become(transformerDeployer); + }); + }); }); diff --git a/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts b/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts index 5460c62d94..34082f359c 100644 --- a/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts +++ b/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts @@ -12,7 +12,6 @@ import { Order } from '@0x/types'; import { BigNumber, hexUtils, ZeroExRevertErrors } from '@0x/utils'; import * as _ from 'lodash'; -import { rlpEncodeNonce } from '../../src/nonce_utils'; import { encodeFillQuoteTransformerData, FillQuoteTransformerData, @@ -29,7 +28,6 @@ import { const { NULL_ADDRESS, NULL_BYTES, MAX_UINT256, ZERO_AMOUNT } = constants; blockchainTests.resets('FillQuoteTransformer', env => { - const deploymentNonce = _.random(0, 0xffffffff); let maker: string; let feeRecipient: string; let exchange: TestFillQuoteTransformerExchangeContract; @@ -56,7 +54,6 @@ blockchainTests.resets('FillQuoteTransformer', env => { env.txDefaults, artifacts, exchange.address, - new BigNumber(deploymentNonce), ); host = await TestFillQuoteTransformerHostContract.deployFrom0xArtifactAsync( artifacts.TestFillQuoteTransformerHost, @@ -585,24 +582,6 @@ blockchainTests.resets('FillQuoteTransformer', env => { makerAssetBalance: qfr.makerAssetBought, }); }); - - it('returns the RLP-encoded nonce', async () => { - const orders = _.times(1, () => createOrder()); - const signatures = orders.map(() => encodeExchangeBehavior()); - const qfr = getExpectedSellQuoteFillResults(orders); - const r = await host - .executeTransform( - transformer.address, - takerToken.address, - qfr.takerAssetSpent, - encodeTransformData({ - orders, - signatures, - }), - ) - .callAsync({ value: qfr.protocolFeePaid }); - expect(r).to.eq(rlpEncodeNonce(deploymentNonce)); - }); }); describe('buy quotes', () => { @@ -881,25 +860,5 @@ blockchainTests.resets('FillQuoteTransformer', env => { makerAssetBalance: qfr.makerAssetBought, }); }); - - it('returns the RLP-encoded nonce', async () => { - const orders = _.times(1, () => createOrder()); - const signatures = orders.map(() => encodeExchangeBehavior()); - const qfr = getExpectedBuyQuoteFillResults(orders); - const r = await host - .executeTransform( - transformer.address, - takerToken.address, - qfr.takerAssetSpent, - encodeTransformData({ - orders, - signatures, - side: FillQuoteTransformerSide.Buy, - fillAmount: qfr.makerAssetBought, - }), - ) - .callAsync({ value: qfr.protocolFeePaid }); - expect(r).to.eq(rlpEncodeNonce(deploymentNonce)); - }); }); }); diff --git a/contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts b/contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts index 3117f19a3e..31f1edfdd2 100644 --- a/contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts +++ b/contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts @@ -3,7 +3,6 @@ import { BigNumber, hexUtils } from '@0x/utils'; import * as _ from 'lodash'; import { ETH_TOKEN_ADDRESS } from '../../src/constants'; -import { rlpEncodeNonce } from '../../src/nonce_utils'; import { encodePayTakerTransformerData } from '../../src/transformer_data_encoders'; import { artifacts } from '../artifacts'; import { PayTakerTransformerContract, TestMintableERC20TokenContract, TestTransformerHostContract } from '../wrappers'; @@ -12,7 +11,6 @@ const { MAX_UINT256, ZERO_AMOUNT } = constants; blockchainTests.resets('PayTakerTransformer', env => { const taker = randomAddress(); - const deploymentNonce = _.random(0, 0xffffffff); let caller: string; let token: TestMintableERC20TokenContract; let transformer: PayTakerTransformerContract; @@ -31,7 +29,6 @@ blockchainTests.resets('PayTakerTransformer', env => { env.provider, env.txDefaults, artifacts, - new BigNumber(deploymentNonce), ); host = await TestTransformerHostContract.deployFrom0xArtifactAsync( artifacts.TestTransformerHost, @@ -147,16 +144,4 @@ blockchainTests.resets('PayTakerTransformer', env => { ethBalance: amounts[1].dividedToIntegerBy(2), }); }); - - it('returns the RLP-encoded nonce', async () => { - const amounts = _.times(2, () => getRandomInteger(1, '1e18')); - const data = encodePayTakerTransformerData({ - amounts, - tokens: [token.address, ETH_TOKEN_ADDRESS], - }); - await mintHostTokensAsync(amounts[0]); - await sendEtherAsync(host.address, amounts[1]); - const r = await host.rawExecuteTransform(transformer.address, hexUtils.random(), taker, data).callAsync(); - expect(r).to.eq(rlpEncodeNonce(deploymentNonce)); - }); }); diff --git a/contracts/zero-ex/test/transformers/transformer_base_test.ts b/contracts/zero-ex/test/transformers/transformer_base_test.ts index 9f8324d74a..bfc5a4247e 100644 --- a/contracts/zero-ex/test/transformers/transformer_base_test.ts +++ b/contracts/zero-ex/test/transformers/transformer_base_test.ts @@ -1,13 +1,11 @@ import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; -import { BigNumber, ZeroExRevertErrors } from '@0x/utils'; +import { 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; @@ -28,17 +26,9 @@ blockchainTests.resets('Transformer (base)', env => { 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(); diff --git a/contracts/zero-ex/test/transformers/weth_transformer_test.ts b/contracts/zero-ex/test/transformers/weth_transformer_test.ts index 6548e40872..cda6809bee 100644 --- a/contracts/zero-ex/test/transformers/weth_transformer_test.ts +++ b/contracts/zero-ex/test/transformers/weth_transformer_test.ts @@ -3,7 +3,6 @@ import { BigNumber, ZeroExRevertErrors } from '@0x/utils'; import * as _ from 'lodash'; import { ETH_TOKEN_ADDRESS } from '../../src/constants'; -import { rlpEncodeNonce } from '../../src/nonce_utils'; import { encodeWethTransformerData } from '../../src/transformer_data_encoders'; import { artifacts } from '../artifacts'; import { TestWethContract, TestWethTransformerHostContract, WethTransformerContract } from '../wrappers'; @@ -11,7 +10,6 @@ import { TestWethContract, TestWethTransformerHostContract, WethTransformerContr const { MAX_UINT256, ZERO_AMOUNT } = constants; blockchainTests.resets('WethTransformer', env => { - const deploymentNonce = _.random(0, 0xffffffff); let weth: TestWethContract; let transformer: WethTransformerContract; let host: TestWethTransformerHostContract; @@ -29,7 +27,6 @@ blockchainTests.resets('WethTransformer', env => { env.txDefaults, artifacts, weth.address, - new BigNumber(deploymentNonce), ); host = await TestWethTransformerHostContract.deployFrom0xArtifactAsync( artifacts.TestWethTransformerHost, @@ -152,14 +149,4 @@ blockchainTests.resets('WethTransformer', env => { wethBalance: amount.dividedToIntegerBy(2), }); }); - - it('returns the RLP-encoded nonce', async () => { - const amount = getRandomInteger(1, '1e18'); - const data = encodeWethTransformerData({ - amount, - token: weth.address, - }); - const r = await host.executeTransform(amount, transformer.address, data).callAsync({ value: amount }); - expect(r).to.eq(rlpEncodeNonce(deploymentNonce)); - }); }); diff --git a/contracts/zero-ex/test/utils/migration.ts b/contracts/zero-ex/test/utils/migration.ts index 4054358aae..1345b004e7 100644 --- a/contracts/zero-ex/test/utils/migration.ts +++ b/contracts/zero-ex/test/utils/migration.ts @@ -67,14 +67,13 @@ export interface FullFeatures extends BootstrapFeatures { } export interface FullMigrationOpts { - transformDeployer: string; + transformerDeployer: string; } export async function deployFullFeaturesAsync( provider: SupportedProvider, txDefaults: Partial, features: Partial = {}, - opts: Partial = {}, ): Promise { return { ...(await deployBootstrapFeaturesAsync(provider, txDefaults)), @@ -93,7 +92,6 @@ export async function deployFullFeaturesAsync( provider, txDefaults, artifacts, - opts.transformDeployer || (txDefaults.from as string), )), }; } @@ -105,7 +103,7 @@ export async function fullMigrateAsync( features: Partial = {}, opts: Partial = {}, ): Promise { - const _features = await deployFullFeaturesAsync(provider, txDefaults, features, opts); + const _features = await deployFullFeaturesAsync(provider, txDefaults, features); const migrator = await FullMigrationContract.deployFrom0xArtifactAsync( artifacts.FullMigration, provider, @@ -113,7 +111,11 @@ export async function fullMigrateAsync( artifacts, txDefaults.from as string, ); - const deployCall = migrator.deploy(owner, toFeatureAdddresses(_features)); + const _opts = { + transformerDeployer: txDefaults.from as string, + ...opts, + }; + const deployCall = migrator.deploy(owner, toFeatureAdddresses(_features), _opts); const zeroEx = new ZeroExContract(await deployCall.callAsync(), provider, {}); await deployCall.awaitTransactionSuccessAsync(); return zeroEx;