Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Swap helpers to always swap through ZETA #163

Merged
merged 7 commits into from
Aug 8, 2024
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
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
Loading