working bridge Fills through weth transformer

This commit is contained in:
Noah Khamliche
2022-10-05 00:08:28 -04:00
committed by elenadimitrova
parent cea47f5719
commit bf3e9991d1
9 changed files with 665 additions and 209 deletions

View File

@@ -209,7 +209,6 @@ contract FillQuoteTransformer is Transformer {
}
state.ethRemaining = address(this).balance;
// Fill the orders.
for (uint256 i = 0; i < data.fillSequence.length; ++i) {
// Check if we've hit our targets.

View File

@@ -1,207 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 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 "src/IZeroEx.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "src/features/TransformERC20Feature.sol";
import "src/external/TransformerDeployer.sol";
import "src/transformers/WethTransformer.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "src/transformers/bridges/BridgeProtocols.sol";
import "src/transformers/bridges/EthereumBridgeAdapter.sol";
import "src/transformers/bridges/PolygonBridgeAdapter.sol";
import "src/transformers/bridges/ArbitrumBridgeAdapter.sol";
import "src/transformers/bridges/OptimismBridgeAdapter.sol";
import "src/transformers/bridges/AvalancheBridgeAdapter.sol";
import "src/transformers/bridges/FantomBridgeAdapter.sol";
import "src/transformers/bridges/BSCBridgeAdapter.sol";
import "src/transformers/bridges/CeloBridgeAdapter.sol";
import "src/transformers/bridges/IBridgeAdapter.sol";
import "src/features/OtcOrdersFeature.sol";
import "forge-std/StdJson.sol";
import "forge-std/Test.sol";
import "./utils/ForkUtils.sol";
import "./utils/TestUtils.sol";
contract OtcBridgeSettlement is
TestUtils,
ForkUtils
{
IBridgeAdapter bridgeAdapter;
FillQuoteTransformer fillQuoteTransformer;
OtcOrdersFeature otcOrdersFeature;
IZeroEx IZERO_EX;
function createBridgeAdapter(IEtherTokenV06 weth) public returns(IBridgeAdapter bridgeAdapter) {
uint chainId;
assembly {
chainId := chainid()
}
if(chainId == 1) {return IBridgeAdapter(new EthereumBridgeAdapter(weth));}
else if( chainId == 56){ return IBridgeAdapter(new BSCBridgeAdapter(weth));}
else if( chainId == 137){return IBridgeAdapter(new PolygonBridgeAdapter(weth));}
else if( chainId == 43114){return IBridgeAdapter(new AvalancheBridgeAdapter(weth));}
else if( chainId == 250){return IBridgeAdapter(new FantomBridgeAdapter(weth));}
else if( chainId == 10){return IBridgeAdapter(new OptimismBridgeAdapter(weth));}
else if( chainId == 42161){return IBridgeAdapter(new ArbitrumBridgeAdapter(weth));}
}
function createFillQuoteTransformer(IBridgeAdapter bridgeAdapter, IZeroEx exchangeProxy) public returns (FillQuoteTransformer fqt){
return new FillQuoteTransformer(bridgeAdapter, exchangeProxy);
}
function deployAndLabel(TokenAddresses memory tokens, Addresses memory contracts) public{
bridgeAdapter = createBridgeAdapter(IEtherTokenV06(tokens.WrappedNativeToken));
fillQuoteTransformer = createFillQuoteTransformer(bridgeAdapter, IZeroEx(contracts.exchangeProxy));
otcOrdersFeature = new OtcOrdersFeature(contracts.exchangeProxy, tokens.WrappedNativeToken);
vm.prank(IZeroEx(contracts.exchangeProxy).owner());
IZeroEx(contracts.exchangeProxy).migrate(
address(otcOrdersFeature),
abi.encodeWithSelector(otcOrdersFeature.migrate.selector, address(otcOrdersFeature)),
address(this)
);
IZERO_EX = IZeroEx(contracts.exchangeProxy);
vm.label(address(bridgeAdapter), "zeroEx/BridgeAdapter");
vm.label(address(fillQuoteTransformer), "zeroEx/FillQuoteTransformer");
vm.label(address(contracts.exchangeProxy), "zeroEx/ExchangeProxy");
vm.label(address(otcOrdersFeature), "zeroEx/OtcOrdersFeature");
}
function _fillOtcOrder(string memory chainName, string memory chainId, TokenAddresses memory tokens, Addresses memory contracts, LiquiditySources memory sources) public returns (uint boughtAmount) {
log_named_address("WETH/NATIVE_ASSET", address(tokens.WrappedNativeToken));
log_named_address("EP", address(contracts.exchangeProxy));
//IBridgeAdapter temp = FillQuoteTransformer(contracts.transformers.fillQuoteTransformer).bridgeAdapter();
//log_named_address("Bridge Adapter", address(temp));
uint256 _chainId;
assembly {
_chainId := chainid()
}
log_named_uint("ChainId", _chainId);
deployAndLabel(tokens, contracts);
buildTransform(tokens,contracts);
}
function buildTransform(TokenAddresses memory tokens, Addresses memory contracts) public {
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
// Use our cheeky search helper to find the nonce rather than hardcode it
// hint: it's 6 for WethTransformer and 22 for this FillQuoteTransformer
transformations[0].deploymentNonce = _findTransformerNonce(address(contracts.transformers.wethTransformer), address(contracts.exchangeProxyTransformerDeployer));
transformations[1].deploymentNonce = _findTransformerNonce(address(fillQuoteTransformer), address(contracts.exchangeProxyTransformerDeployer));
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e9);
// Set up the FillQuoteTransformer data
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
// FQT deals with tokens, not ETH, so it needs a WETH transformer
// to be applied beforehand
fqtData.sellToken = IERC20TokenV06(address(tokens.WrappedNativeToken));
fqtData.buyToken = IERC20TokenV06(address(tokens.USDC));
// the FQT has a sequence, e.g first RFQ then Limit then Bridge
// since solidity doesn't support arrays of different types, this is one simple solution
// We use a Bridge order type here as we will fill on UniswapV2
fqtData.fillSequence = new FillQuoteTransformer.OrderType[](2);
fqtData.fillSequence[0] = FillQuoteTransformer.OrderType.Bridge;
fqtData.fillSequence[1] = FillQuoteTransformer.OrderType.Otc;
// The amount to fill
fqtData.fillAmount = 2e18;
// Now let's set up an OTC fill
fqtData.otcOrders = new FillQuoteTransformer.OtcOrderInfo[](1);
LibNativeOrder.OtcOrder memory order;
FillQuoteTransformer.OtcOrderInfo memory orderInfo;
//build up the otc order info for a 0.1 weth swap to usdc
order.makerToken = IERC20TokenV06(address(tokens.USDC));
order.takerToken = IERC20TokenV06(address(tokens.WrappedNativeToken));
order.makerAmount = 1e4;
order.takerAmount = 1e18;
order.maker = address(0xAc3c9f9a125F569a3112d1C60e008fA55e159B92);
order.taker = address(0);
order.txOrigin = address(tx.origin);
order.expiryAndNonce = uint256(10414516026389248070289760349785577643365704380554799766852394287105);
string memory mnemonic = "test test test test test test test test test test test junk";
uint256 privateKey = vm.deriveKey(mnemonic, 0);
address signer = vm.addr(privateKey);
log_named_address("Signing with address", signer);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey,IZeroEx(contracts.exchangeProxy).getOtcOrderHash(order));
log_named_address("recoveredSigner", ecrecover(IZeroEx(contracts.exchangeProxy).getOtcOrderHash(order), v,r,s));
orderInfo.signature.signatureType = LibSignature.SignatureType.EIP712;
orderInfo.signature.v = v;
orderInfo.signature.r = r;
orderInfo.signature.s = s;
emit log_named_address("Signer Of Hash", LibSignature.getSignerOfHash(IZeroEx(contracts.exchangeProxy).getOtcOrderHash(order), orderInfo.signature));
orderInfo.maxTakerTokenFillAmount = 1e18;
fqtData.otcOrders[0] = orderInfo;
transformations[1].data = abi.encode(getBridgeOrder(fqtData));
//fillOrder(transformations);
}
function getBridgeOrder( FillQuoteTransformer.TransformData memory fqtData) public returns (FillQuoteTransformer.TransformData memory _data){
fqtData.bridgeOrders = new IBridgeAdapter.BridgeOrder[](1);
IBridgeAdapter.BridgeOrder memory bridgeOrder;
bridgeOrder.source = bytes32(uint256(BridgeProtocols.UNISWAPV2) << 128);
// How much we want to fill on this order, which can be different to the total
// e.g 50/50 split this would be half
bridgeOrder.takerTokenAmount = 1e18;
// Set this low as the price of ETH/USDC can change
bridgeOrder.makerTokenAmount = 1;
address[] memory uniPath = new address[](2);
uniPath[0] = address(tokens.WrappedNativeToken);
uniPath[1] = address(tokens.USDC);
bridgeOrder.bridgeData = abi.encode(address(sources.UniswapV2Router), uniPath);
fqtData.bridgeOrders[0] = bridgeOrder;
return (fqtData);
}
function fillOrder(ITransformERC20Feature.Transformation[] memory _transformations) public {
vm.deal(address(this), 5e19);
IZERO_EX.transformERC20{value: 2e18}(
// input token
IERC20TokenV06(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// output token
IERC20TokenV06(address(tokens.USDC)),
// input token amount
2e18,
// min output token amount, set this low as ETH/USDC price will move
1,
// list of transform
_transformations
);
// Hoollly heck we bought some USDC
assertGt(tokens.USDC.balanceOf(address(this)), 0);
emit log_named_uint("USDC bought", tokens.USDC.balanceOf(address(this)));
}
}

