remove calldata signing (#51)

This commit is contained in:
Steve Marx 2020-11-25 16:55:12 -05:00 committed by GitHub
parent 9653eb9e70
commit 88d7e73eba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 31 additions and 549 deletions

View File

@ -7,7 +7,6 @@ import {
IZeroExContract, IZeroExContract,
LogMetadataTransformerContract, LogMetadataTransformerContract,
Signature, Signature,
signCallData,
} from '@0x/contracts-zero-ex'; } from '@0x/contracts-zero-ex';
import { migrateOnceAsync } from '@0x/migrations'; import { migrateOnceAsync } from '@0x/migrations';
import { import {
@ -21,10 +20,10 @@ import {
SignedExchangeProxyMetaTransaction, SignedExchangeProxyMetaTransaction,
} from '@0x/order-utils'; } from '@0x/order-utils';
import { AssetProxyId, Order, SignedOrder } from '@0x/types'; import { AssetProxyId, Order, SignedOrder } from '@0x/types';
import { BigNumber, hexUtils, ZeroExRevertErrors } from '@0x/utils'; import { BigNumber, hexUtils } from '@0x/utils';
import * as ethjs from 'ethereumjs-util'; import * as ethjs from 'ethereumjs-util';
const { MAX_UINT256, NULL_ADDRESS, NULL_BYTES, NULL_BYTES32, ZERO_AMOUNT } = constants; const { MAX_UINT256, NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
function sigstruct(signature: string): Signature { function sigstruct(signature: string): Signature {
return { return {
@ -198,21 +197,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
.getABIEncodedTransactionData(); .getABIEncodedTransactionData();
} }
function getSignedSwapData(swap: SwapInfo, signerKey?: string): string {
return signCallData(
zeroEx
.transformERC20(
swap.inputTokenAddress,
swap.outputTokenAddress,
swap.inputTokenAmount,
swap.minOutputTokenAmount,
swap.transformations,
)
.getABIEncodedTransactionData(),
signerKey ? signerKey : quoteSignerKey,
);
}
async function createMetaTransactionAsync( async function createMetaTransactionAsync(
data: string, data: string,
value: BigNumber, value: BigNumber,
@ -242,12 +226,10 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
); );
} }
it('can call `transformERC20()` with signed calldata and no relayer fee', async () => { it('can call `transformERC20()` with calldata and no relayer fee', async () => {
const swap = await generateSwapAsync(); const swap = await generateSwapAsync();
const callDataHash = hexUtils.hash(getSwapData(swap));
const signedSwapData = getSignedSwapData(swap);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed. const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee, 0); const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee, 0);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer); const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature)) .executeMetaTransaction(mtx, sigstruct(mtx.signature))
@ -269,7 +251,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
[ [
{ {
taker, taker,
callDataHash,
sender: zeroEx.address, sender: zeroEx.address,
data: NULL_BYTES, data: NULL_BYTES,
}, },
@ -278,12 +259,10 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
); );
}); });
it('can call `transformERC20()` with signed calldata and a relayer fee', async () => { it('can call `transformERC20()` with calldata and a relayer fee', async () => {
const swap = await generateSwapAsync(); const swap = await generateSwapAsync();
const callDataHash = hexUtils.hash(getSwapData(swap));
const signedSwapData = getSignedSwapData(swap);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed. const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee); const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer); const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature)) .executeMetaTransaction(mtx, sigstruct(mtx.signature))
@ -305,7 +284,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
[ [
{ {
taker, taker,
callDataHash,
sender: zeroEx.address, sender: zeroEx.address,
data: NULL_BYTES, data: NULL_BYTES,
}, },
@ -314,48 +292,10 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
); );
}); });
it('can call `transformERC20()` with wrongly signed calldata and a relayer fee', async () => { it('`transformERC20()` can fill RFQT order', async () => {
const swap = await generateSwapAsync();
const signedSwapData = getSignedSwapData(swap, hexUtils.random());
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
.awaitTransactionSuccessAsync({ from: relayer, value: mtx.value, gasPrice: GAS_PRICE });
const relayerEthRefund = relayerEthBalanceBefore
.minus(await env.web3Wrapper.getBalanceInWeiAsync(relayer))
.minus(GAS_PRICE.times(receipt.gasUsed));
// Ensure the relayer got back the unused protocol fees.
expect(relayerEthRefund).to.bignumber.eq(protocolFee.times(GAS_PRICE));
// Ensure the relayer got paid mtx fees.
expect(await feeToken.balanceOf(relayer).callAsync()).to.bignumber.eq(mtx.feeAmount);
// Ensure the taker got output tokens.
expect(await outputToken.balanceOf(taker).callAsync()).to.bignumber.eq(swap.minOutputTokenAmount);
// Ensure the maker got input tokens.
expect(await inputToken.balanceOf(maker).callAsync()).to.bignumber.eq(swap.inputTokenAmount);
// Check events.
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
// Only signed calldata should have a nonzero hash.
callDataHash: NULL_BYTES32,
sender: zeroEx.address,
data: NULL_BYTES,
},
],
'TransformerMetadata',
);
});
it('`transformERC20()` can fill RFQT order if calldata is signed', async () => {
const swap = await generateSwapAsync({}, true); const swap = await generateSwapAsync({}, true);
const callDataHash = hexUtils.hash(getSwapData(swap));
const signedSwapData = getSignedSwapData(swap);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed. const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee, 0); const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee, 0);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer); const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
const receipt = await zeroEx const receipt = await zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature)) .executeMetaTransaction(mtx, sigstruct(mtx.signature))
@ -377,7 +317,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
[ [
{ {
taker, taker,
callDataHash,
sender: zeroEx.address, sender: zeroEx.address,
data: NULL_BYTES, data: NULL_BYTES,
}, },
@ -386,10 +325,9 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
); );
}); });
it('`transformERC20()` can fill RFQT order if calldata is not signed but no quote signer configured', async () => { it('`transformERC20()` can fill RFQT order if quote signer configured', async () => {
const swap = await generateSwapAsync({}, true); const swap = await generateSwapAsync({}, true);
const callData = getSwapData(swap); const callData = getSwapData(swap);
const callDataHash = hexUtils.hash(callData);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed. const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(callData, _protocolFee, 0); const mtx = await createMetaTransactionAsync(callData, _protocolFee, 0);
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer); const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
@ -414,7 +352,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
[ [
{ {
taker, taker,
callDataHash,
sender: zeroEx.address, sender: zeroEx.address,
data: NULL_BYTES, data: NULL_BYTES,
}, },
@ -422,15 +359,4 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
'TransformerMetadata', 'TransformerMetadata',
); );
}); });
it('`transformERC20()` cannot fill RFQT order if calldata is not signed', async () => {
const swap = await generateSwapAsync({}, true);
const callData = getSwapData(swap);
const _protocolFee = protocolFee.times(GAS_PRICE).times(swap.orders.length + 1); // Pay a little more fee than needed.
const mtx = await createMetaTransactionAsync(callData, _protocolFee, 0);
const tx = zeroEx
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
.awaitTransactionSuccessAsync({ from: relayer, value: mtx.value, gasPrice: GAS_PRICE });
return expect(tx).to.revertWith(new ZeroExRevertErrors.MetaTransactions.MetaTransactionCallFailedError());
});
}); });

