diff --git a/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol b/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol index f004222ea8..565be0fb75 100644 --- a/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol @@ -35,8 +35,6 @@ import "./LibERC20Transformer.sol"; contract FillQuoteTransformer is IERC20Transformer { - // solhint-disable indent,no-empty-blocks,no-unused-vars - /// @dev Transform data to ABI-encode and pass into `transform()`. struct TransformData { // The token being sold. @@ -76,6 +74,8 @@ 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; @@ -84,9 +84,13 @@ contract FillQuoteTransformer is using LibSafeMathV06 for uint256; using LibRichErrorsV06 for bytes; - constructor(IExchange exchange_) public { + /// @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 { exchange = exchange_; erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID); + deploymentNonce = deploymentNonce_; } /// @dev Sell this contract's entire balance of of `sellToken` in exchange @@ -94,7 +98,9 @@ contract FillQuoteTransformer is /// to this call. `buyToken` and excess ETH will be transferred back to the caller. /// This function cannot be re-entered. /// @param data_ ABI-encoded `TransformData`. - /// @return success `TRANSFORMER_SUCCESS` on success. + /// @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. function transform( bytes32, // callDataHash, address payable, // taker, @@ -102,7 +108,7 @@ contract FillQuoteTransformer is ) external override - returns (bytes4 success) + returns (bytes memory rlpDeploymentNonce) { TransformData memory data = abi.decode(data_, (TransformData)); @@ -211,7 +217,7 @@ contract FillQuoteTransformer is ).rrevert(); } } - return LibERC20Transformer.TRANSFORMER_SUCCESS; + return LibERC20Transformer.rlpEncodeNonce(deploymentNonce); } /// @dev Try to sell up to `sellAmount` from an order. diff --git a/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol b/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol index 1753cc9c68..b0c08a0351 100644 --- a/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/LibERC20Transformer.sol @@ -70,4 +70,45 @@ library LibERC20Transformer { { return isTokenETH(token) ? owner.balance : 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) + internal + pure + returns (bytes memory rlpNonce) + { + if (nonce == 0) { + rlpNonce = new bytes(1); + rlpNonce[0] = 0x80; + } else if (nonce < 0x80) { + rlpNonce = new bytes(1); + rlpNonce[0] = byte(uint8(nonce)); + } else if (nonce <= 0xFF) { + rlpNonce = new bytes(2); + rlpNonce[0] = 0x81; + rlpNonce[1] = byte(uint8(nonce)); + } else if (nonce <= 0xFFFF) { + rlpNonce = new bytes(3); + rlpNonce[0] = 0x82; + rlpNonce[1] = byte(uint8((nonce & 0xFF00) >> 8)); + rlpNonce[2] = byte(uint8(nonce)); + } else if (nonce <= 0xFFFFFF) { + rlpNonce = new bytes(4); + rlpNonce[0] = 0x83; + rlpNonce[1] = byte(uint8((nonce & 0xFF0000) >> 16)); + rlpNonce[2] = byte(uint8((nonce & 0xFF00) >> 8)); + rlpNonce[3] = byte(uint8(nonce)); + } else if (nonce <= 0xFFFFFFFF) { + 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"); + } + } } diff --git a/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol b/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol index 4b668862c1..e5d59f7c7c 100644 --- a/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol @@ -45,10 +45,21 @@ 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 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 success `TRANSFORMER_SUCCESS` on success. + /// @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. function transform( bytes32, // callDataHash, address payable taker, @@ -56,7 +67,7 @@ contract PayTakerTransformer is ) external override - returns (bytes4 success) + returns (bytes memory rlpDeploymentNonce) { TransformData memory data = abi.decode(data_, (TransformData)); @@ -72,6 +83,6 @@ contract PayTakerTransformer is data.tokens[i].transformerTransfer(taker, amount); } } - return LibERC20Transformer.TRANSFORMER_SUCCESS; + 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 003da666e5..69e9e4b33b 100644 --- a/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol +++ b/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol @@ -40,24 +40,29 @@ contract WethTransformer is uint256 amount; } - // solhint-disable /// @dev The WETH contract address. IEtherTokenV06 public immutable weth; - // solhint-enable + /// @dev The nonce of the deployer when deploying this contract. + uint256 public immutable deploymentNonce; using LibRichErrorsV06 for bytes; using LibSafeMathV06 for uint256; using LibERC20Transformer for IERC20TokenV06; - /// @dev Construct the transformer and store the WETH address in an immutable. + /// @dev Create this contract. /// @param weth_ The weth token. - constructor(IEtherTokenV06 weth_) public { + /// @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 { weth = weth_; + deploymentNonce = deploymentNonce_; } /// @dev Wraps and unwraps WETH. /// @param data_ ABI-encoded `TransformData`, indicating which token to wrap/umwrap. - /// @return success `TRANSFORMER_SUCCESS` on success. + /// @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. function transform( bytes32, // callDataHash, address payable, // taker, @@ -65,7 +70,7 @@ contract WethTransformer is ) external override - returns (bytes4 success) + returns (bytes memory rlpDeploymentNonce) { TransformData memory data = abi.decode(data_, (TransformData)); if (!data.token.isTokenETH() && data.token != weth) { @@ -86,6 +91,6 @@ contract WethTransformer is weth.withdraw(amount); } } - return LibERC20Transformer.TRANSFORMER_SUCCESS; + return LibERC20Transformer.rlpEncodeNonce(deploymentNonce); } } diff --git a/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol b/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol index 6b85acd2f5..3f9c196bd8 100644 --- a/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestFillQuoteTransformerHost.sol @@ -35,11 +35,12 @@ 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. - this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); + return this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); } } diff --git a/contracts/zero-ex/contracts/test/TestTransformerHost.sol b/contracts/zero-ex/contracts/test/TestTransformerHost.sol index 23f2fff764..283dc0e4fe 100644 --- a/contracts/zero-ex/contracts/test/TestTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestTransformerHost.sol @@ -37,6 +37,7 @@ contract TestTransformerHost { bytes calldata data ) external + returns (bytes memory rlpDeploymentNonce) { (bool success, bytes memory resultData) = address(transformer).delegatecall(abi.encodeWithSelector( @@ -48,10 +49,7 @@ contract TestTransformerHost { if (!success) { resultData.rrevert(); } - require( - abi.decode(resultData, (bytes4)) == LibERC20Transformer.TRANSFORMER_SUCCESS, - "TestFillQuoteTransformerTaker/UNSUCCESSFUL_RESULT" - ); + assembly { return(add(resultData, 32), mload(resultData)) } } // solhint-disable diff --git a/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol b/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol index 3c0fd83999..fbadc6a9dd 100644 --- a/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol +++ b/contracts/zero-ex/contracts/test/TestWethTransformerHost.sol @@ -43,11 +43,12 @@ 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. - this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); + return this.rawExecuteTransform(transformer, bytes32(0), msg.sender, data); } } diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json index 6a69f8eb38..fb07186d3e 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|FixinCommon|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Transformer|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|SimpleFunctionRegistry|TestCallTarget|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestZeroExFeature|TokenSpender|TransformERC20|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|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|WethTransformer|ZeroEx).json" }, "repository": { "type": "git", diff --git a/contracts/zero-ex/src/artifacts.ts b/contracts/zero-ex/src/artifacts.ts index f68d20e56b..525dcc5da6 100644 --- a/contracts/zero-ex/src/artifacts.ts +++ b/contracts/zero-ex/src/artifacts.ts @@ -7,29 +7,29 @@ import { ContractArtifact } from 'ethereum-types'; import * as FillQuoteTransformer from '../generated-artifacts/FillQuoteTransformer.json'; import * as FullMigration from '../generated-artifacts/FullMigration.json'; +import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json'; import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json'; +import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json'; import * as InitialMigration from '../generated-artifacts/InitialMigration.json'; import * as IOwnable from '../generated-artifacts/IOwnable.json'; import * as ISimpleFunctionRegistry from '../generated-artifacts/ISimpleFunctionRegistry.json'; import * as ITokenSpender from '../generated-artifacts/ITokenSpender.json'; import * as ITransformERC20 from '../generated-artifacts/ITransformERC20.json'; -import * as LibERC20Transformer from '../generated-artifacts/LibERC20Transformer.json'; import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json'; -import * as Puppet from '../generated-artifacts/Puppet.json'; import * as WethTransformer from '../generated-artifacts/WethTransformer.json'; import * as ZeroEx from '../generated-artifacts/ZeroEx.json'; export const artifacts = { ZeroEx: ZeroEx as ContractArtifact, FullMigration: FullMigration as ContractArtifact, InitialMigration: InitialMigration as ContractArtifact, - Puppet: Puppet as ContractArtifact, + IFlashWallet: IFlashWallet as ContractArtifact, + IAllowanceTarget: IAllowanceTarget as ContractArtifact, IERC20Transformer: IERC20Transformer as ContractArtifact, IOwnable: IOwnable as ContractArtifact, ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, ITokenSpender: ITokenSpender as ContractArtifact, ITransformERC20: ITransformERC20 as ContractArtifact, - LibERC20Transformer: LibERC20Transformer as ContractArtifact, + FillQuoteTransformer: FillQuoteTransformer as ContractArtifact, PayTakerTransformer: PayTakerTransformer as ContractArtifact, WethTransformer: WethTransformer as ContractArtifact, - FillQuoteTransformer: FillQuoteTransformer as ContractArtifact, }; diff --git a/contracts/zero-ex/src/nonce_utils.ts b/contracts/zero-ex/src/nonce_utils.ts index 9290fab280..157829fcb2 100644 --- a/contracts/zero-ex/src/nonce_utils.ts +++ b/contracts/zero-ex/src/nonce_utils.ts @@ -19,7 +19,7 @@ export function rlpEncodeNonce(nonce: number): string { } else if (nonce <= 0x7f) { return ethjs.bufferToHex(ethjs.toBuffer(nonce)); } else { - const rlpNonce = ethjs.bufferToHex(ethjs.toBuffer(nonce)); - return hexUtils.concat(rlpNonce.length + 0x80, rlpNonce); + const rlpNonce = ethjs.toBuffer(nonce); + return hexUtils.concat(rlpNonce.length + 0x80, ethjs.bufferToHex(rlpNonce)); } } diff --git a/contracts/zero-ex/src/wrappers.ts b/contracts/zero-ex/src/wrappers.ts index fdbf2d49c0..1778a3cc18 100644 --- a/contracts/zero-ex/src/wrappers.ts +++ b/contracts/zero-ex/src/wrappers.ts @@ -5,14 +5,14 @@ */ export * from '../generated-wrappers/fill_quote_transformer'; export * from '../generated-wrappers/full_migration'; +export * from '../generated-wrappers/i_allowance_target'; export * from '../generated-wrappers/i_erc20_transformer'; +export * from '../generated-wrappers/i_flash_wallet'; export * from '../generated-wrappers/i_ownable'; export * from '../generated-wrappers/i_simple_function_registry'; export * from '../generated-wrappers/i_token_spender'; export * from '../generated-wrappers/i_transform_erc20'; export * from '../generated-wrappers/initial_migration'; -export * from '../generated-wrappers/lib_erc20_transformer'; export * from '../generated-wrappers/pay_taker_transformer'; -export * from '../generated-wrappers/puppet'; export * from '../generated-wrappers/weth_transformer'; export * from '../generated-wrappers/zero_ex'; diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index 26a642efb7..09476a1d5a 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -9,15 +9,16 @@ import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.js import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json'; import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json'; import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json'; +import * as FlashWallet from '../test/generated-artifacts/FlashWallet.json'; import * as FullMigration from '../test/generated-artifacts/FullMigration.json'; import * as IAllowanceTarget from '../test/generated-artifacts/IAllowanceTarget.json'; import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json'; import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json'; import * as IExchange from '../test/generated-artifacts/IExchange.json'; import * as IFeature from '../test/generated-artifacts/IFeature.json'; +import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json'; import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json'; import * as IOwnable from '../test/generated-artifacts/IOwnable.json'; -import * as IPuppet from '../test/generated-artifacts/IPuppet.json'; import * as ISimpleFunctionRegistry from '../test/generated-artifacts/ISimpleFunctionRegistry.json'; import * as ITestSimpleFunctionRegistryFeature from '../test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json'; import * as ITokenSpender from '../test/generated-artifacts/ITokenSpender.json'; @@ -30,7 +31,6 @@ import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRic import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json'; import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErrors.json'; import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.json'; -import * as LibPuppetRichErrors from '../test/generated-artifacts/LibPuppetRichErrors.json'; import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json'; import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json'; import * as LibSpenderRichErrors from '../test/generated-artifacts/LibSpenderRichErrors.json'; @@ -38,10 +38,11 @@ import * as LibStorage from '../test/generated-artifacts/LibStorage.json'; import * as LibTokenSpenderStorage from '../test/generated-artifacts/LibTokenSpenderStorage.json'; import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTransformERC20RichErrors.json'; import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json'; +import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json'; -import * as Puppet from '../test/generated-artifacts/Puppet.json'; import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json'; +import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.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'; @@ -49,7 +50,6 @@ import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMi import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json'; import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json'; import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json'; -import * as TestPuppetTarget from '../test/generated-artifacts/TestPuppetTarget.json'; import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json'; import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json'; import * as TestTokenSpender from '../test/generated-artifacts/TestTokenSpender.json'; @@ -68,14 +68,14 @@ export const artifacts = { LibCommonRichErrors: LibCommonRichErrors as ContractArtifact, LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, LibProxyRichErrors: LibProxyRichErrors as ContractArtifact, - LibPuppetRichErrors: LibPuppetRichErrors as ContractArtifact, LibSimpleFunctionRegistryRichErrors: LibSimpleFunctionRegistryRichErrors as ContractArtifact, LibSpenderRichErrors: LibSpenderRichErrors as ContractArtifact, LibTransformERC20RichErrors: LibTransformERC20RichErrors as ContractArtifact, + LibWalletRichErrors: LibWalletRichErrors as ContractArtifact, AllowanceTarget: AllowanceTarget as ContractArtifact, + FlashWallet: FlashWallet as ContractArtifact, IAllowanceTarget: IAllowanceTarget as ContractArtifact, - IPuppet: IPuppet as ContractArtifact, - Puppet: Puppet as ContractArtifact, + IFlashWallet: IFlashWallet as ContractArtifact, Bootstrap: Bootstrap as ContractArtifact, IBootstrap: IBootstrap as ContractArtifact, IFeature: IFeature as ContractArtifact, @@ -105,6 +105,7 @@ export const artifacts = { WethTransformer: WethTransformer as ContractArtifact, IExchange: IExchange as ContractArtifact, ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, + TestCallTarget: TestCallTarget as ContractArtifact, TestFillQuoteTransformerExchange: TestFillQuoteTransformerExchange as ContractArtifact, TestFillQuoteTransformerHost: TestFillQuoteTransformerHost as ContractArtifact, TestFullMigration: TestFullMigration as ContractArtifact, @@ -112,7 +113,6 @@ export const artifacts = { TestMigrator: TestMigrator as ContractArtifact, TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact, TestMintableERC20Token: TestMintableERC20Token as ContractArtifact, - TestPuppetTarget: TestPuppetTarget as ContractArtifact, TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact, TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact, TestTokenSpender: TestTokenSpender as ContractArtifact, 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 05e920a6b0..7f8c312e45 100644 --- a/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts +++ b/contracts/zero-ex/test/transformers/fill_quote_transformer_test.ts @@ -12,6 +12,7 @@ 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 } from '../../src/transformer_data_encoders'; import { artifacts } from '../artifacts'; import { @@ -24,6 +25,7 @@ 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; @@ -50,6 +52,7 @@ blockchainTests.resets('FillQuoteTransformer', env => { env.txDefaults, artifacts, exchange.address, + new BigNumber(deploymentNonce), ); host = await TestFillQuoteTransformerHostContract.deployFrom0xArtifactAsync( artifacts.TestFillQuoteTransformerHost, @@ -578,6 +581,24 @@ 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', () => { @@ -782,7 +803,7 @@ blockchainTests.resets('FillQuoteTransformer', env => { const BAD_ASSET_DATA = hexUtils.random(36); const orders = _.times(1, () => createOrder({ takerFeeAssetData: BAD_ASSET_DATA })); const signatures = orders.map(() => encodeExchangeBehavior()); - const qfr = getExpectedSellQuoteFillResults(orders); + const qfr = getExpectedBuyQuoteFillResults(orders); const tx = host .executeTransform( transformer.address, @@ -805,7 +826,7 @@ blockchainTests.resets('FillQuoteTransformer', env => { const BAD_ASSET_DATA = hexUtils.concat(ERC20_ASSET_PROXY_ID, hexUtils.leftPad(badToken)); const orders = _.times(1, () => createOrder({ takerFeeAssetData: BAD_ASSET_DATA })); const signatures = orders.map(() => encodeExchangeBehavior()); - const qfr = getExpectedSellQuoteFillResults(orders); + const qfr = getExpectedBuyQuoteFillResults(orders); const tx = host .executeTransform( transformer.address, @@ -824,7 +845,7 @@ blockchainTests.resets('FillQuoteTransformer', env => { it('respects `maxOrderFillAmounts`', async () => { const orders = _.times(2, () => createOrder()); const signatures = orders.map(() => encodeExchangeBehavior()); - const qfr = getExpectedSellQuoteFillResults(orders.slice(1)); + const qfr = getExpectedBuyQuoteFillResults(orders.slice(1)); const protocolFee = singleProtocolFee.times(2); await host .executeTransform( @@ -845,5 +866,23 @@ 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, + }), + ) + .callAsync({ value: qfr.protocolFeePaid }); + expect(r).to.eq(rlpEncodeNonce(deploymentNonce)); + }); }); }); diff --git a/contracts/zero-ex/test/transformers/pay_taker_transformer.ts b/contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts similarity index 89% rename from contracts/zero-ex/test/transformers/pay_taker_transformer.ts rename to contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts index 215544bc87..3117f19a3e 100644 --- a/contracts/zero-ex/test/transformers/pay_taker_transformer.ts +++ b/contracts/zero-ex/test/transformers/pay_taker_transformer_test.ts @@ -3,6 +3,7 @@ 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'; @@ -10,8 +11,9 @@ import { PayTakerTransformerContract, TestMintableERC20TokenContract, TestTransf const { MAX_UINT256, ZERO_AMOUNT } = constants; blockchainTests.resets('PayTakerTransformer', env => { - let caller: string; const taker = randomAddress(); + const deploymentNonce = _.random(0, 0xffffffff); + let caller: string; let token: TestMintableERC20TokenContract; let transformer: PayTakerTransformerContract; let host: TestTransformerHostContract; @@ -29,6 +31,7 @@ blockchainTests.resets('PayTakerTransformer', env => { env.provider, env.txDefaults, artifacts, + new BigNumber(deploymentNonce), ); host = await TestTransformerHostContract.deployFrom0xArtifactAsync( artifacts.TestTransformerHost, @@ -144,4 +147,16 @@ 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/weth_transformer_test.ts b/contracts/zero-ex/test/transformers/weth_transformer_test.ts index c4da09447d..e5c1cc8c26 100644 --- a/contracts/zero-ex/test/transformers/weth_transformer_test.ts +++ b/contracts/zero-ex/test/transformers/weth_transformer_test.ts @@ -3,6 +3,7 @@ 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'; @@ -10,6 +11,7 @@ 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; @@ -27,6 +29,7 @@ blockchainTests.resets('WethTransformer', env => { env.txDefaults, artifacts, weth.address, + new BigNumber(deploymentNonce), ); host = await TestWethTransformerHostContract.deployFrom0xArtifactAsync( artifacts.TestWethTransformerHost, @@ -144,4 +147,14 @@ 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/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index b674f9519c..140573cfdf 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -39,8 +39,11 @@ export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors'; export * from '../test/generated-wrappers/lib_transform_erc20_storage'; export * from '../test/generated-wrappers/lib_wallet_rich_errors'; 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_fill_quote_transformer_exchange'; +export * from '../test/generated-wrappers/test_fill_quote_transformer_host'; export * from '../test/generated-wrappers/test_full_migration'; export * from '../test/generated-wrappers/test_initial_migration'; export * from '../test/generated-wrappers/test_migrator'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index 07a67468db..288e41bd47 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -13,6 +13,8 @@ "generated-artifacts/ITokenSpender.json", "generated-artifacts/ITransformERC20.json", "generated-artifacts/InitialMigration.json", + "generated-artifacts/PayTakerTransformer.json", + "generated-artifacts/WethTransformer.json", "generated-artifacts/ZeroEx.json", "test/generated-artifacts/AllowanceTarget.json", "test/generated-artifacts/Bootstrap.json", @@ -50,8 +52,11 @@ "test/generated-artifacts/LibTransformERC20Storage.json", "test/generated-artifacts/LibWalletRichErrors.json", "test/generated-artifacts/Ownable.json", + "test/generated-artifacts/PayTakerTransformer.json", "test/generated-artifacts/SimpleFunctionRegistry.json", "test/generated-artifacts/TestCallTarget.json", + "test/generated-artifacts/TestFillQuoteTransformerExchange.json", + "test/generated-artifacts/TestFillQuoteTransformerHost.json", "test/generated-artifacts/TestFullMigration.json", "test/generated-artifacts/TestInitialMigration.json", "test/generated-artifacts/TestMigrator.json",