View File

@@ -0,0 +1,166 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "./utils/ForkUtils.sol";
import "./utils/TestUtils.sol";
import "src/IZeroEx.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "src/features/TransformERC20Feature.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";
import "forge-std/StdJson.sol";
contract ETHToERC20TransformTest is Test, ForkUtils, TestUtils {
//use forge-std json library for strings
using stdJson for string;
//utility mapping to get chainId by name
mapping(string => string) public chainsByChainId;
//utility mapping to get indexingChainId by Chain
mapping(string => string) public indexChainsByChain;
string json;
IBridgeAdapter bridgeAdapter;
FillQuoteTransformer fillQuoteTransformer;
/*//////////////////////////////////////////////////////////////
Rpc Setup
//////////////////////////////////////////////////////////////*/
function setUp() public {
//get out addresses.json file that defines contract addresses for each chain we are currently deployed on
createForks();
for (uint256 i = 0; i < chains.length; i++) {
chainsByChainId[chains[i]] = chainIds[i];
indexChainsByChain[chains[i]] = indexChainIds[i];
}
}
/*//////////////////////////////////////////////////////////////
Dispatch
//////////////////////////////////////////////////////////////*/
function testSwapEthForERC20OnUniswap() public {
log_string("SwapEthForERC20OnUniswap");
for (uint256 i = 0; i < chains.length; i++) {
//skip fantom failing test
if( i == 3 || i == 4 ){
continue;
}
vm.selectFork(forkIds[chains[i]]);
log_named_string(" Selecting Fork On", chains[i]);
labelAddresses(chains[i], indexChainsByChain[chains[i]], getTokens(i), getContractAddresses(i), getLiquiditySourceAddresses(i));
swapOnUniswap(chains[i], indexChainsByChain[chains[i]], getTokens(i), getContractAddresses(i), getLiquiditySourceAddresses(i));
}
}
/*//////////////////////////////////////////////////////////////
Settlement
//////////////////////////////////////////////////////////////*/
function swapOnUniswap(string memory chainName, string memory chainId, TokenAddresses memory tokens, Addresses memory addresses, LiquiditySources memory sources) public onlyForked {
if(sources.UniswapV2Router != address(0)) {
// Create our list of transformations, let's do WethTransformer and FillQuoteTransformer
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
createNewFQT(tokens.WrappedNativeToken, addresses.exchangeProxy, addresses.exchangeProxyTransformerDeployer);
vm.label(address(fillQuoteTransformer), "zeroEx/FillQuoteTransformer");
// Use our cheeky search helper to find the nonce rather than hardcode it
// hint: it's 6 for WethTransformer and 22 for this FillQuoteTransformer
transformations[0].deploymentNonce = _findTransformerNonce(address(addresses.wethTransformer), address(addresses.exchangeProxyTransformerDeployer));
transformations[1].deploymentNonce = _findTransformerNonce(address(fillQuoteTransformer), address(addresses.exchangeProxyTransformerDeployer));
emit log_named_uint(" WethTransformer nonce", transformations[0].deploymentNonce);
emit log_named_uint(" FillQuoteTransformer nonce", transformations[1].deploymentNonce);
// Set the first transformation to transform ETH into WETH
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
// Set up the FillQuoteTransformer data
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
// FQT deals with tokens, not ETH, so it needs a WETH transformer
// to be applied beforehand
fqtData.sellToken = IERC20TokenV06(address(tokens.WrappedNativeToken));
fqtData.buyToken = IERC20TokenV06(address(tokens.USDT));
// the FQT has a sequence, e.g first RFQ then Limit then Bridge
// since solidity doesn't support arrays of different types, this is one simple solution
// We use a Bridge order type here as we will fill on UniswapV2
fqtData.fillSequence = new FillQuoteTransformer.OrderType[](1);
fqtData.fillSequence[0] = FillQuoteTransformer.OrderType.Bridge;
// The amount to fill
fqtData.fillAmount = 1e18;
// Now let's set up a UniswapV2 fill
fqtData.bridgeOrders = new IBridgeAdapter.BridgeOrder[](1);
IBridgeAdapter.BridgeOrder memory order;
// The ID is shifted so we can concat <PROTOCOL><NAME>
// e.g <UniswapV2Protocol><UniswapV2>
// or <UniswapV2Protocol><SushiSwap> for forks
order.source = bytes32(uint256(BridgeProtocols.UNISWAPV2) << 128);
// How much we want to fill on this order, which can be different to the total
// e.g 50/50 split this would be half
order.takerTokenAmount = 1e18;
// Set this low as the price of ETH/USDT can change
order.makerTokenAmount = 1;
// The data needed specifically for the source to fill,
// e.g for UniswapV2 it is the router contract and a path. See MixinUniswapV2
address[] memory uniPath = new address[](2);
uniPath[0] = address(tokens.WrappedNativeToken);
uniPath[1] = address(tokens.USDT);
order.bridgeData = abi.encode(address(sources.UniswapV2Router), uniPath);
fqtData.bridgeOrders[0] = order;
// Now encode the FQT data into the transformation
transformations[1].data = abi.encode(fqtData);
vm.deal(address(this), 1e18);
uint256 balanceETHBefore = address(this).balance;
uint256 balanceERC20Before = IERC20TokenV06(tokens.USDT).balanceOf(address(this));
IZeroEx(payable(addresses.exchangeProxy)).transformERC20{value: 1e18}(
// input token
IERC20TokenV06(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// output token
IERC20TokenV06(address(tokens.USDT)),
// input token amount
1e18,
// min output token amount
1,
// list of transform
transformations
);
log_named_uint(" NativeAsset balance before", balanceETHBefore);
log_named_uint(" ERC-20 balance before", balanceERC20Before);
log_named_uint(" NativeAsset balance after", balanceETHBefore - address(this).balance);
log_named_uint(" ERC-20 balance after", IERC20TokenV06(tokens.USDT).balanceOf(address(this)) - balanceERC20Before);
assert(IERC20TokenV06(tokens.USDT).balanceOf(address(this)) > 0);
}
else {
log_string(" Liquidity Source Not available on this chain");
}
}
/*//////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////*/
function createNewFQT(IEtherTokenV06 wrappedNativeToken, address payable exchangeProxy, address transformerDeployer) public {
vm.startPrank(transformerDeployer);
// deploy a new instance of the bridge adapter from the transformerDeployer
bridgeAdapter = createBridgeAdapter(IEtherTokenV06(wrappedNativeToken));
// deploy a new instance of the fill quote transformer from the transformerDeployer
fillQuoteTransformer = new FillQuoteTransformer(IBridgeAdapter(bridgeAdapter), IZeroEx(exchangeProxy));
vm.label(address(fillQuoteTransformer), "zeroEx/FillQuoteTransformer");
vm.label(address(fillQuoteTransformer), "zeroEx/FillQuoteTransformer");
vm.stopPrank();
}
}

View File

@@ -0,0 +1,149 @@
{
"1": {
"zrxToken": "0xe41d2489571d322189246dafa5ebde1f4699f498",
"etherToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"zeroExGovernor": "0x7d3455421bbc5ed534a83c88fd80387dc8271392",
"zrxVault": "0xba7f8b5fb1b19c1211c5d49550fcd149177a5eaf",
"staking": "0x2a17c35ff147b32f13f19f2e311446eeb02503f3",
"stakingProxy": "0xa26e80e7dea86279c6d778d702cc413e6cffa777",
"erc20BridgeProxy": "0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0",
"erc20BridgeSampler": "0xd8c38704c9937ea3312de29f824b4ad3450a5e61",
"exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e",
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"exchangeProxyTransformerDeployer": "0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb",
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
"exchangeProxyLiquidityProviderSandbox": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a",
"zrxTreasury": "0x0bb1810061c2f5b2088054ee184e6c79e1591101",
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
"fillQuoteTransformer": "0xd75a9019a2a1782ea670e4f4a55f04b43514ed53",
"positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd"
},
"56": {
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0xccc9769c1a58766e79423a34b2cc5052d65c1983",
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"exchangeProxyTransformerDeployer": "0x8224aa8fe5c9f07d5a59c735386ff6cc6aaeb568",
"exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
"exchangeProxyLiquidityProviderSandbox": "0xde7b2747624a647600fdb349184d0448ab954929",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"wethTransformer": "0xac3d95668c092e895cd83a9cbafe9c7d9906471f",
"payTakerTransformer": "0x4f5e8ca2cadecd4a467ae441e4b03de4278a4574",
"affiliateFeeTransformer": "0x1be34ab9b2acb5c4ddd89454bdce637967e65230",
"fillQuoteTransformer": "0xbd7fd6e116fc8589bb658fba3a2cc6273050bcf2",
"positiveSlippageFeeTransformer": "0x7f5c79ad1788573b1145f4651a248523c54f5d1f"
},
"137": {
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0x4d3e56c56a55d23fc7aa9a9ffad61631cf7d1ae6",
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"exchangeProxyTransformerDeployer": "0xe6d9207df11c55bce2f7a189ae95e3222d5484d3",
"exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
"exchangeProxyLiquidityProviderSandbox": "0x4dd97080adf36103bd3db822f9d3c0e44890fd69",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38",
"payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1",
"affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8",
"fillQuoteTransformer": "0x01c082e47c8dc6dedd01e3fcb07bfd3eb72e044d",
"positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab"
},
"43114": {
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0xca7bab1b2d1ec7d81710b7f9e2ab4e6788930588",
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"exchangeProxyTransformerDeployer": "0xa60b57833dce6260f4f2411c811755dd980bc0a7",
"exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
"exchangeProxyLiquidityProviderSandbox": "0x8953c63d0858d286cc407cd6f8e26b9cbd02a511",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
"payTakerTransformer": "0x898c6fde239d646c73f0a57e3570b6f86a3d62a3",
"affiliateFeeTransformer": "0x34617b855411e52fbc05899435f44cbd0503022c",
"fillQuoteTransformer": "0xcee9118bc14e1fe740c54c754b901629b322ee4f",
"positiveSlippageFeeTransformer": "0x470ba89da18a6db6e8a0567b3c9214b960861857"
},
"250": {
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0xf760c5b88d970d6f97e64e264dac5a3767dafd74",
"exchangeProxy": "0xdef189deaef76e379df891899eb5a00a94cbc250",
"exchangeProxyTransformerDeployer": "0x47f01db18a38261e4cb153bae6db7d3743acb33c",
"exchangeProxyFlashWallet": "0xb4d961671cadfed687e040b076eee29840c142e5",
"exchangeProxyLiquidityProviderSandbox": "0xca64d4225804f2ae069760cb5ff2f1d8bac1c2f9",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"wethTransformer": "0x9b6aa8f26a92108e7d1f66373d757bb955112703",
"payTakerTransformer": "0x32df54951d33d7460e15fa59b1fcc262183ce4c2",
"affiliateFeeTransformer": "0x67efa679a4b56c38713d478e649c88247f4f8e88",
"fillQuoteTransformer": "0xe40f81ef6e9c95ba04c659b8d032eab73152aafd",
"positiveSlippageFeeTransformer": "0xe87d69b285005cc82b53b844322652c49ed64600"
},
"10": {
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0x4200000000000000000000000000000000000006",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0x6d506b2847df0c6f04d2628da1adaf4d8fb2e81b",
"exchangeProxy": "0xdef1abe32c034e558cdd535791643c58a13acc10",
"exchangeProxyTransformerDeployer": "0x3a539ed6bd42de8fbaf3899fb490c792e153d647",
"exchangeProxyFlashWallet": "0xa3128d9b7cca7d5af29780a56abeec12b05a6740",
"exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"wethTransformer": "0x02ce7af6520e2862f961f5d7eda746642865179c",
"payTakerTransformer": "0x085d10a34f14f6a631ea8ff7d016782ee3ffaa11",
"affiliateFeeTransformer": "0x55cf1d7535250db75bf0190493f55781ee583553",
"fillQuoteTransformer": "0x845c75a791cceb1a451f4ca5778c011226dda95c",
"positiveSlippageFeeTransformer": "0xb11e14565dfbeb702dea9bc0cb47f1a8b32f4783"
},
"42161": {
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0x1fe80d5ad9464dba2d60b88e449305f184823f8a",
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"exchangeProxyTransformerDeployer": "0x29f80c1f685e19ae1807063eda432f431ac623d0",
"exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
"exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"wethTransformer": "0x10e968968f49dd66a5efeebbb2edcb9c49c4fc49",
"payTakerTransformer": "0xae3e8cf7bf340d7084f312dfae2aa8b01c885b02",
"affiliateFeeTransformer": "0x05a24978471869327904ea13da3c4322128e2aaa",
"fillQuoteTransformer": "0x466b00a77662245c2cc7b093a7102a687afc16f3",
"positiveSlippageFeeTransformer": "0xd56b9c014b45ed95e2a048a0c28121db30265f13"
}
}

View File

@@ -0,0 +1,23 @@
{
"1": {
"UniswapV2Router": "0xf164fc0ec4e93095b804a4795bbe1e041497b92a"
},
"56": {
"UniswapV2Router": "0x10ed43c718714eb63d5aa57b78b54704e256024e"
},
"137": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"
},
"43114": {
"UniswapV2Router": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10"
},
"250": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"
},
"10": {
"UniswapV2Router": "0x0000000000000000000000000000000000000000"
},
"42161": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"
}
}

