remove calldata signing (#51)
This commit is contained in:
parent
9653eb9e70
commit
88d7e73eba
@ -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());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -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`.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
@ -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';
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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,
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
|
@ -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';
|
||||||
|
@ -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",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user