497 lines
22 KiB
Solidity
497 lines
22 KiB
Solidity
// SPDX-License-Identifier: Apache-2.0
|
|
/*
|
|
Copyright 2023 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 "./utils/BaseTest.sol";
|
|
import "forge-std/Test.sol";
|
|
import "./utils/LocalTest.sol";
|
|
import "../contracts/src/features/MetaTransactionsFeatureV2.sol";
|
|
import "../contracts/src/features/interfaces/IMetaTransactionsFeatureV2.sol";
|
|
import "../contracts/src/features/interfaces/IMetaTransactionsFeature.sol";
|
|
import "../contracts/test/TestMintTokenERC20Transformer.sol";
|
|
import "../contracts/src/features/libs/LibSignature.sol";
|
|
import "src/features/libs/LibNativeOrder.sol";
|
|
import "../contracts/test/tokens/TestMintableERC20Token.sol";
|
|
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
|
import "@0x/contracts-erc20/src/IEtherToken.sol";
|
|
|
|
contract MetaTransactionTest is LocalTest {
|
|
address private constant USER_ADDRESS = 0x6dc3a54FeAE57B65d185A7B159c5d3FA7fD7FD0F;
|
|
uint256 private constant USER_KEY = 0x1fc1630343b31e60b7a197a53149ca571ed9d9791e2833337bbd8110c30710ec;
|
|
|
|
event MetaTransactionExecuted(bytes32 hash, bytes4 indexed selector, address signer, address sender);
|
|
|
|
function _mtxSignature(
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx
|
|
) private returns (LibSignature.Signature memory) {
|
|
return _mtxSignatureWithSignerKey(mtx, USER_KEY);
|
|
}
|
|
|
|
function _mtxSignatureWithSignerKey(
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx,
|
|
uint256 key
|
|
) private returns (LibSignature.Signature memory) {
|
|
// Mint fee to signer and approve
|
|
for (uint256 i = 0; i < mtx.fees.length; ++i) {
|
|
_mintTo(address(weth), mtx.signer, mtx.fees[i].amount);
|
|
}
|
|
vm.prank(mtx.signer);
|
|
mtx.feeToken.approve(address(zeroExDeployed.zeroEx), 1e18);
|
|
|
|
bytes32 mtxHash = zeroExDeployed.features.metaTransactionsFeatureV2.getMetaTransactionV2Hash(mtx);
|
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(key, mtxHash);
|
|
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
|
|
|
|
return sig;
|
|
}
|
|
|
|
function _getMetaTransaction(
|
|
bytes memory callData
|
|
) private view returns (IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory) {
|
|
IMetaTransactionsFeatureV2.MetaTransactionFeeData[]
|
|
memory fees = new IMetaTransactionsFeatureV2.MetaTransactionFeeData[](1);
|
|
fees[0] = IMetaTransactionsFeatureV2.MetaTransactionFeeData({recipient: address(this), amount: 1});
|
|
return _getMetaTransactionWithFees(callData, fees);
|
|
}
|
|
|
|
function _getMetaTransactionWithFees(
|
|
bytes memory callData,
|
|
IMetaTransactionsFeatureV2.MetaTransactionFeeData[] memory fees
|
|
) private view returns (IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory) {
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx = IMetaTransactionsFeatureV2.MetaTransactionDataV2({
|
|
signer: payable(USER_ADDRESS),
|
|
sender: address(this),
|
|
expirationTimeSeconds: block.timestamp + 60,
|
|
salt: 123,
|
|
callData: callData,
|
|
feeToken: weth,
|
|
fees: fees
|
|
});
|
|
return mtx;
|
|
}
|
|
|
|
function _badSelectorTransformERC20Call() private pure returns (bytes memory) {
|
|
return abi.encodeWithSelector(ITransformERC20Feature.createTransformWallet.selector);
|
|
}
|
|
|
|
function _badTokenTransformERC20Call() private returns (bytes memory) {
|
|
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
|
|
transformations[0] = ITransformERC20Feature.Transformation(
|
|
uint32(transformerNonce),
|
|
abi.encode(address(dai), address(weth), 0, 1e18, 0)
|
|
);
|
|
|
|
_mintTo(address(dai), USER_ADDRESS, 1e18);
|
|
vm.prank(USER_ADDRESS);
|
|
dai.approve(address(zeroExDeployed.zeroEx), 1e18);
|
|
|
|
return
|
|
abi.encodeWithSelector(
|
|
zeroExDeployed.zeroEx.transformERC20.selector, // 0x415565b0
|
|
dai,
|
|
weth,
|
|
1e18,
|
|
1e18,
|
|
transformations
|
|
);
|
|
}
|
|
|
|
function _makeTestRfqOrder(
|
|
IERC20Token makerToken,
|
|
IERC20Token takerToken,
|
|
address makerAddress,
|
|
address takerAddress,
|
|
uint256 makerKey
|
|
) internal returns (bytes memory callData) {
|
|
LibNativeOrder.RfqOrder memory order = LibNativeOrder.RfqOrder({
|
|
makerToken: makerToken,
|
|
takerToken: takerToken,
|
|
makerAmount: 1e18,
|
|
takerAmount: 1e18,
|
|
maker: makerAddress,
|
|
taker: address(0),
|
|
txOrigin: tx.origin,
|
|
pool: 0x0000000000000000000000000000000000000000000000000000000000000000,
|
|
expiry: uint64(block.timestamp + 60),
|
|
salt: 123
|
|
});
|
|
_mintTo(address(order.makerToken), order.maker, order.makerAmount);
|
|
vm.prank(order.maker);
|
|
order.makerToken.approve(address(zeroExDeployed.zeroEx), order.makerAmount);
|
|
_mintTo(address(order.takerToken), takerAddress, order.takerAmount);
|
|
vm.prank(takerAddress);
|
|
order.takerToken.approve(address(zeroExDeployed.zeroEx), order.takerAmount);
|
|
|
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
|
|
makerKey,
|
|
zeroExDeployed.features.nativeOrdersFeature.getRfqOrderHash(order)
|
|
);
|
|
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
|
|
|
|
return
|
|
abi.encodeWithSelector(
|
|
INativeOrdersFeature.fillRfqOrder.selector, // 0xaa77476c
|
|
order, // RFQOrder
|
|
sig, // Order Signature
|
|
1e18 // Fill Amount
|
|
);
|
|
}
|
|
|
|
function _makeTestLimitOrder(
|
|
IERC20Token makerToken,
|
|
IERC20Token takerToken,
|
|
address makerAddress,
|
|
address takerAddress,
|
|
uint256 makerKey
|
|
) internal returns (bytes memory callData) {
|
|
LibNativeOrder.LimitOrder memory order = LibNativeOrder.LimitOrder({
|
|
makerToken: makerToken,
|
|
takerToken: takerToken,
|
|
makerAmount: 1e18,
|
|
takerAmount: 1e18,
|
|
maker: makerAddress,
|
|
taker: address(0),
|
|
sender: address(0),
|
|
takerTokenFeeAmount: 0,
|
|
feeRecipient: address(0),
|
|
pool: 0x0000000000000000000000000000000000000000000000000000000000000000,
|
|
expiry: uint64(block.timestamp + 60),
|
|
salt: 123
|
|
});
|
|
_mintTo(address(order.makerToken), order.maker, order.makerAmount);
|
|
vm.prank(order.maker);
|
|
order.makerToken.approve(address(zeroExDeployed.zeroEx), order.makerAmount);
|
|
_mintTo(address(order.takerToken), takerAddress, order.takerAmount);
|
|
vm.prank(takerAddress);
|
|
order.takerToken.approve(address(zeroExDeployed.zeroEx), order.takerAmount);
|
|
|
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
|
|
makerKey,
|
|
zeroExDeployed.features.nativeOrdersFeature.getLimitOrderHash(order)
|
|
);
|
|
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
|
|
|
|
return
|
|
abi.encodeWithSelector(
|
|
INativeOrdersFeature.fillLimitOrder.selector, // 0xf6274f66
|
|
order, // LimitOrder
|
|
sig, // Order Signature
|
|
1e18 // Fill Amount
|
|
);
|
|
}
|
|
|
|
function _transformERC20Call(
|
|
IERC20Token makerToken,
|
|
IERC20Token takerToken,
|
|
address takerAddress
|
|
) internal returns (bytes memory) {
|
|
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
|
|
transformations[0] = ITransformERC20Feature.Transformation(
|
|
uint32(transformerNonce),
|
|
abi.encode(address(takerToken), address(makerToken), 0, 1e18, 0)
|
|
);
|
|
|
|
_mintTo(address(takerToken), takerAddress, 1e18);
|
|
vm.prank(takerAddress);
|
|
takerToken.approve(address(zeroExDeployed.zeroEx), 1e18);
|
|
|
|
return
|
|
abi.encodeWithSelector(
|
|
zeroExDeployed.zeroEx.transformERC20.selector, // 0x415565b0
|
|
takerToken,
|
|
makerToken,
|
|
1e18,
|
|
1e18,
|
|
transformations
|
|
);
|
|
}
|
|
|
|
function test_createHash() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
|
|
bytes32 mtxHash = zeroExDeployed.features.metaTransactionsFeatureV2.getMetaTransactionV2Hash(mtxData);
|
|
assertTrue(mtxHash != bytes32(0));
|
|
}
|
|
|
|
function test_EIP_712_signature() external {
|
|
// metamask wallet signed data
|
|
bytes32 r_mm = 0xcd6c09d558e23803afae870ca53a8e7bfaf5564c64ee29f23dc4a19e7dd9e9b5;
|
|
bytes32 s_mm = 0x1ae68e89fadab4a7f4d01fd5543e5e0efd5697e87c993f045f671aba3e1f55ac;
|
|
uint8 v_mm = 0x1b;
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionFeeData[]
|
|
memory fees = new IMetaTransactionsFeatureV2.MetaTransactionFeeData[](2);
|
|
fees[0] = IMetaTransactionsFeatureV2.MetaTransactionFeeData({recipient: address(0), amount: 1000000});
|
|
fees[1] = IMetaTransactionsFeatureV2.MetaTransactionFeeData({recipient: address(0), amount: 1000});
|
|
IERC20Token usdcToken = IERC20Token(address(0x2e234DAe75C793f67A35089C9d99245E1C58470b));
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx = IMetaTransactionsFeatureV2.MetaTransactionDataV2({
|
|
signer: address(0),
|
|
sender: address(0),
|
|
expirationTimeSeconds: 99999999,
|
|
salt: 1234,
|
|
callData: new bytes(0),
|
|
feeToken: usdcToken,
|
|
fees: fees
|
|
});
|
|
|
|
bytes32 mtxHash = zeroExDeployed.features.metaTransactionsFeatureV2.getMetaTransactionV2Hash(mtx);
|
|
|
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(USER_KEY, mtxHash);
|
|
//emit log_bytes(abi.encodePacked(r, s, bytes1(v)));
|
|
|
|
// Verify signature matches from what we generated using metamask
|
|
assertTrue(v == v_mm);
|
|
assertTrue(r == r_mm);
|
|
assertTrue(s == s_mm);
|
|
}
|
|
|
|
function test_transformERC20() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
|
|
vm.expectEmit(true, false, false, true);
|
|
emit MetaTransactionExecuted(
|
|
zeroExDeployed.features.metaTransactionsFeatureV2.getMetaTransactionV2Hash(mtxData),
|
|
zeroExDeployed.zeroEx.transformERC20.selector, // 0x415565b0
|
|
USER_ADDRESS,
|
|
address(this)
|
|
);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(weth.balanceOf(address(this)), 1);
|
|
}
|
|
|
|
function test_rfqOrder() external {
|
|
bytes memory callData = _makeTestRfqOrder(zrx, dai, signerAddress, USER_ADDRESS, signerKey);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(callData);
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
|
|
vm.expectEmit(true, false, false, true);
|
|
emit MetaTransactionExecuted(
|
|
zeroExDeployed.features.metaTransactionsFeatureV2.getMetaTransactionV2Hash(mtxData),
|
|
INativeOrdersFeature.fillRfqOrder.selector, // 0xaa77476c
|
|
USER_ADDRESS,
|
|
address(this)
|
|
);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
|
|
assertEq(zrx.balanceOf(signerAddress), 0);
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(dai.balanceOf(signerAddress), 1e18);
|
|
assertEq(weth.balanceOf(address(this)), 1);
|
|
}
|
|
|
|
function test_fillLimitOrder() external {
|
|
bytes memory callData = _makeTestLimitOrder(zrx, dai, signerAddress, USER_ADDRESS, signerKey);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(callData);
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
|
|
vm.expectEmit(true, false, false, true);
|
|
emit MetaTransactionExecuted(
|
|
zeroExDeployed.features.metaTransactionsFeatureV2.getMetaTransactionV2Hash(mtxData),
|
|
INativeOrdersFeature.fillLimitOrder.selector, // 0xf6274f66
|
|
USER_ADDRESS,
|
|
address(this)
|
|
);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
|
|
assertEq(zrx.balanceOf(signerAddress), 0);
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(dai.balanceOf(signerAddress), 1e18);
|
|
assertEq(weth.balanceOf(address(this)), 1);
|
|
}
|
|
|
|
function test_transformERC20WithAnySender() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
mtxData.sender = address(0);
|
|
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(
|
|
mtxData,
|
|
_mtxSignature(mtxData)
|
|
);
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(weth.balanceOf(address(this)), 1);
|
|
}
|
|
|
|
function test_transformERC20WithoutFee() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
IMetaTransactionsFeatureV2.MetaTransactionFeeData[] memory fees;
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransactionWithFees(
|
|
transformCallData,
|
|
fees
|
|
);
|
|
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(
|
|
mtxData,
|
|
_mtxSignature(mtxData)
|
|
);
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(weth.balanceOf(address(this)), 0); // no fee paid out
|
|
}
|
|
|
|
function test_transformERC20MultipleFees() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
IMetaTransactionsFeatureV2.MetaTransactionFeeData[]
|
|
memory fees = new IMetaTransactionsFeatureV2.MetaTransactionFeeData[](2);
|
|
fees[0] = IMetaTransactionsFeatureV2.MetaTransactionFeeData({recipient: address(this), amount: 10});
|
|
fees[1] = IMetaTransactionsFeatureV2.MetaTransactionFeeData({recipient: signerAddress, amount: 20});
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransactionWithFees(
|
|
transformCallData,
|
|
fees
|
|
);
|
|
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(
|
|
mtxData,
|
|
_mtxSignature(mtxData)
|
|
);
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(weth.balanceOf(address(this)), 10);
|
|
assertEq(weth.balanceOf(address(signerAddress)), 20);
|
|
}
|
|
|
|
function test_transformERC20TranslatedCallFail() external {
|
|
bytes memory transformCallData = _badTokenTransformERC20Call();
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
}
|
|
|
|
function test_transformERC20UnsupportedFunction() external {
|
|
bytes memory transformCallData = _badSelectorTransformERC20Call();
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
}
|
|
|
|
function test_transformERC20CantExecuteTwice() external {
|
|
bytes memory callData = _makeTestRfqOrder(zrx, dai, signerAddress, USER_ADDRESS, signerKey);
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(callData);
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
}
|
|
|
|
function test_metaTxnFailsIfExpired() external {
|
|
bytes memory callData = _makeTestRfqOrder(zrx, dai, signerAddress, USER_ADDRESS, signerKey);
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(callData);
|
|
mtxData.expirationTimeSeconds = block.timestamp - 1;
|
|
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
}
|
|
|
|
function test_metaTxnFailsIfWrongSender() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
mtxData.sender = USER_ADDRESS;
|
|
|
|
LibSignature.Signature memory sig = _mtxSignature(mtxData);
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
}
|
|
|
|
function test_metaTxnFailsWrongSignature() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
|
|
|
|
LibSignature.Signature memory sig = _mtxSignatureWithSignerKey(mtxData, signerKey);
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
|
|
}
|
|
|
|
function test_batchExecuteMetaTransactionsMultipleTransactions() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
bytes memory rfqCallData = _makeTestRfqOrder(zrx, shib, signerAddress, USER_ADDRESS, signerKey);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2[]
|
|
memory mtxns = new IMetaTransactionsFeatureV2.MetaTransactionDataV2[](2);
|
|
LibSignature.Signature[] memory sigs = new LibSignature.Signature[](2);
|
|
|
|
mtxns[0] = _getMetaTransaction(transformCallData);
|
|
sigs[0] = _mtxSignature(mtxns[0]);
|
|
mtxns[1] = _getMetaTransaction(rfqCallData);
|
|
sigs[1] = _mtxSignature(mtxns[1]);
|
|
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).batchExecuteMetaTransactionsV2(mtxns, sigs);
|
|
assertEq(zrx.balanceOf(USER_ADDRESS), 2e18);
|
|
assertEq(dai.balanceOf(USER_ADDRESS), 0);
|
|
assertEq(shib.balanceOf(USER_ADDRESS), 0);
|
|
}
|
|
|
|
function test_batchExecuteMetaTransactionsCantExecuteSameTxnTwice() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2[]
|
|
memory mtxns = new IMetaTransactionsFeatureV2.MetaTransactionDataV2[](2);
|
|
LibSignature.Signature[] memory sigs = new LibSignature.Signature[](2);
|
|
|
|
mtxns[0] = _getMetaTransaction(transformCallData);
|
|
sigs[0] = _mtxSignature(mtxns[0]);
|
|
mtxns[1] = mtxns[0];
|
|
sigs[1] = _mtxSignature(mtxns[1]);
|
|
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).batchExecuteMetaTransactionsV2(mtxns, sigs);
|
|
}
|
|
|
|
function test_batchExecuteMetaTransactionsFailsIfTransactionFails() external {
|
|
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
|
|
bytes memory badTransformCallData = _badTokenTransformERC20Call();
|
|
IMetaTransactionsFeatureV2.MetaTransactionDataV2[]
|
|
memory mtxns = new IMetaTransactionsFeatureV2.MetaTransactionDataV2[](2);
|
|
LibSignature.Signature[] memory sigs = new LibSignature.Signature[](2);
|
|
|
|
mtxns[0] = _getMetaTransaction(transformCallData);
|
|
sigs[0] = _mtxSignature(mtxns[0]);
|
|
mtxns[1] = _getMetaTransaction(badTransformCallData);
|
|
sigs[1] = _mtxSignature(mtxns[1]);
|
|
|
|
vm.expectRevert();
|
|
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).batchExecuteMetaTransactionsV2(mtxns, sigs);
|
|
}
|
|
}
|