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

157 lines
6.4 KiB
Solidity

// 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/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 RfqtV2Test is Test, ForkUtils, TestUtils {
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)
);
swapWithOtcOrder(getTokens(i), getContractAddresses(i), getLiquiditySourceAddresses(i));
}
}
/* solhint-disable function-max-lines */
function swapWithOtcOrder(
TokenAddresses memory tokens,
ContractAddresses memory addresses,
LiquiditySources memory sources
) public onlyForked {
IZERO_EX = IZeroEx(addresses.exchangeProxy);
address USDC = address(tokens.USDC);
// Create our list of transformations, let's do WethTransformer and FillQuoteTransformer
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
// Use our cheeky search helper to find the nonce rather than hardcode it
transformations[0].deploymentNonce = _findTransformerNonce(
address(addresses.transformers.wethTransformer),
address(addresses.exchangeProxyTransformerDeployer)
);
emit log_named_uint(" WethTransformer nonce", transformations[0].deploymentNonce);
createNewFQT(tokens.WrappedNativeToken, addresses.exchangeProxy, addresses.exchangeProxyTransformerDeployer);
// Set the first transformation to transform ETH into WETH
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
transformations[1].deploymentNonce = _findTransformerNonce(
address(fillQuoteTransformer),
address(addresses.exchangeProxyTransformerDeployer)
);
log_named_uint(" FillQuoteTransformer nonce", transformations[1].deploymentNonce);
// Set up the FillQuoteTransformer data
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
fqtData.sellToken = IERC20Token(address(tokens.WrappedNativeToken));
fqtData.buyToken = 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[](1);
fqtData.fillSequence[0] = FillQuoteTransformer.OrderType.Otc;
// The amount to fill
fqtData.fillAmount = 1e18;
// Now let's set up an OTC fill
fqtData.otcOrders = new FillQuoteTransformer.OtcOrderInfo[](1);
LibNativeOrder.OtcOrder memory order;
FillQuoteTransformer.OtcOrderInfo memory orderInfo;
order.makerToken = fqtData.buyToken;
order.takerToken = fqtData.sellToken;
order.makerAmount = 1e18;
order.takerAmount = 1e18;
uint privateKey;
(order.maker, privateKey) = _getSigner();
deal(address(order.makerToken), order.maker, 1e20);
vm.prank(order.maker);
IERC20Token(tokens.USDC).approve(address(addresses.exchangeProxy), 1e20);
vm.prank(order.maker);
order.taker = address(0);
order.txOrigin = address(tx.origin);
order.expiryAndNonce = encodeExpiryAndNonce(order.maker);
orderInfo.order = order;
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, IZERO_EX.getOtcOrderHash(order));
// 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.takerAmount = 1e18;
// Set this low as the price of ETH/USDC can change
order.makerAmount = 1e18;
orderInfo.signature.signatureType = LibSignature.SignatureType.EIP712;
orderInfo.signature.v = v;
orderInfo.signature.r = r;
orderInfo.signature.s = s;
orderInfo.maxTakerTokenFillAmount = 1e18;
fqtData.otcOrders[0] = orderInfo;
transformations[1].data = abi.encode(fqtData);
log_string(" Successful fill, makerTokens bought");
IZERO_EX.transformERC20{value: 1e18}(
// input token
IERC20Token(LibERC20Transformer.ETH_TOKEN_ADDRESS),
// output token
tokens.USDC,
// input token amount
order.takerAmount,
// min output token amount
order.makerAmount,
// list of transform
transformations
);
assert(tokens.USDC.balanceOf(address(this)) > 0);
}
/* solhint-enable function-max-lines */
function encodeExpiryAndNonce(address maker) public returns (uint256) {
uint256 expiry = (block.timestamp + 120) << 192;
uint256 bucket = 0 << 128;
uint256 nonce = vm.getNonce(maker);
return expiry | bucket | nonce;
}
}