protocol/contracts/zero-ex/tests/MultiplexMetaTransactionsV2.t.sol
Patrick Dowell ff104e7505
feat: Multiplex + MetaTransaction integration and MetaTransaction Multi-Fee Support [RFQ-795] [LIT-870] (#665)
* MetaTransactionData changes

* MetaTransactionV2 creation and forge tests

* MetaTransactionData changes

* MetaTransactionV2 creation and forge tests

* add multiplexBatchSellTokenForToken, multiplexMultiHopSellTokenForToken, multiplex TokenForEth functions to metatransactions, add msgSender field to multiplex params

* Ran prettier to clean up

* More linting

* Fixing issues with EIP 712 signature, adding test case against MetaMask, and fixing lint issues

* Addressing suggestions from PR reviewers

* Complex rebase of test code based on changes in #655

* Fixing multiplex test failure

* add some tests for multiplex metatransactions

* prettier

* minor test fix

* cleaning up and adding batchExecuteMetaTransaction tests

* Removing ZERO_ADDRESS

* add multiHopBatchSellOtc to MultiplexFeature, fix _computeHopTarget for MultiplexSubcall.OTC [#667]

* fix _computeHopTarget for otc subcalls

* Fixing multiHopSellOtcOrder when params.useSelfBalance is true

* Making executeMetaTransactionV2 nonpayable and addressing a few other minor issues

* Forge update

* Add MetaTransactionsFeatureV2 to exported contracts

---------

Co-authored-by: abls <112491550+abls@users.noreply.github.com>
Co-authored-by: Duncan Townsend <git@duncancmt.com>
2023-04-19 18:20:28 -04:00

408 lines
15 KiB
Solidity

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import {LocalTest} from "utils/LocalTest.sol";
import {MultiplexUtils} from "utils/MultiplexUtils.sol";
import {LibSignature} from "src/features/libs/LibSignature.sol";
import {LibNativeOrder} from "src/features/libs/LibNativeOrder.sol";
import {IMetaTransactionsFeatureV2} from "src/features/interfaces/IMetaTransactionsFeatureV2.sol";
contract MultiplexMetaTransactionsV2 is LocalTest, MultiplexUtils {
function _makeMetaTransactionV2(
bytes memory callData
) private view returns (IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory, LibSignature.Signature memory) {
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx = IMetaTransactionsFeatureV2.MetaTransactionDataV2({
signer: payable(otherSignerAddress),
sender: address(0),
expirationTimeSeconds: block.timestamp + 600,
salt: 123,
callData: callData,
feeToken: dai,
fees: new IMetaTransactionsFeatureV2.MetaTransactionFeeData[](0)
});
bytes32 mtxHash = zeroExDeployed.zeroEx.getMetaTransactionV2Hash(mtx);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(otherSignerKey, mtxHash);
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
return (mtx, sig);
}
function _executeMetaTransaction(bytes memory callData) private {
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx;
LibSignature.Signature memory sig;
(mtx, sig) = _makeMetaTransactionV2(callData);
zeroExDeployed.zeroEx.executeMetaTransactionV2(mtx, sig);
}
// batch
function test_metaTransaction_multiplexBatchSellTokenForToken_rfqOrder() external {
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
rfqOrder.taker = otherSignerAddress;
_mintTo(address(rfqOrder.takerToken), otherSignerAddress, rfqOrder.takerAmount);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeRfqSubcall(rfqOrder)),
rfqOrder.takerAmount,
rfqOrder.makerAmount
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_otcOrder() external {
LibNativeOrder.OtcOrder memory otcOrder = _makeTestOtcOrder();
otcOrder.taker = otherSignerAddress;
_mintTo(address(otcOrder.takerToken), otherSignerAddress, otcOrder.takerAmount);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeOtcSubcall(otcOrder)),
otcOrder.takerAmount,
otcOrder.makerAmount
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_uniswapV2() external {
_createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeUniswapV2BatchSubcall(_makeArray(address(dai), address(zrx)), 1e18, false)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_uniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(zrx)), 1e18)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_liquidityProvider() external {
_mintTo(address(dai), otherSignerAddress, 1e18);
_mintTo(address(zrx), address(liquidityProvider), 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeMockLiquidityProviderBatchSubcall(1e18)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_transformErc20() external {
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeMockTransformERC20Subcall(dai, zrx, 1e18, 1e18)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_rfqOrderUniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
rfqOrder.taker = otherSignerAddress;
_mintTo(address(dai), otherSignerAddress, 2e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(
_makeRfqSubcall(rfqOrder),
_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(zrx)), 1e18)
),
2e18,
11e18
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_rfqOrderFallbackUniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 2e18);
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
rfqOrder.taker = otherSignerAddress;
rfqOrder.expiry = 1;
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(
_makeRfqSubcall(rfqOrder),
_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(zrx)), 1e18)
),
1e18,
10e18
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForToken_uniswapV3_revertsIfIncorrectAmount() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx;
LibSignature.Signature memory sig;
(mtx, sig) = _makeMetaTransactionV2(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(zrx)), 5e17)),
1e18,
1
)
);
vm.expectRevert();
zeroExDeployed.zeroEx.executeMetaTransactionV2(mtx, sig);
}
// multi hop
function test_metaTransaction_multiplexMultiHopSellTokenForToken_uniswapV2() external {
_createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
address[] memory tokens = _makeArray(address(dai), address(zrx));
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector,
tokens,
_makeArray(_makeUniswapV2MultiHopSubcall(tokens, false)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexMultiHopSellTokenForToken_uniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
address[] memory tokens = _makeArray(address(dai), address(zrx));
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector,
tokens,
_makeArray(_makeUniswapV3MultiHopSubcall(tokens)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexMultiHopSellTokenForToken_liquidityProvider() external {
_mintTo(address(dai), otherSignerAddress, 1e18);
_mintTo(address(zrx), address(liquidityProvider), 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector,
_makeArray(address(dai), address(zrx)),
_makeArray(_makeMockLiquidityProviderMultiHopSubcall()),
1e18,
1
)
);
}
function test_metaTransaction_multiplexMultiHopSellTokenForToken_uniswapV2UniswapV3() external {
_createUniswapV2Pool(uniV2Factory, dai, shib, 10e18, 10e18);
_createUniswapV3Pool(uniV3Factory, shib, zrx, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector,
_makeArray(address(dai), address(shib), address(zrx)),
_makeArray(
_makeUniswapV2MultiHopSubcall(_makeArray(address(dai), address(shib)), false),
_makeUniswapV3MultiHopSubcall(_makeArray(address(shib), address(zrx)))
),
1e18,
10e18
)
);
}
// batch for eth
function test_metaTransaction_multiplexBatchSellTokenForEth_uniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, weth, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForEth.selector,
dai,
_makeArray(_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(weth)), 1e18)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexBatchSellTokenForEth_rfqOrderUniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, weth, 10e18, 10e18);
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
rfqOrder.taker = otherSignerAddress;
rfqOrder.makerToken = weth;
_mintTo(address(weth), rfqOrder.maker, rfqOrder.makerAmount);
_mintTo(address(dai), otherSignerAddress, 2e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForEth.selector,
dai,
_makeArray(
_makeRfqSubcall(rfqOrder),
_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(weth)), 1e18)
),
2e18,
11e18
)
);
}
// nested
function test_metaTransaction_multiplexBatchSellTokenForToken_nestedUniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
address[] memory tokens = _makeArray(address(dai), address(zrx));
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken.selector,
dai,
zrx,
_makeArray(
_makeNestedMultiHopSellSubcall(tokens, _makeArray(_makeUniswapV3MultiHopSubcall(tokens)), 1e18)
),
1e18,
1
)
);
}
function test_metaTransaction_multiplexMultiHopSellTokenForToken_nestedUniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector,
_makeArray(address(dai), address(zrx)),
_makeArray(
_makeNestedBatchSellSubcall(
_makeArray(_makeUniswapV3BatchSubcall(_makeArray(address(dai), address(zrx)), 1e18))
)
),
1e18,
1
)
);
}
// multi hop for eth
function test_metaTransaction_multiplexMultiHopSellTokenForEth_uniswapV3() external {
_createUniswapV3Pool(uniV3Factory, dai, weth, 10e18, 10e18);
address[] memory tokens = _makeArray(address(dai), address(weth));
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForEth.selector,
tokens,
_makeArray(_makeUniswapV3MultiHopSubcall(tokens)),
1e18,
1
)
);
}
function test_metaTransaction_multiplexMultiHopSellTokenForEth_uniswapV3_revertsNotWeth() external {
_createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
address[] memory tokens = _makeArray(address(dai), address(zrx));
_mintTo(address(dai), otherSignerAddress, 1e18);
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtx;
LibSignature.Signature memory sig;
(mtx, sig) = _makeMetaTransactionV2(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForEth.selector,
tokens,
_makeArray(_makeUniswapV3MultiHopSubcall(tokens)),
1e18,
1
)
);
vm.expectRevert("MetaTransactionsFeature::multiplexMultiHopSellTokenForEth/NOT_WETH");
zeroExDeployed.zeroEx.executeMetaTransactionV2(mtx, sig);
}
function test_metaTransaction_multiplexMultiHopSellTokenForEth_uniswapV2UniswapV3() external {
_createUniswapV2Pool(uniV2Factory, dai, shib, 10e18, 10e18);
_createUniswapV3Pool(uniV3Factory, shib, weth, 10e18, 10e18);
_mintTo(address(dai), otherSignerAddress, 1e18);
_executeMetaTransaction(
abi.encodeWithSelector(
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken.selector,
_makeArray(address(dai), address(shib), address(weth)),
_makeArray(
_makeUniswapV2MultiHopSubcall(_makeArray(address(dai), address(shib)), false),
_makeUniswapV3MultiHopSubcall(_makeArray(address(shib), address(weth)))
),
1e18,
10e18
)
);
}
}