Skip to content

Commit

Permalink
feat: Swap helpers to always swap through ZETA (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukema95 authored Aug 8, 2024
1 parent e35a767 commit f59445c
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 2 deletions.
84 changes: 84 additions & 0 deletions contracts/SwapHelperLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol";
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IZRC20.sol";
import "@zetachain/protocol-contracts/contracts/zevm/SystemContract.sol";
import "./shared/libraries/UniswapV2Library.sol";

library SwapHelperLib {
uint16 internal constant MAX_DEADLINE = 200;
Expand All @@ -17,6 +18,8 @@ library SwapHelperLib {

error CantBeZeroAddress();

error InvalidPathLength();

// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(
address tokenA,
Expand Down Expand Up @@ -85,13 +88,77 @@ library SwapHelperLib {
IZRC20(zrc20B).balanceOf(uniswapPool) > 0;
}

function _isSufficientLiquidity(
address uniswapV2Factory,
uint256 amountIn,
uint256 minAmountOut,
address[] memory path
) internal view returns (bool) {
if (path.length != 2) revert InvalidPathLength();
bool existsPairPool = _existsPairPool(
uniswapV2Factory,
path[0],
path[1]
);
if (!existsPairPool) {
return false;
}
uint256[] memory amounts = UniswapV2Library.getAmountsOut(uniswapV2Factory, amountIn, path);
return amounts[amounts.length - 1] >= minAmountOut;
}

function swapExactTokensForTokens(
SystemContract systemContract,
address zrc20,
uint256 amount,
address targetZRC20,
uint256 minAmountOut
) internal returns (uint256) {

address[] memory path;
path = new address[](2);
path[0] = zrc20;
path[1] = targetZRC20;

bool isSufficientLiquidity = _isSufficientLiquidity(
systemContract.uniswapv2FactoryAddress(),
amount,
minAmountOut,
path
);

bool isZETA = targetZRC20 == systemContract.wZetaContractAddress() || zrc20 == systemContract.wZetaContractAddress();

if (!isSufficientLiquidity && !isZETA) {
path = new address[](3);
path[0] = zrc20;
path[1] = systemContract.wZetaContractAddress();
path[2] = targetZRC20;
}

IZRC20(zrc20).approve(
address(systemContract.uniswapv2Router02Address()),
amount
);
uint256[] memory amounts = IUniswapV2Router01(
systemContract.uniswapv2Router02Address()
).swapExactTokensForTokens(
amount,
minAmountOut,
path,
address(this),
block.timestamp + MAX_DEADLINE
);
return amounts[path.length - 1];
}

function swapExactTokensForTokensDirectly(
SystemContract systemContract,
address zrc20,
uint256 amount,
address targetZRC20,
uint256 minAmountOut
) internal returns (uint256) {
bool existsPairPool = _existsPairPool(
systemContract.uniswapv2FactoryAddress(),
zrc20,
Expand Down Expand Up @@ -166,4 +233,21 @@ library SwapHelperLib {
);
return amounts[0];
}

function getMinOutAmount(SystemContract systemContract, address zrc20, address target, uint256 amountIn) public view returns (uint256 minOutAmount) {
address[] memory path;

path = new address[](2);
path[0] = zrc20;
path[1] = target;
uint[] memory amounts1 = UniswapV2Library.getAmountsOut(systemContract.uniswapv2FactoryAddress(), amountIn, path);

path = new address[](3);
path[0] = zrc20;
path[1] = systemContract.wZetaContractAddress();
path[2] = target;
uint[] memory amounts2 = UniswapV2Library.getAmountsOut(systemContract.uniswapv2FactoryAddress(), amountIn, path);

minOutAmount = amounts1[amounts1.length - 1] > amounts2[amounts2.length - 1] ? amounts1[amounts1.length - 1] : amounts2[amounts2.length - 1];
}
}
59 changes: 58 additions & 1 deletion typechain-types/contracts/SwapHelperLib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
PopulatedTransaction,
Expand All @@ -22,11 +23,23 @@ import type {

export interface SwapHelperLibInterface extends utils.Interface {
functions: {
"getMinOutAmount(SystemContract,address,address,uint256)": FunctionFragment;
"uniswapv2PairFor(address,address,address)": FunctionFragment;
};

getFunction(nameOrSignatureOrTopic: "uniswapv2PairFor"): FunctionFragment;
getFunction(
nameOrSignatureOrTopic: "getMinOutAmount" | "uniswapv2PairFor"
): FunctionFragment;

encodeFunctionData(
functionFragment: "getMinOutAmount",
values: [
PromiseOrValue<string>,
PromiseOrValue<string>,
PromiseOrValue<string>,
PromiseOrValue<BigNumberish>
]
): string;
encodeFunctionData(
functionFragment: "uniswapv2PairFor",
values: [
Expand All @@ -36,6 +49,10 @@ export interface SwapHelperLibInterface extends utils.Interface {
]
): string;

decodeFunctionResult(
functionFragment: "getMinOutAmount",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "uniswapv2PairFor",
data: BytesLike
Expand Down Expand Up @@ -71,6 +88,14 @@ export interface SwapHelperLib extends BaseContract {
removeListener: OnEvent<this>;

functions: {
getMinOutAmount(
systemContract: PromiseOrValue<string>,
zrc20: PromiseOrValue<string>,
target: PromiseOrValue<string>,
amountIn: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<[BigNumber] & { minOutAmount: BigNumber }>;

uniswapv2PairFor(
factory: PromiseOrValue<string>,
tokenA: PromiseOrValue<string>,
Expand All @@ -79,6 +104,14 @@ export interface SwapHelperLib extends BaseContract {
): Promise<[string] & { pair: string }>;
};

getMinOutAmount(
systemContract: PromiseOrValue<string>,
zrc20: PromiseOrValue<string>,
target: PromiseOrValue<string>,
amountIn: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<BigNumber>;

uniswapv2PairFor(
factory: PromiseOrValue<string>,
tokenA: PromiseOrValue<string>,
Expand All @@ -87,6 +120,14 @@ export interface SwapHelperLib extends BaseContract {
): Promise<string>;

callStatic: {
getMinOutAmount(
systemContract: PromiseOrValue<string>,
zrc20: PromiseOrValue<string>,
target: PromiseOrValue<string>,
amountIn: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<BigNumber>;

uniswapv2PairFor(
factory: PromiseOrValue<string>,
tokenA: PromiseOrValue<string>,
Expand All @@ -98,6 +139,14 @@ export interface SwapHelperLib extends BaseContract {
filters: {};

estimateGas: {
getMinOutAmount(
systemContract: PromiseOrValue<string>,
zrc20: PromiseOrValue<string>,
target: PromiseOrValue<string>,
amountIn: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<BigNumber>;

uniswapv2PairFor(
factory: PromiseOrValue<string>,
tokenA: PromiseOrValue<string>,
Expand All @@ -107,6 +156,14 @@ export interface SwapHelperLib extends BaseContract {
};

populateTransaction: {
getMinOutAmount(
systemContract: PromiseOrValue<string>,
zrc20: PromiseOrValue<string>,
target: PromiseOrValue<string>,
amountIn: PromiseOrValue<BigNumberish>,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;

uniswapv2PairFor(
factory: PromiseOrValue<string>,
tokenA: PromiseOrValue<string>,
Expand Down
Loading

0 comments on commit f59445c

Please sign in to comment.