remove calldata signing (#51)
This commit is contained in:
parent
9653eb9e70
commit
88d7e73eba
@ -7,7 +7,6 @@ import {
|
||||
IZeroExContract,
|
||||
LogMetadataTransformerContract,
|
||||
Signature,
|
||||
signCallData,
|
||||
} from '@0x/contracts-zero-ex';
|
||||
import { migrateOnceAsync } from '@0x/migrations';
|
||||
import {
|
||||
@ -21,10 +20,10 @@ import {
|
||||
SignedExchangeProxyMetaTransaction,
|
||||
} from '@0x/order-utils';
|
||||
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';
|
||||
|
||||
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 {
|
||||
return {
|
||||
@ -198,21 +197,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
|
||||
.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(
|
||||
data: string,
|
||||
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 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 mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee, 0);
|
||||
const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee, 0);
|
||||
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
|
||||
const receipt = await zeroEx
|
||||
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
|
||||
@ -269,7 +251,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
|
||||
[
|
||||
{
|
||||
taker,
|
||||
callDataHash,
|
||||
sender: zeroEx.address,
|
||||
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 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 mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee);
|
||||
const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee);
|
||||
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
|
||||
const receipt = await zeroEx
|
||||
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
|
||||
@ -305,7 +284,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
|
||||
[
|
||||
{
|
||||
taker,
|
||||
callDataHash,
|
||||
sender: zeroEx.address,
|
||||
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 () => {
|
||||
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 () => {
|
||||
it('`transformERC20()` can fill RFQT order', async () => {
|
||||
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 mtx = await createMetaTransactionAsync(signedSwapData, _protocolFee, 0);
|
||||
const mtx = await createMetaTransactionAsync(getSwapData(swap), _protocolFee, 0);
|
||||
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
|
||||
const receipt = await zeroEx
|
||||
.executeMetaTransaction(mtx, sigstruct(mtx.signature))
|
||||
@ -377,7 +317,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
|
||||
[
|
||||
{
|
||||
taker,
|
||||
callDataHash,
|
||||
sender: zeroEx.address,
|
||||
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 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 mtx = await createMetaTransactionAsync(callData, _protocolFee, 0);
|
||||
const relayerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(relayer);
|
||||
@ -414,7 +352,6 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
|
||||
[
|
||||
{
|
||||
taker,
|
||||
callDataHash,
|
||||
sender: zeroEx.address,
|
||||
data: NULL_BYTES,
|
||||
},
|
||||
@ -422,15 +359,4 @@ blockchainTests.resets('exchange proxy - meta-transactions', env => {
|
||||
'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",
|
||||
"pr": 50
|
||||
},
|
||||
{
|
||||
"note": "Remove calldata signing functionality",
|
||||
"pr": 51
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -58,10 +58,6 @@ interface ITransformERC20Feature {
|
||||
// The transformations to execute on the token balance(s)
|
||||
// in sequence.
|
||||
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`.
|
||||
|
@ -29,7 +29,6 @@ import "../fixins/FixinTokenSpender.sol";
|
||||
import "../fixins/FixinEIP712.sol";
|
||||
import "../migrations/LibMigrate.sol";
|
||||
import "../storage/LibMetaTransactionsStorage.sol";
|
||||
import "./libs/LibSignedCallData.sol";
|
||||
import "./IMetaTransactionsFeature.sol";
|
||||
import "./ITransformERC20Feature.sol";
|
||||
import "./libs/LibSignature.sol";
|
||||
@ -433,10 +432,6 @@ contract MetaTransactionsFeature is
|
||||
// Decode call args for `ITransformERC20Feature.transformERC20()` as a struct.
|
||||
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).
|
||||
return _callSelf(
|
||||
state.hash,
|
||||
@ -448,9 +443,7 @@ contract MetaTransactionsFeature is
|
||||
outputToken: args.outputToken,
|
||||
inputTokenAmount: args.inputTokenAmount,
|
||||
minOutputTokenAmount: args.minOutputTokenAmount,
|
||||
transformations: args.transformations,
|
||||
callDataHash: callDataHash,
|
||||
callDataSignature: callDataSignature
|
||||
transformations: args.transformations
|
||||
})
|
||||
),
|
||||
state.mtx.value
|
||||
|
@ -32,7 +32,6 @@ import "../external/FlashWallet.sol";
|
||||
import "../storage/LibTransformERC20Storage.sol";
|
||||
import "../transformers/IERC20Transformer.sol";
|
||||
import "../transformers/LibERC20Transformer.sol";
|
||||
import "./libs/LibSignedCallData.sol";
|
||||
import "./ITransformERC20Feature.sol";
|
||||
import "./IFeature.sol";
|
||||
import "./ISignatureValidatorFeature.sol";
|
||||
@ -177,8 +176,6 @@ contract TransformERC20Feature is
|
||||
payable
|
||||
returns (uint256 outputTokenAmount)
|
||||
{
|
||||
(bytes32 callDataHash, bytes memory callDataSignature) =
|
||||
LibSignedCallData.parseCallData(msg.data);
|
||||
return _transformERC20Private(
|
||||
TransformERC20Args({
|
||||
taker: msg.sender,
|
||||
@ -186,9 +183,7 @@ contract TransformERC20Feature is
|
||||
outputToken: outputToken,
|
||||
inputTokenAmount: inputTokenAmount,
|
||||
minOutputTokenAmount: minOutputTokenAmount,
|
||||
transformations: transformations,
|
||||
callDataHash: callDataHash,
|
||||
callDataSignature: callDataSignature
|
||||
transformations: transformations
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -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.
|
||||
for (uint256 i = 0; i < args.transformations.length; ++i) {
|
||||
_executeTransformation(
|
||||
state.wallet,
|
||||
args.transformations[i],
|
||||
state.transformerDeployer,
|
||||
args.taker,
|
||||
// Transformers will receive a null calldata hash if
|
||||
// the calldata was not properly signed.
|
||||
validCallDataHash
|
||||
args.taker
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -349,13 +335,11 @@ contract TransformERC20Feature is
|
||||
/// @param transformation The transformation.
|
||||
/// @param transformerDeployer The address of the transformer deployer.
|
||||
/// @param taker The taker address.
|
||||
/// @param callDataHash Hash of the calldata.
|
||||
function _executeTransformation(
|
||||
IFlashWallet wallet,
|
||||
Transformation memory transformation,
|
||||
address transformerDeployer,
|
||||
address payable taker,
|
||||
bytes32 callDataHash
|
||||
address payable taker
|
||||
)
|
||||
private
|
||||
{
|
||||
@ -372,7 +356,6 @@ contract TransformERC20Feature is
|
||||
abi.encodeWithSelector(
|
||||
IERC20Transformer.transform.selector,
|
||||
IERC20Transformer.TransformContext({
|
||||
callDataHash: callDataHash,
|
||||
sender: msg.sender,
|
||||
taker: taker,
|
||||
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.ethRemaining = address(this).balance;
|
||||
// RFQT orders can only be filled if we have a valid calldata hash
|
||||
// (calldata was signed), and the actual taker matches the RFQT taker (if set).
|
||||
state.isRfqtAllowed = context.callDataHash != bytes32(0)
|
||||
&& (data.rfqtTakerAddress == address(0) || context.taker == data.rfqtTakerAddress);
|
||||
// RFQT orders can only be filled if the actual taker matches the RFQT
|
||||
// taker (if set).
|
||||
state.isRfqtAllowed = data.rfqtTakerAddress == address(0)
|
||||
|| context.taker == data.rfqtTakerAddress;
|
||||
|
||||
// Fill the orders.
|
||||
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()`.
|
||||
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()`.
|
||||
address payable sender;
|
||||
// taker The taker address, which may be distinct from `sender` in the case
|
||||
|
@ -27,7 +27,7 @@ import "./LibERC20Transformer.sol";
|
||||
contract LogMetadataTransformer is
|
||||
Transformer
|
||||
{
|
||||
event TransformerMetadata(bytes32 callDataHash, address sender, address taker, bytes data);
|
||||
event TransformerMetadata(address sender, address taker, bytes data);
|
||||
|
||||
/// @dev Maximum uint256 value.
|
||||
uint256 private constant MAX_UINT256 = uint256(-1);
|
||||
@ -40,7 +40,7 @@ contract LogMetadataTransformer is
|
||||
override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ contract TestFillQuoteTransformerHost is
|
||||
this.rawExecuteTransform(
|
||||
transformer,
|
||||
IERC20Transformer.TransformContext({
|
||||
callDataHash: bytes32(0),
|
||||
sender: sender,
|
||||
taker: taker,
|
||||
data: data
|
||||
|
@ -34,9 +34,7 @@ contract TestMetaTransactionsTransformERC20Feature is
|
||||
IERC20TokenV06 outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 minOutputTokenAmount,
|
||||
Transformation[] transformations,
|
||||
bytes32 callDataHash,
|
||||
bytes callDataSignature
|
||||
Transformation[] transformations
|
||||
);
|
||||
|
||||
constructor() public TransformERC20Feature(0) {}
|
||||
@ -103,9 +101,7 @@ contract TestMetaTransactionsTransformERC20Feature is
|
||||
args.outputToken,
|
||||
args.inputTokenAmount,
|
||||
args.minOutputTokenAmount,
|
||||
args.transformations,
|
||||
args.callDataHash,
|
||||
args.callDataSignature
|
||||
args.transformations
|
||||
);
|
||||
return 1337;
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ contract TestMintTokenERC20Transformer is
|
||||
event MintTransform(
|
||||
address context,
|
||||
address caller,
|
||||
bytes32 callDataHash,
|
||||
address sender,
|
||||
address taker,
|
||||
bytes data,
|
||||
@ -56,7 +55,6 @@ contract TestMintTokenERC20Transformer is
|
||||
emit MintTransform(
|
||||
address(this),
|
||||
msg.sender,
|
||||
context.callDataHash,
|
||||
context.sender,
|
||||
context.taker,
|
||||
context.data,
|
||||
|
@ -51,7 +51,6 @@ contract TestWethTransformerHost is
|
||||
this.rawExecuteTransform(
|
||||
transformer,
|
||||
IERC20Transformer.TransformContext({
|
||||
callDataHash: bytes32(0),
|
||||
sender: msg.sender,
|
||||
taker: msg.sender,
|
||||
data: data
|
||||
|
@ -42,7 +42,7 @@
|
||||
"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",
|
||||
"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": {
|
||||
"type": "git",
|
||||
|
@ -31,7 +31,6 @@ export {
|
||||
export { artifacts } from './artifacts';
|
||||
export * from './migration';
|
||||
export * from './nonce_utils';
|
||||
export * from './signed_call_data';
|
||||
export * from './signature_utils';
|
||||
export * from './orders';
|
||||
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 LibSignature from '../test/generated-artifacts/LibSignature.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 LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json';
|
||||
import * as LibSpenderRichErrors from '../test/generated-artifacts/LibSpenderRichErrors.json';
|
||||
@ -177,7 +176,6 @@ export const artifacts = {
|
||||
UniswapFeature: UniswapFeature as ContractArtifact,
|
||||
LibNativeOrder: LibNativeOrder as ContractArtifact,
|
||||
LibSignature: LibSignature as ContractArtifact,
|
||||
LibSignedCallData: LibSignedCallData as ContractArtifact,
|
||||
FixinCommon: FixinCommon as ContractArtifact,
|
||||
FixinEIP712: FixinEIP712 as ContractArtifact,
|
||||
FixinProtocolFees: FixinProtocolFees as ContractArtifact,
|
||||
|
@ -12,7 +12,6 @@ import { BigNumber, hexUtils, StringRevertError, ZeroExRevertErrors } from '@0x/
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { Signature } from '../../src/signature_utils';
|
||||
import { generateCallDataSignature, signCallData } from '../../src/signed_call_data';
|
||||
import { IZeroExContract, MetaTransactionsFeatureContract } from '../../src/wrappers';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { abis } from '../utils/abis';
|
||||
@ -26,7 +25,7 @@ import {
|
||||
TestMintableERC20TokenContract,
|
||||
} from '../wrappers';
|
||||
|
||||
const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
|
||||
const { NULL_ADDRESS, ZERO_AMOUNT } = constants;
|
||||
|
||||
blockchainTests.resets('MetaTransactions feature', env => {
|
||||
let owner: string;
|
||||
@ -257,16 +256,14 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
||||
transformations: args.transformations,
|
||||
sender: zeroEx.address,
|
||||
value: mtx.value,
|
||||
callDataHash: hexUtils.hash(mtx.callData),
|
||||
taker: mtx.signer,
|
||||
callDataSignature: NULL_BYTES,
|
||||
},
|
||||
],
|
||||
TestMetaTransactionsTransformERC20FeatureEvents.TransformERC20Called,
|
||||
);
|
||||
});
|
||||
|
||||
it('can call `TransformERC20.transformERC20()` with signed calldata', async () => {
|
||||
it('can call `TransformERC20.transformERC20()` with calldata', async () => {
|
||||
const args = getRandomTransformERC20Args();
|
||||
const callData = transformERC20Feature
|
||||
.transformERC20(
|
||||
@ -277,10 +274,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
||||
args.transformations,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
const callDataSignerKey = hexUtils.random();
|
||||
const callDataSignature = generateCallDataSignature(callData, callDataSignerKey);
|
||||
const signedCallData = signCallData(callData, callDataSignerKey);
|
||||
const mtx = getRandomMetaTransaction({ callData: signedCallData });
|
||||
const mtx = getRandomMetaTransaction({ callData });
|
||||
const signature = await signMetaTransactionAsync(mtx);
|
||||
const callOpts = {
|
||||
gasPrice: mtx.minGasPrice,
|
||||
@ -300,9 +294,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
||||
transformations: args.transformations,
|
||||
sender: zeroEx.address,
|
||||
value: mtx.value,
|
||||
callDataHash: hexUtils.hash(callData),
|
||||
taker: mtx.signer,
|
||||
callDataSignature,
|
||||
},
|
||||
],
|
||||
TestMetaTransactionsTransformERC20FeatureEvents.TransformERC20Called,
|
||||
@ -386,8 +378,6 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
||||
inputTokenAmount: args.inputTokenAmount,
|
||||
minOutputTokenAmount: args.minOutputTokenAmount,
|
||||
transformations: args.transformations,
|
||||
callDataHash: hexUtils.hash(mtx.callData),
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.getABIEncodedTransactionData();
|
||||
return expect(tx).to.revertWith(
|
||||
|
@ -10,10 +10,8 @@ import {
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { ETH_TOKEN_ADDRESS } from '@0x/order-utils';
|
||||
import { AbiEncoder, hexUtils, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils';
|
||||
import { DecodedLogEntry } from 'ethereum-types';
|
||||
import * as ethjs from 'ethereumjs-util';
|
||||
|
||||
import { generateCallDataHashSignature, signCallData } from '../../src/signed_call_data';
|
||||
import { IZeroExContract, TransformERC20FeatureContract } from '../../src/wrappers';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { abis } from '../utils/abis';
|
||||
@ -23,15 +21,10 @@ import {
|
||||
TestMintableERC20TokenContract,
|
||||
TestMintTokenERC20TransformerContract,
|
||||
TestMintTokenERC20TransformerEvents,
|
||||
TestMintTokenERC20TransformerMintTransformEventArgs,
|
||||
TestTransformERC20Contract,
|
||||
TransformERC20FeatureEvents,
|
||||
} from '../wrappers';
|
||||
|
||||
const { NULL_ADDRESS, NULL_BYTES, NULL_BYTES32 } = constants;
|
||||
|
||||
type MintTokenTransformerEvent = DecodedLogEntry<TestMintTokenERC20TransformerMintTransformEventArgs>;
|
||||
|
||||
blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const callDataSignerKey = hexUtils.random();
|
||||
const callDataSigner = ethjs.bufferToHex(ethjs.privateToAddress(ethjs.toBuffer(callDataSignerKey)));
|
||||
@ -236,7 +229,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const minOutputTokenAmount = getRandomInteger(1, '1e18');
|
||||
const outputTokenMintAmount = minOutputTokenAmount;
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const callDataHash = hexUtils.random();
|
||||
const transformation = createMintTokenTransformation({
|
||||
outputTokenMintAmount,
|
||||
inputTokenBurnAmunt: inputTokenAmount,
|
||||
@ -249,8 +241,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations: [transformation],
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: callValue });
|
||||
verifyEventsFromLogs(
|
||||
@ -272,7 +262,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
{
|
||||
sender,
|
||||
taker,
|
||||
callDataHash: NULL_BYTES32,
|
||||
context: wallet.address,
|
||||
caller: zeroEx.address,
|
||||
data: transformation.data,
|
||||
@ -291,7 +280,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const minOutputTokenAmount = getRandomInteger(1, '1e18');
|
||||
const outputTokenMintAmount = minOutputTokenAmount;
|
||||
const callValue = outputTokenMintAmount.times(2);
|
||||
const callDataHash = hexUtils.random();
|
||||
const transformation = createMintTokenTransformation({
|
||||
outputTokenMintAmount,
|
||||
inputTokenBurnAmunt: inputTokenAmount,
|
||||
@ -306,8 +294,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations: [transformation],
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: callValue });
|
||||
verifyEventsFromLogs(
|
||||
@ -329,7 +315,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
{
|
||||
taker,
|
||||
sender,
|
||||
callDataHash: NULL_BYTES32,
|
||||
context: wallet.address,
|
||||
caller: zeroEx.address,
|
||||
data: transformation.data,
|
||||
@ -353,7 +338,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const minOutputTokenAmount = getRandomInteger(1, '1e18');
|
||||
const outputTokenMintAmount = minOutputTokenAmount.plus(1);
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const callDataHash = hexUtils.random();
|
||||
const transformation = createMintTokenTransformation({
|
||||
outputTokenMintAmount,
|
||||
inputTokenBurnAmunt: inputTokenAmount,
|
||||
@ -366,8 +350,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations: [transformation],
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: callValue });
|
||||
verifyEventsFromLogs(
|
||||
@ -389,7 +371,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
{
|
||||
sender,
|
||||
taker,
|
||||
callDataHash: NULL_BYTES32,
|
||||
context: wallet.address,
|
||||
caller: zeroEx.address,
|
||||
data: transformation.data,
|
||||
@ -412,13 +393,11 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const tx = feature
|
||||
._transformERC20({
|
||||
callDataHash: hexUtils.random(),
|
||||
taker,
|
||||
inputToken: inputToken.address,
|
||||
outputToken: outputToken.address,
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
callDataSignature: NULL_BYTES,
|
||||
transformations: [
|
||||
createMintTokenTransformation({
|
||||
outputTokenMintAmount,
|
||||
@ -446,13 +425,11 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const tx = feature
|
||||
._transformERC20({
|
||||
callDataHash: hexUtils.random(),
|
||||
taker,
|
||||
inputToken: inputToken.address,
|
||||
outputToken: outputToken.address,
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
callDataSignature: NULL_BYTES,
|
||||
transformations: [
|
||||
createMintTokenTransformation({
|
||||
outputTokenFeeAmount,
|
||||
@ -477,7 +454,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const minOutputTokenAmount = getRandomInteger(2, '1e18');
|
||||
const outputTokenMintAmount = minOutputTokenAmount;
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const callDataHash = hexUtils.random();
|
||||
// Split the total minting between two transformers.
|
||||
const transformations = [
|
||||
createMintTokenTransformation({
|
||||
@ -497,8 +473,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations,
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: callValue });
|
||||
verifyEventsFromLogs(
|
||||
@ -507,7 +481,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
{
|
||||
sender,
|
||||
taker,
|
||||
callDataHash: NULL_BYTES32,
|
||||
context: wallet.address,
|
||||
caller: zeroEx.address,
|
||||
data: transformations[0].data,
|
||||
@ -517,7 +490,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
{
|
||||
sender,
|
||||
taker,
|
||||
callDataHash: NULL_BYTES32,
|
||||
context: wallet.address,
|
||||
caller: zeroEx.address,
|
||||
data: transformations[1].data,
|
||||
@ -537,7 +509,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
|
||||
const minOutputTokenAmount = getRandomInteger(2, '1e18');
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const callDataHash = hexUtils.random();
|
||||
const transformations = [createMintTokenTransformation({ deploymentNonce: 1337 })];
|
||||
const tx = feature
|
||||
._transformERC20({
|
||||
@ -547,8 +518,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations,
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: callValue });
|
||||
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 () => {
|
||||
const startingInputTokenBalance = getRandomInteger(0, '100e18');
|
||||
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
|
||||
const minOutputTokenAmount = getRandomInteger(1, '1e18');
|
||||
const outputTokenMintAmount = minOutputTokenAmount;
|
||||
const callValue = getRandomInteger(1, '1e18');
|
||||
const callDataHash = hexUtils.random();
|
||||
const transformation = createMintTokenTransformation({
|
||||
outputTokenMintAmount,
|
||||
inputTokenBurnAmunt: startingInputTokenBalance,
|
||||
@ -669,8 +547,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount: MAX_UINT256,
|
||||
minOutputTokenAmount,
|
||||
transformations: [transformation],
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: callValue });
|
||||
verifyEventsFromLogs(
|
||||
@ -693,7 +569,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
await inputToken.mint(taker, ethAttchedAmount).awaitTransactionSuccessAsync();
|
||||
const minOutputTokenAmount = getRandomInteger(1, '1e18');
|
||||
const outputTokenMintAmount = minOutputTokenAmount;
|
||||
const callDataHash = hexUtils.random();
|
||||
const transformation = createMintTokenTransformation({
|
||||
outputTokenMintAmount,
|
||||
inputTokenAddress: ETH_TOKEN_ADDRESS,
|
||||
@ -707,8 +582,6 @@ blockchainTests.resets('TransformERC20 feature', env => {
|
||||
inputTokenAmount: MAX_UINT256,
|
||||
minOutputTokenAmount,
|
||||
transformations: [transformation],
|
||||
callDataHash,
|
||||
callDataSignature: NULL_BYTES,
|
||||
})
|
||||
.awaitTransactionSuccessAsync({ value: ethAttchedAmount });
|
||||
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 { encodeAffiliateFeeTransformerData, ETH_TOKEN_ADDRESS } from '@0x/order-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
@ -88,7 +88,6 @@ blockchainTests.resets('AffiliateFeeTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
sender: randomAddress(),
|
||||
taker: randomAddress(),
|
||||
})
|
||||
@ -119,7 +118,6 @@ blockchainTests.resets('AffiliateFeeTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
sender: randomAddress(),
|
||||
taker: randomAddress(),
|
||||
})
|
||||
@ -150,7 +148,6 @@ blockchainTests.resets('AffiliateFeeTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
sender: randomAddress(),
|
||||
taker: randomAddress(),
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-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 { artifacts } from '../artifacts';
|
||||
@ -80,7 +80,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
taker,
|
||||
sender: randomAddress(),
|
||||
})
|
||||
@ -103,7 +102,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
taker,
|
||||
sender: randomAddress(),
|
||||
})
|
||||
@ -126,7 +124,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
taker,
|
||||
sender: randomAddress(),
|
||||
})
|
||||
@ -149,7 +146,6 @@ blockchainTests.resets('PayTakerTransformer', env => {
|
||||
await host
|
||||
.rawExecuteTransform(transformer.address, {
|
||||
data,
|
||||
callDataHash: hexUtils.random(),
|
||||
taker,
|
||||
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_signature';
|
||||
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_storage';
|
||||
export * from '../test/generated-wrappers/lib_spender_rich_errors';
|
||||
|
@ -85,7 +85,6 @@
|
||||
"test/generated-artifacts/LibReentrancyGuardStorage.json",
|
||||
"test/generated-artifacts/LibSignature.json",
|
||||
"test/generated-artifacts/LibSignatureRichErrors.json",
|
||||
"test/generated-artifacts/LibSignedCallData.json",
|
||||
"test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json",
|
||||
"test/generated-artifacts/LibSimpleFunctionRegistryStorage.json",
|
||||
"test/generated-artifacts/LibSpenderRichErrors.json",
|
||||
|
Loading…
x
Reference in New Issue
Block a user