View File

@ -45,6 +45,10 @@
{ {
"note": "Fix getRfqOrderInfo() to return status INVALID when missing txOrigin", "note": "Fix getRfqOrderInfo() to return status INVALID when missing txOrigin",
"pr": 50 "pr": 50
},
{
"note": "Remove calldata signing functionality",
"pr": 51
} }
] ]
}, },

View File

@ -58,10 +58,6 @@ interface ITransformERC20Feature {
// The transformations to execute on the token balance(s) // The transformations to execute on the token balance(s)
// in sequence. // in sequence.
Transformation[] transformations; Transformation[] transformations;
// The hash of the calldata for the `transformERC20()` call.
bytes32 callDataHash;
// The signature for `callDataHash` signed by `getQuoteSigner()`.
bytes callDataSignature;
} }
/// @dev Raised upon a successful `transformERC20`. /// @dev Raised upon a successful `transformERC20`.

View File

@ -29,7 +29,6 @@ import "../fixins/FixinTokenSpender.sol";
import "../fixins/FixinEIP712.sol"; import "../fixins/FixinEIP712.sol";
import "../migrations/LibMigrate.sol"; import "../migrations/LibMigrate.sol";
import "../storage/LibMetaTransactionsStorage.sol"; import "../storage/LibMetaTransactionsStorage.sol";
import "./libs/LibSignedCallData.sol";
import "./IMetaTransactionsFeature.sol"; import "./IMetaTransactionsFeature.sol";
import "./ITransformERC20Feature.sol"; import "./ITransformERC20Feature.sol";
import "./libs/LibSignature.sol"; import "./libs/LibSignature.sol";
@ -433,10 +432,6 @@ contract MetaTransactionsFeature is
// Decode call args for `ITransformERC20Feature.transformERC20()` as a struct. // Decode call args for `ITransformERC20Feature.transformERC20()` as a struct.
args = abi.decode(encodedStructArgs, (ExternalTransformERC20Args)); args = abi.decode(encodedStructArgs, (ExternalTransformERC20Args));
} }
// Parse the signature and hash out of the calldata so `_transformERC20()`
// can authenticate it.
(bytes32 callDataHash, bytes memory callDataSignature) =
LibSignedCallData.parseCallData(state.mtx.callData);
// Call `ITransformERC20Feature._transformERC20()` (internal variant). // Call `ITransformERC20Feature._transformERC20()` (internal variant).
return _callSelf( return _callSelf(
state.hash, state.hash,
@ -448,9 +443,7 @@ contract MetaTransactionsFeature is
outputToken: args.outputToken, outputToken: args.outputToken,
inputTokenAmount: args.inputTokenAmount, inputTokenAmount: args.inputTokenAmount,
minOutputTokenAmount: args.minOutputTokenAmount, minOutputTokenAmount: args.minOutputTokenAmount,
transformations: args.transformations, transformations: args.transformations
callDataHash: callDataHash,
callDataSignature: callDataSignature
}) })
), ),
state.mtx.value state.mtx.value

View File

