Compare commits

..

14 Commits

Author SHA1 Message Date
Github Actions
03fc744bbd Publish
- @0x/contracts-erc20@4.0.2
 - @0x/contracts-test-utils@5.4.49
 - @0x/contracts-treasury@1.4.42
 - @0x/contracts-utils@4.8.40
 - @0x/contracts-zero-ex@0.39.1
 - @0x/contract-addresses@8.2.0
 - @0x/contract-wrappers@13.22.18
 - @0x/protocol-utils@11.18.1
2023-03-10 01:13:24 +00:00
Github Actions
a23143d1eb Updated CHANGELOGS & MD docs 2023-03-10 01:13:21 +00:00
Savarn Dontamsetti (Sav)
c0ef6fece3 chore: update addresses to reflect AaveV3 L2 encoding removal and KyberElastic Addition (#678)
* Update addresses to reflect AaveV3 L2Encoding removal
2023-03-09 18:35:01 -05:00
Kevin Liao
03ea4e3dba feat:Add Kyber Elastic mixins (#677)
* add kyber elastic mixins

* update changelog

* fix changelog
2023-03-09 12:33:14 -08:00
Savarn Dontamsetti (Sav)
3e939f7780 Removing L2 Encoding from AaveV3 MixIn (#676) 2023-03-09 12:02:36 -05:00
Github Actions
d97dab83cd Publish
- @0x/contracts-erc20@4.0.1
 - @0x/contracts-test-utils@5.4.48
 - @0x/contracts-treasury@1.4.41
 - @0x/contracts-utils@4.8.39
 - @0x/contracts-zero-ex@0.39.0
 - @0x/contract-addresses@8.1.0
 - @0x/contract-wrappers@13.22.17
 - @0x/protocol-utils@11.18.0
2023-03-01 17:58:11 +00:00
Github Actions
f0a4f6aeca Updated CHANGELOGS & MD docs 2023-03-01 17:58:07 +00:00
Kevin Liao
f8a183812e remove test file 2023-03-01 11:17:52 -05:00
Kevin Liao
f6fd374590 testing branch protection 2023-03-01 11:05:03 -05:00
Kevin Liao
09763bcf5e update changelog to reflect adding KyberElastic to BridgeProtocols (#671) 2023-02-28 09:39:57 -05:00
Kevin Liao
3ab12ed254 update erc20 changelog to match .md file (#670) 2023-02-27 22:20:52 -05:00
Kevin Liao
25731653ef chore: update FQT addresses for kyber elastic on mainnet and polygon (#669)
* update FQT addresses for kyber elastic on mainnet and polygon

* lowercase

* update changelog

* remove timestamp
2023-02-27 21:34:41 -05:00
Kyu
ec82c42c1b Skip chain id validation in AbstractBridgeAdapter on testnets (#668) 2023-02-27 18:18:56 -08:00
Andy
38665ffc86 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>
2023-02-22 19:16:48 -05:00
45 changed files with 1381 additions and 363 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -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,

View File

@@ -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

View File

@@ -391,7 +391,6 @@ contract MultiplexFeature is
// Compute the expected address and transfer the input tokens
// there if necessary.
state.from = _computeHopTarget(params, 0);
// If the input tokens are currently held by `msg.sender` but
// the first hop expects them elsewhere, perform a `transferFrom`.
if (!params.useSelfBalance && state.from != msg.sender) {
@@ -408,6 +407,7 @@ contract MultiplexFeature is
// Compute the recipient of the tokens that will be
// bought by the current hop.
state.to = _computeHopTarget(params, state.hopIndex + 1);
if (subcall.id == MultiplexSubcall.UniswapV2) {
_multiHopSellUniswapV2(state, params, subcall.data);
} else if (subcall.id == MultiplexSubcall.UniswapV3) {
@@ -416,8 +416,6 @@ contract MultiplexFeature is
_multiHopSellLiquidityProvider(state, params, subcall.data);
} else if (subcall.id == MultiplexSubcall.BatchSell) {
_nestedBatchSell(state, params, subcall.data);
} else if (subcall.id == MultiplexSubcall.OTC) {
_multiHopSellOtcOrder(state, params, subcall.data);
} else {
revert("MultiplexFeature::_executeMultiHopSell/INVALID_SUBCALL");
}
@@ -533,13 +531,6 @@ contract MultiplexFeature is
} else {
target = address(this);
}
} else if (subcall.id == MultiplexSubcall.OTC) {
//on the first call we want to pull tokens from the taker, subsequent calls should use the EP balance
if (i == 0) {
target = msg.sender;
} else {
target = address(this);
}
} else {
revert("MultiplexFeature::_computeHopTarget/INVALID_SUBCALL");
}

View File

@@ -65,33 +65,4 @@ abstract contract MultiplexOtc is FixinEIP712 {
state.boughtAmount = state.boughtAmount.safeAdd(makerTokenFilledAmount);
} catch {}
}
function _multiHopSellOtcOrder(
IMultiplexFeature.MultiHopSellState memory state,
IMultiplexFeature.MultiHopSellParams memory params,
bytes memory wrappedCallData
) internal {
// Decode the Otc order, and signature.
(LibNativeOrder.OtcOrder memory order, LibSignature.Signature memory signature) = abi
.decode(wrappedCallData, (LibNativeOrder.OtcOrder, LibSignature.Signature));
//Make sure that the otc orders maker and taker tokens match the fill sequence in params.tokens[]
require(
address(order.takerToken) == params.tokens[state.hopIndex] &&
address(order.makerToken) == params.tokens[state.hopIndex + 1],
"MultiplexOtcOrder::_multiHopSellOtcOrder/INVALID_TOKENS"
);
uint256 sellAmount = state.outputTokenAmount;
// Try filling the Otc order. Bubble up reverts.
(uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount) = IOtcOrdersFeature(address(this))
._fillOtcOrder(
order,
signature,
sellAmount.safeDowncastToUint128(),
state.hopIndex == 0 ? msg.sender : address(this),
params.useSelfBalance,
state.to
);
//store the bought amount for the next hop
state.outputTokenAmount = makerTokenFilledAmount;
}
}

View File

@@ -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")));
}
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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",

View 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
);
}
}

