limit order metatransactions (#44)
This commit is contained in:
parent
5306cc03e9
commit
e2ee3414ea
@ -25,6 +25,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Convert metatransactions to use `LibSignature`",
|
"note": "Convert metatransactions to use `LibSignature`",
|
||||||
"pr": 31
|
"pr": 31
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add metatransaction support for limit orders",
|
||||||
|
"pr": 44
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -35,6 +35,7 @@ import "./ITransformERC20Feature.sol";
|
|||||||
import "./libs/LibSignature.sol";
|
import "./libs/LibSignature.sol";
|
||||||
import "./ISignatureValidatorFeature.sol";
|
import "./ISignatureValidatorFeature.sol";
|
||||||
import "./IFeature.sol";
|
import "./IFeature.sol";
|
||||||
|
import "./INativeOrdersFeature.sol";
|
||||||
|
|
||||||
/// @dev MetaTransactions feature.
|
/// @dev MetaTransactions feature.
|
||||||
contract MetaTransactionsFeature is
|
contract MetaTransactionsFeature is
|
||||||
@ -48,7 +49,6 @@ contract MetaTransactionsFeature is
|
|||||||
using LibBytesV06 for bytes;
|
using LibBytesV06 for bytes;
|
||||||
using LibRichErrorsV06 for bytes;
|
using LibRichErrorsV06 for bytes;
|
||||||
|
|
||||||
|
|
||||||
/// @dev Describes the state of a meta transaction.
|
/// @dev Describes the state of a meta transaction.
|
||||||
struct ExecuteState {
|
struct ExecuteState {
|
||||||
// Sender of the meta-transaction.
|
// Sender of the meta-transaction.
|
||||||
@ -292,6 +292,10 @@ contract MetaTransactionsFeature is
|
|||||||
state.selector = state.mtx.callData.readBytes4(0);
|
state.selector = state.mtx.callData.readBytes4(0);
|
||||||
if (state.selector == ITransformERC20Feature.transformERC20.selector) {
|
if (state.selector == ITransformERC20Feature.transformERC20.selector) {
|
||||||
returnResult = _executeTransformERC20Call(state);
|
returnResult = _executeTransformERC20Call(state);
|
||||||
|
} else if (state.selector == INativeOrdersFeature.fillLimitOrder.selector) {
|
||||||
|
returnResult = _executeFillLimitOrderCall(state);
|
||||||
|
} else if (state.selector == INativeOrdersFeature.fillRfqOrder.selector) {
|
||||||
|
returnResult = _executeFillRfqOrderCall(state);
|
||||||
} else {
|
} else {
|
||||||
LibMetaTransactionsRichErrors
|
LibMetaTransactionsRichErrors
|
||||||
.MetaTransactionUnsupportedFunctionError(state.hash, state.selector)
|
.MetaTransactionUnsupportedFunctionError(state.hash, state.selector)
|
||||||
@ -453,6 +457,88 @@ contract MetaTransactionsFeature is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Extract arguments from call data by copying everything after the
|
||||||
|
/// 4-byte selector into a new byte array.
|
||||||
|
/// @param callData The call data from which arguments are to be extracted.
|
||||||
|
/// @return args The extracted arguments as a byte array.
|
||||||
|
function _extractArgumentsFromCallData(
|
||||||
|
bytes memory callData
|
||||||
|
)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns (bytes memory args)
|
||||||
|
{
|
||||||
|
args = new bytes(callData.length - 4);
|
||||||
|
uint256 fromMem;
|
||||||
|
uint256 toMem;
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
fromMem := add(callData, 36) // skip length and 4-byte selector
|
||||||
|
toMem := add(args, 32) // write after length prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
LibBytesV06.memCopy(toMem, fromMem, args.length);
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Execute a `INativeOrdersFeature.fillLimitOrder()` meta-transaction call
|
||||||
|
/// by decoding the call args and translating the call to the internal
|
||||||
|
/// `INativeOrdersFeature._fillLimitOrder()` variant, where we can override
|
||||||
|
/// the taker address.
|
||||||
|
function _executeFillLimitOrderCall(ExecuteState memory state)
|
||||||
|
private
|
||||||
|
returns (bytes memory returnResult)
|
||||||
|
{
|
||||||
|
LibNativeOrder.LimitOrder memory order;
|
||||||
|
LibSignature.Signature memory signature;
|
||||||
|
uint128 takerTokenFillAmount;
|
||||||
|
|
||||||
|
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
|
||||||
|
(order, signature, takerTokenFillAmount) = abi.decode(args, (LibNativeOrder.LimitOrder, LibSignature.Signature, uint128));
|
||||||
|
|
||||||
|
return _callSelf(
|
||||||
|
state.hash,
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
INativeOrdersFeature._fillLimitOrder.selector,
|
||||||
|
order,
|
||||||
|
signature,
|
||||||
|
takerTokenFillAmount,
|
||||||
|
state.mtx.signer, // taker is mtx signer
|
||||||
|
msg.sender
|
||||||
|
),
|
||||||
|
state.mtx.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Execute a `INativeOrdersFeature.fillRfqOrder()` meta-transaction call
|
||||||
|
/// by decoding the call args and translating the call to the internal
|
||||||
|
/// `INativeOrdersFeature._fillRfqOrder()` variant, where we can overrideunimpleme
|
||||||
|
/// the taker address.
|
||||||
|
function _executeFillRfqOrderCall(ExecuteState memory state)
|
||||||
|
private
|
||||||
|
returns (bytes memory returnResult)
|
||||||
|
{
|
||||||
|
LibNativeOrder.RfqOrder memory order;
|
||||||
|
LibSignature.Signature memory signature;
|
||||||
|
uint128 takerTokenFillAmount;
|
||||||
|
|
||||||
|
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
|
||||||
|
(order, signature, takerTokenFillAmount) = abi.decode(args, (LibNativeOrder.RfqOrder, LibSignature.Signature, uint128));
|
||||||
|
|
||||||
|
return _callSelf(
|
||||||
|
state.hash,
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
INativeOrdersFeature._fillRfqOrder.selector,
|
||||||
|
order,
|
||||||
|
signature,
|
||||||
|
takerTokenFillAmount,
|
||||||
|
state.mtx.signer // taker is mtx signer
|
||||||
|
),
|
||||||
|
state.mtx.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Make an arbitrary internal, meta-transaction call.
|
/// @dev Make an arbitrary internal, meta-transaction call.
|
||||||
/// Warning: Do not let unadulterated `callData` into this function.
|
/// Warning: Do not let unadulterated `callData` into this function.
|
||||||
function _callSelf(bytes32 hash, bytes memory callData, uint256 value)
|
function _callSelf(bytes32 hash, bytes memory callData, uint256 value)
|
||||||
|
@ -319,6 +319,7 @@ contract NativeOrdersFeature is
|
|||||||
address sender
|
address sender
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
|
virtual
|
||||||
override
|
override
|
||||||
payable
|
payable
|
||||||
onlySelf
|
onlySelf
|
||||||
@ -355,6 +356,7 @@ contract NativeOrdersFeature is
|
|||||||
address taker
|
address taker
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
|
virtual
|
||||||
override
|
override
|
||||||
payable
|
payable
|
||||||
onlySelf
|
onlySelf
|
||||||
|
@ -38,7 +38,7 @@ library LibSignature {
|
|||||||
/// The valid range is given by fig (283) of the yellow paper.
|
/// The valid range is given by fig (283) of the yellow paper.
|
||||||
uint256 private constant ECDSA_SIGNATURE_S_LIMIT = ECDSA_SIGNATURE_R_LIMIT / 2 + 1;
|
uint256 private constant ECDSA_SIGNATURE_S_LIMIT = ECDSA_SIGNATURE_R_LIMIT / 2 + 1;
|
||||||
|
|
||||||
/// @dev Allowed signature types.
|
/// @dev Allowed signature types.
|
||||||
enum SignatureType {
|
enum SignatureType {
|
||||||
ILLEGAL,
|
ILLEGAL,
|
||||||
INVALID,
|
INVALID,
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 "../src/features/NativeOrdersFeature.sol";
|
||||||
|
import "../src/features/IMetaTransactionsFeature.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract TestMetaTransactionsNativeOrdersFeature is
|
||||||
|
NativeOrdersFeature
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
)
|
||||||
|
public
|
||||||
|
NativeOrdersFeature(address(0), IEtherTokenV06(0), IStaking(0), 0, bytes32(0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
event FillLimitOrderCalled(
|
||||||
|
LibNativeOrder.LimitOrder order,
|
||||||
|
LibSignature.SignatureType signatureType,
|
||||||
|
uint8 v,
|
||||||
|
bytes32 r,
|
||||||
|
bytes32 s,
|
||||||
|
uint128 takerTokenFillAmount,
|
||||||
|
address taker,
|
||||||
|
address sender
|
||||||
|
);
|
||||||
|
|
||||||
|
function _fillLimitOrder(
|
||||||
|
LibNativeOrder.LimitOrder memory order,
|
||||||
|
LibSignature.Signature memory signature,
|
||||||
|
uint128 takerTokenFillAmount,
|
||||||
|
address taker,
|
||||||
|
address sender
|
||||||
|
)
|
||||||
|
public
|
||||||
|
override
|
||||||
|
payable
|
||||||
|
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||||
|
{
|
||||||
|
emit FillLimitOrderCalled(
|
||||||
|
order,
|
||||||
|
signature.signatureType,
|
||||||
|
signature.v,
|
||||||
|
signature.r,
|
||||||
|
signature.s,
|
||||||
|
takerTokenFillAmount,
|
||||||
|
taker,
|
||||||
|
sender
|
||||||
|
);
|
||||||
|
return (0, 1337);
|
||||||
|
}
|
||||||
|
|
||||||
|
event FillRfqOrderCalled(
|
||||||
|
LibNativeOrder.RfqOrder order,
|
||||||
|
LibSignature.SignatureType signatureType,
|
||||||
|
uint8 v,
|
||||||
|
bytes32 r,
|
||||||
|
bytes32 s,
|
||||||
|
uint128 takerTokenFillAmount,
|
||||||
|
address taker
|
||||||
|
);
|
||||||
|
|
||||||
|
function _fillRfqOrder(
|
||||||
|
LibNativeOrder.RfqOrder memory order,
|
||||||
|
LibSignature.Signature memory signature,
|
||||||
|
uint128 takerTokenFillAmount,
|
||||||
|
address taker
|
||||||
|
)
|
||||||
|
public
|
||||||
|
override
|
||||||
|
payable
|
||||||
|
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
|
||||||
|
{
|
||||||
|
emit FillRfqOrderCalled(
|
||||||
|
order,
|
||||||
|
signature.signatureType,
|
||||||
|
signature.v,
|
||||||
|
signature.r,
|
||||||
|
signature.s,
|
||||||
|
takerTokenFillAmount,
|
||||||
|
taker
|
||||||
|
);
|
||||||
|
return (0, 1337);
|
||||||
|
}
|
||||||
|
}
|
@ -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|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|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|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|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",
|
||||||
|
@ -104,6 +104,7 @@ import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMi
|
|||||||
import * as TestLibNativeOrder from '../test/generated-artifacts/TestLibNativeOrder.json';
|
import * as TestLibNativeOrder from '../test/generated-artifacts/TestLibNativeOrder.json';
|
||||||
import * as TestLibSignature from '../test/generated-artifacts/TestLibSignature.json';
|
import * as TestLibSignature from '../test/generated-artifacts/TestLibSignature.json';
|
||||||
import * as TestLiquidityProvider from '../test/generated-artifacts/TestLiquidityProvider.json';
|
import * as TestLiquidityProvider from '../test/generated-artifacts/TestLiquidityProvider.json';
|
||||||
|
import * as TestMetaTransactionsNativeOrdersFeature from '../test/generated-artifacts/TestMetaTransactionsNativeOrdersFeature.json';
|
||||||
import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json';
|
import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json';
|
||||||
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
|
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
|
||||||
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
|
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
|
||||||
@ -237,6 +238,7 @@ export const artifacts = {
|
|||||||
TestLibNativeOrder: TestLibNativeOrder as ContractArtifact,
|
TestLibNativeOrder: TestLibNativeOrder as ContractArtifact,
|
||||||
TestLibSignature: TestLibSignature as ContractArtifact,
|
TestLibSignature: TestLibSignature as ContractArtifact,
|
||||||
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
|
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
|
||||||
|
TestMetaTransactionsNativeOrdersFeature: TestMetaTransactionsNativeOrdersFeature as ContractArtifact,
|
||||||
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
|
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
|
||||||
TestMigrator: TestMigrator as ContractArtifact,
|
TestMigrator: TestMigrator as ContractArtifact,
|
||||||
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
|
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
|
||||||
|
@ -17,7 +17,10 @@ import { IZeroExContract, MetaTransactionsFeatureContract } from '../../src/wrap
|
|||||||
import { artifacts } from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import { abis } from '../utils/abis';
|
import { abis } from '../utils/abis';
|
||||||
import { fullMigrateAsync } from '../utils/migration';
|
import { fullMigrateAsync } from '../utils/migration';
|
||||||
|
import { getRandomLimitOrder, getRandomRfqOrder } from '../utils/orders';
|
||||||
import {
|
import {
|
||||||
|
TestMetaTransactionsNativeOrdersFeatureContract,
|
||||||
|
TestMetaTransactionsNativeOrdersFeatureEvents,
|
||||||
TestMetaTransactionsTransformERC20FeatureContract,
|
TestMetaTransactionsTransformERC20FeatureContract,
|
||||||
TestMetaTransactionsTransformERC20FeatureEvents,
|
TestMetaTransactionsTransformERC20FeatureEvents,
|
||||||
TestMintableERC20TokenContract,
|
TestMintableERC20TokenContract,
|
||||||
@ -27,12 +30,14 @@ const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
|
|||||||
|
|
||||||
blockchainTests.resets('MetaTransactions feature', env => {
|
blockchainTests.resets('MetaTransactions feature', env => {
|
||||||
let owner: string;
|
let owner: string;
|
||||||
|
let maker: string;
|
||||||
let sender: string;
|
let sender: string;
|
||||||
let signers: string[];
|
let signers: string[];
|
||||||
let zeroEx: IZeroExContract;
|
let zeroEx: IZeroExContract;
|
||||||
let feature: MetaTransactionsFeatureContract;
|
let feature: MetaTransactionsFeatureContract;
|
||||||
let feeToken: TestMintableERC20TokenContract;
|
let feeToken: TestMintableERC20TokenContract;
|
||||||
let transformERC20Feature: TestMetaTransactionsTransformERC20FeatureContract;
|
let transformERC20Feature: TestMetaTransactionsTransformERC20FeatureContract;
|
||||||
|
let nativeOrdersFeature: TestMetaTransactionsNativeOrdersFeatureContract;
|
||||||
|
|
||||||
const MAX_FEE_AMOUNT = new BigNumber('1e18');
|
const MAX_FEE_AMOUNT = new BigNumber('1e18');
|
||||||
const TRANSFORM_ERC20_FAILING_VALUE = new BigNumber(666);
|
const TRANSFORM_ERC20_FAILING_VALUE = new BigNumber(666);
|
||||||
@ -41,15 +46,22 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
const REENTRANCY_FLAG_MTX = 0x1;
|
const REENTRANCY_FLAG_MTX = 0x1;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
[owner, sender, ...signers] = await env.getAccountAddressesAsync();
|
[owner, maker, sender, ...signers] = await env.getAccountAddressesAsync();
|
||||||
transformERC20Feature = await TestMetaTransactionsTransformERC20FeatureContract.deployFrom0xArtifactAsync(
|
transformERC20Feature = await TestMetaTransactionsTransformERC20FeatureContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.TestMetaTransactionsTransformERC20Feature,
|
artifacts.TestMetaTransactionsTransformERC20Feature,
|
||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
nativeOrdersFeature = await TestMetaTransactionsNativeOrdersFeatureContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestMetaTransactionsNativeOrdersFeature,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
{},
|
||||||
|
);
|
||||||
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {
|
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {
|
||||||
transformERC20: transformERC20Feature.address,
|
transformERC20: transformERC20Feature.address,
|
||||||
|
nativeOrders: nativeOrdersFeature.address,
|
||||||
});
|
});
|
||||||
feature = new MetaTransactionsFeatureContract(
|
feature = new MetaTransactionsFeatureContract(
|
||||||
zeroEx.address,
|
zeroEx.address,
|
||||||
@ -141,9 +153,77 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const RAW_SUCCESS_RESULT = hexUtils.leftPad(1337);
|
const RAW_TRANSFORM_SUCCESS_RESULT = hexUtils.leftPad(1337);
|
||||||
|
const RAW_ORDER_SUCCESS_RESULT = hexUtils.leftPad(1337, 64);
|
||||||
|
|
||||||
describe('executeMetaTransaction()', () => {
|
describe('executeMetaTransaction()', () => {
|
||||||
|
it('can call NativeOrders.fillLimitOrder()', async () => {
|
||||||
|
const order = getRandomLimitOrder({ maker });
|
||||||
|
const fillAmount = new BigNumber(23456);
|
||||||
|
const sig = await order.getSignatureWithProviderAsync(env.provider);
|
||||||
|
const mtx = getRandomMetaTransaction({
|
||||||
|
callData: nativeOrdersFeature.fillLimitOrder(order, sig, fillAmount).getABIEncodedTransactionData(),
|
||||||
|
});
|
||||||
|
const signature = await signMetaTransactionAsync(mtx);
|
||||||
|
const callOpts = {
|
||||||
|
gasPrice: mtx.minGasPrice,
|
||||||
|
value: mtx.value,
|
||||||
|
};
|
||||||
|
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
||||||
|
expect(rawResult).to.eq(RAW_ORDER_SUCCESS_RESULT);
|
||||||
|
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
|
||||||
|
|
||||||
|
verifyEventsFromLogs(
|
||||||
|
receipt.logs,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
order: _.omit(order, ['verifyingContract', 'chainId']),
|
||||||
|
sender: mtx.sender,
|
||||||
|
taker: mtx.signer,
|
||||||
|
takerTokenFillAmount: fillAmount,
|
||||||
|
signatureType: sig.signatureType,
|
||||||
|
v: sig.v,
|
||||||
|
r: sig.r,
|
||||||
|
s: sig.s,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
TestMetaTransactionsNativeOrdersFeatureEvents.FillLimitOrderCalled,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can call NativeOrders.fillRfqOrder()', async () => {
|
||||||
|
const order = getRandomRfqOrder({ maker });
|
||||||
|
const sig = await order.getSignatureWithProviderAsync(env.provider);
|
||||||
|
const fillAmount = new BigNumber(23456);
|
||||||
|
const mtx = getRandomMetaTransaction({
|
||||||
|
callData: nativeOrdersFeature.fillRfqOrder(order, sig, fillAmount).getABIEncodedTransactionData(),
|
||||||
|
});
|
||||||
|
const signature = await signMetaTransactionAsync(mtx);
|
||||||
|
const callOpts = {
|
||||||
|
gasPrice: mtx.minGasPrice,
|
||||||
|
value: mtx.value,
|
||||||
|
};
|
||||||
|
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
||||||
|
expect(rawResult).to.eq(RAW_ORDER_SUCCESS_RESULT);
|
||||||
|
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
|
||||||
|
|
||||||
|
verifyEventsFromLogs(
|
||||||
|
receipt.logs,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
order: _.omit(order, ['verifyingContract', 'chainId']),
|
||||||
|
taker: mtx.signer,
|
||||||
|
takerTokenFillAmount: fillAmount,
|
||||||
|
signatureType: sig.signatureType,
|
||||||
|
v: sig.v,
|
||||||
|
r: sig.r,
|
||||||
|
s: sig.s,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
TestMetaTransactionsNativeOrdersFeatureEvents.FillRfqOrderCalled,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('can call `TransformERC20.transformERC20()`', async () => {
|
it('can call `TransformERC20.transformERC20()`', async () => {
|
||||||
const args = getRandomTransformERC20Args();
|
const args = getRandomTransformERC20Args();
|
||||||
const mtx = getRandomMetaTransaction({
|
const mtx = getRandomMetaTransaction({
|
||||||
@ -163,7 +243,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
value: mtx.value,
|
value: mtx.value,
|
||||||
};
|
};
|
||||||
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
||||||
expect(rawResult).to.eq(RAW_SUCCESS_RESULT);
|
expect(rawResult).to.eq(RAW_TRANSFORM_SUCCESS_RESULT);
|
||||||
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
|
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
|
||||||
verifyEventsFromLogs(
|
verifyEventsFromLogs(
|
||||||
receipt.logs,
|
receipt.logs,
|
||||||
@ -206,7 +286,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
value: mtx.value,
|
value: mtx.value,
|
||||||
};
|
};
|
||||||
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
||||||
expect(rawResult).to.eq(RAW_SUCCESS_RESULT);
|
expect(rawResult).to.eq(RAW_TRANSFORM_SUCCESS_RESULT);
|
||||||
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
|
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
|
||||||
verifyEventsFromLogs(
|
verifyEventsFromLogs(
|
||||||
receipt.logs,
|
receipt.logs,
|
||||||
@ -249,7 +329,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
from: randomAddress(),
|
from: randomAddress(),
|
||||||
};
|
};
|
||||||
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
||||||
expect(rawResult).to.eq(RAW_SUCCESS_RESULT);
|
expect(rawResult).to.eq(RAW_TRANSFORM_SUCCESS_RESULT);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('works without fee', async () => {
|
it('works without fee', async () => {
|
||||||
@ -273,7 +353,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
value: mtx.value,
|
value: mtx.value,
|
||||||
};
|
};
|
||||||
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
const rawResult = await feature.executeMetaTransaction(mtx, signature).callAsync(callOpts);
|
||||||
expect(rawResult).to.eq(RAW_SUCCESS_RESULT);
|
expect(rawResult).to.eq(RAW_TRANSFORM_SUCCESS_RESULT);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('fails if the translated call fails', async () => {
|
it('fails if the translated call fails', async () => {
|
||||||
@ -638,7 +718,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
|
|||||||
value: BigNumber.sum(...mtxs.map(mtx => mtx.value)),
|
value: BigNumber.sum(...mtxs.map(mtx => mtx.value)),
|
||||||
};
|
};
|
||||||
const rawResults = await feature.batchExecuteMetaTransactions(mtxs, signatures).callAsync(callOpts);
|
const rawResults = await feature.batchExecuteMetaTransactions(mtxs, signatures).callAsync(callOpts);
|
||||||
expect(rawResults).to.eql(mtxs.map(() => RAW_SUCCESS_RESULT));
|
expect(rawResults).to.eql(mtxs.map(() => RAW_TRANSFORM_SUCCESS_RESULT));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cannot execute the same transaction twice', async () => {
|
it('cannot execute the same transaction twice', async () => {
|
||||||
|
@ -102,6 +102,7 @@ export * from '../test/generated-wrappers/test_initial_migration';
|
|||||||
export * from '../test/generated-wrappers/test_lib_native_order';
|
export * from '../test/generated-wrappers/test_lib_native_order';
|
||||||
export * from '../test/generated-wrappers/test_lib_signature';
|
export * from '../test/generated-wrappers/test_lib_signature';
|
||||||
export * from '../test/generated-wrappers/test_liquidity_provider';
|
export * from '../test/generated-wrappers/test_liquidity_provider';
|
||||||
|
export * from '../test/generated-wrappers/test_meta_transactions_native_orders_feature';
|
||||||
export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature';
|
export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature';
|
||||||
export * from '../test/generated-wrappers/test_migrator';
|
export * from '../test/generated-wrappers/test_migrator';
|
||||||
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
|
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
"test/generated-artifacts/TestLibNativeOrder.json",
|
"test/generated-artifacts/TestLibNativeOrder.json",
|
||||||
"test/generated-artifacts/TestLibSignature.json",
|
"test/generated-artifacts/TestLibSignature.json",
|
||||||
"test/generated-artifacts/TestLiquidityProvider.json",
|
"test/generated-artifacts/TestLiquidityProvider.json",
|
||||||
|
"test/generated-artifacts/TestMetaTransactionsNativeOrdersFeature.json",
|
||||||
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
|
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
|
||||||
"test/generated-artifacts/TestMigrator.json",
|
"test/generated-artifacts/TestMigrator.json",
|
||||||
"test/generated-artifacts/TestMintTokenERC20Transformer.json",
|
"test/generated-artifacts/TestMintTokenERC20Transformer.json",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user