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 solidity ^0.6;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "utils/ForkUtils.sol";
|
import {ForkUtils} from "utils/ForkUtils.sol";
|
||||||
import "utils/TestUtils.sol";
|
import "utils/TestUtils.sol";
|
||||||
import "utils/DeployZeroEx.sol";
|
import "utils/DeployZeroEx.sol";
|
||||||
import "forge-std/Test.sol";
|
import "forge-std/Test.sol";
|
||||||
@ -33,7 +33,9 @@ contract WrapEth is Test, ForkUtils, TestUtils {
|
|||||||
DeployZeroEx.ZeroExDeployed zeroExDeployed;
|
DeployZeroEx.ZeroExDeployed zeroExDeployed;
|
||||||
|
|
||||||
function setUp() public {
|
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);
|
vm.deal(address(this), 1e19);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ contract RfqtV2Test is Test, ForkUtils, TestUtils {
|
|||||||
order.makerAmount = 1e18;
|
order.makerAmount = 1e18;
|
||||||
order.takerAmount = 1e18;
|
order.takerAmount = 1e18;
|
||||||
uint privateKey;
|
uint privateKey;
|
||||||
(order.maker, privateKey) = getSigner();
|
(order.maker, privateKey) = _getSigner();
|
||||||
deal(address(order.makerToken), order.maker, 1e20);
|
deal(address(order.makerToken), order.maker, 1e20);
|
||||||
vm.prank(order.maker);
|
vm.prank(order.maker);
|
||||||
IERC20Token(tokens.USDC).approve(address(addresses.exchangeProxy), 1e20);
|
IERC20Token(tokens.USDC).approve(address(addresses.exchangeProxy), 1e20);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
pragma solidity ^0.6;
|
pragma solidity ^0.6;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../utils/ForkUtils.sol";
|
import {ForkUtils} from "../utils/ForkUtils.sol";
|
||||||
import "../utils/TestUtils.sol";
|
import "../utils/TestUtils.sol";
|
||||||
import "../utils/DeployZeroEx.sol";
|
import "../utils/DeployZeroEx.sol";
|
||||||
import "forge-std/Test.sol";
|
import "forge-std/Test.sol";
|
||||||
@ -33,7 +33,9 @@ contract WrapEthTest is Test, ForkUtils, TestUtils {
|
|||||||
DeployZeroEx.ZeroExDeployed zeroExDeployed;
|
DeployZeroEx.ZeroExDeployed zeroExDeployed;
|
||||||
|
|
||||||
function setUp() public {
|
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);
|
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/ERC1155OrdersFeature.sol";
|
||||||
import "src/features/nft_orders/ERC721OrdersFeature.sol";
|
import "src/features/nft_orders/ERC721OrdersFeature.sol";
|
||||||
import "src/features/UniswapFeature.sol";
|
import "src/features/UniswapFeature.sol";
|
||||||
|
import "src/features/UniswapV3Feature.sol";
|
||||||
import "src/features/multiplex/MultiplexFeature.sol";
|
import "src/features/multiplex/MultiplexFeature.sol";
|
||||||
import "src/external/TransformerDeployer.sol";
|
import "src/external/TransformerDeployer.sol";
|
||||||
import "src/external/FeeCollectorController.sol";
|
import "src/external/FeeCollectorController.sol";
|
||||||
|
import "src/external/LiquidityProviderSandbox.sol";
|
||||||
import "src/transformers/WethTransformer.sol";
|
import "src/transformers/WethTransformer.sol";
|
||||||
import "src/transformers/FillQuoteTransformer.sol";
|
import "src/transformers/FillQuoteTransformer.sol";
|
||||||
import "src/transformers/PayTakerTransformer.sol";
|
import "src/transformers/PayTakerTransformer.sol";
|
||||||
@ -62,6 +64,7 @@ contract DeployZeroEx is Test {
|
|||||||
BatchFillNativeOrdersFeature batchFillNativeOrdersFeature;
|
BatchFillNativeOrdersFeature batchFillNativeOrdersFeature;
|
||||||
OtcOrdersFeature otcOrdersFeature;
|
OtcOrdersFeature otcOrdersFeature;
|
||||||
UniswapFeature uniswapFeature;
|
UniswapFeature uniswapFeature;
|
||||||
|
UniswapV3Feature uniswapV3Feature;
|
||||||
FundRecoveryFeature fundRecoveryFeature;
|
FundRecoveryFeature fundRecoveryFeature;
|
||||||
TransformERC20Feature transformERC20Feature;
|
TransformERC20Feature transformERC20Feature;
|
||||||
MetaTransactionsFeature metaTransactionsFeature;
|
MetaTransactionsFeature metaTransactionsFeature;
|
||||||
@ -89,6 +92,22 @@ contract DeployZeroEx is Test {
|
|||||||
|
|
||||||
ZeroExDeployed ZERO_EX_DEPLOYED;
|
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) {
|
function getDeployedZeroEx() public returns (ZeroExDeployed memory) {
|
||||||
if (!isDeployed) {
|
if (!isDeployed) {
|
||||||
deployZeroEx();
|
deployZeroEx();
|
||||||
@ -111,6 +130,7 @@ contract DeployZeroEx is Test {
|
|||||||
);
|
);
|
||||||
emit log_named_address("OtcOrdersFeature", address(ZERO_EX_DEPLOYED.features.otcOrdersFeature));
|
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("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("FundRecoveryFeature", address(ZERO_EX_DEPLOYED.features.fundRecoveryFeature));
|
||||||
emit log_named_address("MetaTransactionsFeature", address(ZERO_EX_DEPLOYED.features.metaTransactionsFeature));
|
emit log_named_address("MetaTransactionsFeature", address(ZERO_EX_DEPLOYED.features.metaTransactionsFeature));
|
||||||
emit log_named_address("ERC1155OrdersFeature", address(ZERO_EX_DEPLOYED.features.erc1155OrdersFeature));
|
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.batchFillNativeOrdersFeature = new BatchFillNativeOrdersFeature(address(ZERO_EX));
|
||||||
ZERO_EX_DEPLOYED.features.otcOrdersFeature = new OtcOrdersFeature(address(ZERO_EX), ZERO_EX_DEPLOYED.weth);
|
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.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.fundRecoveryFeature = new FundRecoveryFeature();
|
||||||
ZERO_EX_DEPLOYED.features.metaTransactionsFeature = new MetaTransactionsFeature(address(ZERO_EX));
|
ZERO_EX_DEPLOYED.features.metaTransactionsFeature = new MetaTransactionsFeature(address(ZERO_EX));
|
||||||
ZERO_EX_DEPLOYED.features.erc1155OrdersFeature = new ERC1155OrdersFeature(
|
ZERO_EX_DEPLOYED.features.erc1155OrdersFeature = new ERC1155OrdersFeature(
|
||||||
@ -187,11 +212,11 @@ contract DeployZeroEx is Test {
|
|||||||
ZERO_EX_DEPLOYED.features.multiplexFeature = new MultiplexFeature(
|
ZERO_EX_DEPLOYED.features.multiplexFeature = new MultiplexFeature(
|
||||||
address(ZERO_EX),
|
address(ZERO_EX),
|
||||||
ZERO_EX_DEPLOYED.weth,
|
ZERO_EX_DEPLOYED.weth,
|
||||||
ILiquidityProviderSandbox(address(0)),
|
new LiquidityProviderSandbox(address(ZERO_EX)),
|
||||||
address(0), // uniswapFactory
|
ZERO_EX_DEPLOY_CONFIG.uniswapFactory,
|
||||||
address(0), // sushiswapFactory
|
ZERO_EX_DEPLOY_CONFIG.sushiswapFactory,
|
||||||
bytes32(0), // uniswapPairInitCodeHash
|
ZERO_EX_DEPLOY_CONFIG.uniswapPairInitCodeHash,
|
||||||
bytes32(0) // sushiswapPairInitCodeHash
|
ZERO_EX_DEPLOY_CONFIG.sushiswapPairInitCodeHash
|
||||||
);
|
);
|
||||||
|
|
||||||
initialMigration.initializeZeroEx(
|
initialMigration.initializeZeroEx(
|
||||||
@ -230,6 +255,11 @@ contract DeployZeroEx is Test {
|
|||||||
abi.encodeWithSelector(UniswapFeature.migrate.selector),
|
abi.encodeWithSelector(UniswapFeature.migrate.selector),
|
||||||
address(this)
|
address(this)
|
||||||
);
|
);
|
||||||
|
IZERO_EX.migrate(
|
||||||
|
address(ZERO_EX_DEPLOYED.features.uniswapV3Feature),
|
||||||
|
abi.encodeWithSelector(UniswapV3Feature.migrate.selector),
|
||||||
|
address(this)
|
||||||
|
);
|
||||||
IZERO_EX.migrate(
|
IZERO_EX.migrate(
|
||||||
address(ZERO_EX_DEPLOYED.features.fundRecoveryFeature),
|
address(ZERO_EX_DEPLOYED.features.fundRecoveryFeature),
|
||||||
abi.encodeWithSelector(FundRecoveryFeature.migrate.selector),
|
abi.encodeWithSelector(FundRecoveryFeature.migrate.selector),
|
||||||
@ -293,7 +323,10 @@ contract DeployZeroEx is Test {
|
|||||||
|
|
||||||
ZERO_EX_DEPLOYED.zeroEx = IZERO_EX;
|
ZERO_EX_DEPLOYED.zeroEx = IZERO_EX;
|
||||||
isDeployed = true;
|
isDeployed = true;
|
||||||
logDeployedZeroEx();
|
if (ZERO_EX_DEPLOY_CONFIG.logDeployed) {
|
||||||
|
logDeployedZeroEx();
|
||||||
|
}
|
||||||
|
|
||||||
return ZERO_EX_DEPLOYED;
|
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
|
//read the uniswapV2 router addresses from file
|
||||||
function readLiquiditySourceAddresses() internal returns (string memory) {
|
function readLiquiditySourceAddresses() internal returns (string memory) {
|
||||||
string memory root = vm.projectRoot();
|
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