@ -32,7 +32,6 @@ import "../external/FlashWallet.sol";
import "../storage/LibTransformERC20Storage.sol"; import "../storage/LibTransformERC20Storage.sol";
import "../transformers/IERC20Transformer.sol"; import "../transformers/IERC20Transformer.sol";
import "../transformers/LibERC20Transformer.sol"; import "../transformers/LibERC20Transformer.sol";
import "./libs/LibSignedCallData.sol";
import "./ITransformERC20Feature.sol"; import "./ITransformERC20Feature.sol";
import "./IFeature.sol"; import "./IFeature.sol";
import "./ISignatureValidatorFeature.sol"; import "./ISignatureValidatorFeature.sol";
@ -177,8 +176,6 @@ contract TransformERC20Feature is
payable payable
returns (uint256 outputTokenAmount) returns (uint256 outputTokenAmount)
{ {
(bytes32 callDataHash, bytes memory callDataSignature) =
LibSignedCallData.parseCallData(msg.data);
return _transformERC20Private( return _transformERC20Private(
TransformERC20Args({ TransformERC20Args({
taker: msg.sender, taker: msg.sender,
@ -186,9 +183,7 @@ contract TransformERC20Feature is
outputToken: outputToken, outputToken: outputToken,
inputTokenAmount: inputTokenAmount, inputTokenAmount: inputTokenAmount,
minOutputTokenAmount: minOutputTokenAmount, minOutputTokenAmount: minOutputTokenAmount,
transformations: transformations, transformations: transformations
callDataHash: callDataHash,
callDataSignature: callDataSignature
}) })
); );
} }
@ -246,22 +241,13 @@ contract TransformERC20Feature is
); );
{ {
// Validate that the calldata was signed by the quote signer.
// `validCallDataHash` will be 0x0 if not.
bytes32 validCallDataHash = _getValidCallDataHash(
args.callDataHash,
args.callDataSignature
);
// Perform transformations. // Perform transformations.
for (uint256 i = 0; i < args.transformations.length; ++i) { for (uint256 i = 0; i < args.transformations.length; ++i) {
_executeTransformation( _executeTransformation(
state.wallet, state.wallet,
args.transformations[i], args.transformations[i],
state.transformerDeployer, state.transformerDeployer,
args.taker, args.taker
// Transformers will receive a null calldata hash if
// the calldata was not properly signed.
validCallDataHash
); );
} }
} }
@ -349,13 +335,11 @@ contract TransformERC20Feature is
/// @param transformation The transformation. /// @param transformation The transformation.
/// @param transformerDeployer The address of the transformer deployer. /// @param transformerDeployer The address of the transformer deployer.
/// @param taker The taker address. /// @param taker The taker address.
/// @param callDataHash Hash of the calldata.
function _executeTransformation( function _executeTransformation(
IFlashWallet wallet, IFlashWallet wallet,
Transformation memory transformation, Transformation memory transformation,
address transformerDeployer, address transformerDeployer,
address payable taker, address payable taker
bytes32 callDataHash
) )
private private
{ {
@ -372,7 +356,6 @@ contract TransformERC20Feature is
abi.encodeWithSelector( abi.encodeWithSelector(
IERC20Transformer.transform.selector, IERC20Transformer.transform.selector,
IERC20Transformer.TransformContext({ IERC20Transformer.TransformContext({
callDataHash: callDataHash,
sender: msg.sender, sender: msg.sender,
taker: taker, taker: taker,
data: transformation.data data: transformation.data

View File

@ -1,72 +0,0 @@
/*
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/LibBytesV06.sol";
/// @dev Library for working with signed calldata.
library LibSignedCallData {
using LibBytesV06 for bytes;
// bytes4(keccak256('SignedCallDataSignature(bytes)'))
bytes4 constant private SIGNATURE_SELECTOR = 0xf86d1d92;
/// @dev Try to parse potentially signed calldata into its hash and signature
/// components. Signed calldata has signature data appended to it.
/// @param callData the raw call data.
/// @return callDataHash If a signature is detected, this will be the hash of
/// the bytes preceding the signature data. Otherwise, this
/// will be the hash of the entire `callData`.
/// @return signature The signature bytes, if present.
function parseCallData(bytes memory callData)
internal
pure
returns (bytes32 callDataHash, bytes memory signature)
{
// Signed calldata has a 70 byte signature appended as:
// ```
// abi.encodePacked(
// callData,
// bytes4(keccak256('SignedCallDataSignature(bytes)')),
// signature // 66 bytes
// );
// ```
// Try to detect an appended signature. This isn't foolproof, but an
// accidental false positive should highly unlikely. Additinally, the
// signature would also have to pass verification, so the risk here is
// low.
if (
// Signed callData has to be at least 70 bytes long.
callData.length < 70 ||
// The bytes4 at offset -70 should equal `SIGNATURE_SELECTOR`.
SIGNATURE_SELECTOR != callData.readBytes4(callData.length - 70)
) {
return (keccak256(callData), signature);
}
// Consider everything before the signature selector as the original
// calldata and everything after as the signature.
assembly {
callDataHash := keccak256(add(callData, 32), sub(mload(callData), 70))
}
signature = callData.slice(callData.length - 66, callData.length);
}
}

View File

@ -180,10 +180,10 @@ contract FillQuoteTransformer is
state.protocolFee = exchange.protocolFeeMultiplier().safeMul(tx.gasprice); state.protocolFee = exchange.protocolFeeMultiplier().safeMul(tx.gasprice);
state.ethRemaining = address(this).balance; state.ethRemaining = address(this).balance;
// RFQT orders can only be filled if we have a valid calldata hash // RFQT orders can only be filled if the actual taker matches the RFQT
// (calldata was signed), and the actual taker matches the RFQT taker (if set). // taker (if set).
state.isRfqtAllowed = context.callDataHash != bytes32(0) state.isRfqtAllowed = data.rfqtTakerAddress == address(0)
&& (data.rfqtTakerAddress == address(0) || context.taker == data.rfqtTakerAddress); || context.taker == data.rfqtTakerAddress;
// Fill the orders. // Fill the orders.
for (uint256 i = 0; i < data.orders.length; ++i) { for (uint256 i = 0; i < data.orders.length; ++i) {

View File

@ -27,9 +27,6 @@ interface IERC20Transformer {
/// @dev Context information to pass into `transform()` by `TransformERC20.transformERC20()`. /// @dev Context information to pass into `transform()` by `TransformERC20.transformERC20()`.
struct TransformContext { struct TransformContext {
// The hash of the `TransformERC20.transformERC20()` calldata.
// Will be null if the calldata is not signed.
bytes32 callDataHash;
// The caller of `TransformERC20.transformERC20()`. // The caller of `TransformERC20.transformERC20()`.
address payable sender; address payable sender;
// taker The taker address, which may be distinct from `sender` in the case // taker The taker address, which may be distinct from `sender` in the case

View File

@ -27,7 +27,7 @@ import "./LibERC20Transformer.sol";
contract LogMetadataTransformer is contract LogMetadataTransformer is
Transformer Transformer
{ {
event TransformerMetadata(bytes32 callDataHash, address sender, address taker, bytes data); event TransformerMetadata(address sender, address taker, bytes data);
/// @dev Maximum uint256 value. /// @dev Maximum uint256 value.
uint256 private constant MAX_UINT256 = uint256(-1); uint256 private constant MAX_UINT256 = uint256(-1);
@ -40,7 +40,7 @@ contract LogMetadataTransformer is
override override
returns (bytes4 success) returns (bytes4 success)
{ {
emit TransformerMetadata(context.callDataHash, context.sender, context.taker, context.data); emit TransformerMetadata(context.sender, context.taker, context.data);
return LibERC20Transformer.TRANSFORMER_SUCCESS; return LibERC20Transformer.TRANSFORMER_SUCCESS;
} }
} }

View File

@ -45,7 +45,6 @@ contract TestFillQuoteTransformerHost is
this.rawExecuteTransform( this.rawExecuteTransform(
transformer, transformer,
IERC20Transformer.TransformContext({ IERC20Transformer.TransformContext({
callDataHash: bytes32(0),
sender: sender, sender: sender,
taker: taker, taker: taker,
data: data data: data

View File

@ -34,9 +34,7 @@ contract TestMetaTransactionsTransformERC20Feature is
IERC20TokenV06 outputToken, IERC20TokenV06 outputToken,
uint256 inputTokenAmount, uint256 inputTokenAmount,
uint256 minOutputTokenAmount, uint256 minOutputTokenAmount,
Transformation[] transformations, Transformation[] transformations
bytes32 callDataHash,
bytes callDataSignature
); );
constructor() public TransformERC20Feature(0) {} constructor() public TransformERC20Feature(0) {}
@ -103,9 +101,7 @@ contract TestMetaTransactionsTransformERC20Feature is
args.outputToken, args.outputToken,
args.inputTokenAmount, args.inputTokenAmount,
args.minOutputTokenAmount, args.minOutputTokenAmount,
args.transformations, args.transformations
args.callDataHash,
args.callDataSignature
); );
return 1337; return 1337;
} }

View File

@ -39,7 +39,6 @@ contract TestMintTokenERC20Transformer is
event MintTransform( event MintTransform(
address context, address context,
address caller, address caller,
bytes32 callDataHash,
address sender, address sender,
address taker, address taker,
bytes data, bytes data,
@ -56,7 +55,6 @@ contract TestMintTokenERC20Transformer is
emit MintTransform( emit MintTransform(
address(this), address(this),
msg.sender, msg.sender,
context.callDataHash,
context.sender, context.sender,
context.taker, context.taker,
context.data, context.data,

View File

@ -51,7 +51,6 @@ contract TestWethTransformerHost is
this.rawExecuteTransform( this.rawExecuteTransform(
transformer, transformer,
IERC20Transformer.TransformContext({ IERC20Transformer.TransformContext({
callDataHash: bytes32(0),
sender: msg.sender, sender: msg.sender,
taker: msg.sender, taker: msg.sender,
data: data data: data

View File

@ -42,7 +42,7 @@
"config": { "config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature", "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json" "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -31,7 +31,6 @@ export {
export { artifacts } from './artifacts'; export { artifacts } from './artifacts';
export * from './migration'; export * from './migration';
export * from './nonce_utils'; export * from './nonce_utils';
export * from './signed_call_data';
export * from './signature_utils'; export * from './signature_utils';
export * from './orders'; export * from './orders';
export * from './eip712_utils'; export * from './eip712_utils';

View File

@ -1,29 +0,0 @@
import { SignatureType } from '@0x/types';
import { hexUtils } from '@0x/utils';
import * as ethjs from 'ethereumjs-util';
/**
* Generate calldata with a signature appended.
*/
export function signCallData(callData: string, privateKey: string): string {
const prefix = ethjs.sha3('SignedCallDataSignature(bytes)').slice(0, 4);
return hexUtils.concat(callData, prefix, generateCallDataSignature(callData, privateKey));
}
/**
* Generate a signature for calldata.
*/
export function generateCallDataSignature(callData: string, privateKey: string): string {
return generateCallDataHashSignature(hexUtils.hash(callData), privateKey);
}
/**
* Generate a signature for calldata hash.
*/
export function generateCallDataHashSignature(callDataHash: string, privateKey: string): string {
const { r, s, v } = ethjs.ecsign(
ethjs.hashPersonalMessage(ethjs.toBuffer(callDataHash)),
ethjs.toBuffer(privateKey),
);
return hexUtils.concat(v, r, s, SignatureType.EthSign);
}

View File

@ -60,7 +60,6 @@ import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.js
import * as LibReentrancyGuardStorage from '../test/generated-artifacts/LibReentrancyGuardStorage.json'; import * as LibReentrancyGuardStorage from '../test/generated-artifacts/LibReentrancyGuardStorage.json';
import * as LibSignature from '../test/generated-artifacts/LibSignature.json'; import * as LibSignature from '../test/generated-artifacts/LibSignature.json';
import * as LibSignatureRichErrors from '../test/generated-artifacts/LibSignatureRichErrors.json'; import * as LibSignatureRichErrors from '../test/generated-artifacts/LibSignatureRichErrors.json';
import * as LibSignedCallData from '../test/generated-artifacts/LibSignedCallData.json';
import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json'; import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json';
import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json'; import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json';
import * as LibSpenderRichErrors from '../test/generated-artifacts/LibSpenderRichErrors.json'; import * as LibSpenderRichErrors from '../test/generated-artifacts/LibSpenderRichErrors.json';
@ -177,7 +176,6 @@ export const artifacts = {
UniswapFeature: UniswapFeature as ContractArtifact, UniswapFeature: UniswapFeature as ContractArtifact,
LibNativeOrder: LibNativeOrder as ContractArtifact, LibNativeOrder: LibNativeOrder as ContractArtifact,
LibSignature: LibSignature as ContractArtifact, LibSignature: LibSignature as ContractArtifact,
LibSignedCallData: LibSignedCallData as ContractArtifact,
FixinCommon: FixinCommon as ContractArtifact, FixinCommon: FixinCommon as ContractArtifact,
FixinEIP712: FixinEIP712 as ContractArtifact, FixinEIP712: FixinEIP712 as ContractArtifact,
FixinProtocolFees: FixinProtocolFees as ContractArtifact, FixinProtocolFees: FixinProtocolFees as ContractArtifact,

View File

@ -12,7 +12,6 @@ import { BigNumber, hexUtils, StringRevertError, ZeroExRevertErrors } from '@0x/
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Signature } from '../../src/signature_utils'; import { Signature } from '../../src/signature_utils';
import { generateCallDataSignature, signCallData } from '../../src/signed_call_data';
import { IZeroExContract, MetaTransactionsFeatureContract } from '../../src/wrappers'; import { IZeroExContract, MetaTransactionsFeatureContract } from '../../src/wrappers';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { abis } from '../utils/abis'; import { abis } from '../utils/abis';
@ -26,7 +25,7 @@ import {
TestMintableERC20TokenContract, TestMintableERC20TokenContract,
} from '../wrappers'; } from '../wrappers';
const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants; const { NULL_ADDRESS, ZERO_AMOUNT } = constants;
blockchainTests.resets('MetaTransactions feature', env => { blockchainTests.resets('MetaTransactions feature', env => {
let owner: string; let owner: string;
@ -257,16 +256,14 @@ blockchainTests.resets('MetaTransactions feature', env => {
transformations: args.transformations, transformations: args.transformations,
sender: zeroEx.address, sender: zeroEx.address,
value: mtx.value, value: mtx.value,
callDataHash: hexUtils.hash(mtx.callData),
taker: mtx.signer, taker: mtx.signer,
callDataSignature: NULL_BYTES,
}, },
], ],
TestMetaTransactionsTransformERC20FeatureEvents.TransformERC20Called, TestMetaTransactionsTransformERC20FeatureEvents.TransformERC20Called,
); );
}); });
it('can call `TransformERC20.transformERC20()` with signed calldata', async () => { it('can call `TransformERC20.transformERC20()` with calldata', async () => {
const args = getRandomTransformERC20Args(); const args = getRandomTransformERC20Args();
const callData = transformERC20Feature const callData = transformERC20Feature
.transformERC20( .transformERC20(
@ -277,10 +274,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
args.transformations, args.transformations,
) )
.getABIEncodedTransactionData(); .getABIEncodedTransactionData();
const callDataSignerKey = hexUtils.random(); const mtx = getRandomMetaTransaction({ callData });
const callDataSignature = generateCallDataSignature(callData, callDataSignerKey);
const signedCallData = signCallData(callData, callDataSignerKey);
const mtx = getRandomMetaTransaction({ callData: signedCallData });
const signature = await signMetaTransactionAsync(mtx); const signature = await signMetaTransactionAsync(mtx);
const callOpts = { const callOpts = {
gasPrice: mtx.minGasPrice, gasPrice: mtx.minGasPrice,
@ -300,9 +294,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
transformations: args.transformations, transformations: args.transformations,
sender: zeroEx.address, sender: zeroEx.address,
value: mtx.value, value: mtx.value,
callDataHash: hexUtils.hash(callData),
taker: mtx.signer, taker: mtx.signer,
callDataSignature,
}, },
], ],
TestMetaTransactionsTransformERC20FeatureEvents.TransformERC20Called, TestMetaTransactionsTransformERC20FeatureEvents.TransformERC20Called,
@ -386,8 +378,6 @@ blockchainTests.resets('MetaTransactions feature', env => {
inputTokenAmount: args.inputTokenAmount, inputTokenAmount: args.inputTokenAmount,
minOutputTokenAmount: args.minOutputTokenAmount, minOutputTokenAmount: args.minOutputTokenAmount,
transformations: args.transformations, transformations: args.transformations,
callDataHash: hexUtils.hash(mtx.callData),
callDataSignature: NULL_BYTES,
}) })
.getABIEncodedTransactionData(); .getABIEncodedTransactionData();
return expect(tx).to.revertWith( return expect(tx).to.revertWith(

View File

@ -10,10 +10,8 @@ import {
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { ETH_TOKEN_ADDRESS } from '@0x/order-utils'; import { ETH_TOKEN_ADDRESS } from '@0x/order-utils';
import { AbiEncoder, hexUtils, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils'; import { AbiEncoder, hexUtils, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils';
import { DecodedLogEntry } from 'ethereum-types';
import * as ethjs from 'ethereumjs-util'; import * as ethjs from 'ethereumjs-util';
import { generateCallDataHashSignature, signCallData } from '../../src/signed_call_data';
import { IZeroExContract, TransformERC20FeatureContract } from '../../src/wrappers'; import { IZeroExContract, TransformERC20FeatureContract } from '../../src/wrappers';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { abis } from '../utils/abis'; import { abis } from '../utils/abis';
@ -23,15 +21,10 @@ import {
TestMintableERC20TokenContract, TestMintableERC20TokenContract,
TestMintTokenERC20TransformerContract, TestMintTokenERC20TransformerContract,
TestMintTokenERC20TransformerEvents, TestMintTokenERC20TransformerEvents,
TestMintTokenERC20TransformerMintTransformEventArgs,
TestTransformERC20Contract, TestTransformERC20Contract,
TransformERC20FeatureEvents, TransformERC20FeatureEvents,
} from '../wrappers'; } from '../wrappers';
const { NULL_ADDRESS, NULL_BYTES, NULL_BYTES32 } = constants;
type MintTokenTransformerEvent = DecodedLogEntry<TestMintTokenERC20TransformerMintTransformEventArgs>;
blockchainTests.resets('TransformERC20 feature', env => { blockchainTests.resets('TransformERC20 feature', env => {
const callDataSignerKey = hexUtils.random(); const callDataSignerKey = hexUtils.random();
const callDataSigner = ethjs.bufferToHex(ethjs.privateToAddress(ethjs.toBuffer(callDataSignerKey))); const callDataSigner = ethjs.bufferToHex(ethjs.privateToAddress(ethjs.toBuffer(callDataSignerKey)));
@ -236,7 +229,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
const minOutputTokenAmount = getRandomInteger(1, '1e18'); const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount; const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({ const transformation = createMintTokenTransformation({
outputTokenMintAmount, outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount, inputTokenBurnAmunt: inputTokenAmount,
@ -249,8 +241,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
transformations: [transformation], transformations: [transformation],
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: callValue }); .awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs( verifyEventsFromLogs(
@ -272,7 +262,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
{ {
sender, sender,
taker, taker,
callDataHash: NULL_BYTES32,
context: wallet.address, context: wallet.address,
caller: zeroEx.address, caller: zeroEx.address,
data: transformation.data, data: transformation.data,
@ -291,7 +280,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
const minOutputTokenAmount = getRandomInteger(1, '1e18'); const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount; const outputTokenMintAmount = minOutputTokenAmount;
const callValue = outputTokenMintAmount.times(2); const callValue = outputTokenMintAmount.times(2);
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({ const transformation = createMintTokenTransformation({
outputTokenMintAmount, outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount, inputTokenBurnAmunt: inputTokenAmount,
@ -306,8 +294,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
transformations: [transformation], transformations: [transformation],
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: callValue }); .awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs( verifyEventsFromLogs(
@ -329,7 +315,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
{ {
taker, taker,
sender, sender,
callDataHash: NULL_BYTES32,
context: wallet.address, context: wallet.address,
caller: zeroEx.address, caller: zeroEx.address,
data: transformation.data, data: transformation.data,
@ -353,7 +338,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
const minOutputTokenAmount = getRandomInteger(1, '1e18'); const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount.plus(1); const outputTokenMintAmount = minOutputTokenAmount.plus(1);
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({ const transformation = createMintTokenTransformation({
outputTokenMintAmount, outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount, inputTokenBurnAmunt: inputTokenAmount,
@ -366,8 +350,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
transformations: [transformation], transformations: [transformation],
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: callValue }); .awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs( verifyEventsFromLogs(
@ -389,7 +371,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
{ {
sender, sender,
taker, taker,
callDataHash: NULL_BYTES32,
context: wallet.address, context: wallet.address,
caller: zeroEx.address, caller: zeroEx.address,
data: transformation.data, data: transformation.data,
@ -412,13 +393,11 @@ blockchainTests.resets('TransformERC20 feature', env => {
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const tx = feature const tx = feature
._transformERC20({ ._transformERC20({
callDataHash: hexUtils.random(),
taker, taker,
inputToken: inputToken.address, inputToken: inputToken.address,
outputToken: outputToken.address, outputToken: outputToken.address,
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
callDataSignature: NULL_BYTES,
transformations: [ transformations: [
createMintTokenTransformation({ createMintTokenTransformation({
outputTokenMintAmount, outputTokenMintAmount,
@ -446,13 +425,11 @@ blockchainTests.resets('TransformERC20 feature', env => {
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const tx = feature const tx = feature
._transformERC20({ ._transformERC20({
callDataHash: hexUtils.random(),
taker, taker,
inputToken: inputToken.address, inputToken: inputToken.address,
outputToken: outputToken.address, outputToken: outputToken.address,
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
callDataSignature: NULL_BYTES,
transformations: [ transformations: [
createMintTokenTransformation({ createMintTokenTransformation({
outputTokenFeeAmount, outputTokenFeeAmount,
@ -477,7 +454,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
const minOutputTokenAmount = getRandomInteger(2, '1e18'); const minOutputTokenAmount = getRandomInteger(2, '1e18');
const outputTokenMintAmount = minOutputTokenAmount; const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
// Split the total minting between two transformers. // Split the total minting between two transformers.
const transformations = [ const transformations = [
createMintTokenTransformation({ createMintTokenTransformation({
@ -497,8 +473,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
transformations, transformations,
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: callValue }); .awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs( verifyEventsFromLogs(
@ -507,7 +481,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
{ {
sender, sender,
taker, taker,
callDataHash: NULL_BYTES32,
context: wallet.address, context: wallet.address,
caller: zeroEx.address, caller: zeroEx.address,
data: transformations[0].data, data: transformations[0].data,
@ -517,7 +490,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
{ {
sender, sender,
taker, taker,
callDataHash: NULL_BYTES32,
context: wallet.address, context: wallet.address,
caller: zeroEx.address, caller: zeroEx.address,
data: transformations[1].data, data: transformations[1].data,
@ -537,7 +509,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
const inputTokenAmount = getRandomPortion(startingInputTokenBalance); const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(2, '1e18'); const minOutputTokenAmount = getRandomInteger(2, '1e18');
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformations = [createMintTokenTransformation({ deploymentNonce: 1337 })]; const transformations = [createMintTokenTransformation({ deploymentNonce: 1337 })];
const tx = feature const tx = feature
._transformERC20({ ._transformERC20({
@ -547,8 +518,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount, inputTokenAmount,
minOutputTokenAmount, minOutputTokenAmount,
transformations, transformations,
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: callValue }); .awaitTransactionSuccessAsync({ value: callValue });
return expect(tx).to.revertWith( return expect(tx).to.revertWith(
@ -560,103 +529,12 @@ blockchainTests.resets('TransformERC20 feature', env => {
); );
}); });
it('passes the calldata hash to transformer with proper signature', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const receipt = await feature
._transformERC20({
taker,
inputToken: inputToken.address,
outputToken: outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations: [transformation],
callDataHash,
callDataSignature: generateCallDataHashSignature(callDataHash, callDataSignerKey),
})
.awaitTransactionSuccessAsync({ value: callValue });
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(callDataHash);
});
it('passes empty calldata hash to transformer with improper signature', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const receipt = await feature
._transformERC20({
taker,
inputToken: inputToken.address,
outputToken: outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations: [transformation],
callDataHash,
callDataSignature: generateCallDataHashSignature(callDataHash, hexUtils.random()),
})
.awaitTransactionSuccessAsync({ value: callValue });
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(NULL_BYTES32);
});
it('passes empty calldata hash to transformer with no signature', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const receipt = await feature
._transformERC20({
taker,
inputToken: inputToken.address,
outputToken: outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations: [transformation],
callDataHash,
callDataSignature: NULL_BYTES,
})
.awaitTransactionSuccessAsync({ value: callValue });
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(NULL_BYTES32);
});
it('can sell entire taker balance', async () => { it('can sell entire taker balance', async () => {
const startingInputTokenBalance = getRandomInteger(0, '100e18'); const startingInputTokenBalance = getRandomInteger(0, '100e18');
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync(); await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const minOutputTokenAmount = getRandomInteger(1, '1e18'); const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount; const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18'); const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({ const transformation = createMintTokenTransformation({
outputTokenMintAmount, outputTokenMintAmount,
inputTokenBurnAmunt: startingInputTokenBalance, inputTokenBurnAmunt: startingInputTokenBalance,
@ -669,8 +547,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount: MAX_UINT256, inputTokenAmount: MAX_UINT256,
minOutputTokenAmount, minOutputTokenAmount,
transformations: [transformation], transformations: [transformation],
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: callValue }); .awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs( verifyEventsFromLogs(
@ -693,7 +569,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
await inputToken.mint(taker, ethAttchedAmount).awaitTransactionSuccessAsync(); await inputToken.mint(taker, ethAttchedAmount).awaitTransactionSuccessAsync();
const minOutputTokenAmount = getRandomInteger(1, '1e18'); const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount; const outputTokenMintAmount = minOutputTokenAmount;
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({ const transformation = createMintTokenTransformation({
outputTokenMintAmount, outputTokenMintAmount,
inputTokenAddress: ETH_TOKEN_ADDRESS, inputTokenAddress: ETH_TOKEN_ADDRESS,
@ -707,8 +582,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
inputTokenAmount: MAX_UINT256, inputTokenAmount: MAX_UINT256,
minOutputTokenAmount, minOutputTokenAmount,
transformations: [transformation], transformations: [transformation],
callDataHash,
callDataSignature: NULL_BYTES,
}) })
.awaitTransactionSuccessAsync({ value: ethAttchedAmount }); .awaitTransactionSuccessAsync({ value: ethAttchedAmount });
verifyEventsFromLogs( verifyEventsFromLogs(
@ -726,164 +599,5 @@ blockchainTests.resets('TransformERC20 feature', env => {
); );
}); });
}); });
describe('transformERC20()', () => {
it('passes the calldata hash to transformer with properly signed calldata', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const bakedCall = feature.transformERC20(
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
);
const callData = bakedCall.getABIEncodedTransactionData();
const signedCallData = signCallData(callData, callDataSignerKey);
const receipt = await bakedCall.awaitTransactionSuccessAsync({
from: taker,
value: callValue,
data: signedCallData,
});
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(hexUtils.hash(callData));
});
it('passes the calldata hash to transformer when no quote signer configured', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const bakedCall = feature.transformERC20(
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
);
const callData = bakedCall.getABIEncodedTransactionData();
await feature.setQuoteSigner(NULL_ADDRESS).awaitTransactionSuccessAsync({ from: owner });
const receipt = await bakedCall.awaitTransactionSuccessAsync({
from: taker,
value: callValue,
data: callData,
});
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(hexUtils.hash(callData));
});
it('passes empty calldata hash to transformer with improperly signed calldata', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const bakedCall = feature.transformERC20(
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
);
const callData = bakedCall.getABIEncodedTransactionData();
const signedCallData = signCallData(callData, hexUtils.random());
const receipt = await bakedCall.awaitTransactionSuccessAsync({
from: taker,
value: callValue,
data: signedCallData,
});
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(NULL_BYTES32);
});
it('passes empty calldata hash to transformer with unsigned calldata', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const bakedCall = feature.transformERC20(
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
);
const callData = bakedCall.getABIEncodedTransactionData();
const receipt = await bakedCall.awaitTransactionSuccessAsync({
from: taker,
value: callValue,
data: callData,
});
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(NULL_BYTES32);
});
it('passes empty calldata hash to transformer with calldata with malformed signature', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const bakedCall = feature.transformERC20(
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
);
const callData = bakedCall.getABIEncodedTransactionData();
const signedCallData = hexUtils.concat(
hexUtils.slice(signCallData(callData, hexUtils.random()), 0, -1),
127,
);
const receipt = await bakedCall.awaitTransactionSuccessAsync({
from: taker,
value: callValue,
data: signedCallData,
});
const { callDataHash: actualCallDataHash } = (receipt.logs[0] as MintTokenTransformerEvent).args;
expect(actualCallDataHash).to.eq(NULL_BYTES32);
});
});
}); });
}); });

View File

@ -1,6 +1,6 @@
import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils';
import { encodeAffiliateFeeTransformerData, ETH_TOKEN_ADDRESS } from '@0x/order-utils'; import { encodeAffiliateFeeTransformerData, ETH_TOKEN_ADDRESS } from '@0x/order-utils';
import { BigNumber, hexUtils } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
@ -88,7 +88,6 @@ blockchainTests.resets('AffiliateFeeTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
sender: randomAddress(), sender: randomAddress(),
taker: randomAddress(), taker: randomAddress(),
}) })
@ -119,7 +118,6 @@ blockchainTests.resets('AffiliateFeeTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
sender: randomAddress(), sender: randomAddress(),
taker: randomAddress(), taker: randomAddress(),
}) })
@ -150,7 +148,6 @@ blockchainTests.resets('AffiliateFeeTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
sender: randomAddress(), sender: randomAddress(),
taker: randomAddress(), taker: randomAddress(),
}) })

View File

@ -1,6 +1,6 @@
import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils';
import { encodePayTakerTransformerData, ETH_TOKEN_ADDRESS } from '@0x/order-utils'; import { encodePayTakerTransformerData, ETH_TOKEN_ADDRESS } from '@0x/order-utils';
import { BigNumber, hexUtils } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
@ -80,7 +80,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
taker, taker,
sender: randomAddress(), sender: randomAddress(),
}) })
@ -103,7 +102,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
taker, taker,
sender: randomAddress(), sender: randomAddress(),
}) })
@ -126,7 +124,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
taker, taker,
sender: randomAddress(), sender: randomAddress(),
}) })
@ -149,7 +146,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
await host await host
.rawExecuteTransform(transformer.address, { .rawExecuteTransform(transformer.address, {
data, data,
callDataHash: hexUtils.random(),
taker, taker,
sender: randomAddress(), sender: randomAddress(),
}) })

View File

@ -58,7 +58,6 @@ export * from '../test/generated-wrappers/lib_proxy_storage';
export * from '../test/generated-wrappers/lib_reentrancy_guard_storage'; export * from '../test/generated-wrappers/lib_reentrancy_guard_storage';
export * from '../test/generated-wrappers/lib_signature'; export * from '../test/generated-wrappers/lib_signature';
export * from '../test/generated-wrappers/lib_signature_rich_errors'; export * from '../test/generated-wrappers/lib_signature_rich_errors';
export * from '../test/generated-wrappers/lib_signed_call_data';
export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors'; export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors';
export * from '../test/generated-wrappers/lib_simple_function_registry_storage'; export * from '../test/generated-wrappers/lib_simple_function_registry_storage';
export * from '../test/generated-wrappers/lib_spender_rich_errors'; export * from '../test/generated-wrappers/lib_spender_rich_errors';

View File

@ -85,7 +85,6 @@
"test/generated-artifacts/LibReentrancyGuardStorage.json", "test/generated-artifacts/LibReentrancyGuardStorage.json",
"test/generated-artifacts/LibSignature.json", "test/generated-artifacts/LibSignature.json",
"test/generated-artifacts/LibSignatureRichErrors.json", "test/generated-artifacts/LibSignatureRichErrors.json",
"test/generated-artifacts/LibSignedCallData.json",
"test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json", "test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json",
"test/generated-artifacts/LibSimpleFunctionRegistryStorage.json", "test/generated-artifacts/LibSimpleFunctionRegistryStorage.json",
"test/generated-artifacts/LibSpenderRichErrors.json", "test/generated-artifacts/LibSpenderRichErrors.json",