View File

@@ -0,0 +1,44 @@
{
"1": {
"WrappedNativeToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"DAI": "0x6b175474e89094c44da98b954eedeac495271d0f",
"USDC": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"USDT": "0xdac17f958d2ee523a2206206994597c13d831ec7"
},
"56": {
"WrappedNativeToken": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"DAI": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3",
"USDC": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
"USDT": "0x55d398326f99059ff775485246999027b3197955"
},
"137": {
"WrappedNativeToken": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270",
"DAI": "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063",
"USDC": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
"USDT": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f"
},
"43114": {
"WrappedNativeToken": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
"DAI": "0xd586e7f844cea2f87f50152665bcbc2c279d8d70",
"USDC": "0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664",
"USDT": "0xc7198437980c041c805A1EDcbA50c1Ce5db95118"
},
"250": {
"WrappedNativeToken": "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83",
"DAI": "0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e",
"USDC": "0x04068da6c83afcfa0e13ba15a6696662335d5b75",
"USDT": "0x049d68029688eabf473097a2fc38ef61633a3c7a"
},
"10": {
"WrappedNativeToken": "0x4200000000000000000000000000000000000006",
"DAI": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1",
"USDC": "0x7f5c764cbc14f9669b88837ca1490cca17c31607",
"USDT": "0x94b008aa00579c1307b0ef2c499ad98a8ce58e58"
},
"42161": {
"WrappedNativeToken": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
"DAI": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1",
"USDC": "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8",
"USDT": "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"
}
}

