Migrate the multiplex tests to foundry (#655)
* add some tests for multiplex using foundry * remove try/catch from multiplex foundry tests * refactor multiplex forge tests * fix broken import, remove dead code --------- Co-authored-by: Patrick Dowell <patrick.dowell@gmail.com>
This commit is contained in:
parent
459fb3ee28
commit
38665ffc86
615
contracts/zero-ex/tests/Multiplex.t.sol
Normal file
615
contracts/zero-ex/tests/Multiplex.t.sol
Normal file
@ -0,0 +1,615 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {LibNativeOrder} from "src/features/libs/LibNativeOrder.sol";
|
||||
import {IMultiplexFeature} from "src/features/interfaces/IMultiplexFeature.sol";
|
||||
import {LocalTest} from "utils/LocalTest.sol";
|
||||
import {MultiplexUtils} from "utils/MultiplexUtils.sol";
|
||||
|
||||
contract Multiplex is LocalTest, MultiplexUtils {
|
||||
event RfqOrderFilled(
|
||||
bytes32 orderHash,
|
||||
address maker,
|
||||
address taker,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint128 takerTokenFilledAmount,
|
||||
uint128 makerTokenFilledAmount,
|
||||
bytes32 pool
|
||||
);
|
||||
|
||||
event OtcOrderFilled(
|
||||
bytes32 orderHash,
|
||||
address maker,
|
||||
address taker,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint128 makerTokenFilledAmount,
|
||||
uint128 takerTokenFilledAmount
|
||||
);
|
||||
|
||||
event ExpiredRfqOrder(bytes32 orderHash, address maker, uint64 expiry);
|
||||
|
||||
event ExpiredOtcOrder(bytes32 orderHash, address maker, uint64 expiry);
|
||||
|
||||
event Transfer(address token, address from, address to, uint256 value);
|
||||
|
||||
event MintTransform(
|
||||
address context,
|
||||
address caller,
|
||||
address sender,
|
||||
address taker,
|
||||
bytes data,
|
||||
uint256 inputTokenBalance,
|
||||
uint256 ethBalance
|
||||
);
|
||||
|
||||
//// batch sells
|
||||
|
||||
// reverts if minBuyAmount is not satisfied
|
||||
function test_multiplexBatchSellTokenForToken_revertsIfMinBuyAmountIsNotSatisfied() public {
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
IMultiplexFeature.BatchSellSubcall memory rfqSubcall = _makeRfqSubcall(rfqOrder);
|
||||
_mintTo(address(rfqOrder.takerToken), rfqOrder.taker, rfqOrder.takerAmount);
|
||||
|
||||
vm.expectRevert("MultiplexFeature::_multiplexBatchSell/UNDERBOUGHT");
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
dai,
|
||||
zrx,
|
||||
_makeArray(rfqSubcall),
|
||||
rfqOrder.takerAmount,
|
||||
rfqOrder.makerAmount + 1
|
||||
);
|
||||
}
|
||||
|
||||
// reverts if given an invalid subcall type
|
||||
function test_multiplexBatchSellTokenForToken_revertsIfGivenAnInvalidSubcallType() public {
|
||||
uint256 sellAmount = 1e18;
|
||||
|
||||
vm.expectRevert("MultiplexFeature::_executeBatchSell/INVALID_SUBCALL");
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
dai,
|
||||
zrx,
|
||||
_makeArray(
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.Invalid,
|
||||
sellAmount: sellAmount,
|
||||
data: hex""
|
||||
})
|
||||
),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// reverts if the full sell amount is not sold
|
||||
function test_multiplexBatchSellTokenForToken_revertsIfTheFullSellAmountIsNotSold() public {
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
IMultiplexFeature.BatchSellSubcall memory rfqSubcall = _makeRfqSubcall(rfqOrder);
|
||||
_mintTo(address(rfqOrder.takerToken), rfqOrder.taker, rfqOrder.takerAmount);
|
||||
|
||||
vm.expectRevert("MultiplexFeature::_executeBatchSell/INCORRECT_AMOUNT_SOLD");
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
rfqOrder.takerToken,
|
||||
rfqOrder.makerToken,
|
||||
_makeArray(rfqSubcall),
|
||||
rfqOrder.takerAmount + 1,
|
||||
rfqOrder.makerAmount
|
||||
);
|
||||
}
|
||||
|
||||
// RFQ, fallback(UniswapV2)
|
||||
function test_multiplexBatchSellTokenForToken_rfqFallbackUniswapV2() public {
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
_createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
_mintTo(address(rfqOrder.takerToken), rfqOrder.taker, rfqOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit RfqOrderFilled(
|
||||
zeroExDeployed.features.nativeOrdersFeature.getRfqOrderHash(rfqOrder),
|
||||
rfqOrder.maker,
|
||||
rfqOrder.taker,
|
||||
address(rfqOrder.makerToken),
|
||||
address(rfqOrder.takerToken),
|
||||
rfqOrder.takerAmount,
|
||||
rfqOrder.makerAmount,
|
||||
rfqOrder.pool
|
||||
);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
rfqOrder.takerToken,
|
||||
zrx,
|
||||
_makeArray(
|
||||
_makeRfqSubcall(rfqOrder),
|
||||
_makeUniswapV2BatchSubcall(_makeArray(address(dai), address(zrx)), rfqOrder.takerAmount, false)
|
||||
),
|
||||
rfqOrder.takerAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// OTC, fallback(UniswapV2)
|
||||
function test_multiplexBatchSellTokenForToken_otcFallbackUniswapV2() public {
|
||||
LibNativeOrder.OtcOrder memory otcOrder = _makeTestOtcOrder();
|
||||
_createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
_mintTo(address(otcOrder.takerToken), otcOrder.taker, otcOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit OtcOrderFilled(
|
||||
zeroExDeployed.features.otcOrdersFeature.getOtcOrderHash(otcOrder),
|
||||
otcOrder.maker,
|
||||
otcOrder.taker,
|
||||
address(otcOrder.makerToken),
|
||||
address(otcOrder.takerToken),
|
||||
otcOrder.makerAmount,
|
||||
otcOrder.takerAmount
|
||||
);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
otcOrder.takerToken,
|
||||
zrx,
|
||||
_makeArray(
|
||||
_makeOtcSubcall(otcOrder),
|
||||
_makeUniswapV2BatchSubcall(_makeArray(address(dai), address(zrx)), otcOrder.takerAmount, false)
|
||||
),
|
||||
otcOrder.takerAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// expired RFQ, fallback(UniswapV2)
|
||||
function test_multiplexBatchSellTokenForToken_expiredRfqFallbackUniswapV2() public {
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
_mintTo(address(rfqOrder.takerToken), rfqOrder.taker, rfqOrder.takerAmount);
|
||||
rfqOrder.expiry = 0;
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit ExpiredRfqOrder(
|
||||
zeroExDeployed.features.nativeOrdersFeature.getRfqOrderHash(rfqOrder),
|
||||
rfqOrder.maker,
|
||||
rfqOrder.expiry
|
||||
);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), rfqOrder.taker, uniV2Pool, rfqOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV2Pool, rfqOrder.taker, 906610893880149131);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
rfqOrder.takerToken,
|
||||
zrx,
|
||||
_makeArray(
|
||||
_makeRfqSubcall(rfqOrder),
|
||||
_makeUniswapV2BatchSubcall(_makeArray(address(dai), address(zrx)), rfqOrder.takerAmount, false)
|
||||
),
|
||||
rfqOrder.takerAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// expired OTC, fallback(UniswapV2)
|
||||
function test_multiplexBatchSellTokenForToken_expiredOtcFallbackUniswapV2() public {
|
||||
LibNativeOrder.OtcOrder memory otcOrder = _makeTestOtcOrder();
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
_mintTo(address(otcOrder.takerToken), otcOrder.taker, otcOrder.takerAmount);
|
||||
otcOrder.expiryAndNonce = 1;
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit ExpiredOtcOrder(
|
||||
zeroExDeployed.features.otcOrdersFeature.getOtcOrderHash(otcOrder),
|
||||
otcOrder.maker,
|
||||
uint64(otcOrder.expiryAndNonce >> 192)
|
||||
);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), otcOrder.taker, uniV2Pool, otcOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV2Pool, otcOrder.taker, 906610893880149131);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
otcOrder.takerToken,
|
||||
zrx,
|
||||
_makeArray(
|
||||
_makeOtcSubcall(otcOrder),
|
||||
_makeUniswapV2BatchSubcall(_makeArray(address(dai), address(zrx)), otcOrder.takerAmount, false)
|
||||
),
|
||||
otcOrder.takerAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// expired RFQ, fallback(TransformERC20)
|
||||
function test_multiplexBatchSellTokenForToken_expiredRfqFallbackTransformErc20() public {
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
_mintTo(address(rfqOrder.takerToken), rfqOrder.taker, rfqOrder.takerAmount);
|
||||
rfqOrder.expiry = 0;
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit ExpiredRfqOrder(
|
||||
zeroExDeployed.features.nativeOrdersFeature.getRfqOrderHash(rfqOrder),
|
||||
rfqOrder.maker,
|
||||
rfqOrder.expiry
|
||||
);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), rfqOrder.taker, address(flashWallet), rfqOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit MintTransform(
|
||||
address(flashWallet),
|
||||
address(zeroExDeployed.zeroEx),
|
||||
address(zeroExDeployed.zeroEx),
|
||||
rfqOrder.taker,
|
||||
abi.encode(dai, zrx, rfqOrder.takerAmount, 5e17, 0),
|
||||
rfqOrder.takerAmount,
|
||||
0
|
||||
);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(flashWallet), address(0), 1e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), address(flashWallet), rfqOrder.taker, 5e17);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
rfqOrder.takerToken,
|
||||
zrx,
|
||||
_makeArray(_makeRfqSubcall(rfqOrder), _makeMockTransformERC20Subcall(dai, zrx, rfqOrder.takerAmount, 5e17)),
|
||||
rfqOrder.takerAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// LiquidityProvider, UniV3, Sushiswap
|
||||
function test_multiplexBatchSellTokenForToken_liquidityProviderUniV3Sushiswap() public {
|
||||
address sushiswapPool = _createUniswapV2Pool(sushiFactory, dai, zrx, 10e18, 10e18);
|
||||
address uniV3Pool = _createUniswapV3Pool(uniV3Factory, dai, zrx, 10e18, 10e18);
|
||||
|
||||
address[] memory tokens = _makeArray(address(dai), address(zrx));
|
||||
IMultiplexFeature.BatchSellSubcall memory lpSubcall = _makeMockLiquidityProviderBatchSubcall(4e17);
|
||||
IMultiplexFeature.BatchSellSubcall memory uniV3Subcall = _makeUniswapV3BatchSubcall(tokens, 5e17);
|
||||
IMultiplexFeature.BatchSellSubcall memory sushiswapSubcall = _makeUniswapV2BatchSubcall(tokens, 6e17, true);
|
||||
uint256 sellAmount = lpSubcall.sellAmount + uniV3Subcall.sellAmount + sushiswapSubcall.sellAmount - 1;
|
||||
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), address(liquidityProvider), lpSubcall.sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), address(liquidityProvider), address(this), 0);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV3Pool, address(this), 10e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), uniV3Pool, uniV3Subcall.sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), sushiswapPool, sushiswapSubcall.sellAmount - 1);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), sushiswapPool, address(this), 564435470174180520);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
dai,
|
||||
zrx,
|
||||
_makeArray(lpSubcall, uniV3Subcall, sushiswapSubcall),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// proportional fill amounts
|
||||
function test_multiplexBatchSellTokenForToken_proportionalFillAmounts() public {
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
|
||||
uint256 sellAmount = 1e18;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), rfqOrder.taker, rfqOrder.maker, 42e16);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), rfqOrder.maker, rfqOrder.taker, 42e16);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), rfqOrder.taker, uniV2Pool, 58e16);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV2Pool, rfqOrder.taker, 546649448964196380);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
dai,
|
||||
zrx,
|
||||
_makeArray(
|
||||
_makeRfqSubcall(rfqOrder, _encodeFractionalFillAmount(42)),
|
||||
_makeUniswapV2BatchSubcall(
|
||||
_makeArray(address(dai), address(zrx)),
|
||||
_encodeFractionalFillAmount(100),
|
||||
false
|
||||
)
|
||||
),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// RFQ, MultiHop(UniV3, UniV2)
|
||||
function test_multiplexBatchSellTokenForToken_rfqMultiHopUniV3UniV2() public {
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, shib, zrx, 10e18, 10e18);
|
||||
address uniV3Pool = _createUniswapV3Pool(uniV3Factory, dai, shib, 10e18, 10e18);
|
||||
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
IMultiplexFeature.BatchSellSubcall memory rfqSubcall = _makeRfqSubcall(rfqOrder);
|
||||
IMultiplexFeature.BatchSellSubcall memory nestedMultiHopSubcall = _makeNestedMultiHopSellSubcall(
|
||||
_makeArray(address(dai), address(shib), address(zrx)),
|
||||
_makeArray(
|
||||
_makeUniswapV3MultiHopSubcall(_makeArray(address(dai), address(shib))),
|
||||
_makeUniswapV2MultiHopSubcall(_makeArray(address(shib), address(zrx)), false)
|
||||
),
|
||||
5e17
|
||||
);
|
||||
|
||||
uint256 sellAmount = rfqSubcall.sellAmount + nestedMultiHopSubcall.sellAmount;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), rfqOrder.taker, rfqOrder.maker, rfqOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), rfqOrder.maker, rfqOrder.taker, rfqOrder.makerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), uniV3Pool, uniV2Pool, 10e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), rfqOrder.taker, uniV3Pool, nestedMultiHopSubcall.sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV2Pool, rfqOrder.taker, 4992488733099649474);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexBatchSellTokenForToken(
|
||||
dai,
|
||||
zrx,
|
||||
_makeArray(rfqSubcall, nestedMultiHopSubcall),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
//// multihop sells
|
||||
|
||||
// reverts if given an invalid subcall type
|
||||
function test_multiplexMultiHopSellTokenForToken_revertsIfGivenAnInvalidSubcallType() public {
|
||||
vm.expectRevert("MultiplexFeature::_computeHopTarget/INVALID_SUBCALL");
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(zrx)),
|
||||
_makeArray(
|
||||
IMultiplexFeature.MultiHopSellSubcall({id: IMultiplexFeature.MultiplexSubcall.Invalid, data: hex""})
|
||||
),
|
||||
1e18,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// reverts if minBuyAmount is not satisfied
|
||||
function test_multiplexMultiHopSellTokenForToken_revertsIfMinBuyAmountIsNotSatisfied() public {
|
||||
_createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
|
||||
uint256 sellAmount = 5e17;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectRevert("MultiplexFeature::_multiplexMultiHopSell/UNDERBOUGHT");
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(zrx)),
|
||||
_makeArray(_makeUniswapV2MultiHopSubcall(_makeArray(address(dai), address(zrx)), false)),
|
||||
sellAmount,
|
||||
type(uint256).max
|
||||
);
|
||||
}
|
||||
|
||||
// reverts if array lengths are mismatched
|
||||
function test_multiplexMultiHopSellTokenForToken_revertsIfArrayLengthsAreMismatched() public {
|
||||
_createUniswapV2Pool(uniV2Factory, dai, zrx, 10e18, 10e18);
|
||||
IMultiplexFeature.MultiHopSellSubcall memory uniswapV2Subcall = _makeUniswapV2MultiHopSubcall(
|
||||
_makeArray(address(dai), address(zrx)),
|
||||
false
|
||||
);
|
||||
|
||||
uint256 sellAmount = 5e17;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectRevert("MultiplexFeature::_multiplexMultiHopSell/MISMATCHED_ARRAY_LENGTHS");
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(zrx)),
|
||||
_makeArray(uniswapV2Subcall, uniswapV2Subcall),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// UniswapV2 -> LiquidityProvider
|
||||
function test_multiplexMultiHopSellTokenForToken_uniswapV2ToLiquidityProvider() public {
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, dai, shib, 10e18, 10e18);
|
||||
IMultiplexFeature.MultiHopSellSubcall memory lpSubcall = _makeMockLiquidityProviderMultiHopSubcall();
|
||||
IMultiplexFeature.MultiHopSellSubcall memory uniswapV2Subcall = _makeUniswapV2MultiHopSubcall(
|
||||
_makeArray(address(dai), address(shib)),
|
||||
false
|
||||
);
|
||||
|
||||
uint256 sellAmount = 5e17;
|
||||
uint256 buyAmount = 6e17;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
_mintTo(address(zrx), address(liquidityProvider), buyAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), uniV2Pool, sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), uniV2Pool, address(liquidityProvider), 474829737581559270);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), address(liquidityProvider), address(this), buyAmount);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(shib), address(zrx)),
|
||||
_makeArray(uniswapV2Subcall, lpSubcall),
|
||||
sellAmount,
|
||||
buyAmount
|
||||
);
|
||||
}
|
||||
|
||||
// LiquidityProvider -> Sushiswap
|
||||
function test_multiplexMultiHopSellTokenForToken_liquidityProviderToSushiswap() public {
|
||||
address sushiPool = _createUniswapV2Pool(sushiFactory, shib, zrx, 10e18, 10e18);
|
||||
IMultiplexFeature.MultiHopSellSubcall memory lpSubcall = _makeMockLiquidityProviderMultiHopSubcall();
|
||||
IMultiplexFeature.MultiHopSellSubcall memory sushiswapSubcall = _makeUniswapV2MultiHopSubcall(
|
||||
_makeArray(address(shib), address(zrx)),
|
||||
true
|
||||
);
|
||||
|
||||
uint256 sellAmount = 5e17;
|
||||
uint256 shibAmount = 6e17;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
_mintTo(address(shib), address(liquidityProvider), shibAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), address(liquidityProvider), sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), address(liquidityProvider), sushiPool, shibAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), sushiPool, address(this), 564435470174180521);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(shib), address(zrx)),
|
||||
_makeArray(lpSubcall, sushiswapSubcall),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// UniswapV3 -> BatchSell(RFQ, UniswapV2)
|
||||
function test_multiplexMultiHopSellTokenForToken_uniswapV3ToBatchSellRfqUniswapV2() public {
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, shib, zrx, 10e18, 10e18);
|
||||
address uniV3Pool = _createUniswapV3Pool(uniV3Factory, dai, shib, 10e18, 10e18);
|
||||
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder();
|
||||
rfqOrder.takerToken = shib;
|
||||
rfqOrder.makerToken = zrx;
|
||||
|
||||
IMultiplexFeature.BatchSellSubcall memory rfqSubcall = _makeRfqSubcall(rfqOrder);
|
||||
rfqSubcall.sellAmount = _encodeFractionalFillAmount(42);
|
||||
|
||||
uint256 sellAmount = 5e17;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), uniV3Pool, address(zeroExDeployed.zeroEx), 10e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), uniV3Pool, sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), address(zeroExDeployed.zeroEx), rfqOrder.maker, 1e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), rfqOrder.maker, address(this), 1e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), address(zeroExDeployed.zeroEx), uniV2Pool, 9e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV2Pool, address(this), 4729352237389975227);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(shib), address(zrx)),
|
||||
_makeArray(
|
||||
_makeUniswapV3MultiHopSubcall(_makeArray(address(dai), address(shib))),
|
||||
_makeNestedBatchSellSubcall(
|
||||
_makeArray(
|
||||
rfqSubcall,
|
||||
_makeUniswapV2BatchSubcall(
|
||||
_makeArray(address(shib), address(zrx)),
|
||||
_encodeFractionalFillAmount(100),
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// BatchSell(RFQ, UniswapV2) -> UniswapV3
|
||||
function test_multiplexMultiHopSellTokenForToken_batchSellRfqUniswapV2ToUniswapV3() public {
|
||||
address uniV2Pool = _createUniswapV2Pool(uniV2Factory, dai, shib, 10e18, 10e18);
|
||||
address uniV3Pool = _createUniswapV3Pool(uniV3Factory, shib, zrx, 10e18, 10e18);
|
||||
|
||||
LibNativeOrder.RfqOrder memory rfqOrder = _makeTestRfqOrder({makerToken: shib, takerToken: dai});
|
||||
|
||||
IMultiplexFeature.BatchSellSubcall memory rfqSubcall = _makeRfqSubcall(rfqOrder);
|
||||
IMultiplexFeature.BatchSellSubcall memory uniswapV2Subcall = _makeUniswapV2BatchSubcall(
|
||||
_makeArray(address(dai), address(shib)),
|
||||
5e17,
|
||||
false
|
||||
);
|
||||
|
||||
uint256 sellAmount = rfqSubcall.sellAmount + uniswapV2Subcall.sellAmount;
|
||||
_mintTo(address(dai), address(this), sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), rfqOrder.maker, rfqOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), rfqOrder.maker, address(zeroExDeployed.zeroEx), rfqOrder.takerAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(dai), address(this), uniV2Pool, uniswapV2Subcall.sellAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), uniV2Pool, address(zeroExDeployed.zeroEx), 474829737581559270);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(zrx), uniV3Pool, address(this), 10e18);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Transfer(address(shib), address(zeroExDeployed.zeroEx), uniV3Pool, 1474829737581559270);
|
||||
|
||||
zeroExDeployed.zeroEx.multiplexMultiHopSellTokenForToken(
|
||||
_makeArray(address(dai), address(shib), address(zrx)),
|
||||
_makeArray(
|
||||
_makeNestedBatchSellSubcall(_makeArray(rfqSubcall, uniswapV2Subcall)),
|
||||
_makeUniswapV3MultiHopSubcall(_makeArray(address(shib), address(zrx)))
|
||||
),
|
||||
sellAmount,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "utils/ForkUtils.sol";
|
||||
import {ForkUtils} from "utils/ForkUtils.sol";
|
||||
import "utils/TestUtils.sol";
|
||||
import "utils/DeployZeroEx.sol";
|
||||
import "forge-std/Test.sol";
|
||||
@ -33,7 +33,9 @@ contract WrapEth is Test, ForkUtils, TestUtils {
|
||||
DeployZeroEx.ZeroExDeployed zeroExDeployed;
|
||||
|
||||
function setUp() public {
|
||||
zeroExDeployed = new DeployZeroEx().deployZeroEx();
|
||||
zeroExDeployed = new DeployZeroEx(
|
||||
DeployZeroEx.ZeroExDeployConfiguration(address(0), address(0), address(0), 0, 0, 0, true)
|
||||
).deployZeroEx();
|
||||
vm.deal(address(this), 1e19);
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ contract RfqtV2Test is Test, ForkUtils, TestUtils {
|
||||
order.makerAmount = 1e18;
|
||||
order.takerAmount = 1e18;
|
||||
uint privateKey;
|
||||
(order.maker, privateKey) = getSigner();
|
||||
(order.maker, privateKey) = _getSigner();
|
||||
deal(address(order.makerToken), order.maker, 1e20);
|
||||
vm.prank(order.maker);
|
||||
IERC20Token(tokens.USDC).approve(address(addresses.exchangeProxy), 1e20);
|
||||
|
@ -15,7 +15,7 @@
|
||||
pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../utils/ForkUtils.sol";
|
||||
import {ForkUtils} from "../utils/ForkUtils.sol";
|
||||
import "../utils/TestUtils.sol";
|
||||
import "../utils/DeployZeroEx.sol";
|
||||
import "forge-std/Test.sol";
|
||||
@ -33,7 +33,9 @@ contract WrapEthTest is Test, ForkUtils, TestUtils {
|
||||
DeployZeroEx.ZeroExDeployed zeroExDeployed;
|
||||
|
||||
function setUp() public {
|
||||
zeroExDeployed = new DeployZeroEx().deployZeroEx();
|
||||
zeroExDeployed = new DeployZeroEx(
|
||||
DeployZeroEx.ZeroExDeployConfiguration(address(0), address(0), address(0), 0, 0, 0, true)
|
||||
).deployZeroEx();
|
||||
vm.deal(address(this), 1e19);
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,11 @@ import "src/features/MetaTransactionsFeature.sol";
|
||||
import "src/features/nft_orders/ERC1155OrdersFeature.sol";
|
||||
import "src/features/nft_orders/ERC721OrdersFeature.sol";
|
||||
import "src/features/UniswapFeature.sol";
|
||||
import "src/features/UniswapV3Feature.sol";
|
||||
import "src/features/multiplex/MultiplexFeature.sol";
|
||||
import "src/external/TransformerDeployer.sol";
|
||||
import "src/external/FeeCollectorController.sol";
|
||||
import "src/external/LiquidityProviderSandbox.sol";
|
||||
import "src/transformers/WethTransformer.sol";
|
||||
import "src/transformers/FillQuoteTransformer.sol";
|
||||
import "src/transformers/PayTakerTransformer.sol";
|
||||
@ -62,6 +64,7 @@ contract DeployZeroEx is Test {
|
||||
BatchFillNativeOrdersFeature batchFillNativeOrdersFeature;
|
||||
OtcOrdersFeature otcOrdersFeature;
|
||||
UniswapFeature uniswapFeature;
|
||||
UniswapV3Feature uniswapV3Feature;
|
||||
FundRecoveryFeature fundRecoveryFeature;
|
||||
TransformERC20Feature transformERC20Feature;
|
||||
MetaTransactionsFeature metaTransactionsFeature;
|
||||
@ -89,6 +92,22 @@ contract DeployZeroEx is Test {
|
||||
|
||||
ZeroExDeployed ZERO_EX_DEPLOYED;
|
||||
|
||||
struct ZeroExDeployConfiguration {
|
||||
address uniswapFactory;
|
||||
address sushiswapFactory;
|
||||
address uniswapV3Factory;
|
||||
bytes32 uniswapPairInitCodeHash;
|
||||
bytes32 sushiswapPairInitCodeHash;
|
||||
bytes32 uniswapV3PoolInitCodeHash;
|
||||
bool logDeployed;
|
||||
}
|
||||
|
||||
ZeroExDeployConfiguration ZERO_EX_DEPLOY_CONFIG;
|
||||
|
||||
constructor(ZeroExDeployConfiguration memory configuration) public {
|
||||
ZERO_EX_DEPLOY_CONFIG = configuration;
|
||||
}
|
||||
|
||||
function getDeployedZeroEx() public returns (ZeroExDeployed memory) {
|
||||
if (!isDeployed) {
|
||||
deployZeroEx();
|
||||
@ -111,6 +130,7 @@ contract DeployZeroEx is Test {
|
||||
);
|
||||
emit log_named_address("OtcOrdersFeature", address(ZERO_EX_DEPLOYED.features.otcOrdersFeature));
|
||||
emit log_named_address("UniswapFeature", address(ZERO_EX_DEPLOYED.features.uniswapFeature));
|
||||
emit log_named_address("UniswapV3Feature", address(ZERO_EX_DEPLOYED.features.uniswapV3Feature));
|
||||
emit log_named_address("FundRecoveryFeature", address(ZERO_EX_DEPLOYED.features.fundRecoveryFeature));
|
||||
emit log_named_address("MetaTransactionsFeature", address(ZERO_EX_DEPLOYED.features.metaTransactionsFeature));
|
||||
emit log_named_address("ERC1155OrdersFeature", address(ZERO_EX_DEPLOYED.features.erc1155OrdersFeature));
|
||||
@ -174,6 +194,11 @@ contract DeployZeroEx is Test {
|
||||
ZERO_EX_DEPLOYED.features.batchFillNativeOrdersFeature = new BatchFillNativeOrdersFeature(address(ZERO_EX));
|
||||
ZERO_EX_DEPLOYED.features.otcOrdersFeature = new OtcOrdersFeature(address(ZERO_EX), ZERO_EX_DEPLOYED.weth);
|
||||
ZERO_EX_DEPLOYED.features.uniswapFeature = new UniswapFeature(ZERO_EX_DEPLOYED.weth);
|
||||
ZERO_EX_DEPLOYED.features.uniswapV3Feature = new UniswapV3Feature(
|
||||
ZERO_EX_DEPLOYED.weth,
|
||||
ZERO_EX_DEPLOY_CONFIG.uniswapV3Factory,
|
||||
ZERO_EX_DEPLOY_CONFIG.uniswapV3PoolInitCodeHash
|
||||
);
|
||||
ZERO_EX_DEPLOYED.features.fundRecoveryFeature = new FundRecoveryFeature();
|
||||
ZERO_EX_DEPLOYED.features.metaTransactionsFeature = new MetaTransactionsFeature(address(ZERO_EX));
|
||||
ZERO_EX_DEPLOYED.features.erc1155OrdersFeature = new ERC1155OrdersFeature(
|
||||
@ -187,11 +212,11 @@ contract DeployZeroEx is Test {
|
||||
ZERO_EX_DEPLOYED.features.multiplexFeature = new MultiplexFeature(
|
||||
address(ZERO_EX),
|
||||
ZERO_EX_DEPLOYED.weth,
|
||||
ILiquidityProviderSandbox(address(0)),
|
||||
address(0), // uniswapFactory
|
||||
address(0), // sushiswapFactory
|
||||
bytes32(0), // uniswapPairInitCodeHash
|
||||
bytes32(0) // sushiswapPairInitCodeHash
|
||||
new LiquidityProviderSandbox(address(ZERO_EX)),
|
||||
ZERO_EX_DEPLOY_CONFIG.uniswapFactory,
|
||||
ZERO_EX_DEPLOY_CONFIG.sushiswapFactory,
|
||||
ZERO_EX_DEPLOY_CONFIG.uniswapPairInitCodeHash,
|
||||
ZERO_EX_DEPLOY_CONFIG.sushiswapPairInitCodeHash
|
||||
);
|
||||
|
||||
initialMigration.initializeZeroEx(
|
||||
@ -230,6 +255,11 @@ contract DeployZeroEx is Test {
|
||||
abi.encodeWithSelector(UniswapFeature.migrate.selector),
|
||||
address(this)
|
||||
);
|
||||
IZERO_EX.migrate(
|
||||
address(ZERO_EX_DEPLOYED.features.uniswapV3Feature),
|
||||
abi.encodeWithSelector(UniswapV3Feature.migrate.selector),
|
||||
address(this)
|
||||
);
|
||||
IZERO_EX.migrate(
|
||||
address(ZERO_EX_DEPLOYED.features.fundRecoveryFeature),
|
||||
abi.encodeWithSelector(FundRecoveryFeature.migrate.selector),
|
||||
@ -293,7 +323,10 @@ contract DeployZeroEx is Test {
|
||||
|
||||
ZERO_EX_DEPLOYED.zeroEx = IZERO_EX;
|
||||
isDeployed = true;
|
||||
logDeployedZeroEx();
|
||||
if (ZERO_EX_DEPLOY_CONFIG.logDeployed) {
|
||||
logDeployedZeroEx();
|
||||
}
|
||||
|
||||
return ZERO_EX_DEPLOYED;
|
||||
}
|
||||
}
|
||||
|
@ -227,15 +227,6 @@ contract ForkUtils is Test {
|
||||
}
|
||||
}
|
||||
|
||||
//gets a dummy signer to be used for an OTC order
|
||||
function getSigner() public returns (address, uint) {
|
||||
string memory mnemonic = "test test test test test test test test test test test junk";
|
||||
uint256 privateKey = vm.deriveKey(mnemonic, 0);
|
||||
|
||||
vm.label(vm.addr(privateKey), "zeroEx/MarketMaker");
|
||||
return (vm.addr(privateKey), privateKey);
|
||||
}
|
||||
|
||||
//read the uniswapV2 router addresses from file
|
||||
function readLiquiditySourceAddresses() internal returns (string memory) {
|
||||
string memory root = vm.projectRoot();
|
||||
|
140
contracts/zero-ex/tests/utils/LocalTest.sol
Normal file
140
contracts/zero-ex/tests/utils/LocalTest.sol
Normal file
@ -0,0 +1,140 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {Test} from "forge-std/Test.sol";
|
||||
import {IERC20Token} from "@0x/contracts-erc20/src/IERC20Token.sol";
|
||||
import {IEtherToken} from "@0x/contracts-erc20/src/IEtherToken.sol";
|
||||
import {WETH9V06} from "@0x/contracts-erc20/src/v06/WETH9V06.sol";
|
||||
import {IFlashWallet} from "src/external/IFlashWallet.sol";
|
||||
import {LibERC20Transformer} from "src/transformers/LibERC20Transformer.sol";
|
||||
import {LibNativeOrder} from "src/features/libs/LibNativeOrder.sol";
|
||||
import {LibSignature} from "src/features/libs/LibSignature.sol";
|
||||
import {IMultiplexFeature} from "src/features/interfaces/IMultiplexFeature.sol";
|
||||
import {ITransformERC20Feature} from "src/features/interfaces/ITransformERC20Feature.sol";
|
||||
import {TestUtils} from "utils/TestUtils.sol";
|
||||
import {DeployZeroEx} from "utils/DeployZeroEx.sol";
|
||||
import {TestMintTokenERC20Transformer} from "../../contracts/test/TestMintTokenERC20Transformer.sol";
|
||||
import {TestMintableERC20Token} from "../../contracts/test/tokens/TestMintableERC20Token.sol";
|
||||
import {TestUniswapV2Factory} from "../../contracts/test/integration/TestUniswapV2Factory.sol";
|
||||
import {TestUniswapV2Pool} from "../../contracts/test/integration/TestUniswapV2Pool.sol";
|
||||
import {TestUniswapV3Factory} from "../../contracts/test/integration/TestUniswapV3Factory.sol";
|
||||
import {TestUniswapV3Pool} from "../../contracts/test/integration/TestUniswapV3Pool.sol";
|
||||
import {TestLiquidityProvider} from "../../contracts/test/integration/TestLiquidityProvider.sol";
|
||||
|
||||
contract LocalTest is Test, TestUtils {
|
||||
uint24 internal constant UNIV3_POOL_FEE = 1234;
|
||||
|
||||
DeployZeroEx.ZeroExDeployed internal zeroExDeployed;
|
||||
IFlashWallet internal flashWallet;
|
||||
IERC20Token internal shib;
|
||||
IERC20Token internal dai;
|
||||
IERC20Token internal zrx;
|
||||
IEtherToken internal weth;
|
||||
|
||||
TestUniswapV2Factory internal sushiFactory;
|
||||
TestUniswapV2Factory internal uniV2Factory;
|
||||
TestUniswapV3Factory internal uniV3Factory;
|
||||
TestLiquidityProvider internal liquidityProvider;
|
||||
uint256 internal transformerNonce;
|
||||
|
||||
address internal signerAddress;
|
||||
uint256 internal signerKey;
|
||||
|
||||
function _infiniteApprovals() private {
|
||||
shib.approve(address(zeroExDeployed.zeroEx), type(uint256).max);
|
||||
dai.approve(address(zeroExDeployed.zeroEx), type(uint256).max);
|
||||
zrx.approve(address(zeroExDeployed.zeroEx), type(uint256).max);
|
||||
weth.approve(address(zeroExDeployed.zeroEx), type(uint256).max);
|
||||
}
|
||||
|
||||
function setUp() public {
|
||||
(signerAddress, signerKey) = _getSigner();
|
||||
|
||||
sushiFactory = new TestUniswapV2Factory();
|
||||
uniV2Factory = new TestUniswapV2Factory();
|
||||
uniV3Factory = new TestUniswapV3Factory();
|
||||
liquidityProvider = new TestLiquidityProvider();
|
||||
|
||||
zeroExDeployed = new DeployZeroEx(
|
||||
DeployZeroEx.ZeroExDeployConfiguration({
|
||||
uniswapFactory: address(uniV2Factory),
|
||||
sushiswapFactory: address(sushiFactory),
|
||||
uniswapV3Factory: address(uniV3Factory),
|
||||
uniswapPairInitCodeHash: uniV2Factory.POOL_INIT_CODE_HASH(),
|
||||
sushiswapPairInitCodeHash: sushiFactory.POOL_INIT_CODE_HASH(),
|
||||
uniswapV3PoolInitCodeHash: uniV3Factory.POOL_INIT_CODE_HASH(),
|
||||
logDeployed: false
|
||||
})
|
||||
).deployZeroEx();
|
||||
|
||||
transformerNonce = zeroExDeployed.transformerDeployer.nonce();
|
||||
vm.prank(zeroExDeployed.transformerDeployer.authorities(0));
|
||||
zeroExDeployed.transformerDeployer.deploy(type(TestMintTokenERC20Transformer).creationCode);
|
||||
|
||||
flashWallet = zeroExDeployed.zeroEx.getTransformWallet();
|
||||
|
||||
shib = IERC20Token(address(new TestMintableERC20Token()));
|
||||
dai = IERC20Token(address(new TestMintableERC20Token()));
|
||||
zrx = IERC20Token(address(new TestMintableERC20Token()));
|
||||
weth = zeroExDeployed.weth;
|
||||
|
||||
_infiniteApprovals();
|
||||
vm.startPrank(signerAddress);
|
||||
_infiniteApprovals();
|
||||
vm.stopPrank();
|
||||
|
||||
vm.deal(address(this), 10e18);
|
||||
}
|
||||
|
||||
function _mintTo(address token, address recipient, uint256 amount) internal {
|
||||
if (token == address(weth)) {
|
||||
IEtherToken(token).deposit{value: amount}();
|
||||
WETH9V06(payable(token)).transfer(recipient, amount);
|
||||
} else {
|
||||
TestMintableERC20Token(token).mint(recipient, amount);
|
||||
}
|
||||
}
|
||||
|
||||
function _createUniswapV2Pool(
|
||||
TestUniswapV2Factory factory,
|
||||
IERC20Token tokenA,
|
||||
IERC20Token tokenB,
|
||||
uint112 balanceA,
|
||||
uint112 balanceB
|
||||
) internal returns (address poolAddress) {
|
||||
TestUniswapV2Pool pool = factory.createPool(tokenA, tokenB);
|
||||
_mintTo(address(tokenA), address(pool), balanceA);
|
||||
_mintTo(address(tokenB), address(pool), balanceB);
|
||||
|
||||
(uint112 balance0, uint112 balance1) = tokenA < tokenB ? (balanceA, balanceB) : (balanceB, balanceA);
|
||||
pool.setReserves(balance0, balance1, 0);
|
||||
|
||||
return address(pool);
|
||||
}
|
||||
|
||||
function _createUniswapV3Pool(
|
||||
TestUniswapV3Factory factory,
|
||||
IERC20Token tokenA,
|
||||
IERC20Token tokenB,
|
||||
uint112 balanceA,
|
||||
uint112 balanceB
|
||||
) internal returns (address poolAddress) {
|
||||
poolAddress = address(factory.createPool(tokenA, tokenB, UNIV3_POOL_FEE));
|
||||
_mintTo(address(tokenA), poolAddress, balanceA);
|
||||
_mintTo(address(tokenB), poolAddress, balanceB);
|
||||
}
|
||||
}
|
304
contracts/zero-ex/tests/utils/MultiplexUtils.sol
Normal file
304
contracts/zero-ex/tests/utils/MultiplexUtils.sol
Normal file
@ -0,0 +1,304 @@
|
||||
// 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {IERC20Token} from "@0x/contracts-erc20/src/IERC20Token.sol";
|
||||
import {LibNativeOrder} from "src/features/libs/LibNativeOrder.sol";
|
||||
import {LibSignature} from "src/features/libs/LibSignature.sol";
|
||||
import {IMultiplexFeature} from "src/features/interfaces/IMultiplexFeature.sol";
|
||||
import {ITransformERC20Feature} from "src/features/interfaces/ITransformERC20Feature.sol";
|
||||
import {LocalTest} from "utils/LocalTest.sol";
|
||||
|
||||
contract MultiplexUtils is LocalTest {
|
||||
function _makeTestRfqOrder(
|
||||
IERC20Token makerToken,
|
||||
IERC20Token takerToken
|
||||
) internal returns (LibNativeOrder.RfqOrder memory order) {
|
||||
order = LibNativeOrder.RfqOrder({
|
||||
makerToken: makerToken,
|
||||
takerToken: takerToken,
|
||||
makerAmount: 1e18,
|
||||
takerAmount: 1e18,
|
||||
maker: signerAddress,
|
||||
taker: address(this),
|
||||
txOrigin: tx.origin,
|
||||
pool: 0x0000000000000000000000000000000000000000000000000000000000000000,
|
||||
expiry: uint64(block.timestamp + 60),
|
||||
salt: 123
|
||||
});
|
||||
_mintTo(address(order.makerToken), order.maker, order.makerAmount);
|
||||
}
|
||||
|
||||
function _makeTestRfqOrder() internal returns (LibNativeOrder.RfqOrder memory order) {
|
||||
return _makeTestRfqOrder(zrx, dai);
|
||||
}
|
||||
|
||||
function _makeTestOtcOrder() internal returns (LibNativeOrder.OtcOrder memory order) {
|
||||
order = LibNativeOrder.OtcOrder({
|
||||
makerToken: zrx,
|
||||
takerToken: dai,
|
||||
makerAmount: 1e18,
|
||||
takerAmount: 1e18,
|
||||
maker: signerAddress,
|
||||
taker: address(this),
|
||||
txOrigin: tx.origin,
|
||||
expiryAndNonce: ((block.timestamp + 60) << 192) | 1
|
||||
});
|
||||
_mintTo(address(order.makerToken), order.maker, order.makerAmount);
|
||||
}
|
||||
|
||||
function _makeRfqSubcall(
|
||||
LibNativeOrder.RfqOrder memory order,
|
||||
uint256 sellAmount
|
||||
) internal view returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
|
||||
signerKey,
|
||||
zeroExDeployed.features.nativeOrdersFeature.getRfqOrderHash(order)
|
||||
);
|
||||
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
|
||||
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.RFQ,
|
||||
sellAmount: sellAmount,
|
||||
data: abi.encode(order, sig)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeRfqSubcall(
|
||||
LibNativeOrder.RfqOrder memory order
|
||||
) internal view returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
return _makeRfqSubcall(order, order.takerAmount);
|
||||
}
|
||||
|
||||
function _makeOtcSubcall(
|
||||
LibNativeOrder.OtcOrder memory order
|
||||
) internal view returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
|
||||
signerKey,
|
||||
zeroExDeployed.features.otcOrdersFeature.getOtcOrderHash(order)
|
||||
);
|
||||
LibSignature.Signature memory sig = LibSignature.Signature(LibSignature.SignatureType.EIP712, v, r, s);
|
||||
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.OTC,
|
||||
sellAmount: order.takerAmount,
|
||||
data: abi.encode(order, sig)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeUniswapV2MultiHopSubcall(
|
||||
address[] memory tokens,
|
||||
bool isSushi
|
||||
) internal pure returns (IMultiplexFeature.MultiHopSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.MultiHopSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.UniswapV2,
|
||||
data: abi.encode(tokens, isSushi)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeUniswapV2BatchSubcall(
|
||||
address[] memory tokens,
|
||||
uint256 sellAmount,
|
||||
bool isSushi
|
||||
) internal pure returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.UniswapV2,
|
||||
sellAmount: sellAmount,
|
||||
data: abi.encode(tokens, isSushi)
|
||||
});
|
||||
}
|
||||
|
||||
function _encodePathUniswapV3(address[] memory tokens) private pure returns (bytes memory path) {
|
||||
path = new bytes(tokens.length * 23 - 3);
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
assembly {
|
||||
let p := add(add(path, 32), mul(i, 23))
|
||||
if gt(i, 0) {
|
||||
mstore(sub(p, 3), shl(232, UNIV3_POOL_FEE))
|
||||
}
|
||||
|
||||
let a := add(add(tokens, 32), mul(i, 32))
|
||||
mstore(p, shl(96, mload(a)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _makeUniswapV3MultiHopSubcall(
|
||||
address[] memory tokens
|
||||
) internal pure returns (IMultiplexFeature.MultiHopSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.MultiHopSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.UniswapV3,
|
||||
data: _encodePathUniswapV3(tokens)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeUniswapV3BatchSubcall(
|
||||
address[] memory tokens,
|
||||
uint256 sellAmount
|
||||
) internal pure returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.UniswapV3,
|
||||
sellAmount: sellAmount,
|
||||
data: _encodePathUniswapV3(tokens)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeMockLiquidityProviderMultiHopSubcall()
|
||||
internal
|
||||
view
|
||||
returns (IMultiplexFeature.MultiHopSellSubcall memory)
|
||||
{
|
||||
return
|
||||
IMultiplexFeature.MultiHopSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.LiquidityProvider,
|
||||
data: abi.encode(address(liquidityProvider), hex"")
|
||||
});
|
||||
}
|
||||
|
||||
function _makeMockLiquidityProviderBatchSubcall(
|
||||
uint256 sellAmount
|
||||
) internal view returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.LiquidityProvider,
|
||||
sellAmount: sellAmount,
|
||||
data: abi.encode(address(liquidityProvider), hex"")
|
||||
});
|
||||
}
|
||||
|
||||
function _makeMockTransformERC20Subcall(
|
||||
IERC20Token inputToken,
|
||||
IERC20Token outputToken,
|
||||
uint256 sellAmount,
|
||||
uint256 mintAmount
|
||||
) internal view returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
|
||||
transformations[0] = ITransformERC20Feature.Transformation(
|
||||
uint32(transformerNonce),
|
||||
abi.encode(address(inputToken), address(outputToken), sellAmount, mintAmount, 0)
|
||||
);
|
||||
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.TransformERC20,
|
||||
sellAmount: sellAmount,
|
||||
data: abi.encode(transformations)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeNestedBatchSellSubcall(
|
||||
IMultiplexFeature.BatchSellSubcall[] memory calls
|
||||
) internal pure returns (IMultiplexFeature.MultiHopSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.MultiHopSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.BatchSell,
|
||||
data: abi.encode(calls)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeNestedMultiHopSellSubcall(
|
||||
address[] memory tokens,
|
||||
IMultiplexFeature.MultiHopSellSubcall[] memory calls,
|
||||
uint256 sellAmount
|
||||
) internal pure returns (IMultiplexFeature.BatchSellSubcall memory) {
|
||||
return
|
||||
IMultiplexFeature.BatchSellSubcall({
|
||||
id: IMultiplexFeature.MultiplexSubcall.MultiHopSell,
|
||||
sellAmount: sellAmount,
|
||||
data: abi.encode(tokens, calls)
|
||||
});
|
||||
}
|
||||
|
||||
function _makeArray(
|
||||
IMultiplexFeature.MultiHopSellSubcall memory first
|
||||
) internal pure returns (IMultiplexFeature.MultiHopSellSubcall[] memory subcalls) {
|
||||
subcalls = new IMultiplexFeature.MultiHopSellSubcall[](1);
|
||||
subcalls[0] = first;
|
||||
}
|
||||
|
||||
function _makeArray(
|
||||
IMultiplexFeature.MultiHopSellSubcall memory first,
|
||||
IMultiplexFeature.MultiHopSellSubcall memory second
|
||||
) internal pure returns (IMultiplexFeature.MultiHopSellSubcall[] memory subcalls) {
|
||||
subcalls = new IMultiplexFeature.MultiHopSellSubcall[](2);
|
||||
subcalls[0] = first;
|
||||
subcalls[1] = second;
|
||||
}
|
||||
|
||||
function _makeArray(
|
||||
IMultiplexFeature.BatchSellSubcall memory first
|
||||
) internal pure returns (IMultiplexFeature.BatchSellSubcall[] memory subcalls) {
|
||||
subcalls = new IMultiplexFeature.BatchSellSubcall[](1);
|
||||
subcalls[0] = first;
|
||||
}
|
||||
|
||||
function _makeArray(
|
||||
IMultiplexFeature.BatchSellSubcall memory first,
|
||||
IMultiplexFeature.BatchSellSubcall memory second
|
||||
) internal pure returns (IMultiplexFeature.BatchSellSubcall[] memory subcalls) {
|
||||
subcalls = new IMultiplexFeature.BatchSellSubcall[](2);
|
||||
subcalls[0] = first;
|
||||
subcalls[1] = second;
|
||||
}
|
||||
|
||||
function _makeArray(
|
||||
IMultiplexFeature.BatchSellSubcall memory first,
|
||||
IMultiplexFeature.BatchSellSubcall memory second,
|
||||
IMultiplexFeature.BatchSellSubcall memory third
|
||||
) internal pure returns (IMultiplexFeature.BatchSellSubcall[] memory subcalls) {
|
||||
subcalls = new IMultiplexFeature.BatchSellSubcall[](3);
|
||||
subcalls[0] = first;
|
||||
subcalls[1] = second;
|
||||
subcalls[2] = third;
|
||||
}
|
||||
|
||||
function _makeArray(address first) internal pure returns (address[] memory addresses) {
|
||||
addresses = new address[](1);
|
||||
addresses[0] = first;
|
||||
}
|
||||
|
||||
function _makeArray(address first, address second) internal pure returns (address[] memory addresses) {
|
||||
addresses = new address[](2);
|
||||
addresses[0] = first;
|
||||
addresses[1] = second;
|
||||
}
|
||||
|
||||
function _makeArray(
|
||||
address first,
|
||||
address second,
|
||||
address third
|
||||
) internal pure returns (address[] memory addresses) {
|
||||
addresses = new address[](3);
|
||||
addresses[0] = first;
|
||||
addresses[1] = second;
|
||||
addresses[2] = third;
|
||||
}
|
||||
|
||||
function _encodeFractionalFillAmount(uint256 frac) internal pure returns (uint256) {
|
||||
return (2 ** 255) + (frac * 1e16);
|
||||
}
|
||||
}
|
@ -29,4 +29,13 @@ contract TestUtils is Test {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gets a dummy signer
|
||||
function _getSigner() internal returns (address, uint) {
|
||||
string memory mnemonic = "test test test test test test test test test test test junk";
|
||||
uint256 privateKey = vm.deriveKey(mnemonic, 0);
|
||||
|
||||
vm.label(vm.addr(privateKey), "zeroEx/MarketMaker");
|
||||
return (vm.addr(privateKey), privateKey);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user