Skip to content
This repository was archived by the owner on Nov 11, 2022. It is now read-only.

make findOptimalSwap view #30

Merged
merged 1 commit into from
Aug 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/CowSwapSeller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct Quote {
uint256[] poolFees; // specific pool fees involved in the optimal swap path, typically in Uniswap V3
}
interface OnChainPricing {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external returns (Quote memory);
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (Quote memory);
}
// END OnchainPricing

Expand Down
4 changes: 2 additions & 2 deletions contracts/OnChainPricingMainnet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ contract OnChainPricingMainnet {
/// @param tokenIn - The token you want to sell
/// @param tokenOut - The token you want to buy
/// @param amountIn - The amount of token you want to sell
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external virtual returns (Quote memory) {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view virtual returns (Quote memory) {
return _findOptimalSwap(tokenIn, tokenOut, amountIn);
}

/// @dev View function for testing the routing of the strategy
/// See {findOptimalSwap}
function _findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) internal returns (Quote memory) {
function _findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) internal view returns (Quote memory) {
bool wethInvolved = (tokenIn == WETH || tokenOut == WETH);
uint256 length = wethInvolved? 5 : 7; // Add length you need

Expand Down
2 changes: 1 addition & 1 deletion contracts/OnChainPricingMainnetLenient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract OnChainPricingMainnetLenient is OnChainPricingMainnet {
// === PRICING === //

/// @dev View function for testing the routing of the strategy
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external override returns (Quote memory q) {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view override returns (Quote memory q) {
q = _findOptimalSwap(tokenIn, tokenOut, amountIn);
q.amountOut = q.amountOut * (MAX_BPS - slippage) / MAX_BPS;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/OnChainSwapMainnet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct Quote {
}

interface OnChainPricing {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external returns (Quote memory);
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (Quote memory);
}

/// @dev Mainnet Version of swap for various on-chain dex
Expand Down
42 changes: 42 additions & 0 deletions contracts/tests/PricerWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma solidity 0.8.10;
pragma experimental ABIEncoderV2;

enum SwapType {
CURVE, //0
UNIV2, //1
SUSHI, //2
UNIV3, //3
UNIV3WITHWETH, //4
BALANCER, //5
BALANCERWITHWETH //6
}

// Onchain Pricing Interface
struct Quote {
SwapType name;
uint256 amountOut;
bytes32[] pools; // specific pools involved in the optimal swap path
uint256[] poolFees; // specific pool fees involved in the optimal swap path, typically in Uniswap V3
}
interface OnChainPricing {
function isPairSupported(address tokenIn, address tokenOut, uint256 amountIn) external view returns (bool);
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (Quote memory);
}
// END OnchainPricing

contract PricerWrapper {
address public pricer;
constructor(address _pricer) {
pricer = _pricer;
}

function isPairSupported(address tokenIn, address tokenOut, uint256 amountIn) external view returns (bool) {
return OnChainPricing(pricer).isPairSupported(tokenIn, tokenOut, amountIn);
}

function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (uint256, Quote memory) {
uint256 _gasBefore = gasleft();
Quote memory q = OnChainPricing(pricer).findOptimalSwap(tokenIn, tokenOut, amountIn);
return (_gasBefore - gasleft(), q);
}
}
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@
def swapexecutor():
return OnChainSwapMainnet.deploy({"from": accounts[0]})

@pytest.fixture
def pricerwrapper():
univ3simulator = UniV3SwapSimulator.deploy({"from": accounts[0]})
balancerV2Simulator = BalancerSwapSimulator.deploy({"from": accounts[0]})
pricer = OnChainPricingMainnet.deploy(univ3simulator.address, balancerV2Simulator.address, {"from": accounts[0]})
return PricerWrapper.deploy(pricer.address, {"from": accounts[0]})

@pytest.fixture
def pricer():
univ3simulator = UniV3SwapSimulator.deploy({"from": accounts[0]})
Expand Down
67 changes: 37 additions & 30 deletions tests/gas_benchmark/benchmark_pricer_gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,80 +8,87 @@
Rename the file to test_benchmark_pricer_gas.py to make this part of the testing suite if required
"""

def test_gas_only_uniswap_v2(oneE18, weth, pricer):
def test_gas_only_uniswap_v2(oneE18, weth, pricerwrapper):
pricer = pricerwrapper
token = "0xBC7250C8c3eCA1DfC1728620aF835FCa489bFdf3" # some swap (GM-WETH) only in Uniswap V2
## 1e18
sell_count = 100000000
sell_amount = sell_count * 1000000000 ## 1e9

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert tx.return_value[0] == 1 ## UNIV2
assert tx.return_value[1] > 0
assert tx.gas_used <= 80000 ## 73925 in test simulation
assert tx[1][0] == 1 ## UNIV2
assert tx[1][1] > 0
assert tx[0] <= 80000 ## 73925 in test simulation

def test_gas_uniswap_v2_sushi(oneE18, weth, pricer):
def test_gas_uniswap_v2_sushi(oneE18, weth, pricerwrapper):
pricer = pricerwrapper
token = "0x2e9d63788249371f1DFC918a52f8d799F4a38C94" # some swap (TOKE-WETH) only in Uniswap V2 & SushiSwap
## 1e18
sell_count = 5000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert (tx.return_value[0] == 1 or tx.return_value[0] == 2) ## UNIV2 or SUSHI
assert tx.return_value[1] > 0
assert tx.gas_used <= 90000 ## 83158 in test simulation
assert (tx[1][0] == 1 or tx[1][0] == 2) ## UNIV2 or SUSHI
assert tx[1][1] > 0
assert tx[0] <= 90000 ## 83158 in test simulation

def test_gas_only_balancer_v2(oneE18, weth, aura, pricer):
def test_gas_only_balancer_v2(oneE18, weth, aura, pricerwrapper):
pricer = pricerwrapper
token = aura # some swap (AURA-WETH) only in Balancer V2
## 1e18
sell_count = 2000
sell_count = 8000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert tx.return_value[0] == 5 ## BALANCER
assert tx.return_value[1] > 0
assert tx.gas_used <= 110000 ## 101190 in test simulation
assert tx[1][0] == 5 ## BALANCER
assert tx[1][1] > 0
assert tx[0] <= 110000 ## 101190 in test simulation

def test_gas_only_balancer_v2_with_weth(oneE18, wbtc, aura, pricer):
def test_gas_only_balancer_v2_with_weth(oneE18, wbtc, aura, pricerwrapper):
pricer = pricerwrapper
token = aura # some swap (AURA-WETH-WBTC) only in Balancer V2 via WETH in between as connector
## 1e18
sell_count = 2000
sell_count = 8000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, wbtc.address, sell_amount)
assert tx.return_value[0] == 6 ## BALANCERWITHWETH
assert tx.return_value[1] > 0
assert tx.gas_used <= 170000 ## 161690 in test simulation
assert tx[1][0] == 6 ## BALANCERWITHWETH
assert tx[1][1] > 0
assert tx[0] <= 170000 ## 161690 in test simulation

def test_gas_only_uniswap_v3(oneE18, weth, pricer):
def test_gas_only_uniswap_v3(oneE18, weth, pricerwrapper):
pricer = pricerwrapper
token = "0xf4d2888d29D722226FafA5d9B24F9164c092421E" # some swap (LOOKS-WETH) only in Uniswap V3
## 1e18
sell_count = 600000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert tx.return_value[0] == 3 ## UNIV3
assert tx.return_value[1] > 0
assert tx.gas_used <= 160000 ## 158204 in test simulation
assert tx[1][0] == 3 ## UNIV3
assert tx[1][1] > 0
assert tx[0] <= 160000 ## 158204 in test simulation

def test_gas_only_uniswap_v3_with_weth(oneE18, wbtc, pricer):
def test_gas_only_uniswap_v3_with_weth(oneE18, wbtc, pricerwrapper):
pricer = pricerwrapper
token = "0xf4d2888d29D722226FafA5d9B24F9164c092421E" # some swap (LOOKS-WETH-WBTC) only in Uniswap V3 via WETH in between as connector
## 1e18
sell_count = 600000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, wbtc.address, sell_amount)
assert tx.return_value[0] == 4 ## UNIV3WITHWETH
assert tx.return_value[1] > 0
assert tx.gas_used <= 230000 ## 227498 in test simulation
assert tx[1][0] == 4 ## UNIV3WITHWETH
assert tx[1][1] > 0
assert tx[0] <= 230000 ## 227498 in test simulation

def test_gas_almost_everything(oneE18, wbtc, weth, pricer):
def test_gas_almost_everything(oneE18, wbtc, weth, pricerwrapper):
pricer = pricerwrapper
token = weth # some swap (WETH-WBTC) almost in every DEX, the most gas-consuming scenario
## 1e18
sell_count = 10
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, wbtc.address, sell_amount)
assert (tx.return_value[0] <= 3 or tx.return_value[0] == 5) ## CURVE or UNIV2 or SUSHI or UNIV3 or BALANCER
assert tx.return_value[1] > 0
assert tx.gas_used <= 210000 ## 200229 in test simulation
assert (tx[1][0] <= 3 or tx[1][0] == 5) ## CURVE or UNIV2 or SUSHI or UNIV3 or BALANCER
assert tx[1][1] > 0
assert tx[0] <= 210000 ## 200229 in test simulation

7 changes: 4 additions & 3 deletions tests/gas_benchmark/benchmark_token_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@
]

@pytest.mark.parametrize("token,count", TOP_DECIMAL18_TOKENS)
def test_token_decimal18(oneE18, weth, token, count, pricer):
def test_token_decimal18(oneE18, weth, token, count, pricerwrapper):
pricer = pricerwrapper
sell_token = token
## 1e18
sell_count = count
sell_amount = sell_count * oneE18 ## 1e18

quote = pricer.findOptimalSwap.call(sell_token, weth.address, sell_amount)
assert quote[1] > 0
quote = pricer.findOptimalSwap(sell_token, weth.address, sell_amount)
assert quote[1][1] > 0

Loading