View File

@@ -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);
}

View File

@@ -1,220 +0,0 @@
// 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 "../utils/ForkUtils.sol";
import "../utils/TestUtils.sol";
import "src/IZeroEx.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "src/features/TransformERC20Feature.sol";
import "src/features/multiplex/MultiplexFeature.sol";
import "src/external/TransformerDeployer.sol";
import "src/transformers/WethTransformer.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "src/transformers/bridges/BridgeProtocols.sol";
import "src/features/OtcOrdersFeature.sol";
contract MultiplexRfqtTest is Test, ForkUtils, TestUtils {
using LibERC20TokenV06 for IERC20Token;
using LibERC20TokenV06 for IEtherToken;
function setUp() public {
_setup();
}
function test_swapEthForUSDTThroughFqtOtcs() public {
log_string("SwapEthForUSDTThroughFqtOtc");
/* */
for (uint256 i = 0; i < 1; i++) {
//skip fantom/avax failing test
if (i == 3 || i == 4) {
continue;
}
vm.selectFork(forkIds[chains[i]]);
log_named_string(" Selecting Fork On", chains[i]);
vm.deal(address(this), 1e18);
labelAddresses(
chains[i],
indexChainsByChain[chains[i]],
getTokens(i),
getContractAddresses(i),
getLiquiditySourceAddresses(i)
);
//redeploy and migrate multiplexFeature and OtcOrders for logging
MultiplexFeature multiplexFeature = new MultiplexFeature(
address(IZERO_EX),
IEtherToken(tokens.WrappedNativeToken),
ILiquidityProviderSandbox(addresses.exchangeProxyLiquidityProviderSandbox),
address(0), // uniswapFactory
address(0), // sushiswapFactory
bytes32(0), // uniswapPairInitCodeHash
bytes32(0) // sushiswapPairInitCodeHash
);
OtcOrdersFeature otcOrdersFeature = new OtcOrdersFeature(
address(addresses.exchangeProxy),
tokens.WrappedNativeToken
);
vm.label(address(multiplexFeature), "zeroEx/NewMultiplexFeature");
vm.label(address(otcOrdersFeature), "zeroEx/NewOtcOrdersFeature");
vm.prank(IZeroEx(addresses.exchangeProxy).owner());
IZeroEx(addresses.exchangeProxy).migrate(
address(otcOrdersFeature),
abi.encodeWithSelector(OtcOrdersFeature.migrate.selector),
address(addresses.exchangeProxy)
);
vm.prank(IZeroEx(addresses.exchangeProxy).owner());
IZeroEx(addresses.exchangeProxy).migrate(
address(multiplexFeature),
abi.encodeWithSelector(MultiplexFeature.migrate.selector),
address(addresses.exchangeProxy)
);
swapMultihopOtc(getTokens(i), getContractAddresses(i), getLiquiditySourceAddresses(i));
}
}
/* solhint-disable function-max-lines */
function swapMultihopOtc(
TokenAddresses memory tokens,
ContractAddresses memory addresses,
LiquiditySources memory sources
) public onlyForked {
IZERO_EX = IZeroEx(addresses.exchangeProxy);
address[] memory tradeTokens = new address[](3);
tradeTokens[0] = address(tokens.WrappedNativeToken);
tradeTokens[1] = address(tokens.USDC);
tradeTokens[2] = address(tokens.DAI);
deal(tradeTokens[0], address(this), 1e18);
tokens.WrappedNativeToken.approveIfBelow(addresses.exchangeProxy, uint(-1));
uint inputAmount = 1e18;
uint outputAmount = 5e17;
IMultiplexFeature.MultiHopSellSubcall[] memory subcalls = new IMultiplexFeature.MultiHopSellSubcall[](2);
IMultiplexFeature.MultiHopSellSubcall memory subcall1;
subcall1.id = IMultiplexFeature.MultiplexSubcall.OTC;
//subcall.data = abi.encode(address[], LibNativeOrder.OtcOrder, LibSignature.Signature);
(LibNativeOrder.OtcOrder memory order1, LibSignature.Signature memory signature1) = createOtcOrder(
tokens.WrappedNativeToken,
tokens.USDC,
1e18,
5e17,
0
);
subcall1.data = abi.encode(order1, signature1);
IMultiplexFeature.MultiHopSellSubcall memory subcall2;
subcall2.id = IMultiplexFeature.MultiplexSubcall.OTC;
(LibNativeOrder.OtcOrder memory order2, LibSignature.Signature memory signature2) = createOtcOrder(
tokens.USDC,
tokens.DAI,
5e17,
5e17,
1
);
subcall2.data = abi.encode(order2, signature2);
subcalls[0] = subcall1;
subcalls[1] = subcall2;
uint balanceBefore = tokens.DAI.balanceOf(address(this));
emit log_named_uint("DAI Balance Before", balanceBefore);
emit log_string("Multihop Rfqt: WETH->USDC->DAI");
/// @dev Sells `sellAmount` of the input token (`tokens[0]`)
/// via the given sequence of tokens and calls.
/// The last token in `tokens` is the output token that
/// will ultimately be sent to `msg.sender`
/// @param tokens The sequence of tokens to use for the sell,
/// i.e. `tokens[i]` will be sold for `tokens[i+1]` via
/// `calls[i]`.
/// @param calls The sequence of calls to use for the sell.
/// @param sellAmount The amount of `inputToken` to sell.
/// @param minBuyAmount The minimum amount of output tokens that
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of output tokens bought.
IZERO_EX.multiplexMultiHopSellTokenForToken(
// input token[] [input, intermediate, output]
tradeTokens,
//array of subcalls [{},{}]
subcalls,
// input token amount
inputAmount,
// min output token amount
outputAmount
);
uint balanceAfter = tokens.DAI.balanceOf(address(this));
emit log_named_uint("DAI Balance After", balanceAfter - balanceBefore);
require(balanceAfter >= 5e17, "Failed: UNDERBOUGHT");
}
function createOtcOrder(
IERC20Token inputToken,
IERC20Token ouputToken,
uint128 takerAmount,
uint128 makerAmount,
uint bump
) public returns (LibNativeOrder.OtcOrder memory order, LibSignature.Signature memory signature) {
LibNativeOrder.OtcOrder memory order;
FillQuoteTransformer.OtcOrderInfo memory orderInfo;
LibSignature.Signature memory signature;
order.makerToken = ouputToken;
order.takerToken = inputToken;
order.takerAmount = takerAmount;
order.makerAmount = makerAmount;
uint privateKey;
(order.maker, privateKey) = getSigner();
deal(address(order.makerToken), order.maker, 2e20);
deal(address(order.takerToken), order.maker, 2e20);
vm.startPrank(order.maker);
IERC20Token(order.makerToken).approveIfBelow(addresses.exchangeProxy, 2e20);
order.taker = address(0);
order.txOrigin = address(tx.origin);
order.expiryAndNonce = encodeExpiryAndNonce(order.maker, bump);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, IZERO_EX.getOtcOrderHash(order));
vm.stopPrank();
signature.signatureType = LibSignature.SignatureType.EIP712;
signature.v = v;
signature.r = r;
signature.s = s;
return (order, signature);
}
/* solhint-enable function-max-lines */
function encodeExpiryAndNonce(address maker, uint bump) public returns (uint256) {
uint256 expiry = (block.timestamp + 120) << 192;
uint256 bucket = (0 + bump) << 128;
uint256 nonce = vm.getNonce(maker);
return expiry | bucket | nonce;
}
}

View File

@@ -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);

View File

@@ -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]]);

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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();

View 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);
}
}

View 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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": [

View File

@@ -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)

View File

@@ -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"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contract-addresses",
"version": "8.0.3",
"version": "8.2.0",
"engines": {
"node": ">=6.12"
},

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -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",

View File

@@ -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

View File

@@ -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",