/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Contract, ethers, Wallet, BigNumber, BigNumberish } from "ethers"; import IERC20 from "../abi/IERC20.json"; import IERC721 from "../abi/IERC721.json"; import IMiniChefV2 from "../abi/IMiniChefV2.json"; import ILendingPool from "../abi/ILendingPool.json"; import IUniswapV2Router from "../abi/IUniswapV2Router.json"; import INonfungiblePositionManager from "../abi/INonfungiblePositionManager.json"; import IAaveIncentivesController from "../abi/IAaveIncentivesController.json"; import ILiquidityGaugeV4 from "../abi/ILiquidityGaugeV4.json"; import IBalancerRewardsGauge from "../abi/IBalancerRewardsGauge.json"; import { MaxUint128, nonfungiblePositionManagerAddress, routerAddress, gpv2SettlementAddress, stakingAddress, limitOrderAddress } from "../config"; import { Dapp, Transaction, FundComposition, AssetEnabled, Network, LyraOptionMarket, LyraOptionType, LyraTradeType, LyraPosition, SDKOptions, LimitOrderInfo } from "../types"; import { Utils } from "./utils"; import { getDecreaseLiquidityTxData, getIncreaseLiquidityTxData, getUniswapV3MintTxData } from "../services/uniswap/V3Liquidity"; import { getEasySwapperTxData } from "../services/toros/easySwapper"; import { getAaveV3ClaimTxData } from "../services/aave/incentives"; import { getClOwner, getVelodromeAddLiquidityTxData, getVelodromeRemoveLiquidityTxData } from "../services/velodrome/liquidity"; import { getVelodromeClaimTxData, getVelodromeCLClaimTxData, getVelodromeStakeTxData } from "../services/velodrome/staking"; import { getLyraOptionTxData } from "../services/lyra/trade"; import { getOptionPositions } from "../services/lyra/positions"; import { getDeadline } from "../utils/deadline"; import { getOneInchSwapTxData } from "../services/oneInch"; import { getPoolTxOrGasEstimate, isSdkOptionsBoolean } from "../utils/contract"; import { cancelOrderViaFlatMoney, mintUnitViaFlatMoney, redeemUnitViaFlatMoney } from "../services/flatmoney/stableLp"; import { getCompoundV3LendTxData, getCompoundV3WithdrawTxData } from "../services/compound/lending"; import { getCompoundV3ClaimTxData } from "../services/compound/rewards"; import { getPancakeHarvestClaimTxData, getPancakeStakeTxData, getPancakeUnStakeTxData } from "../services/pancake/staking"; import { getOdosSwapTxData } from "../services/odos"; import { getPendleMintTxData, getPendleSwapTxData } from "../services/pendle"; import { getCompleteWithdrawalTxData, TrackedAsset } from "../services/toros/completeWithdrawal"; import { getDytmBorrowTxData, getDytmDepositTxData, getDytmRepayTxData, getDytmWithdrawTxData } from "../services/dytm"; import { getCreateLimitOrderTxData, getModifyLimitOrderTxData, getDeleteLimitOrderTxData, getTorosLimitOrder, hasActiveTorosLimitOrder } from "../services/toros/limitOrder"; import { getKyberSwapTxData } from "../services/kyberSwap"; import { getCowSwapTxData } from "../services/cowSwap"; import { getOndoSwapTxData } from "../services/ondo"; import { getClosePositionHyperliquidTxData, getDepositHyperliquidTxData, getLimitOrderHyperliquidTxData, getSendAssetHyperliquidTxData, getWithdrawSpotHyperliquidTxData } from "../services/hyperliquid"; import { CORE_WRITER_ADDRESS, SPOT_DEX_ID } from "../services/hyperliquid/constants"; export class Pool { public readonly poolLogic: Contract; public readonly managerLogic: Contract; public readonly factory: Contract; public readonly signer: Wallet; public readonly address: string; public readonly utils: Utils; public readonly network: Network; public readonly isDhedge: boolean; public constructor( network: Network, signer: Wallet, poolLogic: Contract, mangerLogic: Contract, utils: Utils, factory: Contract, isDhedge = true ) { this.network = network; this.poolLogic = poolLogic; this.address = poolLogic.address; this.managerLogic = mangerLogic; this.signer = signer; this.utils = utils; this.factory = factory; this.isDhedge = isDhedge; } /** * Return the assets with balances and deposit info of a pool * @returns {Promise} Composition of assets with balance, deposit info */ async getComposition(): Promise { const result = await this.managerLogic.getFundComposition(); const fundComposition: FundComposition[] = result[0].map( (item: AssetEnabled, index: string | number) => { const { asset, isDeposit } = item; return { asset: asset, isDeposit: isDeposit, balance: result[1][index], rate: result[2][index] }; } ); return fundComposition; } //Invest functions /** * Approve the asset that can be deposited into a pool * @param {string} asset Address of deposit asset * @param {BigNumber | string} amount Amount to be approved * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async approveDeposit( asset: string, amount: BigNumber | string, options: any = null, estimateGas = false ): Promise { const iERC20 = new ethers.Contract(asset, IERC20.abi, this.signer); if (estimateGas) { return await iERC20.estimateGas.approve(this.address, amount, options); } const tx = await iERC20.approve(this.address, amount, options); return tx; } /** * Deposit asset into a pool * @param {string} asset Address of asset * @param {BigNumber | string} amount Amount to be deposited * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async deposit( asset: string, amount: string | BigNumber, options: any = null, estimateGas = false ): Promise { if (estimateGas) { return await this.poolLogic.estimateGas.deposit(asset, amount, options); } const tx = await this.poolLogic.deposit(asset, amount, options); return tx; } /** * Withdraw assets from a pool * @param fundTokenAmount Amount of pool tokens to be withdrawn * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async withdraw( fundTokenAmount: string | BigNumber, options: any = null, estimateGas = false ): Promise { if (estimateGas) { return await this.poolLogic.estimateGas.withdraw( fundTokenAmount, options ); } const tx = await this.poolLogic.withdraw(fundTokenAmount, options); return tx; } //Manager functions /** * Approve the asset for trading and providing liquidity * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} asset Address of asset * @param {BigNumber | string} Amount to be approved * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async approve( dapp: Dapp, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iERC20 = new ethers.utils.Interface(IERC20.abi); const approveTxData = iERC20.encodeFunctionData("approve", [ routerAddress[this.network][dapp], amount ]); const tx = await getPoolTxOrGasEstimate( this, [asset, approveTxData, options], sdkOptions ); return tx; } /** * Approve the liquidity pool token for staking * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} asset Address of liquidity pool token * @param {BigNumber | string} amount Amount to be approved * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async approveStaking( dapp: Dapp, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iERC20 = new ethers.utils.Interface(IERC20.abi); const approveTxData = iERC20.encodeFunctionData("approve", [ stakingAddress[this.network][dapp], amount ]); const tx = await getPoolTxOrGasEstimate( this, [asset, approveTxData, options], sdkOptions ); return tx; } /** * Approve an asset for the Uniswap V3 NonfungiblePositionManager * (used before mint/increase liquidity calls) * @param {string} asset Address of asset to approve * @param {BigNumber | string} amount Amount to be approved * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async approveUniswapV3Liquidity( asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iERC20 = new ethers.utils.Interface(IERC20.abi); const approveTxData = iERC20.encodeFunctionData("approve", [ nonfungiblePositionManagerAddress[this.network][Dapp.UNISWAPV3], amount ]); const tx = await getPoolTxOrGasEstimate( this, [asset, approveTxData, options], sdkOptions ); return tx; } /** * Approve the asset for provided spender address * @param {string} spender Spender address * @param {string} asset Address of asset * @param {BigNumber | string} amount to be approved * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async approveSpender( spender: string, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iERC20 = new ethers.utils.Interface(IERC20.abi); const approveTxData = iERC20.encodeFunctionData("approve", [ spender, amount ]); const tx = await getPoolTxOrGasEstimate( this, [asset, approveTxData, options], sdkOptions ); return tx; } /** * Approve NFT for provided spender address * @param {string} spender Spender address * @param {string} asset Address of asset * @param {string} tokenId NFT id * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async approveSpenderNFT( spender: string, asset: string, tokenId: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iERC721 = new ethers.utils.Interface(IERC721.abi); const approveTxData = iERC721.encodeFunctionData("approve", [ spender, tokenId ]); const tx = await getPoolTxOrGasEstimate( this, [asset, approveTxData, options], sdkOptions ); return tx; } /** * Trade an asset into another asset * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} assetFrom Asset to trade from * @param {string} assetTo Asset to trade into * @param {BigNumber | string} amountIn Amount * @param {number} slippage Slippage tolerance in % * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async trade( dapp: Dapp, assetFrom: string, assetTo: string, amountIn: BigNumber | string, slippage = 0.5, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let swapTxData: string; let minAmountOut: string | null = null; switch (dapp) { case Dapp.ONEINCH: ({ swapTxData, dstAmount: minAmountOut } = await getOneInchSwapTxData( this, assetFrom, assetTo, amountIn, slippage )); break; case Dapp.BALANCER: swapTxData = await this.utils.getBalancerSwapTx( this, assetFrom, assetTo, amountIn, slippage ); break; case Dapp.TOROS: ({ swapTxData, minAmountOut } = await getEasySwapperTxData( this, assetFrom, assetTo, ethers.BigNumber.from(amountIn), slippage )); break; case Dapp.ODOS: ({ swapTxData, minAmountOut } = await getOdosSwapTxData( this, assetFrom, assetTo, amountIn, slippage )); break; case Dapp.PENDLE: ({ swapTxData, minAmountOut } = await getPendleSwapTxData( this, assetFrom, assetTo, amountIn, slippage )); break; case Dapp.KYBERSWAP: ({ swapTxData, minAmountOut } = await getKyberSwapTxData( this, assetFrom, assetTo, amountIn, slippage )); break; case Dapp.ONDO: ({ swapTxData, minAmountOut } = await getOndoSwapTxData( this, assetFrom, assetTo, amountIn.toString(), slippage )); break; case Dapp.COWSWAP: { const cowSwapEstimateGas = isSdkOptionsBoolean(sdkOptions) ? sdkOptions : sdkOptions.estimateGas; if ( cowSwapEstimateGas || (!isSdkOptionsBoolean(sdkOptions) && sdkOptions.onlyGetTxData) ) { throw new Error( "CowSwap requires two sequential transactions (submit + preSign) and does not support estimateGas or onlyGetTxData" ); } const { encodedTypedData, preSignTxData, minAmountOut: cowMinOut } = await getCowSwapTxData( this, assetFrom, assetTo, amountIn, slippage ); // Tx 1: manager calls submit() directly on TypedStructuredDataValidator (not via pool.execTransaction) const validatorContract = new Contract( routerAddress[this.network][dapp] as string, [ "function submit(address _poolLogic, uint8 _dataType, bytes memory _structuredData) external" ], this.signer ); const submitTx = await validatorContract.submit( this.address, 1 /* COWSWAP_ORDER */, encodedTypedData, ...(options ? [options] : []) ); const submitReceipt = await submitTx.wait(3); if (submitReceipt.status === 0) { return submitReceipt; } // Tx 2: pool.execTransaction → setPreSignature() on GPv2Settlement — guard checks stored digest, solvers execute return getPoolTxOrGasEstimate( this, [ gpv2SettlementAddress[this.network], preSignTxData, options, cowMinOut ], sdkOptions ); } default: const iUniswapV2Router = new ethers.utils.Interface( IUniswapV2Router.abi ); const calculatedMinAmountOut = await this.utils.getMinAmountOut( dapp, assetFrom, assetTo, amountIn, slippage ); swapTxData = iUniswapV2Router.encodeFunctionData(Transaction.SWAP, [ amountIn, calculatedMinAmountOut, [assetFrom, assetTo], this.address, await getDeadline(this) ]); } const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], swapTxData, options, minAmountOut], sdkOptions ); return tx; } /** * Add liquidity to a liquidity pool * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amountA Amount first asset * @param {BigNumber | string} amountB Amount second asset * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async addLiquidity( dapp: Dapp, assetA: string, assetB: string, amountA: BigNumber | string, amountB: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iUniswapV2Router = new ethers.utils.Interface(IUniswapV2Router.abi); const addLiquidityTxData = iUniswapV2Router.encodeFunctionData( Transaction.ADD_LIQUIDITY, [ assetA, assetB, amountA, amountB, 0, 0, this.address, await getDeadline(this) ] ); const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], addLiquidityTxData, options], sdkOptions ); return tx; } /** * Remove liquidity from a liquidity pool * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amount Amount of liquidity pool tokens * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async removeLiquidity( dapp: Dapp, assetA: string, assetB: string, amount: string | BigNumber, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iUniswapV2Router = new ethers.utils.Interface(IUniswapV2Router.abi); const removeLiquidityTxData = iUniswapV2Router.encodeFunctionData( Transaction.REMOVE_LIQUIDITY, [assetA, assetB, amount, 0, 0, this.address, await getDeadline(this)] ); const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], removeLiquidityTxData, options], sdkOptions ); return tx; } /** * Stake liquidity pool tokens in a yield farm * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} asset Liquidity pool token * @param {BigNumber | string} amount Amount of liquidity pool tokens * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async stake( dapp: Dapp, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iMiniChefV2 = new ethers.utils.Interface(IMiniChefV2.abi); const poolId = await this.utils.getLpPoolId(dapp, asset); const stakeTxData = iMiniChefV2.encodeFunctionData(Transaction.DEPOSIT, [ poolId, amount, this.address ]); const tx = await getPoolTxOrGasEstimate( this, [stakingAddress[this.network][dapp], stakeTxData, options], sdkOptions ); return tx; } /** * Stake liquidity pool tokens in gauge contract * @param {Dapp} dapp Platform like Balancer or Velodrome * @param {string} gauge Gauge contract address * @param {BigNumber | string} amount Amount of liquidity pool tokens or token ID for Velodrome CL * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async stakeInGauge( dapp: Dapp, gauge: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let stakeTxData; switch (dapp) { case Dapp.BALANCER: const rewardsGauge = new ethers.utils.Interface( IBalancerRewardsGauge.abi ); stakeTxData = rewardsGauge.encodeFunctionData("deposit(uint256)", [ amount ]); break; case Dapp.VELODROME: stakeTxData = getVelodromeStakeTxData(amount, false); break; case Dapp.VELODROMEV2: case Dapp.AERODROME: case Dapp.VELODROMECL: case Dapp.AERODROMECL: stakeTxData = getVelodromeStakeTxData(amount, true); break; case Dapp.PANCAKECL: stakeTxData = getPancakeStakeTxData(this, amount.toString(), gauge); break; default: throw new Error("dapp not supported"); } const txTo = dapp !== Dapp.PANCAKECL ? gauge : nonfungiblePositionManagerAddress[this.network][dapp]; const tx = await getPoolTxOrGasEstimate( this, [txTo, stakeTxData, options], sdkOptions ); return tx; } /** * Unstake liquidity pool tokens from a yield farm * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} asset Liquidity pool token * @param {BigNumber | string} amount Amount of liquidity pool tokens * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async unStake( dapp: Dapp, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iMiniChefV2 = new ethers.utils.Interface(IMiniChefV2.abi); const poolId = await this.utils.getLpPoolId(dapp, asset); const unStakeTxData = iMiniChefV2.encodeFunctionData(Transaction.WITHDRAW, [ poolId, amount, this.address ]); const tx = await getPoolTxOrGasEstimate( this, [stakingAddress[this.network][dapp], unStakeTxData, options], sdkOptions ); return tx; } /** * Unstake liquidity pool tokens from Velodrome or Balancer gauge * @param {string} gauge Gauge contract address * @param {BigNumber | string} amount Amount of liquidity pool tokens or CL token ID * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async unstakeFromGauge( gauge: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let unstakeTxData; const rewardsGauge = new ethers.utils.Interface(IBalancerRewardsGauge.abi); if ( gauge.toLowerCase() === stakingAddress[this.network][Dapp.PANCAKECL]?.toLowerCase() ) { unstakeTxData = getPancakeUnStakeTxData(this, amount.toString()); } else { unstakeTxData = rewardsGauge.encodeFunctionData("withdraw(uint256)", [ amount ]); } const tx = await getPoolTxOrGasEstimate( this, [gauge, unstakeTxData, options], sdkOptions ); return tx; } /** * Lend asset to a lending pool * @param {Dapp} dapp Platform like Aave * @param {string} asset Asset * @param {BigNumber | string} amount Amount of asset to lend * @param {number} referralCode Code from Aave referral program * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async lend( dapp: Dapp, asset: string, amount: BigNumber | string, referralCode = 0, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let depositTxData: string; if (dapp === Dapp.DYTM) { depositTxData = getDytmDepositTxData(this, asset, amount); } else { const iLendingPool = new ethers.utils.Interface(ILendingPool.abi); depositTxData = iLendingPool.encodeFunctionData(Transaction.DEPOSIT, [ asset, amount, this.address, referralCode ]); } const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], depositTxData, options], sdkOptions ); return tx; } /** * Lend asset to a Compound V3 or Fluid lending pool * @param {string} market Address of cToken or fToken * @param {string} asset Asset * @param {BigNumber | string} amount Amount of asset to lend * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async lendCompoundV3( market: string, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const supplyTxData = await getCompoundV3LendTxData( this, market, asset, amount ); const tx = await getPoolTxOrGasEstimate( this, [market, supplyTxData, options], sdkOptions ); return tx; } /** * Withdraw asset from a lending pool * @param {Dapp} dapp Platform like Aave * @param {string} asset Asset * @param {BigNumber | string} amount Amount of asset to lend * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async withdrawDeposit( dapp: Dapp, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let withdrawTxData: string; if (dapp === Dapp.DYTM) { withdrawTxData = await getDytmWithdrawTxData(this, asset, amount); } else { const iLendingPool = new ethers.utils.Interface(ILendingPool.abi); withdrawTxData = iLendingPool.encodeFunctionData(Transaction.WITHDRAW, [ asset, amount, this.address ]); } const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], withdrawTxData, options], sdkOptions ); return tx; } /** * Withdraw asset from a Compound V3 or Fluid lending pool * @param {string} market Address of cToken or fToken * @param {string} asset Asset * @param {BigNumber | string} amount Amount of asset to withdraw * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async withdrawCompoundV3( market: string, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const withdrawTxData = await getCompoundV3WithdrawTxData( this, market, asset, amount ); const tx = await getPoolTxOrGasEstimate( this, [market, withdrawTxData, options], sdkOptions ); return tx; } /** * Borrow asset from a lending pool * @param {Dapp} dapp Platform like Aave * @param {string} asset Asset * @param {BigNumber | string} amount Amount of asset to lend * @param {number} referralCode Code from Aave referral program * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async borrow( dapp: Dapp, asset: string, amount: BigNumber | string, referralCode = 0, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let borrowTxData: string; if (dapp === Dapp.DYTM) { borrowTxData = getDytmBorrowTxData(this, asset, amount); } else { const iLendingPool = new ethers.utils.Interface(ILendingPool.abi); borrowTxData = iLendingPool.encodeFunctionData(Transaction.BORROW, [ asset, amount, 2, referralCode, this.address ]); } const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], borrowTxData, options], sdkOptions ); return tx; } /** * Repays borrowed asset to a lending pool * @param {Dapp} dapp Platform like Aave * @param {string} asset Asset * @param {BigNumber | string} amount Amount of asset to lend * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async repay( dapp: Dapp, asset: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let repayTxData: string; if (dapp === Dapp.DYTM) { repayTxData = await getDytmRepayTxData(this, asset, amount); } else { const iLendingPool = new ethers.utils.Interface(ILendingPool.abi); repayTxData = iLendingPool.encodeFunctionData(Transaction.REPAY, [ asset, amount, 2, this.address ]); } const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][dapp], repayTxData, options], sdkOptions ); return tx; } /** * Claim rewards of staked liquidity pool tokens * @param {Dapp} dapp Platform like Sushiswap or Uniswap * @param {string} asset Liquidity pool token * @param {any} options Transaction option * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async harvestRewards( dapp: Dapp, asset: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const iMiniChefV2 = new ethers.utils.Interface(IMiniChefV2.abi); const poolId = await this.utils.getLpPoolId(dapp, asset); const harvestTxData = iMiniChefV2.encodeFunctionData(Transaction.HARVEST, [ poolId, this.address ]); const tx = await getPoolTxOrGasEstimate( this, [stakingAddress[this.network][dapp], harvestTxData, options], sdkOptions ); return tx; } /** * Change enabled pool assets * @param {AssetEnabled[]} assets New pool assets * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ public async changeAssets( assets: AssetEnabled[], options: any = null, estimateGas = false ): Promise { const currentAssetsEnabled = await this.getComposition(); const currentAssets = currentAssetsEnabled.map(e => e.asset.toLocaleLowerCase() ); const newAssets = assets.map(e => e.asset.toLocaleLowerCase()); const candidateRemovals = currentAssets.filter(e => !newAssets.includes(e)); const changedAssets = assets.map(e => [e.asset, e.isDeposit]); // Simulate each removal to filter out assets that can't be removed // (non-zero balance, guard dependency, active order, etc.) const removedAssets: string[] = []; for (const asset of candidateRemovals) { try { await this.managerLogic.callStatic.changeAssets([], [asset]); removedAssets.push(asset); } catch (err) { console.warn( `changeAssets: skipping removal of ${asset} — ${ (err as Error).message }` ); } } if (estimateGas) { return await this.managerLogic.estimateGas.changeAssets( changedAssets, removedAssets, options ); } const tx = await this.managerLogic.changeAssets( changedAssets, removedAssets, options ); return tx; } /** * Set a new trader with trading permissions * @param {string} trader Address trader account * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async setTrader( trader: string, options: any = null, estimateGas = false ): Promise { if (estimateGas) { return await this.managerLogic.estimateGas.setTrader(trader, options); } const tx = await this.managerLogic.setTrader(trader, options); return tx; } /** * Sets a pool private or public * @param {boolean} _private True for private, false for public * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async setPrivate( _private: boolean, options: any = null, estimateGas = false ): Promise { if (estimateGas) { return await this.managerLogic.estimateGas.setPoolPrivate( _private, options ); } const tx = await this.managerLogic.setPoolPrivate(_private, options); return tx; } /** * Sets max supply cap for a pool * @param {BigNumberish} _maxSupplyCapD18 Max supply cap with 18 decimals * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async setMaxCap( _maxSupplyCapD18: BigNumberish, options: any = null, estimateGas = false ): Promise { if (estimateGas) { return await this.managerLogic.estimateGas.setMaxSupplyCap( _maxSupplyCapD18, options ); } const tx = await this.managerLogic.setMaxSupplyCap( _maxSupplyCapD18, options ); return tx; } /** * Invest into a Balancer pool * @param {string} poolId Balancer pool id * @param {string[] | } assetsIn Array of balancer pool assets * @param {BigNumber[] | string[]} amountsIn Array of maximum amounts to provide to pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async joinBalancerPool( poolId: string, assets: string[], amountsIn: string[] | BigNumber[], options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const joinPoolTxData = this.utils.getBalancerJoinPoolTx( this, poolId, assets, amountsIn ); const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][Dapp.BALANCER], joinPoolTxData, options], sdkOptions ); return tx; } /** * Exit a Balancer pool * @param {string} poolId Balancer pool id * @param {string[]} assets Array of balancer pool assets * @param {BigNumber | string} amount Amount of pool tokens to withdraw * @param {null | number} singleExitAssetIndex Index of asset to withdraw to * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async exitBalancerPool( poolId: string, assets: string[], amount: string | BigNumber, singleExitAssetIndex: number | null = null, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const exitPoolTxData = this.utils.getBalancerExitPoolTx( this, poolId, assets, singleExitAssetIndex, amount ); const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][Dapp.BALANCER], exitPoolTxData, options], sdkOptions ); return tx; } /** * Claim rewards from Aave platform * @param {string[]} assets Aave tokens (deposit/debt) hold by pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async harvestAaveRewards( assets: string[], options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const aaveIncentivesAddress = stakingAddress[this.network][ Dapp.AAVE ] as string; const iAaveIncentivesController = new ethers.utils.Interface( IAaveIncentivesController.abi ); const aaveIncentivesController = new ethers.Contract( aaveIncentivesAddress, iAaveIncentivesController, this.signer ); const amount = await aaveIncentivesController.getUserUnclaimedRewards( this.address ); const claimTxData = iAaveIncentivesController.encodeFunctionData( Transaction.CLAIM_REWARDS, [assets, amount, this.address] ); const tx = await getPoolTxOrGasEstimate( this, [aaveIncentivesAddress, claimTxData, options], sdkOptions ); return tx; } /** * Claim rewards from Aave platform * @param {string[]} assets Assets invested in Aave * @param {string} rewardAssets Reward token address * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async harvestAaveV3Rewards( assets: string[], rewardAsset: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const claimTxData = await getAaveV3ClaimTxData(this, assets, rewardAsset); const tx = await getPoolTxOrGasEstimate( this, [ stakingAddress[this.network][Dapp.AAVEV3] as string, claimTxData, options ], sdkOptions ); return tx; } /** * Claim rewards from CompoundV3 * @param {string} asset Compound lending asset * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async harvestCompoundV3Rewards( asset: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const claimTxData = await getCompoundV3ClaimTxData(this, asset); const tx = await getPoolTxOrGasEstimate( this, [ stakingAddress[this.network][Dapp.COMPOUNDV3] as string, claimTxData, options ], sdkOptions ); return tx; } /** * Create UniswapV3 liquidity pool * @param {dapp} Platform UniswapV3, VelodromeCL, AerodromeCL or RamesesCL * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amountA Amount first asset * @param {BigNumber | string} amountB Amount second asset * @param { number } minPrice Lower price range (assetB per assetA) * @param { number } maxPrice Upper price range (assetB per assetA) * @param { number } minTick Lower tick range * @param { number } maxTick Upper tick range * @param { number } feeAmountOrTickSpacing Fee tier UniswapV3 or tick spacing VelodromeCL * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async addLiquidityUniswapV3( dapp: Dapp.UNISWAPV3 | Dapp.VELODROMECL | Dapp.AERODROMECL | Dapp.PANCAKECL, assetA: string, assetB: string, amountA: BigNumber | string, amountB: BigNumber | string, minPrice: number | null, maxPrice: number | null, minTick: number | null, maxTick: number | null, feeAmountOrTickSpacing: number, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { if ( (minPrice === null || maxPrice === null) && (minTick === null || maxTick === null) ) throw new Error("Need to provide price or tick range"); if ((minPrice || maxPrice) && dapp !== Dapp.UNISWAPV3) throw new Error("no price conversion for Aerodrome/Velodrome CL"); const mintTxData = await getUniswapV3MintTxData( dapp, this, assetA, assetB, amountA, amountB, minPrice, maxPrice, minTick, maxTick, feeAmountOrTickSpacing ); const tx = await getPoolTxOrGasEstimate( this, [ nonfungiblePositionManagerAddress[this.network][dapp], mintTxData, options ], sdkOptions ); return tx; } /** * Remove liquidity from an UniswapV3 or Arrakis liquidity pool * @param {Dapp} dapp Platform either UniswapV3 or Arrakis * @param {string} tokenId Token Id of UniswapV3 position * @param {number} amount Amount in percent of assets to be removed * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async decreaseLiquidity( dapp: Dapp, tokenId: string, amount = 100, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let dappAddress; let isStaked = false; let txData; switch (dapp) { case Dapp.UNISWAPV3: dappAddress = nonfungiblePositionManagerAddress[this.network][dapp]; break; case Dapp.VELODROMECL: case Dapp.AERODROMECL: case Dapp.PANCAKECL: const tokenIdOwner = await getClOwner(this, dapp, tokenId); if (tokenIdOwner.toLowerCase() === this.address.toLowerCase()) { dappAddress = nonfungiblePositionManagerAddress[this.network][dapp]; } else { //staked in gauge dappAddress = tokenIdOwner; isStaked = true; } break; case Dapp.ARRAKIS: dappAddress = routerAddress[this.network][dapp]; break; default: throw new Error("dapp not supported"); } if (!isStaked || dapp === Dapp.PANCAKECL) { txData = await getDecreaseLiquidityTxData( this, dapp, tokenId, amount, isStaked ); } else { throw new Error( "unsupported decreaseStakedLiquidity: unstake first to decrease lp" ); } const tx = await getPoolTxOrGasEstimate( this, [dappAddress, txData, options], sdkOptions ); return tx; } /** * Increase liquidity of an UniswapV, VelodromeCL or Arrakis liquidity pool * @param {Dapp} dapp Platform either UniswapV3 or Arrakis * @param {string} tokenId Token Id of UniswapV3 position * @param {BigNumber | string} amountA Amount first asset * @param {BigNumber | string} amountB Amount second asset * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async increaseLiquidity( dapp: Dapp, tokenId: string, amountA: BigNumber | string, amountB: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let dappAddress; let isStaked = false; let txData; switch (dapp) { case Dapp.UNISWAPV3: dappAddress = nonfungiblePositionManagerAddress[this.network][dapp]; break; case Dapp.VELODROMECL: case Dapp.AERODROMECL: case Dapp.PANCAKECL: const tokenIdOwner = await getClOwner(this, dapp, tokenId); if (tokenIdOwner.toLowerCase() === this.address.toLowerCase()) { dappAddress = nonfungiblePositionManagerAddress[this.network][dapp]; } else { //staked in gauge dappAddress = tokenIdOwner; isStaked = true; } break; case Dapp.ARRAKIS: dappAddress = routerAddress[this.network][dapp]; break; default: throw new Error("dapp not supported"); } //PancakeCL supports increase liquidity to staked position if (!isStaked || dapp === Dapp.PANCAKECL) { txData = await getIncreaseLiquidityTxData( this, dapp, tokenId, amountA, amountB ); } else { throw new Error( "unsupported increaseStakedLiquidity: unstake first to increase lp" ); } const tx = await getPoolTxOrGasEstimate( this, [dappAddress, txData, options], sdkOptions ); return tx; } /** * Claim fees of an UniswapV3 liquidity or Arrakis pool * @param {Dapp} dapp Platform either UniswapV3 or Arrakis * @param {string} tokenId Token Id of UniswapV3 or Gauge address * @param {any} options Transaction option * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async claimFees( dapp: Dapp, tokenId: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { let txData; let contractAddress; const iNonfungiblePositionManager = new ethers.utils.Interface( INonfungiblePositionManager.abi ); switch (dapp) { case Dapp.UNISWAPV3: contractAddress = nonfungiblePositionManagerAddress[this.network][dapp]; txData = iNonfungiblePositionManager.encodeFunctionData( Transaction.COLLECT, [[tokenId, this.address, MaxUint128, MaxUint128]] ); break; case Dapp.ARRAKIS: case Dapp.BALANCER: contractAddress = tokenId; const abi = new ethers.utils.Interface(ILiquidityGaugeV4.abi); txData = abi.encodeFunctionData("claim_rewards()", []); break; case Dapp.VELODROME: contractAddress = tokenId; txData = getVelodromeClaimTxData(this, tokenId, false); break; case Dapp.VELODROMEV2: case Dapp.AERODROME: contractAddress = tokenId; txData = getVelodromeClaimTxData(this, tokenId, true); break; case Dapp.VELODROMECL: case Dapp.AERODROMECL: case Dapp.PANCAKECL: const tokenIdOwner = await getClOwner(this, dapp, tokenId); if (tokenIdOwner.toLowerCase() === this.address.toLowerCase()) { contractAddress = nonfungiblePositionManagerAddress[this.network][dapp]; txData = iNonfungiblePositionManager.encodeFunctionData( Transaction.COLLECT, [[tokenId, this.address, MaxUint128, MaxUint128]] ); } else { //staked in gauge or pancake masterchef contractAddress = tokenIdOwner; if (dapp === Dapp.PANCAKECL) { txData = getPancakeHarvestClaimTxData(this, tokenId); } else { txData = getVelodromeCLClaimTxData(tokenId); } } break; default: throw new Error("dapp not supported"); } const tx = await getPoolTxOrGasEstimate( this, [contractAddress, txData, options], sdkOptions ); return tx; } /** * Add liquidity to Velodrome pool * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amountA Amount first asset * @param {BigNumber | string} amountB Amount second asset * @param { boolean } isStable Is stable pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async addLiquidityVelodrome( assetA: string, assetB: string, amountA: BigNumber | string, amountB: BigNumber | string, isStable: boolean, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][Dapp.VELODROME], await getVelodromeAddLiquidityTxData( this, assetA, assetB, amountA, amountB, isStable ), options ], sdkOptions ); return tx; } /** * Remove liquidity from Velodrome pool * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amount Amount of LP tokens * @param { boolean } isStable Is stable pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async removeLiquidityVelodrome( assetA: string, assetB: string, amount: BigNumber | string, isStable: boolean, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][Dapp.VELODROME], await getVelodromeRemoveLiquidityTxData( this, assetA, assetB, amount, isStable ), options ], sdkOptions ); return tx; } /** * Add liquidity to Velodrome V2 pool * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amountA Amount first asset * @param {BigNumber | string} amountB Amount second asset * @param { boolean } isStable Is stable pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async addLiquidityVelodromeV2( assetA: string, assetB: string, amountA: BigNumber | string, amountB: BigNumber | string, isStable: boolean, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][Dapp.VELODROMEV2], await getVelodromeAddLiquidityTxData( this, assetA, assetB, amountA, amountB, isStable ), options ], sdkOptions ); return tx; } /** * Remove liquidity from Velodrome V2 pool * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amount Amount of LP tokens * @param { boolean } isStable Is stable pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async removeLiquidityVelodromeV2( assetA: string, assetB: string, amount: BigNumber | string, isStable: boolean, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][Dapp.VELODROMEV2], await getVelodromeRemoveLiquidityTxData( this, assetA, assetB, amount, isStable ), options ], sdkOptions ); return tx; } /** * Add liquidity to Velodrome V2 or Aerodrome pool * @param {Dapp} dapp VelodromeV2 or Aerodrome * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amountA Amount first asset * @param {BigNumber | string} amountB Amount second asset * @param { boolean } isStable Is stable pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async addLiquidityV2( dapp: Dapp.VELODROMEV2 | Dapp.AERODROME, assetA: string, assetB: string, amountA: BigNumber | string, amountB: BigNumber | string, isStable: boolean, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][dapp], await getVelodromeAddLiquidityTxData( this, assetA, assetB, amountA, amountB, isStable ), options ], sdkOptions ); return tx; } /** * Remove liquidity from Velodrome V2 or Aerodrome pool * @param {Dapp} dapp VelodromeV2 or Aerodrome * @param {string} assetA First asset * @param {string} assetB Second asset * @param {BigNumber | string} amount Amount of LP tokens * @param { boolean } isStable Is stable pool * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async removeLiquidityV2( dapp: Dapp.VELODROMEV2 | Dapp.AERODROME, assetA: string, assetB: string, amount: BigNumber | string, isStable: boolean, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][dapp], await getVelodromeRemoveLiquidityTxData( this, assetA, assetB, amount, isStable ), options ], sdkOptions ); return tx; } /** * Trade options on lyra * @param {LyraOptionMarket} market Underlying market e.g. eth * @param {number} expiry Expiry timestamp * @param { number} strike Strike price * @param {LyraOptionType} optionType Call or put * @param { LyraTradeType} tradeType By or sell * @param {BigNumber | string } optionAmount Option amount * @param {string } assetIn Asset to invest * @param {BigNumber | string } collateralChangeAmount Collateral amount to add when shorting options and to remove when covering shorts * @param {boolean} isCoveredCall Selling covered call options * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async tradeLyraOption( market: LyraOptionMarket, expiry: number, strike: number, optionType: LyraOptionType, tradeType: LyraTradeType, optionAmount: BigNumber | string, assetIn: string, collateralChangeAmount: BigNumber | string = "0", isCoveredCall = false, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const swapxData = await getLyraOptionTxData( this, market, optionType, expiry, strike, tradeType, optionAmount, assetIn, BigNumber.from(collateralChangeAmount), isCoveredCall ); const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network][Dapp.LYRA], swapxData, options], sdkOptions ); return tx; } /** * Gets Lyra option positions * @returns {Promise} Transaction */ async getLyraPositions(market: LyraOptionMarket): Promise { return await getOptionPositions(this, market); } /** * mintManagerFee * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas * @returns {Promise} Transaction */ async mintManagerFee(options: any = null, estimateGas = false): Promise { if (estimateGas) { return await this.poolLogic.estimateGas.mintManagerFee(options); } const tx = await this.poolLogic.mintManagerFee(options); return tx; } /** * getAvailableManagerFee * @returns {Promise} fee */ async getAvailableManagerFee(): Promise { const fundValue = await this.managerLogic.totalFundValue(); const fee = await this.poolLogic.calculateAvailableManagerFee(fundValue); return BigNumber.from(fee); } /** deposit rETH to mint UNIT via the Flat Money protocol * * @param { BigNumber | string } depositAmount Amount of rETH to deposit * @param { number } slippage slippage, 0.5 represents 0.5% * @param { number | null } maxKeeperFeeInUsd 5 represents $5; null will skip the maxKeeperFee check * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async mintUnitViaFlatMoney( depositAmount: ethers.BigNumber | string, slippage = 0.5, maxKeeperFeeInUsd: number | null, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await mintUnitViaFlatMoney( this, depositAmount, slippage, maxKeeperFeeInUsd, options, sdkOptions ); return tx; } /** redeem UNIT via the Flat Money protocol * * @param { BigNumber | string } depositAmount Amount of UNIT to withdraw * @param { number } slippage slippage, 0.5 represents 0.5% * @param { number | null } maxKeeperFeeInUsd 5 represents $5; null will skip the maxKeeperFee check * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async redeemUnitViaFlatMoney( withdrawAmount: ethers.BigNumber | string, slippage = 0.5, maxKeeperFeeInUsd: number | null, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await redeemUnitViaFlatMoney( this, withdrawAmount, slippage, maxKeeperFeeInUsd, options, sdkOptions ); return tx; } /** * Cancel a previously announced FlatMoney order (mint/redeem UNIT) before it executes * @param {any} options Transaction options * @param {boolean} estimateGas Simulate/estimate gas instead of sending * @returns {Promise} Transaction */ async cancelOrderViaFlatMoney( options: any = null, estimateGas = false ): Promise { const tx = await cancelOrderViaFlatMoney(this, options, estimateGas); return tx; } /** * Complete a Toros withdrawal to a single asset * @param {string} destinationToken Address of destination asset * @param {number} slippage Slippage tolerance in % * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @param {any} trackedAssets Tracked assets information (only for tx data generation) * @returns {Promise} Transaction */ async completeTorosWithdrawal( destinationToken: string, slippage = 0.5, options: any = null, sdkOptions: SDKOptions = { estimateGas: false }, trackedAssets: TrackedAsset[] = [] ): Promise { const txData = await getCompleteWithdrawalTxData( this, destinationToken, slippage * 100, false, trackedAssets ); const tx = await getPoolTxOrGasEstimate( this, [routerAddress[this.network].toros, txData, options], sdkOptions ); return tx; } /** * Mint PT and YT tokens on Pendle * @param {string} assetFrom Asset to mint from (only underlying asset) * @param {string} pt PT address * @param {BigNumber | string} amountIn Amount underlying asset * @param {number} slippage Slippage tolerance in % * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async mintPendle( assetFrom: string, pt: string, amountIn: BigNumber | string, slippage = 0.5, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const { swapTxData, minAmountOut } = await getPendleMintTxData( this, assetFrom, pt, amountIn, slippage ); const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][Dapp.PENDLE], swapTxData, options, minAmountOut ], sdkOptions ); return tx; } /** Deposit USDC from EVM to a HyperCore trading dex via the CoreDepositWallet. * This bridges USDC on-chain to Hyperliquid for perp/spot trading. * * @param {BigNumber | string} amount USDC amount to deposit (6 decimals, e.g. "1000000" = 1 USDC) * @param {number} dexId Destination dex ID where USDC will be available (default 0) * - 0: Core Perp dex (standard perps like BTC, ETH) * - 1: xyz HIP-3 dex (builder perps like TSLA, GOLD) * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async depositHyperliquid( amount: BigNumber | string, dexId = 0, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ routerAddress[this.network][Dapp.HYPERLIQUID], getDepositHyperliquidTxData(dexId, amount), options ], sdkOptions ); return tx; } /** Move USDC from a HyperCore trading dex to the Spot wallet. * Required before calling withdrawHyperliquid() to bridge USDC back to EVM. * * @param {number} dexId Source dex ID where USDC currently sits * - 0: Core Perp dex (standard perps like BTC, ETH) * - 1: xyz HIP-3 dex (builder perps like TSLA, GOLD) * @param {BigNumber | string} amount USDC amount to transfer (6 decimals, e.g. "1000000" = 1 USDC) * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async perpToSpotHyperliquid( dexId: number, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ CORE_WRITER_ADDRESS, getSendAssetHyperliquidTxData(dexId, SPOT_DEX_ID, this.address, amount), options ], sdkOptions ); return tx; } /** Move USDC from HyperCore spot wallet to a trading dex. * * @param {number} dexId Destination dex ID where USDC will be moved to * - 0: Core Perp dex (standard perps like BTC, ETH) * - 1: xyz HIP-3 dex (builder perps like TSLA, GOLD) * @param {BigNumber | string} amount USDC amount to transfer (6 decimals, e.g. "1000000" = 1 USDC) * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async spotToPerpHyperliquid( dexId: number, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ CORE_WRITER_ADDRESS, getSendAssetHyperliquidTxData(SPOT_DEX_ID, dexId, this.address, amount), options ], sdkOptions ); return tx; } /** Withdraw USDC from Hyperliquid Spot wallet back to EVM. * USDC must be in the Spot wallet first — use perpToSpotHyperliquid() to move it from a trading dex. * * @param {BigNumber | string} amount USDC amount to withdraw (6 decimals, e.g. "1000000" = 1 USDC) * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async withdrawHyperliquid( amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [CORE_WRITER_ADDRESS, getWithdrawSpotHyperliquidTxData(amount), options], sdkOptions ); return tx; } /** Open a market order on Hyperliquid * @param {number} assetId Asset id * @param {boolean} isLong Long or short (Note: Spot assets only support long positions) * @param {number} value Order value in base asset units (positive for opening/increasing, * negative for closing/reducing or selling spot) * @param {number } slippage Slippage tolerance in % * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async openMarketOrderHyperliquid( assetId: number, isLong: boolean, value: number, slippage = 0.5, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ CORE_WRITER_ADDRESS, await getLimitOrderHyperliquidTxData(assetId, isLong, value, slippage), options ], sdkOptions ); return tx; } /** Close a position on Hyperliquid * @param {number} assetId Asset id * @param {number} percentageToClose Percentage of position to close (0-100) * @param {number } slippage Slippage tolerance in % * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async closePositionHyperliquid( assetId: number, percentageToClose = 100, slippage = 0.5, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const tx = await getPoolTxOrGasEstimate( this, [ CORE_WRITER_ADDRESS, await getClosePositionHyperliquidTxData( assetId, percentageToClose, slippage, this.address ), options ], sdkOptions ); return tx; } /** * Approve the Toros vault token for the PoolLimitOrderManager * Must be called before createTorosLimitOrder * @param {string} vaultAddress Address of the Toros vault token to approve * @param {BigNumber | string} amount Amount to approve * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async approveTorosLimitOrder( vaultAddress: string, amount: BigNumber | string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const managerAddress = limitOrderAddress[this.network]; const iERC20 = new ethers.utils.Interface(IERC20.abi); const approveTxData = iERC20.encodeFunctionData("approve", [ managerAddress, amount ]); return getPoolTxOrGasEstimate( this, [vaultAddress, approveTxData, options], sdkOptions ); } /** * Create a Toros limit order (stop-loss / take-profit) * @param {string} vaultAddress Address of the Toros vault token * @param {BigNumber | string} amount Vault token amount (18 decimals) * @param {BigNumber | string | null | undefined} stopLossPriceD18 Stop-loss price in D18 (0 or null/undefined = disabled) * @param {BigNumber | string | null | undefined} takeProfitPriceD18 Take-profit price in D18 (MaxUint256 or null/undefined = disabled) * @param {string} pricingAsset Address of the pricing asset (e.g. USDC) * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async createTorosLimitOrder( vaultAddress: string, amount: BigNumber | string, stopLossPriceD18: BigNumber | string | null | undefined, takeProfitPriceD18: BigNumber | string | null | undefined, pricingAsset: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const managerAddress = limitOrderAddress[this.network]; if (!managerAddress) { throw new Error(`Limit orders not supported on ${this.network}`); } const resolvedStopLoss = stopLossPriceD18 == null ? BigNumber.from(0) : BigNumber.from(stopLossPriceD18); const resolvedTakeProfit = takeProfitPriceD18 == null ? ethers.constants.MaxUint256 : BigNumber.from(takeProfitPriceD18); const info: LimitOrderInfo = { amount: BigNumber.from(amount), stopLossPriceD18: resolvedStopLoss, takeProfitPriceD18: resolvedTakeProfit, user: this.address, pool: vaultAddress, pricingAsset }; const txData = getCreateLimitOrderTxData(info); return getPoolTxOrGasEstimate( this, [managerAddress, txData, options], sdkOptions ); } /** * Modify an existing Toros limit order * @param {string} vaultAddress Address of the Toros vault token * @param {BigNumber | string} amount New vault token amount (18 decimals) * @param {BigNumber | string | null | undefined} stopLossPriceD18 New stop-loss price in D18 (0 or null/undefined = disabled) * @param {BigNumber | string | null | undefined} takeProfitPriceD18 New take-profit price in D18 (MaxUint256 or null/undefined = disabled) * @param {string} pricingAsset Address of the pricing asset * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async modifyTorosLimitOrder( vaultAddress: string, amount: BigNumber | string, stopLossPriceD18: BigNumber | string | null | undefined, takeProfitPriceD18: BigNumber | string | null | undefined, pricingAsset: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const managerAddress = limitOrderAddress[this.network]; if (!managerAddress) { throw new Error(`Limit orders not supported on ${this.network}`); } const resolvedStopLoss = stopLossPriceD18 == null ? BigNumber.from(0) : BigNumber.from(stopLossPriceD18); const resolvedTakeProfit = takeProfitPriceD18 == null ? ethers.constants.MaxUint256 : BigNumber.from(takeProfitPriceD18); const info: LimitOrderInfo = { amount: BigNumber.from(amount), stopLossPriceD18: resolvedStopLoss, takeProfitPriceD18: resolvedTakeProfit, user: this.address, pool: vaultAddress, pricingAsset }; const txData = getModifyLimitOrderTxData(info); return getPoolTxOrGasEstimate( this, [managerAddress, txData, options], sdkOptions ); } /** * Delete an existing Toros limit order * @param {string} vaultAddress Address of the Toros vault token * @param {any} options Transaction options * @param {SDKOptions} sdkOptions SDK options including estimateGas * @returns {Promise} Transaction */ async deleteTorosLimitOrder( vaultAddress: string, options: any = null, sdkOptions: SDKOptions = { estimateGas: false } ): Promise { const managerAddress = limitOrderAddress[this.network]; if (!managerAddress) { throw new Error(`Limit orders not supported on ${this.network}`); } const txData = getDeleteLimitOrderTxData(vaultAddress); return getPoolTxOrGasEstimate( this, [managerAddress, txData, options], sdkOptions ); } /** * Fetch a Toros limit order for a given user and vault * @param {string} userAddress Address of the order owner (the dHEDGE pool) * @param {string} vaultAddress Address of the Toros vault token * @returns {Promise} Order info, or null if none exists */ async getTorosLimitOrder( userAddress: string, vaultAddress: string ): Promise { return getTorosLimitOrder(this, userAddress, vaultAddress); } /** * Check whether an active Toros limit order exists for a given user and vault * @param {string} userAddress Address of the order owner (the dHEDGE pool) * @param {string} vaultAddress Address of the Toros vault token * @returns {Promise} */ async hasActiveTorosLimitOrder( userAddress: string, vaultAddress: string ): Promise { return hasActiveTorosLimitOrder(this, userAddress, vaultAddress); } }