View File

@@ -0,0 +1,111 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "./utils/ForkUtils.sol";
import "./utils/TestUtils.sol";
import "src/IZeroEx.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "src/features/TransformERC20Feature.sol";
import "src/external/TransformerDeployer.sol";
import "src/transformers/WethTransformer.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "src/transformers/bridges/BridgeProtocols.sol";
import "src/transformers/bridges/EthereumBridgeAdapter.sol";
import "src/transformers/bridges/PolygonBridgeAdapter.sol";
import "src/transformers/bridges/ArbitrumBridgeAdapter.sol";
import "src/transformers/bridges/OptimismBridgeAdapter.sol";
import "src/transformers/bridges/AvalancheBridgeAdapter.sol";
import "src/transformers/bridges/FantomBridgeAdapter.sol";
import "src/transformers/bridges/CeloBridgeAdapter.sol";
import "src/features/OtcOrdersFeature.sol";
import "forge-std/StdJson.sol";
contract transformERC20Tests is Test, ForkUtils, TestUtils {
//use forge-std json library for strings
using stdJson for string;
//utility mapping to get chainId by name
mapping(string => string) public chainsByChainId;
//utility mapping to get indexingChainId by Chain
mapping(string => string) public indexChainsByChain;
string json;
function setUp() public {
//get out addresses.json file that defines contract addresses for each chain we are currently deployed on
string memory root = vm.projectRoot();
string memory path = string(abi.encodePacked(root, "/", "contracts/test/foundry/addresses/addresses.json"));
json = vm.readFile(path);
createForks();
for (uint256 i = 0; i < chains.length; i++) {
chainsByChainId[chains[i]] = chainIds[i];
indexChainsByChain[chains[i]] = indexChainIds[i];
bytes memory details = json.parseRaw(indexChainIds[i]);
addresses = abi.decode(details, (Addresses));
}
}
function testTransformERC20Forked() public {
log_string("TransformERC20Tests");
for (uint256 i = 0; i < chains.length; i++) {
vm.selectFork(forkIds[chains[i]]);
log_named_string(" Selecting Fork On", chains[i]);
_wrapNativeToken(chains[i], indexChainsByChain[chains[i]]);
_swapERC20ForERC20(chains[i], indexChainsByChain[chains[i]]);
//_transformERC20Forked(chains[i], indexChainsByChain[chains[i]]);
}
}
function logAddresses(string memory chainName, string memory chainId) public {
bytes memory details = json.parseRaw(chainId);
addresses = abi.decode(details, (Addresses));
}
function _wrapNativeToken(string memory chainName, string memory chainId) public onlyForked {
bytes memory details = json.parseRaw(chainId);
addresses = abi.decode(details, (Addresses));
vm.deal(address(this), 1e19);
emit log_string("-----Preparing ETH->WETH transformation through TransformERC20()-----");
emit log_string(" --Building Up Transformations--");
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
emit log_named_address(
" Finding TransformerDeployer nonce @", address(addresses.exchangeProxyTransformerDeployer)
);
emit log_named_uint(
" Deployer nonce",
_findTransformerNonce(
address(addresses.wethTransformer), address(addresses.exchangeProxyTransformerDeployer)
)
);
transformations[0].deploymentNonce = _findTransformerNonce(
address(addresses.wethTransformer), address(addresses.exchangeProxyTransformerDeployer)
);
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
emit log_string(" ---Calling TransformERC20()---");
uint256 balanceETHBefore = address(this).balance;
uint256 balanceWETHBefore = IERC20TokenV06(addresses.etherToken).balanceOf(address(this));
IZeroEx(payable(addresses.exchangeProxy)).transformERC20{value: 1e18}(
// input token
IERC20TokenV06(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// output token
IERC20TokenV06(address(addresses.etherToken)),
// input token amount
1e18,
// min output token amount
1e18,
// list of transform
transformations
);
log_named_uint(" NativeAsset balance before", balanceETHBefore);
log_named_uint(" ERC-20 balance before", balanceWETHBefore);
log_named_uint(" NativeAsset balance after", balanceETHBefore - address(this).balance);
log_named_uint(" ERC-20 balance after", IERC20TokenV06(addresses.etherToken).balanceOf(address(this)) - balanceWETHBefore);
}
}

View File

@@ -21,11 +21,69 @@ pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
<<<<<<< HEAD
=======
import "src/features/TransformERC20Feature.sol";
import "src/external/TransformerDeployer.sol";
import "src/transformers/WethTransformer.sol";
import "src/transformers/FillQuoteTransformer.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "src/transformers/bridges/BridgeProtocols.sol";
import "src/transformers/bridges/EthereumBridgeAdapter.sol";
import "src/transformers/bridges/PolygonBridgeAdapter.sol";
import "src/transformers/bridges/BSCBridgeAdapter.sol";
import "src/transformers/bridges/ArbitrumBridgeAdapter.sol";
import "src/transformers/bridges/OptimismBridgeAdapter.sol";
import "src/transformers/bridges/AvalancheBridgeAdapter.sol";
import "src/transformers/bridges/FantomBridgeAdapter.sol";
import "src/transformers/bridges/CeloBridgeAdapter.sol";
import "src/IZeroEx.sol";
//contract-addresses/addresses.json interfaces
//need to be alphebetized in solidity but not in addresses.json
struct Addresses {
address affiliateFeeTransformer;
address erc20BridgeProxy;
address erc20BridgeSampler;
address etherToken;
address payable exchangeProxy;
address exchangeProxyFlashWallet;
address exchangeProxyGovernor;
address exchangeProxyLiquidityProviderSandbox;
address exchangeProxyTransformerDeployer;
address fillQuoteTransformer;
address payTakerTransformer;
address positiveSlippageFeeTransformer;
address staking;
address stakingProxy;
address wethTransformer;
address zeroExGovernor;
address zrxToken;
address zrxTreasury;
address zrxVault;
}
struct TokenAddresses {
IERC20TokenV06 DAI;
IERC20TokenV06 USDC;
IERC20TokenV06 USDT;
IEtherTokenV06 WrappedNativeToken;
}
struct LiquiditySources {
address UniswapV2Router;
}
interface IFQT{
function bridgeAdapter() external returns (address);
}
>>>>>>> 725dfe4db (working bridge Fills through weth transformer)
contract ForkUtils is Test {
/// Only run this function if the block number
// is greater than some constant for Ethereum Mainnet
<<<<<<< HEAD
modifier onlyForked {
if (block.number >= 14206900) {
_;
@@ -34,3 +92,112 @@ contract ForkUtils is Test {
}
}
}
=======
string addressesJson;
string tokensJson;
string sourcesJson;
function createForks() public returns (uint256[] memory) {
for (uint256 i = 0; i < chains.length; i++) {
forkIds[chains[i]] = vm.createFork(vm.rpcUrl(chains[i]), blockNumber[i]);
}
}
function readLiquiditySourceAddresses() public returns (string memory) {
string memory root = vm.projectRoot();
string memory path = string(abi.encodePacked(root, "/", "contracts/test/foundry/addresses/sourceAddresses.json"));
sourcesJson = vm.readFile(path);
return vm.readFile(path);
}
function getLiquiditySourceAddresses(uint index) public returns (LiquiditySources memory sources ) {
readLiquiditySourceAddresses();
bytes memory liquiditySources = sourcesJson.parseRaw(indexChainIds[index]);
return abi.decode(liquiditySources, (LiquiditySources));
}
function readAddresses() public returns (string memory){
string memory root = vm.projectRoot();
string memory path = string(abi.encodePacked(root, "/", "contracts/test/foundry/addresses/addresses.json"));
addressesJson = vm.readFile(path);
return vm.readFile(path);
}
function getContractAddresses(uint index) public returns (Addresses memory addresses){
readAddresses();
bytes memory contractAddresses = addressesJson.parseRaw(indexChainIds[index]);
return abi.decode(contractAddresses, (Addresses));
//log_named_address("WETH/NATIVE_ASSET", address(tokens.WrappedNativeToken));
}
function readTokens() public returns (string memory){
string memory root = vm.projectRoot();
string memory path = string(abi.encodePacked(root, "/", "contracts/test/foundry/addresses/tokenAddresses.json"));
tokensJson = vm.readFile(path);
return vm.readFile(path);
}
function getTokens(uint index) public returns (TokenAddresses memory addresses){
readTokens();
bytes memory chainTokens = tokensJson.parseRaw(indexChainIds[index]);
return abi.decode(chainTokens, (TokenAddresses));
//log_named_address("WETH/NATIVE_ASSET", address(tokens.WrappedNativeToken));
}
function createBridgeAdapter(IEtherTokenV06 weth) public returns(IBridgeAdapter bridgeAdapter) {
uint chainId;
assembly {
chainId := chainid()
}
if(chainId == 1) {return IBridgeAdapter(new EthereumBridgeAdapter(weth));}
else if( chainId == 56){ return IBridgeAdapter(new BSCBridgeAdapter(weth));}
else if( chainId == 137){return IBridgeAdapter(new PolygonBridgeAdapter(weth));}
else if( chainId == 43114){return IBridgeAdapter(new AvalancheBridgeAdapter(weth));}
else if( chainId == 250){return IBridgeAdapter(new FantomBridgeAdapter(weth));}
else if( chainId == 10){return IBridgeAdapter(new OptimismBridgeAdapter(weth));}
else if( chainId == 42161){return IBridgeAdapter(new ArbitrumBridgeAdapter(weth));}
}
function labelAddresses(string memory chainName, string memory chainId, TokenAddresses memory tokens, Addresses memory addresses, LiquiditySources memory sources) public {
log_named_string(" Using contract addresses on chain",chainName);
// log_named_address(" zeroEx/exchangeProxy",addresses.exchangeProxy);
// log_named_address(" zeroEx/fillQuoteTransformer",addresses.fillQuoteTransformer);
// log_named_address(" zeroEx/payTakerTransformer",addresses.payTakerTransformer);
// log_named_address(" zeroEx/positiveSlippageFeeTransformer",addresses.positiveSlippageFeeTransformer);
// log_named_address(" zeroEx/wethTransformer",addresses.wethTransformer);
// vm.label(addresses.affiliateFeeTransformer, "zeroEx/affiliateFeeTransformer");
vm.label(addresses.erc20BridgeProxy, "zeroEx/erc20BridgeProxy");
vm.label(addresses.erc20BridgeSampler, "zeroEx/erc20BridgeSampler");
vm.label(addresses.etherToken, "zeroEx/etherToken");
vm.label(addresses.exchangeProxy, "zeroEx/exchangeProxy");
vm.label(addresses.exchangeProxyFlashWallet, "zeroEx/exchangeProxyFlashWallet");
vm.label(addresses.exchangeProxyGovernor, "zeroEx/exchangeProxyGovernor");
vm.label(addresses.exchangeProxyLiquidityProviderSandbox, "zeroEx/exchangeProxyLiquidityProviderSandbox");
vm.label(addresses.exchangeProxyTransformerDeployer, "zeroEx/exchangeProxyTransformerDeployer");
vm.label(addresses.fillQuoteTransformer, "zeroEx/fillQuoteTransformer");
vm.label(addresses.payTakerTransformer, "zeroEx/payTakerTransformer");
vm.label(addresses.positiveSlippageFeeTransformer, "zeroEx/positiveSlippageFeeTransformer");
vm.label(addresses.staking, "zeroEx/staking");
vm.label(addresses.stakingProxy, "zeroEx/stakingProxy");
vm.label(addresses.wethTransformer, "zeroEx/wethTransformer");
vm.label(addresses.zeroExGovernor, "zeroEx/zeroExGovernor");
vm.label(addresses.zrxToken, "zeroEx/zrxToken");
vm.label(addresses.zrxTreasury, "zeroEx/zrxTreasury");
vm.label(addresses.zrxVault, "zeroEx/zrxVault");
vm.label(address(tokens.WrappedNativeToken), "WrappedNativeToken");
vm.label(address(tokens.USDT), "USDT");
vm.label(address(tokens.USDC), "USDC");
vm.label(address(tokens.DAI), "DAI");
vm.label(address(sources.UniswapV2Router), "UniswapRouter");
}
modifier onlyForked() {
if (block.number >= 15000000) {
_;
} else {
emit log_string("Requires fork mode, skipping");
}
}
}
>>>>>>> 725dfe4db (working bridge Fills through weth transformer)

View File

@@ -60,6 +60,7 @@ contract TestUtils is Test {
return nstr;
}
<<<<<<< HEAD
function _findTransformerNonce(
address transformer,
address deployer
@@ -68,6 +69,9 @@ contract TestUtils is Test {
pure
returns (uint32)
{
=======
function _findTransformerNonce(address transformer, address deployer) internal returns (uint32) {
>>>>>>> 725dfe4db (working bridge Fills through weth transformer)
address current;
for (uint32 i = 0; i < 1024; i++) {
current = LibERC20Transformer.getDeployedAddress(deployer, i);