Compare commits
14 Commits
feat/Multi
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
03fc744bbd | ||
|
a23143d1eb | ||
|
c0ef6fece3 | ||
|
03ea4e3dba | ||
|
3e939f7780 | ||
|
d97dab83cd | ||
|
f0a4f6aeca | ||
|
f8a183812e | ||
|
f6fd374590 | ||
|
09763bcf5e | ||
|
3ab12ed254 | ||
|
25731653ef | ||
|
ec82c42c1b | ||
|
38665ffc86 |
@@ -1,4 +1,30 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "4.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Migrated package to foundry"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "3.3.57",
|
||||
|
@@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.0 - _February 16, 2023_
|
||||
## v4.0.2 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.1 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.0 - _Invalid date_
|
||||
|
||||
* Migrated package to foundry
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -24,11 +24,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/contracts-utils": "^4.8.38",
|
||||
"@0x/contracts-utils": "^4.8.40",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"typedoc": "~0.16.11"
|
||||
},
|
||||
"dependencies": {},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "5.4.49",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "5.4.48",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "5.4.47",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.4.49 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.48 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.47 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.4.47",
|
||||
"version": "5.4.49",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,7 +41,7 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.35",
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"@0x/contract-addresses": "^8.0.3",
|
||||
"@0x/contract-addresses": "^8.2.0",
|
||||
"@0x/dev-utils": "^5.0.0",
|
||||
"@0x/json-schemas": "^6.4.4",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "1.4.42",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "1.4.41",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "1.4.40",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.4.42 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.41 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.40 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.4.40",
|
||||
"version": "1.4.42",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -46,12 +46,12 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.8.1",
|
||||
"@0x/contract-addresses": "^8.0.3",
|
||||
"@0x/contract-addresses": "^8.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-erc20": "3.3.57",
|
||||
"@0x/contracts-gen": "^2.0.48",
|
||||
"@0x/contracts-staking": "^2.0.45",
|
||||
"@0x/contracts-test-utils": "^5.4.47",
|
||||
"@0x/contracts-test-utils": "^5.4.49",
|
||||
"@0x/sol-compiler": "^4.8.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
@@ -73,7 +73,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"@0x/protocol-utils": "^11.17.6",
|
||||
"@0x/protocol-utils": "^11.18.1",
|
||||
"@0x/subproviders": "^7.0.0",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "4.8.40",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "4.8.39",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "4.8.38",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.8.40 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.39 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.38 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.8.38",
|
||||
"version": "4.8.40",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -46,7 +46,7 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.8.1",
|
||||
"@0x/contracts-gen": "^2.0.48",
|
||||
"@0x/contracts-test-utils": "^5.4.47",
|
||||
"@0x/contracts-test-utils": "^5.4.49",
|
||||
"@0x/dev-utils": "^5.0.0",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-compiler": "^4.8.2",
|
||||
|
@@ -1,11 +1,24 @@
|
||||
[
|
||||
{
|
||||
"version": "0.39.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add KyberElastic mixin for Optimism and BSC"
|
||||
}
|
||||
],
|
||||
"timestamp": 1678410794
|
||||
},
|
||||
{
|
||||
"version": "0.39.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add KyberElastic mixin for Ethereum, Polygon, Arbitrum, Avalanche"
|
||||
},
|
||||
{
|
||||
"note": "Skip chain id validation in AbstractBridgeAdapter on testnets"
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1677693479
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
|
@@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.39.1 - _March 10, 2023_
|
||||
|
||||
* Add KyberElastic mixin for Optimism and BSC
|
||||
|
||||
## v0.39.0 - _March 1, 2023_
|
||||
|
||||
* Add KyberElastic mixin for Ethereum, Polygon, Arbitrum, Avalanche
|
||||
* Skip chain id validation in AbstractBridgeAdapter on testnets
|
||||
|
||||
## v0.38.6 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -23,8 +23,14 @@ abstract contract AbstractBridgeAdapter is IBridgeAdapter {
|
||||
assembly {
|
||||
chainId := chainid()
|
||||
}
|
||||
// Allow testing on Ganache
|
||||
if (chainId != expectedChainId && chainId != 1337) {
|
||||
// Skip chain id validation on Ganache (1337), Anvil (31337), Goerli (5), Mumbai (80001), Base Goerli (84531)
|
||||
bool skipValidation = (chainId == 1337 ||
|
||||
chainId == 31337 ||
|
||||
chainId == 5 ||
|
||||
chainId == 80001 ||
|
||||
chainId == 84531);
|
||||
|
||||
if (chainId != expectedChainId && !skipValidation) {
|
||||
revert(string(abi.encodePacked(expectedChainName, "BridgeAdapter.constructor: wrong chain ID")));
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ contract ArbitrumBridgeAdapter is
|
||||
MixinWOOFi,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(true) {}
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) {}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
|
@@ -45,7 +45,7 @@ contract AvalancheBridgeAdapter is
|
||||
MixinWOOFi,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(false) {}
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) {}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
|
@@ -21,6 +21,7 @@ import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyberDmm.sol";
|
||||
import "./mixins/MixinKyberElastic.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
@@ -33,6 +34,7 @@ contract BSCBridgeAdapter is
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyberDmm,
|
||||
MixinKyberElastic,
|
||||
MixinMooniswap,
|
||||
MixinNerve,
|
||||
MixinUniswapV2,
|
||||
@@ -84,6 +86,11 @@ contract BSCBridgeAdapter is
|
||||
return (0, true);
|
||||
}
|
||||
boughtAmount = _tradeKyberDmm(buyToken, sellAmount, order.bridgeData);
|
||||
} else if (protocolId == BridgeProtocols.KYBERELASTIC) {
|
||||
if (dryRun) {
|
||||
return (0, true);
|
||||
}
|
||||
boughtAmount = _tradeKyberElastic(sellToken, sellAmount, order.bridgeData);
|
||||
} else if (protocolId == BridgeProtocols.WOOFI) {
|
||||
if (dryRun) {
|
||||
return (0, true);
|
||||
|
@@ -21,6 +21,7 @@ import "./mixins/MixinAaveV3.sol";
|
||||
import "./mixins/MixinBalancerV2Batch.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
import "./mixins/MixinKyberElastic.sol";
|
||||
import "./mixins/MixinNerve.sol";
|
||||
import "./mixins/MixinSolidly.sol";
|
||||
import "./mixins/MixinSynthetix.sol";
|
||||
@@ -34,6 +35,7 @@ contract OptimismBridgeAdapter is
|
||||
MixinBalancerV2Batch,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
MixinKyberElastic,
|
||||
MixinNerve,
|
||||
MixinSynthetix,
|
||||
MixinUniswapV3,
|
||||
@@ -41,7 +43,7 @@ contract OptimismBridgeAdapter is
|
||||
MixinWOOFi,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(true) {}
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) {}
|
||||
|
||||
/* solhint-disable function-max-lines */
|
||||
function _trade(
|
||||
@@ -102,6 +104,11 @@ contract OptimismBridgeAdapter is
|
||||
return (0, true);
|
||||
}
|
||||
boughtAmount = _tradeWOOFi(sellToken, buyToken, sellAmount, order.bridgeData);
|
||||
} else if (protocolId == BridgeProtocols.KYBERELASTIC) {
|
||||
if (dryRun) {
|
||||
return (0, true);
|
||||
}
|
||||
boughtAmount = _tradeKyberElastic(sellToken, sellAmount, order.bridgeData);
|
||||
}
|
||||
|
||||
emit BridgeFill(order.source, sellToken, buyToken, sellAmount, boughtAmount);
|
||||
|
@@ -53,7 +53,7 @@ contract PolygonBridgeAdapter is
|
||||
MixinWOOFi,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(false) {}
|
||||
constructor(IEtherToken weth) public MixinCurve(weth) {}
|
||||
|
||||
function _trade(
|
||||
BridgeOrder memory order,
|
||||
|
@@ -47,63 +47,16 @@ interface IPool {
|
||||
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
|
||||
}
|
||||
|
||||
// Minimal Aave V3 L2Pool interface
|
||||
interface IL2Pool {
|
||||
/**
|
||||
* @notice Calldata efficient wrapper of the supply function on behalf of the caller
|
||||
* @param args Arguments for the supply function packed in one bytes32
|
||||
* 96 bits 16 bits 128 bits 16 bits
|
||||
* | 0-padding | referralCode | shortenedAmount | assetId |
|
||||
* @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to
|
||||
* type(uint256).max
|
||||
* @dev assetId is the index of the asset in the reservesList.
|
||||
*/
|
||||
function supply(bytes32 args) external;
|
||||
|
||||
/**
|
||||
* @notice Calldata efficient wrapper of the withdraw function, withdrawing to the caller
|
||||
* @param args Arguments for the withdraw function packed in one bytes32
|
||||
* 112 bits 128 bits 16 bits
|
||||
* | 0-padding | shortenedAmount | assetId |
|
||||
* @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to
|
||||
* type(uint256).max
|
||||
* @dev assetId is the index of the asset in the reservesList.
|
||||
*/
|
||||
function withdraw(bytes32 args) external;
|
||||
}
|
||||
|
||||
contract MixinAaveV3 {
|
||||
using LibERC20TokenV06 for IERC20Token;
|
||||
|
||||
bool private immutable _isL2;
|
||||
|
||||
constructor(bool isL2) public {
|
||||
_isL2 = isL2;
|
||||
}
|
||||
|
||||
function _tradeAaveV3(
|
||||
IERC20Token sellToken,
|
||||
IERC20Token buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
) internal returns (uint256) {
|
||||
if (_isL2) {
|
||||
(IL2Pool pool, address aToken, bytes32 l2Params) = abi.decode(bridgeData, (IL2Pool, address, bytes32));
|
||||
|
||||
sellToken.approveIfBelow(address(pool), sellAmount);
|
||||
|
||||
if (address(buyToken) == aToken) {
|
||||
pool.supply(l2Params);
|
||||
// 1:1 mapping token --> aToken and have the same number of decimals as the underlying token
|
||||
return sellAmount;
|
||||
} else if (address(sellToken) == aToken) {
|
||||
pool.withdraw(l2Params);
|
||||
return sellAmount;
|
||||
}
|
||||
|
||||
revert("MixinAaveV3/UNSUPPORTED_TOKEN_PAIR");
|
||||
}
|
||||
(IPool pool, address aToken, ) = abi.decode(bridgeData, (IPool, address, bytes32));
|
||||
(IPool pool, address aToken) = abi.decode(bridgeData, (IPool, address));
|
||||
|
||||
sellToken.approveIfBelow(address(pool), sellAmount);
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-zero-ex",
|
||||
"version": "0.38.6",
|
||||
"version": "0.39.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,10 +51,10 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.8.1",
|
||||
"@0x/contract-addresses": "^8.0.3",
|
||||
"@0x/contract-addresses": "^8.2.0",
|
||||
"@0x/contracts-erc20": "^3.3.57",
|
||||
"@0x/contracts-gen": "^2.0.48",
|
||||
"@0x/contracts-test-utils": "^5.4.47",
|
||||
"@0x/contracts-test-utils": "^5.4.49",
|
||||
"@0x/dev-utils": "^5.0.0",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-compiler": "^4.8.2",
|
||||
@@ -80,7 +80,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"@0x/protocol-utils": "^11.17.6",
|
||||
"@0x/protocol-utils": "^11.18.1",
|
||||
"@0x/subproviders": "^7.0.0",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
|
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);
|
||||
|
@@ -38,8 +38,8 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
|
||||
|
||||
function test_swapERC20ForERC20OnKyberElastic() public {
|
||||
for (uint256 i = 0; i < chains.length; i++) {
|
||||
// kyberelastic mixin not deployed to these chains yet (bsc, fantom, optimism)
|
||||
if (i == 1 || i == 4 || i == 5) {
|
||||
// kyberelastic mixin not added to fantom yet
|
||||
if (i == 4) {
|
||||
continue;
|
||||
}
|
||||
vm.selectFork(forkIds[chains[i]]);
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,24 @@
|
||||
[
|
||||
{
|
||||
"version": "8.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Upgrade Polygon, Avalanche, Arbitrum, and Optimism FillQuoteTransformers to remove Aave V3 L2 Encoding and support KyberElastic",
|
||||
"pr": 678
|
||||
}
|
||||
],
|
||||
"timestamp": 1678410794
|
||||
},
|
||||
{
|
||||
"version": "8.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Upgrade Mainnet and Polygon FillQuoteTransformers to support KyberElastic",
|
||||
"pr": 669
|
||||
}
|
||||
],
|
||||
"timestamp": 1677693479
|
||||
},
|
||||
{
|
||||
"version": "8.0.3",
|
||||
"changes": [
|
||||
|
@@ -6,6 +6,12 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v8.2.0 - _March 10, 2023_
|
||||
|
||||
* Upgrade Polygon, Avalanche, Arbitrum, and Optimism FillQuoteTransformers to remove Aave V3 L2 Encoding and support KyberElastic (#678)
|
||||
## v8.1.0 - _March 1, 2023_
|
||||
|
||||
* Upgrade Mainnet and Polygon FillQuoteTransformers to support KyberElastic (#669)
|
||||
## v8.0.3 - _February 1, 2023_
|
||||
|
||||
* Upgrade Arbitrum FillQuoteTransformer to support Woofi (#653)
|
||||
|
@@ -18,7 +18,7 @@
|
||||
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
||||
"payTakerTransformer": "0xea500d073652336a58846ada15c25f2c6d2d241f",
|
||||
"affiliateFeeTransformer": "0x8146cbbe327364b13d0699f2ced39c637f92501a",
|
||||
"fillQuoteTransformer": "0xd8e10b0689d0b2f28136777635caa4abd2bb9f04",
|
||||
"fillQuoteTransformer": "0xd7a6ced9e0eaa8e5ad6e7335d25d46b6f456d4fd",
|
||||
"positiveSlippageFeeTransformer": "0x818a4a855bfeb16c305cb65e8d4fb239a308bc48"
|
||||
}
|
||||
},
|
||||
@@ -110,7 +110,7 @@
|
||||
"wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38",
|
||||
"payTakerTransformer": "0xed8932ca083e1ef1960dea875a132926e6b242ab",
|
||||
"affiliateFeeTransformer": "0xf79071e2f860d48a08fd7e091d4b126a1d757148",
|
||||
"fillQuoteTransformer": "0xe35653ead385b6299099f6d43b7c17cc12df9110",
|
||||
"fillQuoteTransformer": "0xcc46d6a09cbdc75f2f174493c33cab45492d868b",
|
||||
"positiveSlippageFeeTransformer": "0x8f5e7188f443a9a8dc180f4618fd23915043ea15"
|
||||
}
|
||||
},
|
||||
@@ -156,7 +156,7 @@
|
||||
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
|
||||
"payTakerTransformer": "0xb9a4c32547bc3cdc2ee2fb13cc1a0717dac9888f",
|
||||
"affiliateFeeTransformer": "0x105679f99d668001370b4621ad8648ac570c860f",
|
||||
"fillQuoteTransformer": "0x3fad2c4a73b9a8f263b2749cd266e43c99b988fa",
|
||||
"fillQuoteTransformer": "0x7991f2c35ab19472dbfb6f27593f7f6f38fb3eab",
|
||||
"positiveSlippageFeeTransformer": "0xadbfdc58a24b6dbc16f21541800f43dd6e282250"
|
||||
}
|
||||
},
|
||||
@@ -225,7 +225,7 @@
|
||||
"wethTransformer": "0x02ce7af6520e2862f961f5d7eda746642865179c",
|
||||
"payTakerTransformer": "0xa6c3ca183a67fcb4299fb4199c12ca74874ca489",
|
||||
"affiliateFeeTransformer": "0x3102aea537ecb6f164550b094663c82a8c53a972",
|
||||
"fillQuoteTransformer": "0xfead4c05220a8fddc74008ae43199badc3becaf9",
|
||||
"fillQuoteTransformer": "0xd140adb61d4e3e3978d4f32ac6b92240ff6e3a6e",
|
||||
"positiveSlippageFeeTransformer": "0x9a4947d3fb77a7afc2c9cd6714bbae96dddde059"
|
||||
}
|
||||
},
|
||||
@@ -248,7 +248,7 @@
|
||||
"wethTransformer": "0x10e968968f49dd66a5efeebbb2edcb9c49c4fc49",
|
||||
"payTakerTransformer": "0xd81e65fc9bb7323bdbef8b2cdddd3b83fe41d630",
|
||||
"affiliateFeeTransformer": "0x970e318b8f074c20bf0cee06970f01dc7a761e50",
|
||||
"fillQuoteTransformer": "0x2142414a2c19b4dc4ec050eb1391d1d49d096da1",
|
||||
"fillQuoteTransformer": "0x5d3a221bad31c3f3c07bea2f1de9b3ec17664b69",
|
||||
"positiveSlippageFeeTransformer": "0x20f935b037e8490d8027f2751f9452725eee01ad"
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contract-addresses",
|
||||
"version": "8.0.3",
|
||||
"version": "8.2.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "13.22.18",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "13.22.17",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "13.22.16",
|
||||
|
@@ -6,6 +6,12 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v13.22.18 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
## v13.22.17 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
## v13.22.16 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contract-wrappers",
|
||||
"version": "13.22.16",
|
||||
"version": "13.22.18",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -59,7 +59,7 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.35",
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"@0x/contract-addresses": "^8.0.3",
|
||||
"@0x/contract-addresses": "^8.2.0",
|
||||
"@0x/json-schemas": "^6.4.4",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/utils": "^7.0.0",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "11.18.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "11.18.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add KyberElastic support"
|
||||
}
|
||||
],
|
||||
"timestamp": 1677693479
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "11.17.6",
|
||||
|
@@ -6,6 +6,12 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v11.18.1 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
## v11.18.0 - _March 1, 2023_
|
||||
|
||||
* Add KyberElastic support
|
||||
## v11.17.6 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/protocol-utils",
|
||||
"version": "11.17.6",
|
||||
"version": "11.18.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -62,8 +62,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.35",
|
||||
"@0x/contract-addresses": "^8.0.3",
|
||||
"@0x/contract-wrappers": "^13.22.16",
|
||||
"@0x/contract-addresses": "^8.2.0",
|
||||
"@0x/contract-wrappers": "^13.22.18",
|
||||
"@0x/json-schemas": "^6.4.4",
|
||||
"@0x/subproviders": "^7.0.0",
|
||||
"@0x/utils": "^7.0.0",
|
||||
|
Reference in New Issue
Block a user