diff --git a/src/boosting.ts b/src/boosting.ts index 77ea65f7..7791624e 100644 --- a/src/boosting.ts +++ b/src/boosting.ts @@ -1,25 +1,29 @@ -import { Contract } from "ethers"; +import {Contract} from "ethers"; import BigNumber from "bignumber.js"; -import { curve } from "./curve.js"; -import { IDict, IChainId } from "./interfaces"; -import feeDistributorViewABI from "./constants/abis/fee_distributor_view.json" with { type: 'json' }; -import feeDistributorCrvUSDViewABI from "./constants/abis/fee_distributor_crvusd_view.json" with { type: 'json' }; +import {type Curve} from "./curve.js"; +import {IChainId, IDict} from "./interfaces"; +import feeDistributorViewABI from "./constants/abis/fee_distributor_view.json" with {type: "json"}; +import feeDistributorCrvUSDViewABI from "./constants/abis/fee_distributor_crvusd_view.json" with {type: "json"}; import { + _ensureAllowance, _getBalances, - _prepareAddresses, DIGas, + _prepareAddresses, + BN, + DIGas, ensureAllowance, ensureAllowanceEstimateGas, hasAllowance, mulBy1_3, + parseUnits, smartNumber, + toBN, + toStringFromBN, } from "./utils.js"; -import { _ensureAllowance, toBN, toStringFromBN, parseUnits, BN } from './utils.js'; -import { _generateBoostingProof } from './external-api.js'; +import {_generateBoostingProof} from './external-api.js'; - -export const getCrv = async (...addresses: string[] | string[][]): Promise | string> => { - addresses = _prepareAddresses(addresses); - const rawBalances = (await _getBalances([curve.constants.ALIASES.crv], addresses)); +export async function getCrv(this: Curve, ...addresses: string[] | string[][]): Promise | string> { + addresses = _prepareAddresses.call(this, addresses); + const rawBalances = (await _getBalances.call(this, [this.constants.ALIASES.crv], addresses)); const balances: IDict = {}; for (const address of addresses) { @@ -29,30 +33,30 @@ export const getCrv = async (...addresses: string[] | string[][]): Promise | { lockedAmount: string, unlockTime: number }> => { - addresses = _prepareAddresses(addresses); - const veContract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; +export async function getLockedAmountAndUnlockTime(this: Curve, ...addresses: string[] | string[][]): + Promise | { lockedAmount: string, unlockTime: number }> { + addresses = _prepareAddresses.call(this, addresses); + const veContract = this.contracts[this.constants.ALIASES.voting_escrow].multicallContract; const contractCalls = addresses.map((address: string) => veContract.locked(address)); - const response: (string | number)[][] = (await curve.multicallProvider.all(contractCalls) as bigint[][]).map( - (value: bigint[]) => [curve.formatUnits(value[0]), Number(curve.formatUnits(value[1], 0)) * 1000]); + const response: (string | number)[][] = (await this.multicallProvider.all(contractCalls) as bigint[][]).map( + (value: bigint[]) => [this.formatUnits(value[0]), Number(this.formatUnits(value[1], 0)) * 1000]); const result: IDict<{ lockedAmount: string, unlockTime: number }> = {}; addresses.forEach((addr: string, i: number) => { - result[addr] = { lockedAmount: response[i][0] as string, unlockTime: response[i][1] as number}; + result[addr] = {lockedAmount: response[i][0] as string, unlockTime: response[i][1] as number}; }); return addresses.length === 1 ? result[addresses[0]] : result } -export const getVeCrv = async (...addresses: string[] | string[][]): Promise | string> => { - addresses = _prepareAddresses(addresses); +export async function getVeCrv(this: Curve, ...addresses: string[] | string[][]): Promise | string> { + addresses = _prepareAddresses.call(this, addresses); - const veContract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; + const veContract = this.contracts[this.constants.ALIASES.voting_escrow].multicallContract; const contractCalls = addresses.map((address: string) => veContract.balanceOf(address)); - const response: string[] = (await curve.multicallProvider.all(contractCalls) as bigint[]).map( - (value: bigint) => curve.formatUnits(value)); + const response: string[] = (await this.multicallProvider.all(contractCalls) as bigint[]).map( + (value: bigint) => this.formatUnits(value)); const result: IDict = {}; addresses.forEach((addr: string, i: number) => { @@ -62,15 +66,15 @@ export const getVeCrv = async (...addresses: string[] | string[][]): Promise | string> => { - addresses = _prepareAddresses(addresses); +export async function getVeCrvPct(this: Curve, ...addresses: string[] | string[][]): Promise | string> { + addresses = _prepareAddresses.call(this, addresses); - const veContract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; + const veContract = this.contracts[this.constants.ALIASES.voting_escrow].multicallContract; const contractCalls = [veContract.totalSupply()]; addresses.forEach((address: string) => { contractCalls.push(veContract.balanceOf(address)); }); - const response: BigNumber[] = (await curve.multicallProvider.all(contractCalls) as bigint[]).map( + const response: BigNumber[] = (await this.multicallProvider.all(contractCalls) as bigint[]).map( (value: bigint) => toBN(value)); const [veTotalSupply] = response.splice(0, 1); @@ -88,33 +92,33 @@ export const getVeCrvPct = async (...addresses: string[] | string[][]): Promise< return addresses.length === 1 ? result[addresses[0]] : result } -export const isApproved = async (amount: number | string): Promise => { - return await hasAllowance([curve.constants.ALIASES.crv], [amount], curve.signerAddress, curve.constants.ALIASES.voting_escrow); +export async function isApproved(this: Curve, amount: number | string): Promise { + return await hasAllowance.call(this, [this.constants.ALIASES.crv], [amount], this.signerAddress, this.constants.ALIASES.voting_escrow); } -export const approveEstimateGas = async (amount: number | string): Promise => { - return await ensureAllowanceEstimateGas([curve.constants.ALIASES.crv], [amount], curve.constants.ALIASES.voting_escrow, false); +export async function approveEstimateGas(this: Curve, amount: number | string): Promise { + return await ensureAllowanceEstimateGas.call(this, [this.constants.ALIASES.crv], [amount], this.constants.ALIASES.voting_escrow, false); } -export const approve = async (amount: number | string): Promise => { - return await ensureAllowance([curve.constants.ALIASES.crv], [amount], curve.constants.ALIASES.voting_escrow, false); +export async function approve(this: Curve, amount: number | string): Promise { + return await ensureAllowance.call(this, [this.constants.ALIASES.crv], [amount], this.constants.ALIASES.voting_escrow, false); } -export const createLockEstimateGas = async (amount: number | string, days: number): Promise => { - const crvBalance = await getCrv() as string; +export async function createLockEstimateGas(this: Curve, amount: number | string, days: number): Promise { + const crvBalance = await getCrv.call(this) as string; if (Number(crvBalance) < Number(amount)) { throw Error(`Not enough . Actual: ${crvBalance}, required: ${amount}`); } - if (!(await hasAllowance([curve.constants.ALIASES.crv], [amount], curve.signerAddress, curve.constants.ALIASES.voting_escrow))) { + if (!(await hasAllowance.call(this, [this.constants.ALIASES.crv], [amount], this.signerAddress, this.constants.ALIASES.voting_escrow))) { throw Error("Token allowance is needed to estimate gas") } const _amount = parseUnits(amount); const unlockTime = Math.floor(Date.now() / 1000) + (days * 86400); - return Number(await curve.contracts[curve.constants.ALIASES.voting_escrow].contract.create_lock.estimateGas(_amount, unlockTime, curve.constantOptions)) + return Number(await this.contracts[this.constants.ALIASES.voting_escrow].contract.create_lock.estimateGas(_amount, unlockTime, this.constantOptions)) } export const calcUnlockTime = (days: number, start = Date.now()): number => { @@ -156,221 +160,223 @@ export const calculateVeCrv = ( return veCrvBN.toNumber() } -export const createLock = async (amount: number | string, days: number): Promise => { +export async function createLock(this: Curve, amount: number | string, days: number): Promise { const _amount = parseUnits(amount); const unlockTime = Math.floor(Date.now() / 1000) + (86400 * days); - await _ensureAllowance([curve.constants.ALIASES.crv], [_amount], curve.constants.ALIASES.voting_escrow, false); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; + await _ensureAllowance.call(this, [this.constants.ALIASES.crv], [_amount], this.constants.ALIASES.voting_escrow, false); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.create_lock.estimateGas(_amount, unlockTime, curve.constantOptions))); - return (await contract.create_lock(_amount, unlockTime, { ...curve.options, gasLimit })).hash + await this.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await contract.create_lock.estimateGas(_amount, unlockTime, this.constantOptions))); + return (await contract.create_lock(_amount, unlockTime, { ...this.options, gasLimit })).hash } -export const increaseAmountEstimateGas = async (amount: number | string): Promise => { - const crvBalance = await getCrv() as string; +export async function increaseAmountEstimateGas(this: Curve, amount: number | string): Promise { + const crvBalance = await getCrv.call(this) as string; if (Number(crvBalance) < Number(amount)) { throw Error(`Not enough. Actual: ${crvBalance}, required: ${amount}`); } - if (!(await hasAllowance([curve.constants.ALIASES.crv], [amount], curve.signerAddress, curve.constants.ALIASES.voting_escrow))) { + if (!(await hasAllowance.call(this, [this.constants.ALIASES.crv], [amount], this.signerAddress, this.constants.ALIASES.voting_escrow))) { throw Error("Token allowance is needed to estimate gas") } const _amount = parseUnits(amount); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - return Number(await contract.increase_amount.estimateGas(_amount, curve.constantOptions)) + return Number(await contract.increase_amount.estimateGas(_amount, this.constantOptions)) } -export const increaseAmount = async (amount: number | string): Promise => { +export async function increaseAmount(this: Curve, amount: number | string): Promise { const _amount = parseUnits(amount); - await _ensureAllowance([curve.constants.ALIASES.crv], [_amount], curve.constants.ALIASES.voting_escrow, false); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; + await _ensureAllowance.call(this, [this.constants.ALIASES.crv], [_amount], this.constants.ALIASES.voting_escrow, false); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.increase_amount.estimateGas(_amount, curve.constantOptions))); - return (await contract.increase_amount(_amount, { ...curve.options, gasLimit })).hash + await this.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await contract.increase_amount.estimateGas(_amount, this.constantOptions))); + return (await contract.increase_amount(_amount, { ...this.options, gasLimit })).hash } -export const increaseUnlockTimeEstimateGas = async (days: number): Promise => { - const { unlockTime } = await getLockedAmountAndUnlockTime() as { lockedAmount: string, unlockTime: number }; +export async function increaseUnlockTimeEstimateGas(this: Curve, days: number): Promise { + const {unlockTime} = await getLockedAmountAndUnlockTime.call(this) as { lockedAmount: string, unlockTime: number }; const newUnlockTime = Math.floor(unlockTime / 1000) + (days * 86400); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - return Number(DIGas(await contract.increase_unlock_time.estimateGas(newUnlockTime, curve.constantOptions))) + return Number(DIGas(await contract.increase_unlock_time.estimateGas(newUnlockTime, this.constantOptions))) } -export const increaseUnlockTime = async (days: number): Promise => { - const { unlockTime } = await getLockedAmountAndUnlockTime() as { lockedAmount: string, unlockTime: number }; +export async function increaseUnlockTime(this: Curve, days: number): Promise { + const {unlockTime} = await getLockedAmountAndUnlockTime.call(this) as { lockedAmount: string, unlockTime: number }; const newUnlockTime = Math.floor(unlockTime / 1000) + (days * 86400); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.increase_unlock_time.estimateGas(newUnlockTime, curve.constantOptions))); - return (await contract.increase_unlock_time(newUnlockTime, { ...curve.options, gasLimit })).hash + await this.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await contract.increase_unlock_time.estimateGas(newUnlockTime, this.constantOptions))); + return (await contract.increase_unlock_time(newUnlockTime, {...this.options, gasLimit})).hash } -export const withdrawLockedCrvEstimateGas = async (): Promise => { - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; +export async function withdrawLockedCrvEstimateGas(this: Curve): Promise { + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - return Number(DIGas(await contract.withdraw.estimateGas(curve.constantOptions))) + return Number(DIGas(await contract.withdraw.estimateGas(this.constantOptions))) } -export const withdrawLockedCrv = async (): Promise => { - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; +export async function withdrawLockedCrv(this: Curve): Promise { + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.withdraw.estimateGas(curve.constantOptions))); - return (await contract.withdraw({ ...curve.options, gasLimit })).hash + await this.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await contract.withdraw.estimateGas(this.constantOptions))); + return (await contract.withdraw({ ...this.options, gasLimit })).hash } -export const claimableFees = async (address = ""): Promise => { - address = address || curve.signerAddress; - const contract = new Contract(curve.constants.ALIASES.fee_distributor, feeDistributorViewABI, curve.provider) - return curve.formatUnits(await contract.claim(address, curve.constantOptions)); +export async function claimableFees(this: Curve, address = ""): Promise { + address = address || this.signerAddress; + const contract = new Contract(this.constants.ALIASES.fee_distributor, feeDistributorViewABI, this.provider) + return this.formatUnits(await contract.claim(address, this.constantOptions)); } -export const claimFeesEstimateGas = async (address = ""): Promise => { - address = address || curve.signerAddress; - const contract = curve.contracts[curve.constants.ALIASES.fee_distributor].contract; +export async function claimFeesEstimateGas(this: Curve, address = ""): Promise { + address = address || this.signerAddress; + const contract = this.contracts[this.constants.ALIASES.fee_distributor].contract; - return Number(DIGas(await contract.claim.estimateGas(address, curve.constantOptions))); + return Number(DIGas(await contract.claim.estimateGas(address, this.constantOptions))); } -export const claimFees = async (address = ""): Promise => { - if(curve.chainId !== 1) { +export async function claimFees(this: Curve, address = ""): Promise { + if(this.chainId !== 1) { throw Error('This method is only available for the network with chainId 1'); } - address = address || curve.signerAddress; - const contract = curve.contracts[curve.constants.ALIASES.fee_distributor].contract; + address = address || this.signerAddress; + const contract = this.contracts[this.constants.ALIASES.fee_distributor].contract; - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.claim.estimateGas(address, curve.constantOptions))); - return (await contract.claim(address, { ...curve.options, gasLimit })).hash + await this.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await contract.claim.estimateGas(address, this.constantOptions))); + return (await contract.claim(address, { ...this.options, gasLimit })).hash } -export const claimableFeesCrvUSD = async (address = ""): Promise => { - if(curve.chainId !== 1) { +export async function claimableFeesCrvUSD(this: Curve, address = ""): Promise { + if(this.chainId !== 1) { throw Error('This method is only available for the network with chainId 1'); } - address = address || curve.signerAddress; - const contract = new Contract(curve.constants.ALIASES.fee_distributor_crvusd, feeDistributorCrvUSDViewABI, curve.provider) - return curve.formatUnits(await contract.claim(address, curve.constantOptions)); + address = address || this.signerAddress; + const contract = new Contract(this.constants.ALIASES.fee_distributor_crvusd, feeDistributorCrvUSDViewABI, this.provider) + return this.formatUnits(await contract.claim(address, this.constantOptions)); } -export const claimFeesCrvUSDEstimateGas = async (address = ""): Promise => { - if(curve.chainId !== 1) { +export async function claimFeesCrvUSDEstimateGas(this: Curve, address = ""): Promise { + if(this.chainId !== 1) { throw Error('This method is only available for the network with chainId 1'); } - address = address || curve.signerAddress; - const contract = curve.contracts[curve.constants.ALIASES.fee_distributor_crvusd].contract; + address = address || this.signerAddress; + const contract = this.contracts[this.constants.ALIASES.fee_distributor_crvusd].contract; - return Number(DIGas(await contract.claim.estimateGas(address, curve.constantOptions))); + return Number(DIGas(await contract.claim.estimateGas(address, this.constantOptions))); } -export const claimFeesCrvUSD = async (address = ""): Promise => { - address = address || curve.signerAddress; - const contract = curve.contracts[curve.constants.ALIASES.fee_distributor_crvusd].contract; +export async function claimFeesCrvUSD(this: Curve, address = ""): Promise { + address = address || this.signerAddress; + const contract = this.contracts[this.constants.ALIASES.fee_distributor_crvusd].contract; - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.claim.estimateGas(address, curve.constantOptions))); + await this.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await contract.claim.estimateGas(address, this.constantOptions))); - return (await contract.claim(address, { ...curve.options, gasLimit })).hash + return (await contract.claim(address, { ...this.options, gasLimit })).hash } // ------------ SIDECHAIN ------------ -export const lastEthBlock = async (): Promise => { - if (curve.chainId === 1) throw Error("There is no lastBlock method on ethereum network"); - const veOracleContract = curve.contracts[curve.constants.ALIASES.voting_escrow_oracle].contract; +export async function lastEthBlock(this: Curve): Promise { + if (this.chainId === 1) throw Error("There is no lastBlock method on ethereum network"); + const veOracleContract = this.contracts[this.constants.ALIASES.voting_escrow_oracle].contract; - return Number(await veOracleContract.last_eth_block_number(curve.constantOptions)); + return Number(await veOracleContract.last_eth_block_number(this.constantOptions)); } -export const getAnycallBalance = async (): Promise => { - if (curve.chainId === 1) throw Error("There is no getAnycallBalance method on ethereum network"); - const anycallContract = curve.contracts[curve.constants.ALIASES.anycall].contract; - const _balance = await anycallContract.executionBudget(curve.constants.ALIASES.voting_escrow_oracle, curve.constantOptions); +export async function getAnycallBalance(this: Curve): Promise { + if (this.chainId === 1) throw Error("There is no getAnycallBalance method on ethereum network"); + const anycallContract = this.contracts[this.constants.ALIASES.anycall].contract; + const _balance = await anycallContract.executionBudget(this.constants.ALIASES.voting_escrow_oracle, this.constantOptions); + return this.formatUnits(_balance) +} - return curve.formatUnits(_balance) +function defaultAmount(this: Curve) { + return (this.chainId === 42161 || this.chainId === 10) ? 0.00001 : 0.1; } -const DEFAULT_AMOUNT = (curve.chainId === 42161 || curve.chainId === 10) ? 0.00001 : 0.1; -const _topUpAnycall = async (amount: number | string, estimateGas: boolean): Promise => { - if (curve.chainId === 1) throw Error("There is no topUpAnycall method on ethereum network"); - const anycallContract = curve.contracts[curve.constants.ALIASES.anycall].contract; - const value = curve.parseUnits(String(amount)); - const gas = await anycallContract.deposit.estimateGas(curve.constants.ALIASES.voting_escrow_oracle, { ...curve.constantOptions, value}); +async function _topUpAnycall(this: Curve, amount: number | string, estimateGas: boolean): Promise { + if (this.chainId === 1) throw Error("There is no topUpAnycall method on ethereum network"); + const anycallContract = this.contracts[this.constants.ALIASES.anycall].contract; + const value = this.parseUnits(String(amount)); + const gas = await anycallContract.deposit.estimateGas(this.constants.ALIASES.voting_escrow_oracle, { ...this.constantOptions, value}); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await anycallContract.deposit(curve.constants.ALIASES.voting_escrow_oracle, { ...curve.options, gasLimit, value })).hash; + return (await anycallContract.deposit(this.constants.ALIASES.voting_escrow_oracle, { ...this.options, gasLimit, value })).hash; } -export const topUpAnycallEstimateGas = async (amount: number | string = DEFAULT_AMOUNT): Promise => { - return await _topUpAnycall(amount, true) as number; +export async function topUpAnycallEstimateGas(this: Curve, amount: number | string = defaultAmount.call(this)): Promise { + return await _topUpAnycall.call(this, amount, true) as number; } -export const topUpAnycall = async (amount: number | string = DEFAULT_AMOUNT): Promise => { - return await _topUpAnycall(amount, false) as string; +export async function topUpAnycall(this: Curve, amount: number | string = defaultAmount.call(this)): Promise { + return await _topUpAnycall.call(this, amount, false) as string; } -export const lastBlockSent = async (chainId: IChainId): Promise => { - if (curve.chainId !== 1) throw Error("lastBlockNumberSent method is on ethereum network only"); - const veOracleContract = curve.contracts[curve.constants.ALIASES.voting_escrow_oracle].contract; +export async function lastBlockSent(this: Curve, chainId: IChainId): Promise { + if (this.chainId !== 1) throw Error("lastBlockNumberSent method is on ethereum network only"); + const veOracleContract = this.contracts[this.constants.ALIASES.voting_escrow_oracle].contract; - return Number(await veOracleContract.get_last_block_number_sent(chainId, curve.constantOptions)); + return Number(await veOracleContract.get_last_block_number_sent(chainId, this.constantOptions)); } -export const blockToSend = async (): Promise => { - if (curve.chainId !== 1) throw Error("blockToSend method is on ethereum network only"); - return (await curve.provider.getBlockNumber()) - 128; +export async function blockToSend(this: Curve): Promise { + if (this.chainId !== 1) throw Error("blockToSend method is on ethereum network only"); + return (await this.provider.getBlockNumber()) - 128; } -const _sendBlockhash = async (block: number, chainId: IChainId, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("sendBlockhash method is on ethereum network only"); - const veOracleContract = curve.contracts[curve.constants.ALIASES.voting_escrow_oracle].contract; - const gas = await veOracleContract.send_blockhash.estimateGas(block, chainId, curve.constantOptions); +async function _sendBlockhash(this: Curve, block: number, chainId: IChainId, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("sendBlockhash method is on ethereum network only"); + const veOracleContract = this.contracts[this.constants.ALIASES.voting_escrow_oracle].contract; + const gas = await veOracleContract.send_blockhash.estimateGas(block, chainId, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await veOracleContract.send_blockhash(block, chainId, { ...curve.options, gasLimit })).hash; + return (await veOracleContract.send_blockhash(block, chainId, { ...this.options, gasLimit })).hash; } -export const sendBlockhashEstimateGas = async (block: number, chainId: IChainId): Promise => { - return await _sendBlockhash(block, chainId, true) as number; +export async function sendBlockhashEstimateGas(this: Curve, block: number, chainId: IChainId): Promise { + return await _sendBlockhash.call(this, block, chainId, true) as number; } -export const sendBlockhash = async (block: number, chainId: IChainId): Promise => { - return await _sendBlockhash(block, chainId, false) as string; +export async function sendBlockhash(this: Curve, block: number, chainId: IChainId): Promise { + return await _sendBlockhash.call(this, block, chainId, false) as string; } -const _submitProof = async (block: number, address = curve.signerAddress, estimateGas: boolean): Promise => { - if (curve.chainId === 1) throw Error("submitProof method is on ethereum network only"); +async function _submitProof(this: Curve, block: number, address = this.signerAddress, estimateGas: boolean): Promise { + if (this.chainId === 1) throw Error("submitProof method is on ethereum network only"); if (address === "") throw Error("Pass address you want to submit proof for") const proof = await _generateBoostingProof(block, address); - const veOracleContract = curve.contracts[curve.constants.ALIASES.voting_escrow_oracle].contract; - const gas = await veOracleContract.submit_state.estimateGas(address, "0x" + proof.block_header_rlp, "0x" + proof.proof_rlp, curve.constantOptions); + const veOracleContract = this.contracts[this.constants.ALIASES.voting_escrow_oracle].contract; + const gas = await veOracleContract.submit_state.estimateGas(address, "0x" + proof.block_header_rlp, "0x" + proof.proof_rlp, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await veOracleContract.submit_state(address, "0x" + proof.block_header_rlp, "0x" + proof.proof_rlp, { ...curve.options, gasLimit })).hash; + return (await veOracleContract.submit_state(address, "0x" + proof.block_header_rlp, "0x" + proof.proof_rlp, { ...this.options, gasLimit })).hash; } -export const submitProofEstimateGas = async (block: number, address = curve.signerAddress): Promise => { - return await _submitProof(block, address, true) as number; +export async function submitProofEstimateGas(this: Curve, block: number, address = this.signerAddress): Promise { + return await _submitProof.call(this, block, address, true) as number; } -export const submitProof = async (block: number, address = curve.signerAddress): Promise => { - return await _submitProof(block, address, false) as string; +export async function submitProof(this: Curve, block: number, address = this.signerAddress): Promise { + return await _submitProof.call(this, block, address, false) as string; } diff --git a/src/cached.ts b/src/cached.ts index 8f6ca58e..9bdde084 100644 --- a/src/cached.ts +++ b/src/cached.ts @@ -1,7 +1,6 @@ import memoize from "memoizee"; import {IDict, IExtendedPoolDataFromApi, INetworkName, IPoolType} from "./interfaces.js"; -import {uncached_getAllPoolsFromApi, createCrvApyDict, createUsdPricesDict} from './external-api.js' -import {curve} from "./curve"; +import {createCrvApyDict, createUsdPricesDict, uncached_getAllPoolsFromApi} from './external-api.js' /** * This function is used to cache the data fetched from the API and the data derived from it. @@ -33,14 +32,12 @@ export const _getAllPoolsFromApi = async (network: INetworkName, isLiteChain = f return poolLists } -export const _getUsdPricesFromApi = async (): Promise> => { - const network = curve.constants.NETWORK_NAME; +export const _getUsdPricesFromApi = async (network:INetworkName): Promise> => { const {usdPrices} = await _getCachedData(network, false); return usdPrices } -export const _getCrvApyFromApi = async (): Promise> => { - const network = curve.constants.NETWORK_NAME; +export const _getCrvApyFromApi = async (network:INetworkName): Promise> => { const {crvApy} = await _getCachedData(network, false); return crvApy } diff --git a/src/constants/utils.ts b/src/constants/utils.ts index cb45bb0a..fc0a31f6 100644 --- a/src/constants/utils.ts +++ b/src/constants/utils.ts @@ -1,6 +1,10 @@ -import { curve } from "../curve.js"; -import { IDict, IPoolData } from "../interfaces.js"; +import {IDict, IPoolData} from "../interfaces.js"; +import {BigNumberish, ethers, Numeric} from "ethers"; +import memoize from "memoizee"; +import {Curve} from "../curve"; +export const formatUnits = (value: BigNumberish, unit?: string | Numeric): string => ethers.formatUnits(value, unit); +export const parseUnits = (value: string, unit?: string | Numeric) => ethers.parseUnits(value, unit) export const lowerCasePoolDataAddresses = (poolsData: IDict): IDict => { for (const poolId in poolsData) { @@ -42,10 +46,10 @@ export const extractDecimals = (poolsData: IDict): IDict => { return DECIMALS; } -export const extractGauges = (poolsData: IDict): string[] => { +export function extractGauges(this: Curve, poolsData: IDict): string[] { const GAUGES: string[] = []; for (const poolData of Object.values(poolsData)) { - if (poolData.gauge_address === curve.constants.ZERO_ADDRESS) continue; + if (poolData.gauge_address === this.constants.ZERO_ADDRESS) continue; GAUGES.push(poolData.gauge_address); } @@ -53,11 +57,24 @@ export const extractGauges = (poolsData: IDict): string[] => { } export const lowerCaseValues = (dict: IDict): IDict => { - // @ts-ignore return Object.fromEntries(Object.entries(dict).map((entry) => [entry[0], entry[1].toLowerCase()])) } export const lowerCaseKeys = (dict: IDict): IDict => { - // @ts-ignore return Object.fromEntries(Object.entries(dict).map((entry) => [entry[0].toLowerCase(), entry[1]])) } + +/** + * Memoizes a method of an object by binding it to this when needed. + * The memoized method will cache the result for 5 minutes. + * @param obj The object to which the method belongs. + * @param name The name of the method to memoize. It must be unique within the object. + * @param method The method to memoize. It must be a function that returns a Promise. + * @returns The memoized method. + */ +export const memoizeMethod = Promise>(obj: Obj, name: string, method: Method) => { + if (!(name in obj)) { + (obj as any)[name] = memoize(method.bind(obj), { promise: true, maxAge: 5 * 60 * 1000 /* 5m */ }); + } + return (obj as any)[name] as Method; +} diff --git a/src/curve.ts b/src/curve.ts index a0c83c5d..3e593f40 100644 --- a/src/curve.ts +++ b/src/curve.ts @@ -1,60 +1,65 @@ import { - ethers, - Contract, - Networkish, - BigNumberish, - Numeric, AbstractProvider, + BigNumberish, BrowserProvider, + Contract, + ethers, JsonRpcProvider, + Networkish, + Numeric, Signer, } from "ethers"; -import { Provider as MulticallProvider, Contract as MulticallContract } from "@curvefi/ethcall"; -import { NETWORK_CONSTANTS } from "./constants/network_constants.js"; -import { STABLE_FACTORY_CONSTANTS, CRYPTO_FACTORY_CONSTANTS } from "./constants/factory/index.js"; -import { getFactoryPoolData } from "./factory/factory.js"; -import { getFactoryPoolsDataFromApi } from "./factory/factory-api.js"; -import { getCryptoFactoryPoolData } from "./factory/factory-crypto.js"; -import { getTricryptoFactoryPoolData } from "./factory/factory-tricrypto.js"; -import {IPoolData, IDict, ICurve, IChainId, IFactoryPoolType, Abi, INetworkConstants} from "./interfaces"; -import ERC20Abi from './constants/abis/ERC20.json' with { type: 'json' }; -import cERC20Abi from './constants/abis/cERC20.json' with { type: 'json' }; -import yERC20Abi from './constants/abis/yERC20.json' with { type: 'json' }; -import childGaugeFactoryABI from './constants/abis/gauge_factory/child_gauge_factory.json' with { type: 'json' }; -import minterMainnetABI from './constants/abis/minter_mainnet.json' with { type: 'json' }; -import votingEscrowABI from './constants/abis/votingescrow.json' with { type: 'json' }; -import anycallABI from './constants/abis/anycall.json' with { type: 'json' }; -import votingEscrowOracleABI from './constants/abis/voting_escrow_oracle.json' with { type: 'json' }; -import votingEscrowOracleEthABI from './constants/abis/voting_escrow_oracle_eth.json' with { type: 'json' }; -import feeDistributorABI from './constants/abis/fee_distributor.json' with { type: 'json' }; -import feeDistributorCrvUSDABI from './constants/abis/fee_distributor_crvusd.json' with { type: 'json' }; -import gaugeControllerABI from './constants/abis/gaugecontroller.json' with { type: 'json' }; -import depositAndStakeABI from './constants/abis/deposit_and_stake.json' with { type: 'json' }; -import depositAndStakeNgOnlyABI from './constants/abis/deposit_and_stake_ng_only.json' with { type: 'json' }; -import cryptoCalcZapABI from './constants/abis/crypto_calc.json' with { type: 'json' }; -import StableCalcZapABI from './constants/abis/stable_calc.json' with { type: 'json' }; -import routerABI from './constants/abis/router.json' with { type: 'json' }; -import routerPolygonABI from './constants/abis/routerPolygon.json' with { type: 'json' }; -import routerNgPoolsOnlyABI from './constants/abis/router-ng-pools-only.json' with { type: 'json' }; -import streamerABI from './constants/abis/streamer.json' with { type: 'json' }; -import factoryABI from './constants/abis/factory.json' with { type: 'json' }; -import factoryEywaABI from './constants/abis/factory-eywa.json' with { type: 'json' }; -import factoryAdminABI from './constants/abis/factory-admin.json' with { type: 'json' }; -import cryptoFactoryABI from './constants/abis/factory-crypto.json' with { type: 'json' }; -import twocryptoFactoryABI from './constants/abis/factory-twocrypto-ng.json' with { type: 'json' }; -import tricryptoFactoryMainnetABI from './constants/abis/factory-tricrypto-mainnet.json' with { type: 'json' }; -import tricryptoFactorySidechainABI from './constants/abis/factory-tricrypto-sidechain.json' with { type: 'json' }; -import stableNgFactoryABI from './constants/abis/factory-stable-ng.json' with { type: 'json' }; -import gasOracleABI from './constants/abis/gas_oracle_optimism.json' with { type: 'json' }; -import gasOracleBlobABI from './constants/abis/gas_oracle_optimism_blob.json' with { type: 'json' }; -import votingProposalABI from './constants/abis/voting_proposal.json' with { type: 'json' }; -import circulatingSupplyABI from './constants/abis/circulating_supply.json' with { type: 'json' }; -import rootGaugeFactoryABI from "./constants/abis/gauge_factory/root_gauge_factory.json" with { type: 'json' }; - -import { lowerCasePoolDataAddresses, extractDecimals, extractGauges } from "./constants/utils.js"; +import {Contract as MulticallContract, Provider as MulticallProvider} from "@curvefi/ethcall"; +import {NETWORK_CONSTANTS} from "./constants/network_constants.js"; +import {CRYPTO_FACTORY_CONSTANTS, STABLE_FACTORY_CONSTANTS} from "./constants/factory/index.js"; +import {getFactoryPoolData} from "./factory/factory.js"; +import {getFactoryPoolsDataFromApi} from "./factory/factory-api.js"; +import {getCryptoFactoryPoolData} from "./factory/factory-crypto.js"; +import {getTricryptoFactoryPoolData} from "./factory/factory-tricrypto.js"; +import {Abi, IChainId, ICurve, IDict, IFactoryPoolType, INetworkConstants, IPoolData} from "./interfaces"; +import ERC20Abi from './constants/abis/ERC20.json' with {type: 'json'}; +import cERC20Abi from './constants/abis/cERC20.json' with {type: 'json'}; +import yERC20Abi from './constants/abis/yERC20.json' with {type: 'json'}; +import childGaugeFactoryABI from './constants/abis/gauge_factory/child_gauge_factory.json' with {type: 'json'}; +import minterMainnetABI from './constants/abis/minter_mainnet.json' with {type: 'json'}; +import votingEscrowABI from './constants/abis/votingescrow.json' with {type: 'json'}; +import anycallABI from './constants/abis/anycall.json' with {type: 'json'}; +import votingEscrowOracleABI from './constants/abis/voting_escrow_oracle.json' with {type: 'json'}; +import votingEscrowOracleEthABI from './constants/abis/voting_escrow_oracle_eth.json' with {type: 'json'}; +import feeDistributorABI from './constants/abis/fee_distributor.json' with {type: 'json'}; +import feeDistributorCrvUSDABI from './constants/abis/fee_distributor_crvusd.json' with {type: 'json'}; +import gaugeControllerABI from './constants/abis/gaugecontroller.json' with {type: 'json'}; +import depositAndStakeABI from './constants/abis/deposit_and_stake.json' with {type: 'json'}; +import depositAndStakeNgOnlyABI from './constants/abis/deposit_and_stake_ng_only.json' with {type: 'json'}; +import cryptoCalcZapABI from './constants/abis/crypto_calc.json' with {type: 'json'}; +import StableCalcZapABI from './constants/abis/stable_calc.json' with {type: 'json'}; +import routerABI from './constants/abis/router.json' with {type: 'json'}; +import routerPolygonABI from './constants/abis/routerPolygon.json' with {type: 'json'}; +import routerNgPoolsOnlyABI from './constants/abis/router-ng-pools-only.json' with {type: 'json'}; +import streamerABI from './constants/abis/streamer.json' with {type: 'json'}; +import factoryABI from './constants/abis/factory.json' with {type: 'json'}; +import factoryEywaABI from './constants/abis/factory-eywa.json' with {type: 'json'}; +import factoryAdminABI from './constants/abis/factory-admin.json' with {type: 'json'}; +import cryptoFactoryABI from './constants/abis/factory-crypto.json' with {type: 'json'}; +import twocryptoFactoryABI from './constants/abis/factory-twocrypto-ng.json' with {type: 'json'}; +import tricryptoFactoryMainnetABI from './constants/abis/factory-tricrypto-mainnet.json' with {type: 'json'}; +import tricryptoFactorySidechainABI from './constants/abis/factory-tricrypto-sidechain.json' with {type: 'json'}; +import stableNgFactoryABI from './constants/abis/factory-stable-ng.json' with {type: 'json'}; +import gasOracleABI from './constants/abis/gas_oracle_optimism.json' with {type: 'json'}; +import gasOracleBlobABI from './constants/abis/gas_oracle_optimism_blob.json' with {type: 'json'}; +import votingProposalABI from './constants/abis/voting_proposal.json' with {type: 'json'}; +import circulatingSupplyABI from './constants/abis/circulating_supply.json' with {type: 'json'}; +import rootGaugeFactoryABI from "./constants/abis/gauge_factory/root_gauge_factory.json" with {type: "json"}; +import { + extractDecimals, + extractGauges, + formatUnits, + lowerCasePoolDataAddresses, + parseUnits, +} from "./constants/utils.js"; import {_getHiddenPools} from "./external-api.js"; -import { L2Networks } from "./constants/L2Networks.js"; -import { getTwocryptoFactoryPoolData } from "./factory/factory-twocrypto.js"; +import {L2Networks} from "./constants/L2Networks.js"; +import {getTwocryptoFactoryPoolData} from "./factory/factory-twocrypto.js"; import {getNetworkConstants} from "./utils.js"; @@ -90,7 +95,7 @@ export const memoizedMulticallContract = (): (address: string, abi: any) => Mult export type ContractItem = { contract: Contract, multicallContract: MulticallContract, abi: Abi }; -class Curve implements ICurve { +export class Curve implements ICurve { provider: ethers.BrowserProvider | ethers.JsonRpcProvider; isNoRPC: boolean; multicallProvider: MulticallProvider; @@ -106,16 +111,13 @@ class Curve implements ICurve { constants: INetworkConstants; constructor() { - // @ts-ignore - this.provider = null; - // @ts-ignore + this.provider = null!; this.signer = null; this.isNoRPC = false; this.signerAddress = ''; this.chainId = 1; this.isLiteChain = false; - // @ts-ignore - this.multicallProvider = null; + this.multicallProvider = null!; this.contracts = {}; this.feeData = {} this.constantOptions = { gasLimit: 12000000 } @@ -149,15 +151,12 @@ class Curve implements ICurve { providerSettings: { url?: string, privateKey?: string, batchMaxCount? : number } | { externalProvider: ethers.Eip1193Provider } | { network?: Networkish, apiKey?: string } | 'NoRPC', options: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number, chainId?: number } = {} // gasPrice in Gwei ): Promise { - // @ts-ignore - this.provider = null; - // @ts-ignore + this.provider = null!; this.signer = null; this.isNoRPC = false; this.signerAddress = ''; this.chainId = 1; - // @ts-ignore - this.multicallProvider = null; + this.multicallProvider = null!; this.contracts = {}; this.feeData = {} this.constantOptions = { gasLimit: 12000000 } @@ -210,7 +209,7 @@ class Curve implements ICurve { } else if (!providerSettings.url?.startsWith("https://rpc.gnosischain.com")) { try { this.signer = await this.provider.getSigner(); - } catch (e) { + } catch { this.signer = null; } } @@ -245,7 +244,7 @@ class Curve implements ICurve { this.isLiteChain = !(this.chainId in NETWORK_CONSTANTS); - const network_constants = await getNetworkConstants(this.chainId); + const network_constants = await getNetworkConstants.call(this, this.chainId); this.constants.NATIVE_TOKEN = network_constants.NATIVE_COIN; this.constants.NETWORK_NAME = network_constants.NAME; this.constants.ALIASES = network_constants.ALIASES; @@ -258,7 +257,7 @@ class Curve implements ICurve { this.constants.DECIMALS = extractDecimals({...this.constants.POOLS_DATA, ...this.constants.LLAMMAS_DATA}); this.constants.DECIMALS[this.constants.NATIVE_TOKEN.address] = 18; this.constants.DECIMALS[this.constants.NATIVE_TOKEN.wrappedAddress] = 18; - this.constants.GAUGES = extractGauges(this.constants.POOLS_DATA); + this.constants.GAUGES = extractGauges.call(this, this.constants.POOLS_DATA); if(this.isLiteChain) { this.constants.API_CONSTANTS = network_constants.API_CONSTANTS @@ -287,7 +286,7 @@ class Curve implements ICurve { if (this.signer) { try { this.signerAddress = await this.signer.getAddress(); - } catch (err) { + } catch { this.signer = null; } } else { @@ -438,47 +437,29 @@ class Curve implements ICurve { curveInstance.setContract(curveInstance.constants.ALIASES.gas_oracle, gasOracleABI); curveInstance.setContract(curveInstance.constants.ALIASES.gas_oracle_blob, gasOracleBlobABI); - // @ts-ignore - if(AbstractProvider.prototype.originalEstimate) { - // @ts-ignore - AbstractProvider.prototype.estimateGas = AbstractProvider.prototype.originalEstimate; + if('originalEstimate' in AbstractProvider.prototype) { + AbstractProvider.prototype.estimateGas = AbstractProvider.prototype.originalEstimate as any; } const originalEstimate = AbstractProvider.prototype.estimateGas; - const oldEstimate = async function(arg: any) { - // @ts-ignore - const originalEstimateFunc = originalEstimate.bind(this); - - const gas = await originalEstimateFunc(arg); - - return gas; - } + const oldEstimate = originalEstimate.bind(this) //Override const newEstimate = async function(arg: any) { - // @ts-ignore - const L2EstimateGas = originalEstimate.bind(this); - + const L2EstimateGas = oldEstimate; const L1GasUsed = await curveInstance.contracts[curveInstance.constants.ALIASES.gas_oracle_blob].contract.getL1GasUsed(arg.data); const L1Fee = await curveInstance.contracts[curveInstance.constants.ALIASES.gas_oracle_blob].contract.getL1Fee(arg.data); - curveInstance.L1WeightedGasPrice = Number(L1Fee)/Number(L1GasUsed); - const L2GasUsed = await L2EstimateGas(arg); - return [L2GasUsed,L1GasUsed]; } - // @ts-ignore - AbstractProvider.prototype.estimateGas = newEstimate; - // @ts-ignore - AbstractProvider.prototype.originalEstimate = oldEstimate; + AbstractProvider.prototype.estimateGas = newEstimate as any; + (AbstractProvider.prototype as any).originalEstimate = oldEstimate; } else { - // @ts-ignore - if(AbstractProvider.prototype.originalEstimate) { - // @ts-ignore - AbstractProvider.prototype.estimateGas = AbstractProvider.prototype.originalEstimate; + if('originalEstimate' in AbstractProvider.prototype) { + AbstractProvider.prototype.estimateGas = AbstractProvider.prototype.originalEstimate as any; } } } @@ -514,13 +495,12 @@ class Curve implements ICurve { async _filterHiddenPools(pools: IDict): Promise> { const hiddenPools = (await _getHiddenPools())[this.constants.NETWORK_NAME] || []; - // @ts-ignore - return Object.fromEntries(Object.entries(pools).filter(([id]) => !hiddenPools.includes(id))); + return Object.fromEntries(Object.entries(pools).filter(([id]) => !hiddenPools.includes(id))) as IDict; } _updateDecimalsAndGauges(pools: IDict): void { this.constants.DECIMALS = { ...this.constants.DECIMALS, ...extractDecimals(pools) }; - this.constants.GAUGES = [ ...this.constants.GAUGES, ...extractGauges(pools) ]; + this.constants.GAUGES = [ ...this.constants.GAUGES, ...extractGauges.call(this, pools) ]; } fetchFactoryPools = async (useApi = true): Promise => { @@ -808,11 +788,11 @@ class Curve implements ICurve { } formatUnits(value: BigNumberish, unit?: string | Numeric): string { - return ethers.formatUnits(value, unit); + return formatUnits(value, unit); } parseUnits(value: string, unit?: string | Numeric): bigint { - return ethers.parseUnits(value, unit); + return parseUnits(value, unit); } async updateFeeData(): Promise { diff --git a/src/dao.ts b/src/dao.ts index 357c6cfe..57c05f49 100644 --- a/src/dao.ts +++ b/src/dao.ts @@ -1,62 +1,65 @@ -import { curve } from "./curve.js"; -import { Contract } from "ethers"; -import { _getAllGauges, _getDaoProposalList, _getDaoProposal } from './external-api.js'; +import { type Curve} from "./curve.js"; +import {Contract} from "ethers"; +import {_getAllGauges, _getDaoProposal, _getDaoProposalList} from './external-api.js'; import { _getAddress, - DIGas, ensureAllowance, ensureAllowanceEstimateGas, hasAllowance, + BN, + DIGas, + ensureAllowance, + ensureAllowanceEstimateGas, + hasAllowance, mulBy1_3, parseUnits, smartNumber, toBN, - BN, } from './utils.js'; import { - IGaugeUserVote, - IVotingGauge, + IDaoProposal, IDaoProposalListItem, IDaoProposalUserListItem, - IDaoProposal, IDict, + IGaugeUserVote, + IVotingGauge, TVoteType, } from './interfaces'; -import feeDistributorViewABI from "./constants/abis/fee_distributor_view.json" with { type: 'json' }; +import feeDistributorViewABI from "./constants/abis/fee_distributor_view.json" with {type: "json"}; // ----------------- Refactored boosting stuff ----------------- -export const crvSupplyStats = async (): Promise<{ circulating: string, locked: string, total: string, veCrv: string, averageLockTime: string }> => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const crvContract = curve.contracts[curve.constants.ALIASES.crv].multicallContract; - const veContract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; - const csContract = curve.contracts[curve.constants.ALIASES.circulating_supply].multicallContract; - const [_circulating, _locked, _veCrv] = await curve.multicallProvider.all([ +export async function crvSupplyStats(this: Curve): Promise<{ circulating: string, locked: string, total: string, veCrv: string, averageLockTime: string }> { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const crvContract = this.contracts[this.constants.ALIASES.crv].multicallContract; + const veContract = this.contracts[this.constants.ALIASES.voting_escrow].multicallContract; + const csContract = this.contracts[this.constants.ALIASES.circulating_supply].multicallContract; + const [_circulating, _locked, _veCrv] = await this.multicallProvider.all([ csContract.circulating_supply(), - crvContract.balanceOf(curve.constants.ALIASES.voting_escrow), + crvContract.balanceOf(this.constants.ALIASES.voting_escrow), veContract.totalSupply(), ]) as [bigint, bigint, bigint]; return { - circulating: curve.formatUnits(_circulating), - locked: curve.formatUnits(_locked), - total: curve.formatUnits(_circulating + _locked), - veCrv: curve.formatUnits(_veCrv), + circulating: this.formatUnits(_circulating), + locked: this.formatUnits(_locked), + total: this.formatUnits(_circulating + _locked), + veCrv: this.formatUnits(_veCrv), averageLockTime: toBN(_veCrv).div(toBN(_locked)).times(4).toFixed(4), // years } } -export const userCrv = async (address = ""): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - address = _getAddress(address); - const _balance: bigint = await curve.contracts[curve.constants.ALIASES.crv].contract.balanceOf(address); +export async function userCrv(this: Curve, address = ""): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + address = _getAddress.call(this, address); + const _balance: bigint = await this.contracts[this.constants.ALIASES.crv].contract.balanceOf(address); - return curve.formatUnits(_balance) + return this.formatUnits(_balance) } -export const userVeCrv = async (address = ""): Promise<{ veCrv: string, veCrvPct: string, lockedCrv: string, unlockTime: number }> => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - address = _getAddress(address); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; - const [_veCrv, _veCrvTotal, _locked] = await curve.multicallProvider.all([ +export async function userVeCrv(this: Curve, address = ""): Promise<{ veCrv: string, veCrvPct: string, lockedCrv: string, unlockTime: number }> { + if (this.chainId !== 1) throw Error("Ethereum-only method") + address = _getAddress.call(this, address); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].multicallContract; + const [_veCrv, _veCrvTotal, _locked] = await this.multicallProvider.all([ contract.balanceOf(address), contract.totalSupply(), contract.locked(address), @@ -65,26 +68,26 @@ export const userVeCrv = async (address = ""): Promise<{ veCrv: string, veCrvPct const _unlockTime = (_locked as bigint[])[1]; return { - veCrv: curve.formatUnits(_veCrv), + veCrv: this.formatUnits(_veCrv), veCrvPct: toBN(_veCrv).div(toBN(_veCrvTotal)).times(100).toString(), - lockedCrv: curve.formatUnits(_lockedCrv), - unlockTime: Number(curve.formatUnits(_unlockTime, 0)) * 1000, + lockedCrv: this.formatUnits(_lockedCrv), + unlockTime: Number(this.formatUnits(_unlockTime, 0)) * 1000, } } -export const crvLockIsApproved = async (amount: number | string): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - return await hasAllowance([curve.constants.ALIASES.crv], [amount], curve.signerAddress, curve.constants.ALIASES.voting_escrow); +export async function crvLockIsApproved(this: Curve, amount: number | string): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + return await hasAllowance.call(this, [this.constants.ALIASES.crv], [amount], this.signerAddress, this.constants.ALIASES.voting_escrow); } -export const crvLockApproveEstimateGas = async (amount: number | string): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - return await ensureAllowanceEstimateGas([curve.constants.ALIASES.crv], [amount], curve.constants.ALIASES.voting_escrow, false); +export async function crvLockApproveEstimateGas(this: Curve, amount: number | string): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + return await ensureAllowanceEstimateGas.call(this, [this.constants.ALIASES.crv], [amount], this.constants.ALIASES.voting_escrow, false); } -export const crvLockApprove = async (amount: number | string): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - return await ensureAllowance([curve.constants.ALIASES.crv], [amount], curve.constants.ALIASES.voting_escrow, false); +export async function crvLockApprove(this: Curve, amount: number | string): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + return await ensureAllowance.call(this, [this.constants.ALIASES.crv], [amount], this.constants.ALIASES.voting_escrow, false); } export const calcCrvUnlockTime = (days: number | string, start: number | string = Date.now()): number => { @@ -95,132 +98,127 @@ export const calcCrvUnlockTime = (days: number | string, start: number | string return Math.floor(unlockTime / week) * week * 1000; } -const _createCrvLock = async (amount: number | string, days: number, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const crvBalance = await userCrv(); +async function _createCrvLock(this: Curve, amount: number | string, days: number, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const crvBalance = await userCrv.call(this); if (BN(crvBalance).lt(amount)) throw Error(`Not enough CRV. Wallet balance: ${crvBalance}, required: ${amount}`); - if (!(await crvLockIsApproved(amount))) throw Error("Token allowance is needed to estimate gas") + if (!(await crvLockIsApproved.call(this, amount))) throw Error("Token allowance is needed to estimate gas") const _amount = parseUnits(amount); const unlockTime = Math.floor(Date.now() / 1000) + (days * 86400); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; - const gas = await contract.create_lock.estimateGas(_amount, unlockTime, curve.constantOptions); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; + const gas = await contract.create_lock.estimateGas(_amount, unlockTime, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.create_lock(_amount, unlockTime, { ...curve.options, gasLimit })).hash; + return (await contract.create_lock(_amount, unlockTime, { ...this.options, gasLimit })).hash; } -export const createCrvLockEstimateGas = async (amount: number | string, days: number | string): Promise => { - return await _createCrvLock(amount, Number(days), true) as number | number[]; +export async function createCrvLockEstimateGas(this: Curve, amount: number | string, days: number | string): Promise { + return await _createCrvLock.call(this, amount, Number(days), true) as number | number[]; } -export const createCrvLock = async (amount: number | string, days: number | string): Promise => { - return await _createCrvLock(amount, Number(days), false) as string; +export async function createCrvLock(this: Curve, amount: number | string, days: number | string): Promise { + return await _createCrvLock.call(this, amount, Number(days), false) as string; } -const _increaseCrvLockedAmount = async (amount: number | string, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const crvBalance = await userCrv(); +async function _increaseCrvLockedAmount(this: Curve, amount: number | string, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const crvBalance = await userCrv.call(this); if (BN(crvBalance).lt(amount)) throw Error(`Not enough CRV. Wallet balance: ${crvBalance}, required: ${amount}`); - if (!(await crvLockIsApproved(amount))) throw Error("Token allowance is needed to estimate gas") + if (!(await crvLockIsApproved.call(this, amount))) throw Error("Token allowance is needed to estimate gas") const _amount = parseUnits(amount); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; - const gas = await contract.increase_amount.estimateGas(_amount, curve.constantOptions); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; + const gas = await contract.increase_amount.estimateGas(_amount, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.increase_amount(_amount, { ...curve.options, gasLimit })).hash; + return (await contract.increase_amount(_amount, { ...this.options, gasLimit })).hash; } -export const increaseCrvLockedAmountEstimateGas = async (amount: number | string): Promise => { - return await _increaseCrvLockedAmount(amount, true) as number | number[]; +export async function increaseCrvLockedAmountEstimateGas(this: Curve, amount: number | string): Promise { + return await _increaseCrvLockedAmount.call(this, amount, true) as number | number[]; } -export const increaseCrvLockedAmount = async (amount: number | string): Promise => { - return await _increaseCrvLockedAmount(amount, false) as string; +export async function increaseCrvLockedAmount(this: Curve, amount: number | string): Promise { + return await _increaseCrvLockedAmount.call(this, amount, false) as string; } -const _increaseCrvUnlockTime = async (days: number, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const { unlockTime } = await userVeCrv(); +async function _increaseCrvUnlockTime(this: Curve, days: number, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const { unlockTime } = await userVeCrv.call(this); const newUnlockTime = Math.floor(unlockTime / 1000) + (days * 86400); - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; - const gas = await contract.increase_unlock_time.estimateGas(newUnlockTime, curve.constantOptions); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; + const gas = await contract.increase_unlock_time.estimateGas(newUnlockTime, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.increase_unlock_time(newUnlockTime, { ...curve.options, gasLimit })).hash; + return (await contract.increase_unlock_time(newUnlockTime, { ...this.options, gasLimit })).hash; } -export const increaseCrvUnlockTimeEstimateGas = async (days: number | string): Promise => { - return await _increaseCrvUnlockTime(Number(days), true) as number | number[]; +export async function increaseCrvUnlockTimeEstimateGas(this: Curve, days: number | string): Promise { + return await _increaseCrvUnlockTime.call(this, Number(days), true) as number | number[]; } -export const increaseCrvUnlockTime = async (days: number | string): Promise => { - return await _increaseCrvUnlockTime(Number(days), false) as string; +export async function increaseCrvUnlockTime(this: Curve, days: number | string): Promise { + return await _increaseCrvUnlockTime.call(this, Number(days), false) as string; } -const _withdrawLockedCrv = async (estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method"); - const { unlockTime } = await userVeCrv(); +async function _withdrawLockedCrv(this: Curve, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method"); + const { unlockTime } = await userVeCrv.call(this); if (unlockTime > Date.now()) throw Error("The lock haven't expired yet") - const contract = curve.contracts[curve.constants.ALIASES.voting_escrow].contract; - const gas = await contract.withdraw.estimateGas(curve.constantOptions); + const contract = this.contracts[this.constants.ALIASES.voting_escrow].contract; + const gas = await contract.withdraw.estimateGas(this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.withdraw({ ...curve.options, gasLimit })).hash; + return (await contract.withdraw({ ...this.options, gasLimit })).hash; } -export const withdrawLockedCrvEstimateGas = async (): Promise => { - return await _withdrawLockedCrv(true) as number | number[]; +export async function withdrawLockedCrvEstimateGas(this: Curve): Promise { + return await _withdrawLockedCrv.call(this, true) as number | number[]; } -export const withdrawLockedCrv = async (): Promise => { - return await _withdrawLockedCrv(false) as string; +export async function withdrawLockedCrv(this: Curve): Promise { + return await _withdrawLockedCrv.call(this, false) as string; } -export const claimableFees = async (address = ""): Promise => { - address = _getAddress(address); - const contract = new Contract(curve.constants.ALIASES.fee_distributor, feeDistributorViewABI, curve.provider) - return curve.formatUnits(await contract.claim(address, curve.constantOptions)); +export async function claimableFees(this: Curve, address = ""): Promise { + address = _getAddress.call(this, address); + const contract = new Contract(this.constants.ALIASES.fee_distributor, feeDistributorViewABI, this.provider) + return this.formatUnits(await contract.claim(address, this.constantOptions)); } -const _claimFees = async (address: string, estimateGas: boolean): Promise => { - address = _getAddress(address); - const contract = curve.contracts[curve.constants.ALIASES.fee_distributor].contract; - const gas = await contract.claim.estimateGas(address, curve.constantOptions); +async function _claimFees(this: Curve, address: string, estimateGas: boolean): Promise { + address = _getAddress.call(this, address); + const contract = this.contracts[this.constants.ALIASES.fee_distributor].contract; + const gas = await contract.claim.estimateGas(address, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.claim(address, { ...curve.options, gasLimit })).hash; + return (await contract.claim(address, { ...this.options, gasLimit })).hash; } -export const claimFeesEstimateGas = async (address = ""): Promise => { - return await _claimFees(address,true) as number | number[]; +export async function claimFeesEstimateGas(this: Curve, address = ""): Promise { + return await _claimFees.call(this, address,true) as number | number[]; } -export const claimFees = async (address = ""): Promise => { - return await _claimFees(address,false) as string; +export async function claimFees(this: Curve, address = ""): Promise { + return await _claimFees.call(this, address,false) as string; } // ----------------- Gauge weights ----------------- -const _extractNetworkFromPoolUrl = (poolUrl: string): string => { - if (!poolUrl) return "unknown"; - return poolUrl.split("/")[4] -} - -export const getVotingGaugeList = async (): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") +export async function getVotingGaugeList(this: Curve): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") const gaugeData = Object.values(await _getAllGauges()); const res = []; for (let i = 0; i < gaugeData.length; i++) { @@ -232,8 +230,8 @@ export const getVotingGaugeList = async (): Promise => { poolAddress: gaugeData[i].swap || '', lpTokenAddress: gaugeData[i].swap_token || '', poolName: gaugeData[i].shortName, - totalVeCrv: curve.formatUnits(gaugeData[i].gauge_controller.get_gauge_weight, 18), - relativeWeight: curve.formatUnits(gaugeData[i].gauge_controller.gauge_relative_weight, 16), + totalVeCrv: this.formatUnits(gaugeData[i].gauge_controller.get_gauge_weight, 18), + relativeWeight: this.formatUnits(gaugeData[i].gauge_controller.gauge_relative_weight, 16), isKilled: gaugeData[i].is_killed ?? false, }); } @@ -241,11 +239,11 @@ export const getVotingGaugeList = async (): Promise => { return res } -export const userGaugeVotes = async (address = ""): Promise<{ gauges: IGaugeUserVote[], powerUsed: string, veCrvUsed: string } > => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - address = _getAddress(address); - const gcMulticallContract = curve.contracts[curve.constants.ALIASES.gauge_controller].multicallContract; - const veMulticallContract = curve.contracts[curve.constants.ALIASES.voting_escrow]. multicallContract; +export async function userGaugeVotes(this: Curve, address = ""): Promise<{ gauges: IGaugeUserVote[], powerUsed: string, veCrvUsed: string }> { + if (this.chainId !== 1) throw Error("Ethereum-only method") + address = _getAddress.call(this, address); + const gcMulticallContract = this.contracts[this.constants.ALIASES.gauge_controller].multicallContract; + const veMulticallContract = this.contracts[this.constants.ALIASES.voting_escrow]. multicallContract; const gaugeData = Object.values(await _getAllGauges()); const calls: any[] = [veMulticallContract.balanceOf(address)]; @@ -253,7 +251,7 @@ export const userGaugeVotes = async (address = ""): Promise<{ gauges: IGaugeUser const gaugeAddress = d.rootGauge ? d.rootGauge : d.gauge; calls.push(gcMulticallContract.vote_user_slopes(address, gaugeAddress)); } - const [veCrvBalance, ...votes] = await curve.multicallProvider.all(calls) as [bigint, bigint[]]; + const [veCrvBalance, ...votes] = await this.multicallProvider.all(calls) as [bigint, bigint[]]; const res: { gauges: IGaugeUserVote[], powerUsed: string, veCrvUsed: string } = { gauges: [], powerUsed: "0.0", veCrvUsed: "0.0" }; let powerUsed = BigInt(0); @@ -263,9 +261,9 @@ export const userGaugeVotes = async (address = ""): Promise<{ gauges: IGaugeUser let dt = votes[i][2] - BigInt(Math.floor(Date.now() / 1000)); if (dt < BigInt(0)) dt = BigInt(0); res.gauges.push({ - userPower: curve.formatUnits(votes[i][1], 2), - userVeCrv: curve.formatUnits(votes[i][0] * dt, 18), - userFutureVeCrv: curve.formatUnits(veCrvBalance * votes[i][1] / BigInt(10000), 18), + userPower: this.formatUnits(votes[i][1], 2), + userVeCrv: this.formatUnits(votes[i][0] * dt, 18), + userFutureVeCrv: this.formatUnits(veCrvBalance * votes[i][1] / BigInt(10000), 18), expired: dt === BigInt(0), gaugeData: { poolUrl: gaugeData[i].poolUrls?.swap[0] || '', @@ -274,81 +272,81 @@ export const userGaugeVotes = async (address = ""): Promise<{ gauges: IGaugeUser poolAddress: gaugeData[i].swap || '', lpTokenAddress: gaugeData[i].swap_token || '', poolName: gaugeData[i].shortName, - totalVeCrv: curve.formatUnits(gaugeData[i].gauge_controller.get_gauge_weight, 18), - relativeWeight: curve.formatUnits(gaugeData[i].gauge_controller.gauge_relative_weight, 16), + totalVeCrv: this.formatUnits(gaugeData[i].gauge_controller.get_gauge_weight, 18), + relativeWeight: this.formatUnits(gaugeData[i].gauge_controller.gauge_relative_weight, 16), isKilled: gaugeData[i].is_killed ?? false, }, }); powerUsed += votes[i][1]; veCrvUsed += votes[i][0] * dt; } - res.powerUsed = curve.formatUnits(powerUsed, 2); - res.veCrvUsed = curve.formatUnits(veCrvUsed.toString(), 18); + res.powerUsed = this.formatUnits(powerUsed, 2); + res.veCrvUsed = this.formatUnits(veCrvUsed.toString(), 18); return res } -export const voteForGaugeNextTime = async (gauge: string): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const _lastVote: bigint = await curve.contracts[curve.constants.ALIASES.gauge_controller].contract.last_user_vote(curve.signerAddress, gauge, curve.constantOptions); +export async function voteForGaugeNextTime(this: Curve, gauge: string): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const _lastVote: bigint = await this.contracts[this.constants.ALIASES.gauge_controller].contract.last_user_vote(this.signerAddress, gauge, this.constantOptions); return (Number(_lastVote) + (10 * 86400)) * 1000; } -const _voteForGauge = async (gauge: string, power: number | string, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const gcContract = curve.contracts[curve.constants.ALIASES.gauge_controller].contract; - const gcMulticallContract = curve.contracts[curve.constants.ALIASES.gauge_controller].multicallContract; +async function _voteForGauge(this: Curve, gauge: string, power: number | string, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const gcContract = this.contracts[this.constants.ALIASES.gauge_controller].contract; + const gcMulticallContract = this.contracts[this.constants.ALIASES.gauge_controller].multicallContract; const _power = parseUnits(power, 2); - const [_powerUsed, _vote_slopes] = await curve.multicallProvider.all([ - gcMulticallContract.vote_user_power(curve.signerAddress), - gcMulticallContract.vote_user_slopes(curve.signerAddress, gauge), + const [_powerUsed, _vote_slopes] = await this.multicallProvider.all([ + gcMulticallContract.vote_user_power(this.signerAddress), + gcMulticallContract.vote_user_slopes(this.signerAddress, gauge), ]) as [bigint, bigint[]]; const _freePower = BigInt(10000) - _powerUsed; - if (_power > _freePower + _vote_slopes[1]) throw Error(`User have only ${curve.formatUnits(_freePower, 2)} % free power. Trying to use ${curve.formatUnits(_power, 2)}`); - const nextVoteTime = await voteForGaugeNextTime(gauge); + if (_power > _freePower + _vote_slopes[1]) throw Error(`User have only ${this.formatUnits(_freePower, 2)} % free power. Trying to use ${this.formatUnits(_power, 2)}`); + const nextVoteTime = await voteForGaugeNextTime.call(this, gauge); if (Date.now() < nextVoteTime) throw Error(`User can't change vote for this gauge earlier than ${new Date(nextVoteTime)}`); - const gas = await gcContract.vote_for_gauge_weights.estimateGas(gauge, _power, curve.constantOptions); + const gas = await gcContract.vote_for_gauge_weights.estimateGas(gauge, _power, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await gcContract.vote_for_gauge_weights(gauge, _power, { ...curve.options, gasLimit })).hash; + return (await gcContract.vote_for_gauge_weights(gauge, _power, { ...this.options, gasLimit })).hash; } -export const voteForGaugeEstimateGas = async (gauge: string, power: number | string): Promise => { - return await _voteForGauge(gauge, power, true) as number | number[]; +export async function voteForGaugeEstimateGas(this: Curve, gauge: string, power: number | string): Promise { + return await _voteForGauge.call(this, gauge, power, true) as number | number[]; } -export const voteForGauge = async (gauge: string, power: number | string): Promise => { - return await _voteForGauge(gauge, power, false) as string; +export async function voteForGauge(this: Curve, gauge: string, power: number | string): Promise { + return await _voteForGauge.call(this, gauge, power, false) as string; } // ----------------- Proposals ----------------- -export const getProposalList = async (): Promise => { +export async function getProposalList(this: Curve): Promise { return await _getDaoProposalList(); } -export const getProposal = async (type: "PARAMETER" | "OWNERSHIP", id: number): Promise => { +export async function getProposal(this: Curve, type: "PARAMETER" | "OWNERSHIP", id: number): Promise { return await _getDaoProposal(type, id); } -export const userProposalVotes = async (address = ""): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - address = _getAddress(address); +export async function userProposalVotes(this: Curve, address = ""): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + address = _getAddress.call(this, address); const proposalList = await _getDaoProposalList(); const calls = []; for (const proposal of proposalList) { if (proposal.voteType.toUpperCase() == "PARAMETER") { - calls.push(curve.contracts[curve.constants.ALIASES.voting_parameter].multicallContract.getVoterState(proposal.voteId, address)); + calls.push(this.contracts[this.constants.ALIASES.voting_parameter].multicallContract.getVoterState(proposal.voteId, address)); } else { - calls.push(curve.contracts[curve.constants.ALIASES.voting_ownership].multicallContract.getVoterState(proposal.voteId, address)); + calls.push(this.contracts[this.constants.ALIASES.voting_ownership].multicallContract.getVoterState(proposal.voteId, address)); } } - const userState: number[] = (await curve.multicallProvider.all(calls)).map(Number); + const userState: number[] = (await this.multicallProvider.all(calls)).map(Number); const userProposalList: IDaoProposalUserListItem[] = []; const voteEnum: IDict<"yes" | "no" | "even"> = { @@ -363,52 +361,52 @@ export const userProposalVotes = async (address = ""): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const contractAddress = type.toUpperCase() === "PARAMETER" ? curve.constants.ALIASES.voting_parameter : curve.constants.ALIASES.voting_ownership; - const contract = curve.contracts[contractAddress].contract; +async function _voteForProposal(this: Curve, type: TVoteType, id: number, support: boolean, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const contractAddress = type.toUpperCase() === "PARAMETER" ? this.constants.ALIASES.voting_parameter : this.constants.ALIASES.voting_ownership; + const contract = this.contracts[contractAddress].contract; const yesPct = support ? BigInt(10**18) : BigInt(0); const noPct = BigInt(10**18) - yesPct; - const gas = await contract.votePct.estimateGas(id, yesPct, noPct, true, curve.constantOptions); + const gas = await contract.votePct.estimateGas(id, yesPct, noPct, true, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.votePct(id, yesPct, noPct, false, { ...curve.options, gasLimit })).hash; + return (await contract.votePct(id, yesPct, noPct, false, { ...this.options, gasLimit })).hash; } -export const voteForProposalEstimateGas = async (type: TVoteType, id: number, support: boolean): Promise => { - return await _voteForProposal(type, id, support, true) as number | number[]; +export async function voteForProposalEstimateGas(this: Curve, type: TVoteType, id: number, support: boolean): Promise { + return await _voteForProposal.call(this, type, id, support, true) as number | number[]; } -export const voteForProposal = async (type: TVoteType, id: number, support: boolean): Promise => { - return await _voteForProposal(type, id, support, false) as string; +export async function voteForProposal(this: Curve, type: TVoteType, id: number, support: boolean): Promise { + return await _voteForProposal.call(this, type, id, support, false) as string; } -const _executeVote = async (type: TVoteType, id: number, estimateGas = false): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const contractAddress = type.toUpperCase() === "PARAMETER" ? curve.constants.ALIASES.voting_parameter : curve.constants.ALIASES.voting_ownership; - const contract = curve.contracts[contractAddress].contract; - const gas = await contract.executeVote.estimateGas(id, curve.constantOptions); +async function _executeVote(this: Curve, type: TVoteType, id: number, estimateGas = false): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const contractAddress = type.toUpperCase() === "PARAMETER" ? this.constants.ALIASES.voting_parameter : this.constants.ALIASES.voting_ownership; + const contract = this.contracts[contractAddress].contract; + const gas = await contract.executeVote.estimateGas(id, this.constantOptions); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); + await this.updateFeeData(); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.executeVote(id, { ...curve.options, gasLimit })).hash; + return (await contract.executeVote(id, { ...this.options, gasLimit })).hash; } -export const executeVoteEstimateGas = async (type: TVoteType, id: number): Promise => { - return await _executeVote(type, id, true) as number | number[]; +export async function executeVoteEstimateGas(this: Curve, type: TVoteType, id: number): Promise { + return await _executeVote.call(this, type, id, true) as number | number[]; } -export const executeVote = async (type:TVoteType, id: number): Promise => { - return await _executeVote(type, id, false) as string; +export async function executeVote(this: Curve, type: TVoteType, id: number): Promise { + return await _executeVote.call(this, type, id, false) as string; } -export const isCanVoteExecute = async (type: TVoteType, id: number): Promise => { - if (curve.chainId !== 1) throw Error("Ethereum-only method") - const contractAddress = type.toUpperCase() === "PARAMETER" ? curve.constants.ALIASES.voting_parameter : curve.constants.ALIASES.voting_ownership; - const contract = curve.contracts[contractAddress].contract; +export async function isCanVoteExecute(this: Curve, type: TVoteType, id: number): Promise { + if (this.chainId !== 1) throw Error("Ethereum-only method") + const contractAddress = type.toUpperCase() === "PARAMETER" ? this.constants.ALIASES.voting_parameter : this.constants.ALIASES.voting_ownership; + const contract = this.contracts[contractAddress].contract; - return await contract.canExecute(id, { ...curve.options }); + return await contract.canExecute(id, { ...this.options }); } diff --git a/src/external-api.ts b/src/external-api.ts index c804cb12..92253c5f 100644 --- a/src/external-api.ts +++ b/src/external-api.ts @@ -12,7 +12,7 @@ import { } from "./interfaces"; -const uncached_getPoolsFromApi = async (network: INetworkName, poolType: IPoolType, isLiteChain = false): Promise => { +const uncached_getPoolsFromApi = async (network: INetworkName, poolType: IPoolType, isLiteChain: boolean): Promise => { const api = isLiteChain ? "https://api-core.curve.finance/v1/" : "https://api.curve.finance/api"; const url = `${api}/getPools/${network}/${poolType}`; return await fetchData(url) ?? { poolData: [], tvl: 0, tvlAll: 0 }; @@ -21,7 +21,7 @@ const uncached_getPoolsFromApi = async (network: INetworkName, poolType: IPoolTy const getPoolTypes = (isLiteChain: boolean) => isLiteChain ? ["factory-twocrypto", "factory-tricrypto", "factory-stable-ng"] as const : ["main", "crypto", "factory", "factory-crvusd", "factory-eywa", "factory-crypto", "factory-twocrypto", "factory-tricrypto", "factory-stable-ng"] as const; -export const uncached_getAllPoolsFromApi = async (network: INetworkName, isLiteChain = false): Promise> => +export const uncached_getAllPoolsFromApi = async (network: INetworkName, isLiteChain: boolean): Promise> => Object.fromEntries( await Promise.all(getPoolTypes(isLiteChain).map(async (poolType) => { const data = await uncached_getPoolsFromApi(network, poolType, isLiteChain); diff --git a/src/factory/common.ts b/src/factory/common.ts index 2fafa841..3562f575 100644 --- a/src/factory/common.ts +++ b/src/factory/common.ts @@ -1,5 +1,6 @@ import { ICurve, IPoolDataShort } from "../interfaces"; import { getPoolIdBySwapAddress } from "../utils.js"; +import {Curve} from "../curve"; export function setFactoryZapContracts(this: ICurve, isCrypto: boolean): void { const basePoolIdZapDict = (isCrypto ? this.constants.CRYPTO_FACTORY_CONSTANTS : this.constants.STABLE_FACTORY_CONSTANTS).basePoolIdZapDict ?? {}; @@ -13,11 +14,11 @@ export function setFactoryZapContracts(this: ICurve, isCrypto: boolean): void { } } -export function getPoolIdByAddress(poolList: IPoolDataShort[] , address: string): string { +export function getPoolIdByAddress(this: Curve, poolList: IPoolDataShort[] , address: string): string { const pool = poolList.find((item) => item.address.toLowerCase() === address.toLowerCase()) if(pool) { return pool.id; } else { - return getPoolIdBySwapAddress(address.toLowerCase()) + return getPoolIdBySwapAddress.call(this, address.toLowerCase()) } } \ No newline at end of file diff --git a/src/factory/deploy.ts b/src/factory/deploy.ts index a299bf0f..264f1aa9 100644 --- a/src/factory/deploy.ts +++ b/src/factory/deploy.ts @@ -1,17 +1,16 @@ -import { ethers, Contract, Typed } from "ethers"; -import { curve } from "../curve.js"; -import { NETWORK_CONSTANTS } from "../constants/network_constants.js"; -import { getPool } from "../pools/index.js"; -import { parseUnits, BN, mulBy1_3, getPoolIdBySwapAddress, DIGas, smartNumber } from '../utils.js'; -import CurveLpTokenV5ABI from "../constants/abis/curve_lp_token_v5.json" with { type: 'json' }; -import Plain2ETHOracleABIABI from "../constants/abis/factory-v2/Plain2ETHOracle.json" with { type: 'json' }; -import rootGaugeFactoryABI from '../constants/abis/gauge_factory/root_gauge_factory.json' with { type: 'json' }; - +import {Contract, ethers, EventLog, Typed} from "ethers"; +import {Curve} from "../curve.js"; +import {NETWORK_CONSTANTS} from "../constants/network_constants.js"; +import {getPool} from "../pools/index.js"; +import {BN, DIGas, getPoolIdBySwapAddress, mulBy1_3, parseUnits, smartNumber} from '../utils.js'; +import CurveLpTokenV5ABI from "../constants/abis/curve_lp_token_v5.json" with {type: "json"}; +import Plain2ETHOracleABIABI from "../constants/abis/factory-v2/Plain2ETHOracle.json" with {type: "json"}; // ------- STABLE PLAIN POOLS ------- -const _deployStablePlainPool = async ( +async function _deployStablePlainPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -23,14 +22,14 @@ const _deployStablePlainPool = async ( oracleAddress: string, methodName: string, estimateGas: boolean -): Promise => { +): Promise { if (name.length > 32) throw Error("Max name length = 32"); if (symbol.length > 10) throw Error("Max symbol length = 10"); if (![2, 3, 4].includes(coins.length)) throw Error("Invalid number of coins. Must be 2, 3 or 4"); if (BN(fee).lt(0.04)) throw Error(`fee must be >= 0.04%. Passed fee = ${fee}`); if (BN(fee).gt(1)) throw Error(`fee must be <= 1%. Passed fee = ${fee}`); if (![0, 1, 2, 3].includes(assetType)) throw Error("Invalid assetType. Must be one of: 0 = USD, 1 = ETH, 2 = BTC, 3 = Other"); - if (curve.chainId !== 1 || coins.length > 2) { + if (this.chainId !== 1 || coins.length > 2) { if (![0, 1, 2, 3].includes(implementationIdx)) throw Error("Invalid implementationIdx. Must be one 0, 1, 2 or 3"); } else { if (![0, 1, 2, 3, 4, 5].includes(implementationIdx)) throw Error("Invalid implementationIdx. Must be one 0, 1, 2, 3, 4 or 5"); @@ -39,15 +38,15 @@ const _deployStablePlainPool = async ( const _A = parseUnits(A, 0); const _fee = parseUnits(fee, 8); - const _coins = coins.concat(Array(4 - coins.length).fill(curve.constants.ZERO_ADDRESS)); + const _coins = coins.concat(Array(4 - coins.length).fill(this.constants.ZERO_ADDRESS)); - const useProxy = (curve.chainId === 1 && coins.length === 2 && implementationIdx === 4 && emaTime !== 600) || - (curve.chainId === 1 && coins.length === 2 && implementationIdx === 5 && emaTime !== 600) || - ((curve.chainId === 42161 || curve.chainId == 10) && coins.length === 2 && implementationIdx === 0 && emaTime !== 600); - const setOracle = ((curve.chainId === 42161 || curve.chainId == 10) && coins.length === 2 && implementationIdx === 2); + const useProxy = (this.chainId === 1 && coins.length === 2 && implementationIdx === 4 && emaTime !== 600) || + (this.chainId === 1 && coins.length === 2 && implementationIdx === 5 && emaTime !== 600) || + ((this.chainId === 42161 || this.chainId == 10) && coins.length === 2 && implementationIdx === 0 && emaTime !== 600); + const setOracle = ((this.chainId === 42161 || this.chainId == 10) && coins.length === 2 && implementationIdx === 2); - const contractAddress = (useProxy || setOracle) ? curve.constants.ALIASES.factory_admin : curve.constants.ALIASES.factory; - const contract = curve.contracts[contractAddress].contract; + const contractAddress = (useProxy || setOracle) ? this.constants.ALIASES.factory_admin : this.constants.ALIASES.factory; + const contract = this.contracts[contractAddress].contract; const args = [name, symbol, _coins, _A, _fee, assetType, implementationIdx]; if (useProxy || setOracle) args.push(parseUnits(Math.floor(emaTime / Math.log(2)), 0)); if (setOracle) { @@ -55,15 +54,16 @@ const _deployStablePlainPool = async ( args.push(methodId, oracleAddress); } const methodToCall = setOracle ? "deploy_plain_pool_and_set_oracle" : "deploy_plain_pool"; - const gas = await contract[methodToCall].estimateGas(...args, curve.constantOptions); + const gas = await contract[methodToCall].estimateGas(...args, this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract[methodToCall](...args, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract[methodToCall](...args, {...this.options, gasLimit}); } -export const deployStablePlainPoolEstimateGas = async ( +export async function deployStablePlainPoolEstimateGas( + this: Curve, name: string, symbol: string, coins: string[], @@ -72,13 +72,14 @@ export const deployStablePlainPoolEstimateGas = async ( assetType: 0 | 1 | 2 | 3, // 0 = USD, 1 = ETH, 2 = BTC, 3 = Other implementationIdx: 0 | 1 | 2 | 3 | 4 | 5, emaTime = 600, // seconds - oracleAddress = curve.constants.ZERO_ADDRESS, + oracleAddress = this.constants.ZERO_ADDRESS, methodName = "0x00000000" -): Promise => { - return await _deployStablePlainPool(name, symbol, coins, A, fee, assetType, implementationIdx, emaTime, oracleAddress, methodName, true) as number; +): Promise { + return await _deployStablePlainPool.call(this, name, symbol, coins, A, fee, assetType, implementationIdx, emaTime, oracleAddress, methodName, true) as number; } -export const deployStablePlainPool = async ( +export async function deployStablePlainPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -87,13 +88,14 @@ export const deployStablePlainPool = async ( assetType: 0 | 1 | 2 | 3, // 0 = USD, 1 = ETH, 2 = BTC, 3 = Other implementationIdx: 0 | 1 | 2 | 3 | 4 | 5, emaTime = 600, // seconds - oracleAddress = curve.constants.ZERO_ADDRESS, + oracleAddress = this.constants.ZERO_ADDRESS, methodName = "0x00000000" -): Promise => { - return await _deployStablePlainPool(name, symbol, coins, A, fee, assetType, implementationIdx, emaTime, oracleAddress, methodName, false) as ethers.ContractTransactionResponse; +): Promise { + return await _deployStablePlainPool.call(this, name, symbol, coins, A, fee, assetType, implementationIdx, emaTime, oracleAddress, methodName, false) as ethers.ContractTransactionResponse; } -const _deployStableNgPlainPool = async ( +async function _deployStableNgPlainPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -106,7 +108,7 @@ const _deployStableNgPlainPool = async ( oracleAddresses: string[], methodNames: string[], estimateGas: boolean -): Promise => { +): Promise { if (name.length > 32) throw Error("Max name length = 32"); if (symbol.length > 10) throw Error("Max symbol length = 10"); if (coins.length < 1) throw Error("Invalid number of coins. Must be more than 1"); @@ -114,22 +116,22 @@ const _deployStableNgPlainPool = async ( if (BN(fee).gt(1)) throw Error(`fee must be <= 1%. Passed fee = ${fee}`); let _oracleAddresses: string[]; - if(oracleAddresses.length === 0) { - _oracleAddresses = new Array(coins.length).fill(curve.constants.ZERO_ADDRESS); + if (oracleAddresses.length === 0) { + _oracleAddresses = new Array(coins.length).fill(this.constants.ZERO_ADDRESS); } else { _oracleAddresses = oracleAddresses; } let _methodNames: string[]; - if(methodNames.length === 0) { + if (methodNames.length === 0) { _methodNames = new Array(coins.length).fill("0x00000000"); } else { _methodNames = methodNames; } - if(coins.length !== assetTypes.length) throw Error("Invalid length of assetTypes. Must be same coins length"); - if(coins.length !== _oracleAddresses.length) throw Error("Invalid length of oracleAddresses. Must be same coins length"); - if(coins.length !== _methodNames.length) throw Error("Invalid length of methodNames. Must be same coins length"); + if (coins.length !== assetTypes.length) throw Error("Invalid length of assetTypes. Must be same coins length"); + if (coins.length !== _oracleAddresses.length) throw Error("Invalid length of oracleAddresses. Must be same coins length"); + if (coins.length !== _methodNames.length) throw Error("Invalid length of methodNames. Must be same coins length"); assetTypes.forEach((item, index) => { if (![0, 1, 2, 3].includes(item)) throw Error(`Invalid assetType. Must be one of: 0 = Standard, 1 = Oracle, 2 = Rebasing, 3 = ERC4626 for assetTypes[${index}]`); }) @@ -141,13 +143,13 @@ const _deployStableNgPlainPool = async ( const _offpegFeeMultiplier = parseUnits(offpegFeeMultiplier, 10); const _coins = coins; - const contractAddress = curve.constants.ALIASES.stable_ng_factory; - const contract = curve.contracts[contractAddress].contract; + const contractAddress = this.constants.ALIASES.stable_ng_factory; + const contract = this.contracts[contractAddress].contract; const methodIds: string[] = []; _methodNames.forEach((item) => { - if(item === '0x00000000' || item === '') { + if (item === '0x00000000' || item === '') { methodIds.push('0x00000000') } else { methodIds.push(ethers.id(item).substring(0, 10)) @@ -155,15 +157,16 @@ const _deployStableNgPlainPool = async ( }) const args = [name, symbol, _coins, _A, _fee, _offpegFeeMultiplier, emaTime, implementationIdx, assetTypes, methodIds, _oracleAddresses]; - const gas = await contract.deploy_plain_pool.estimateGas(...args, curve.constantOptions); + const gas = await contract.deploy_plain_pool.estimateGas(...args, this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract.deploy_plain_pool(...args, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract.deploy_plain_pool(...args, {...this.options, gasLimit}); } -export const deployStableNgPlainPoolEstimateGas = async ( +export async function deployStableNgPlainPoolEstimateGas( + this: Curve, name: string, symbol: string, coins: string[], @@ -175,11 +178,12 @@ export const deployStableNgPlainPoolEstimateGas = async ( emaTime: number, // seconds oracleAddresses: string[], methodNames: string[] -): Promise => { - return await _deployStableNgPlainPool(name, symbol, coins, A, fee, offpegFeeMultiplier, assetTypes, implementationIdx, emaTime, oracleAddresses, methodNames, true) as number; +): Promise { + return await _deployStableNgPlainPool.call(this, name, symbol, coins, A, fee, offpegFeeMultiplier, assetTypes, implementationIdx, emaTime, oracleAddresses, methodNames, true) as number; } -export const deployStableNgPlainPool = async ( +export async function deployStableNgPlainPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -191,41 +195,41 @@ export const deployStableNgPlainPool = async ( emaTime: number, // seconds oracleAddresses: string[], methodNames: string[] -): Promise => { - return await _deployStableNgPlainPool(name, symbol, coins, A, fee, offpegFeeMultiplier, assetTypes, implementationIdx, emaTime, oracleAddresses, methodNames, false) as ethers.ContractTransactionResponse; +): Promise { + return await _deployStableNgPlainPool.call(this, name, symbol, coins, A, fee, offpegFeeMultiplier, assetTypes, implementationIdx, emaTime, oracleAddresses, methodNames, false) as ethers.ContractTransactionResponse; } - -export const getDeployedStablePlainPoolAddress = async (tx: ethers.ContractTransactionResponse): Promise => { +export async function getDeployedStablePlainPoolAddress(this: Curve, tx: ethers.ContractTransactionResponse): Promise { const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info"); return txInfo.logs[0].address.toLowerCase(); } -export const _setOracle = async (poolAddress: string, oracleAddress: string, methodName: string, estimateGas: boolean): Promise => { - curve.setContract(poolAddress, Plain2ETHOracleABIABI); - const poolContract = curve.contracts[poolAddress].contract; +export async function _setOracle(this: Curve, poolAddress: string, oracleAddress: string, methodName: string, estimateGas: boolean): Promise { + this.setContract(poolAddress, Plain2ETHOracleABIABI); + const poolContract = this.contracts[poolAddress].contract; const methodId = methodName === "0x00000000" ? "0x00000000" : ethers.id(methodName).substring(0, 10); - const _gas = await poolContract.set_oracle.estimateGas(methodId, oracleAddress, curve.constantOptions); + const _gas = await poolContract.set_oracle.estimateGas(methodId, oracleAddress, this.constantOptions); if (estimateGas) return Number(_gas); const gasLimit = mulBy1_3(_gas); - await curve.updateFeeData(); - return await poolContract.set_oracle(methodId, oracleAddress, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await poolContract.set_oracle(methodId, oracleAddress, {...this.options, gasLimit}); } -export const setOracleEstimateGas = async (poolAddress: string, oracleAddress = curve.constants.ZERO_ADDRESS, methodName = "0x00000000"): Promise => { - return await _setOracle(poolAddress, oracleAddress, methodName, true) as number; +export async function setOracleEstimateGas(this: Curve, poolAddress: string, oracleAddress = this.constants.ZERO_ADDRESS, methodName = "0x00000000"): Promise { + return await _setOracle.call(this, poolAddress, oracleAddress, methodName, true) as number; } -export const setOracle = async (poolAddress: string, oracleAddress = curve.constants.ZERO_ADDRESS, methodName = "0x00000000"): Promise => { - return await _setOracle(poolAddress, oracleAddress, methodName, false) as ethers.ContractTransactionResponse; +export async function setOracle(this: Curve, poolAddress: string, oracleAddress = this.constants.ZERO_ADDRESS, methodName = "0x00000000"): Promise { + return await _setOracle.call(this, poolAddress, oracleAddress, methodName, false) as ethers.ContractTransactionResponse; } // ------- STABLE META POOLS ------- -const _deployStableMetaPool = async ( +async function _deployStableMetaPool( + this: Curve, basePool: string, name: string, symbol: string, @@ -234,7 +238,7 @@ const _deployStableMetaPool = async ( fee: number | string, // % implementationIdx: 0 | 1, estimateGas: boolean -): Promise => { +): Promise { if (name.length > 32) throw Error("Max name length = 32"); if (symbol.length > 10) throw Error("Max symbol length = 10"); if (BN(fee).lt(0.04)) throw Error(`fee must be >= 0.04%. Passed fee = ${fee}`); @@ -244,16 +248,20 @@ const _deployStableMetaPool = async ( const _A = parseUnits(A, 0); const _fee = parseUnits(fee, 8); - const contract = curve.contracts[curve.constants.ALIASES.factory].contract; - const gas = await contract.deploy_metapool.estimateGas(basePool, name, symbol, coin, _A, _fee, implementationIdx, curve.constantOptions); + const contract = this.contracts[this.constants.ALIASES.factory].contract; + const gas = await contract.deploy_metapool.estimateGas(basePool, name, symbol, coin, _A, _fee, implementationIdx, this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract.deploy_metapool(basePool, name, symbol, coin, _A, _fee, implementationIdx, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract.deploy_metapool(basePool, name, symbol, coin, _A, _fee, implementationIdx, { + ...this.options, + gasLimit, + }); } -export const deployStableMetaPoolEstimateGas = async ( +export async function deployStableMetaPoolEstimateGas( + this: Curve, basePool: string, name: string, symbol: string, @@ -261,11 +269,12 @@ export const deployStableMetaPoolEstimateGas = async ( A: number | string, fee: number | string, // % implementationIdx: 0 | 1 -): Promise => { - return await _deployStableMetaPool(basePool, name, symbol, coin, A, fee, implementationIdx, true) as number; +): Promise { + return await _deployStableMetaPool.call(this, basePool, name, symbol, coin, A, fee, implementationIdx, true) as number; } -export const deployStableMetaPool = async ( +export async function deployStableMetaPool( + this: Curve, basePool: string, name: string, symbol: string, @@ -273,11 +282,12 @@ export const deployStableMetaPool = async ( A: number | string, fee: number | string, // % implementationIdx: 0 | 1 -): Promise => { - return await _deployStableMetaPool(basePool, name, symbol, coin, A, fee, implementationIdx, false) as ethers.ContractTransactionResponse; +): Promise { + return await _deployStableMetaPool.call(this, basePool, name, symbol, coin, A, fee, implementationIdx, false) as ethers.ContractTransactionResponse; } -const _deployStableNgMetaPool = async ( +async function _deployStableNgMetaPool( + this: Curve, basePool: string, name: string, symbol: string, @@ -289,9 +299,9 @@ const _deployStableNgMetaPool = async ( emaTime = 600, // seconds implementationIdx = 0, methodName = "0x00000000", - oracleAddress = curve.constants.ZERO_ADDRESS, + oracleAddress = this.constants.ZERO_ADDRESS, estimateGas: boolean -): Promise => { +): Promise { if (name.length > 32) throw Error("Max name length = 32"); if (symbol.length > 10) throw Error("Max symbol length = 10"); if (BN(fee).gt(1)) throw Error(`fee must be <= 1%. Passed fee = ${fee}`); @@ -303,17 +313,21 @@ const _deployStableNgMetaPool = async ( const methodId = methodName === "0x00000000" ? "0x00000000" : ethers.id(methodName).substring(0, 10); - const contract = curve.contracts[curve.constants.ALIASES.stable_ng_factory].contract; + const contract = this.contracts[this.constants.ALIASES.stable_ng_factory].contract; - const gas = await contract.deploy_metapool.estimateGas(basePool, name, symbol, coin, _A, _fee, _offpegFeeMultiplier, emaTime, implementationIdx, assetType, methodId, oracleAddress, curve.constantOptions); + const gas = await contract.deploy_metapool.estimateGas(basePool, name, symbol, coin, _A, _fee, _offpegFeeMultiplier, emaTime, implementationIdx, assetType, methodId, oracleAddress, this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract.deploy_metapool(basePool, name, symbol, coin, _A, _fee, _offpegFeeMultiplier, emaTime, implementationIdx, assetType, methodId, oracleAddress, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract.deploy_metapool(basePool, name, symbol, coin, _A, _fee, _offpegFeeMultiplier, emaTime, implementationIdx, assetType, methodId, oracleAddress, { + ...this.options, + gasLimit, + }); } -export const deployStableNgMetaPoolEstimateGas = async ( +export async function deployStableNgMetaPoolEstimateGas( + this: Curve, basePool: string, name: string, symbol: string, @@ -326,11 +340,12 @@ export const deployStableNgMetaPoolEstimateGas = async ( implementationIdx: 0, methodName: string, oracleAddress: string -): Promise => { - return await _deployStableNgMetaPool(basePool, name, symbol, coin, A, fee, offpegFeeMultiplier, assetType, emaTime, implementationIdx, methodName, oracleAddress, true) as number; +): Promise { + return await _deployStableNgMetaPool.call(this, basePool, name, symbol, coin, A, fee, offpegFeeMultiplier, assetType, emaTime, implementationIdx, methodName, oracleAddress, true) as number; } -export const deployStableNgMetaPool = async ( +export async function deployStableNgMetaPool( + this: Curve, basePool: string, name: string, symbol: string, @@ -343,17 +358,17 @@ export const deployStableNgMetaPool = async ( assetType: 0 | 1 | 2 | 3, // 0 = Standard, 1 = Oracle, 2 = Rebasing, 3 = ERC4626 methodName: string, oracleAddress: string -): Promise => { - return await _deployStableNgMetaPool(basePool, name, symbol, coin, A, fee, offpegFeeMultiplier, assetType, emaTime, implementationIdx, methodName, oracleAddress, false) as ethers.ContractTransactionResponse; +): Promise { + return await _deployStableNgMetaPool.call(this, basePool, name, symbol, coin, A, fee, offpegFeeMultiplier, assetType, emaTime, implementationIdx, methodName, oracleAddress, false) as ethers.ContractTransactionResponse; } -export const getDeployedStableMetaPoolAddress = async (tx: ethers.ContractTransactionResponse): Promise => { +export async function getDeployedStableMetaPoolAddress(this: Curve, tx: ethers.ContractTransactionResponse): Promise { const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info"); for (let i = txInfo.logs.length - 1; i > -1; i--) { if ("args" in txInfo.logs[i]) { - const basePoolId = getPoolIdBySwapAddress((txInfo.logs[i] as ethers.EventLog).args[1]); - const basePool = getPool(basePoolId); + const basePoolId = getPoolIdBySwapAddress.call(this, (txInfo.logs[i] as ethers.EventLog).args[1]); + const basePool = getPool.call(this, basePoolId); return txInfo.logs[basePool.underlyingCoins.length].address.toLowerCase(); } } @@ -364,7 +379,8 @@ export const getDeployedStableMetaPoolAddress = async (tx: ethers.ContractTransa // ------- CRYPTO POOLS ------- -const _deployCryptoPool = async ( +async function _deployCryptoPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -378,7 +394,7 @@ const _deployCryptoPool = async ( maHalfTime: number, // Seconds initialPrice: number | string, estimateGas: boolean -): Promise => { +): Promise { if (name.length > 32) throw Error("Max name length = 32"); if (symbol.length > 10) throw Error("Max symbol length = 10"); if (coins.length !== 2) throw Error("Invalid number of coins. Must be 2"); @@ -411,7 +427,7 @@ const _deployCryptoPool = async ( const _adjustmentStep = parseUnits(adjustmentStep); const _maHalfTime = parseUnits(maHalfTime, 0); const _initialPrice = parseUnits(initialPrice); - const contract = curve.contracts[curve.constants.ALIASES.crypto_factory].contract; + const contract = this.contracts[this.constants.ALIASES.crypto_factory].contract; const gas = await contract.deploy_pool.estimateGas( name, @@ -427,12 +443,12 @@ const _deployCryptoPool = async ( 5000000000, _maHalfTime, _initialPrice, - curve.constantOptions + this.constantOptions ); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); + await this.updateFeeData(); return await contract.deploy_pool( name, symbol, @@ -447,11 +463,12 @@ const _deployCryptoPool = async ( 5000000000, // 50% _maHalfTime, _initialPrice, - { ...curve.options, gasLimit } + {...this.options, gasLimit} ); } -export const deployCryptoPoolEstimateGas = async ( +export async function deployCryptoPoolEstimateGas( + this: Curve, name: string, symbol: string, coins: string[], @@ -464,8 +481,9 @@ export const deployCryptoPoolEstimateGas = async ( adjustmentStep: number | string, maHalfTime: number, // Seconds initialPrice: number | string -): Promise => { - return await _deployCryptoPool( +): Promise { + return await _deployCryptoPool.call( + this, name, symbol, coins, @@ -482,7 +500,8 @@ export const deployCryptoPoolEstimateGas = async ( ) as number } -export const deployCryptoPool = async ( +export async function deployCryptoPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -495,8 +514,9 @@ export const deployCryptoPool = async ( adjustmentStep: number | string, maHalfTime: number, // Seconds initialPrice: number | string -): Promise => { - return await _deployCryptoPool( +): Promise { + return await _deployCryptoPool.call( + this, name, symbol, coins, @@ -513,17 +533,18 @@ export const deployCryptoPool = async ( ) as ethers.ContractTransactionResponse } -export const getDeployedCryptoPoolAddress = async (tx: ethers.ContractTransactionResponse): Promise => { +export async function getDeployedCryptoPoolAddress(this: Curve, tx: ethers.ContractTransactionResponse): Promise { const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info") const lpTokenAddress = txInfo.logs[0].address; - const contract = new Contract(lpTokenAddress, CurveLpTokenV5ABI, curve.provider) - return (await contract.minter(curve.constantOptions) as string).toLowerCase(); + const contract = new Contract(lpTokenAddress, CurveLpTokenV5ABI, this.provider) + return (await contract.minter(this.constantOptions) as string).toLowerCase(); } // ------- TWOCRYPTO POOLS ------- -const _deployTwocryptoPool = async ( +async function _deployTwocryptoPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -537,15 +558,15 @@ const _deployTwocryptoPool = async ( maHalfTime: number, // Seconds initialPrice: number | string, estimateGas: boolean -): Promise => { +): Promise { if (name.length > 32) throw Error("Max name length = 32"); if (symbol.length > 10) throw Error("Max symbol length = 10"); if (coins.length !== 2) throw Error("Invalid number of coins. Must be 2"); if (coins[0] === coins[1]) throw Error("Coins must be different"); if (BN(A).lt(4000)) throw Error(`A must be >= 4000. Passed A = ${A}`); if (BN(A).gt(4 * (10 ** 9))) throw Error(`A must be <= 4 * 10 ** 9. Passed A = ${A}`); - const MIN_GAMMA = BN((10**10) / (10**18)); - const MAX_GAMMA = BN(199 * (10**15) / (10**18)); + const MIN_GAMMA = BN((10 ** 10) / (10 ** 18)); + const MAX_GAMMA = BN(199 * (10 ** 15) / (10 ** 18)); if (BN(gamma).lt(MIN_GAMMA)) throw Error(`gamma must be >= ${MIN_GAMMA}. Passed gamma = ${gamma}`); if (BN(gamma).gt(MAX_GAMMA)) throw Error(`gamma must be <= ${MAX_GAMMA}. Passed gamma = ${gamma}`); if (BN(midFee).lt(0.005)) throw Error(`midFee must be >= 0.005. Passed midFee = ${midFee}`); @@ -572,7 +593,7 @@ const _deployTwocryptoPool = async ( const _adjustmentStep = parseUnits(adjustmentStep); const _maHalfTime = parseUnits(maHalfTime, 0); const _initialPrice = parseUnits(initialPrice); - const contract = curve.contracts[curve.constants.ALIASES.twocrypto_factory].contract; + const contract = this.contracts[this.constants.ALIASES.twocrypto_factory].contract; const gas = await contract.deploy_pool.estimateGas( name, @@ -588,12 +609,12 @@ const _deployTwocryptoPool = async ( _adjustmentStep, _maHalfTime, _initialPrice, - curve.constantOptions + this.constantOptions ); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); + await this.updateFeeData(); return await contract.deploy_pool( name, symbol, @@ -608,11 +629,12 @@ const _deployTwocryptoPool = async ( _adjustmentStep, _maHalfTime, _initialPrice, - { ...curve.options, gasLimit } + {...this.options, gasLimit} ); } -export const deployTwocryptoPoolEstimateGas = async ( +export async function deployTwocryptoPoolEstimateGas( + this: Curve, name: string, symbol: string, coins: string[], @@ -625,8 +647,9 @@ export const deployTwocryptoPoolEstimateGas = async ( adjustmentStep: number | string, maHalfTime: number, // Seconds initialPrice: number | string -): Promise => { - return await _deployTwocryptoPool( +): Promise { + return await _deployTwocryptoPool.call( + this, name, symbol, coins, @@ -643,7 +666,8 @@ export const deployTwocryptoPoolEstimateGas = async ( ) as number } -export const deployTwocryptoPool = async ( +export async function deployTwocryptoPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -656,8 +680,9 @@ export const deployTwocryptoPool = async ( adjustmentStep: number | string, maHalfTime: number, // Seconds initialPrice: number | string -): Promise => { - return await _deployTwocryptoPool( +): Promise { + return await _deployTwocryptoPool.call( + this, name, symbol, coins, @@ -674,13 +699,12 @@ export const deployTwocryptoPool = async ( ) as ethers.ContractTransactionResponse } -export const getDeployedTwocryptoPoolAddress = async (tx: ethers.ContractTransactionResponse): Promise => { +export async function getDeployedTwocryptoPoolAddress(this: Curve, tx: ethers.ContractTransactionResponse): Promise { const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info"); for (let i = txInfo.logs.length - 1; i > -1; i--) { if ("args" in txInfo.logs[i]) { - // @ts-ignore - return txInfo.logs[i].args[0]; + return (txInfo.logs[i] as EventLog).args[0]; } } throw Error("Can't get deployed tricrypto pool address"); @@ -690,7 +714,8 @@ export const getDeployedTwocryptoPoolAddress = async (tx: ethers.ContractTransac // ------- TRICRYPTO POOLS ------- -const _deployTricryptoPool = async ( +async function _deployTricryptoPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -704,7 +729,7 @@ const _deployTricryptoPool = async ( emaTime: number, // Seconds initialPrices: (number | string)[], estimateGas: boolean -): Promise => { +): Promise { if (name.length > 64) throw Error("Max name length = 64"); if (symbol.length > 32) throw Error("Max symbol length = 32"); if (coins.length !== 3) throw Error("Invalid number of coins. Must be 3"); @@ -740,14 +765,14 @@ const _deployTricryptoPool = async ( const _adjustmentStep = parseUnits(adjustmentStep); const _emaTime = parseUnits(Math.floor(emaTime / Math.log(2)), 0); const _initialPrices = [parseUnits(initialPrices[0]), parseUnits(initialPrices[1])]; - const contract = curve.contracts[curve.constants.ALIASES.tricrypto_factory].contract; + const contract = this.contracts[this.constants.ALIASES.tricrypto_factory].contract; const gas = await contract.deploy_pool.estimateGas( name, symbol, coins, - curve.constants.ZERO_ADDRESS, - curve.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.implementationIdx ?? 0, + this.constants.ZERO_ADDRESS, + this.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.implementationIdx ?? 0, _A, _gamma, _midFee, @@ -757,18 +782,18 @@ const _deployTricryptoPool = async ( _adjustmentStep, _emaTime, _initialPrices, - curve.constantOptions + this.constantOptions ); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); + await this.updateFeeData(); return await contract.deploy_pool( name, symbol, coins, - curve.constants.NATIVE_TOKEN.wrappedAddress, - curve.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.implementationIdx ?? 0, + this.constants.NATIVE_TOKEN.wrappedAddress, + this.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.implementationIdx ?? 0, _A, _gamma, _midFee, @@ -778,11 +803,12 @@ const _deployTricryptoPool = async ( _adjustmentStep, _emaTime, _initialPrices, - { ...curve.options, gasLimit } + {...this.options, gasLimit} ); } -export const deployTricryptoPoolEstimateGas = async ( +export async function deployTricryptoPoolEstimateGas( + this: Curve, name: string, symbol: string, coins: string[], @@ -795,8 +821,9 @@ export const deployTricryptoPoolEstimateGas = async ( adjustmentStep: number | string, emaTime: number, // Seconds initialPrices: (number | string)[] -): Promise => { - return await _deployTricryptoPool( +): Promise { + return await _deployTricryptoPool.call( + this, name, symbol, coins, @@ -813,7 +840,8 @@ export const deployTricryptoPoolEstimateGas = async ( ) as number } -export const deployTricryptoPool = async ( +export async function deployTricryptoPool( + this: Curve, name: string, symbol: string, coins: string[], @@ -826,8 +854,9 @@ export const deployTricryptoPool = async ( adjustmentStep: number | string, emaTime: number, // Seconds initialPrices: (number | string)[] -): Promise => { - return await _deployTricryptoPool( +): Promise { + return await _deployTricryptoPool.call( + this, name, symbol, coins, @@ -844,13 +873,12 @@ export const deployTricryptoPool = async ( ) as ethers.ContractTransactionResponse } -export const getDeployedTricryptoPoolAddress = async (tx: ethers.ContractTransactionResponse): Promise => { +export async function getDeployedTricryptoPoolAddress(this: Curve, tx: ethers.ContractTransactionResponse): Promise { const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info"); for (let i = txInfo.logs.length - 1; i > -1; i--) { if ("args" in txInfo.logs[i]) { - // @ts-ignore - return txInfo.logs[i].args[0]; + return (txInfo.logs[i] as EventLog).args[0]; } } throw Error("Can't get deployed tricrypto pool address"); @@ -859,73 +887,73 @@ export const getDeployedTricryptoPoolAddress = async (tx: ethers.ContractTransac // ------- GAUGE ------- -const _deployGauge = async (pool: string, factory: string, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("There is no deployGauge method on sidechain network"); - const contract = curve.contracts[factory].contract; - const gas = await contract.deploy_gauge.estimateGas(pool, curve.constantOptions); +async function _deployGauge(this: Curve, pool: string, factory: string, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("There is no deployGauge method on sidechain network"); + const contract = this.contracts[factory].contract; + const gas = await contract.deploy_gauge.estimateGas(pool, this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract.deploy_gauge(pool, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract.deploy_gauge(pool, {...this.options, gasLimit}); } -const _deployGaugeSidechain = async (pool: string, salt: string, estimateGas: boolean): Promise => { - if (curve.chainId === 1) throw Error("There is no deployGaugeSidechain method on ethereum network"); - const contract = curve.contracts[curve.constants.ALIASES.child_gauge_factory].contract; +async function _deployGaugeSidechain(this: Curve, pool: string, salt: string, estimateGas: boolean): Promise { + if (this.chainId === 1) throw Error("There is no deployGaugeSidechain method on ethereum network"); + const contract = this.contracts[this.constants.ALIASES.child_gauge_factory].contract; const _salt = ethers.encodeBytes32String(salt) - const gas = await contract.deploy_gauge.estimateGas(pool, Typed.bytes32(_salt), curve.signerAddress, curve.constantOptions); + const gas = await contract.deploy_gauge.estimateGas(pool, Typed.bytes32(_salt), this.signerAddress, this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract.deploy_gauge(pool,Typed.bytes32(_salt),curve.signerAddress, { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract.deploy_gauge(pool, Typed.bytes32(_salt), this.signerAddress, {...this.options, gasLimit}); } -const _deployGaugeMirror = async (chainId: number, salt: string, estimateGas: boolean): Promise => { - if (curve.chainId !== 1) throw Error("There is no deployGaugeMirror method on sidechain network"); - const rootGaugeFactory = chainId !== 42161? NETWORK_CONSTANTS[curve.chainId].ALIASES.root_gauge_factory: NETWORK_CONSTANTS[curve.chainId].ALIASES.root_gauge_factory_arbitrum; - const contract = curve.contracts[rootGaugeFactory].contract; +async function _deployGaugeMirror(this: Curve, chainId: number, salt: string, estimateGas: boolean): Promise { + if (this.chainId !== 1) throw Error("There is no deployGaugeMirror method on sidechain network"); + const rootGaugeFactory = chainId !== 42161? NETWORK_CONSTANTS[this.chainId].ALIASES.root_gauge_factory: NETWORK_CONSTANTS[this.chainId].ALIASES.root_gauge_factory_arbitrum; + const contract = this.contracts[rootGaugeFactory].contract; const _salt = ethers.encodeBytes32String(salt) - const gas = await contract.deploy_gauge.estimateGas(chainId, Typed.bytes32(_salt), curve.constantOptions); + const gas = await contract.deploy_gauge.estimateGas(chainId, Typed.bytes32(_salt), this.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - await curve.updateFeeData(); - return await contract.deploy_gauge(chainId,Typed.bytes32(_salt), { ...curve.options, gasLimit }); + await this.updateFeeData(); + return await contract.deploy_gauge(chainId,Typed.bytes32(_salt), { ...this.options, gasLimit }); } -export const deployGaugeEstimateGas = async (pool: string, factory: string): Promise => await _deployGauge(pool, factory, true) as number; +export async function deployGaugeEstimateGas(this: Curve, pool: string, factory: string): Promise { return await _deployGauge.call(this, pool, factory, true) as number; } -export const deployGauge = async (pool: string, factory: string): Promise => await _deployGauge(pool, factory, false) as ethers.ContractTransactionResponse; +export async function deployGauge(this: Curve, pool: string, factory: string): Promise { return await _deployGauge.call(this, pool, factory, false) as ethers.ContractTransactionResponse; } -export const deployGaugeSidechainEstimateGas = async (pool: string, salt: string): Promise => await _deployGaugeSidechain(pool, salt, true) as number; +export async function deployGaugeSidechainEstimateGas(this: Curve, pool: string, salt: string): Promise { return await _deployGaugeSidechain.call(this, pool, salt, true) as number; } -export const deployGaugeSidechain = async (pool: string, salt: string): Promise => await _deployGaugeSidechain(pool, salt, false) as ethers.ContractTransactionResponse; +export async function deployGaugeSidechain(this: Curve, pool: string, salt: string): Promise { return await _deployGaugeSidechain.call(this, pool, salt, false) as ethers.ContractTransactionResponse; } -export const deployGaugeMirrorEstimateGas = async (chainId: number, salt: string): Promise => await _deployGaugeMirror(chainId, salt, true) as number; +export async function deployGaugeMirrorEstimateGas(this: Curve, chainId: number, salt: string): Promise { return await _deployGaugeMirror.call(this, chainId, salt, true) as number; } -export const deployGaugeMirror = async (chainId: number, salt: string): Promise => await _deployGaugeMirror(chainId, salt, false) as ethers.ContractTransactionResponse; +export async function deployGaugeMirror(this: Curve, chainId: number, salt: string): Promise { return await _deployGaugeMirror.call(this, chainId, salt, false) as ethers.ContractTransactionResponse; } -export const getDeployedGaugeAddress = async (tx: ethers.ContractTransactionResponse): Promise => { +export async function getDeployedGaugeAddress(this: Curve, tx: ethers.ContractTransactionResponse): Promise { const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info"); - // @ts-ignore - return txInfo.logs[0].args[txInfo.logs[0].args.length - 1].toLowerCase(); + const log = txInfo.logs[0] as EventLog; + return log.args[log.args.length - 1].toLowerCase(); } -export const getDeployedGaugeMirrorAddressByTx = async (tx: ethers.ContractTransactionResponse): Promise => { - if(curve.chainId !== 1) throw Error("There is no getDeployedGaugeMirrorAddressByTx method on sidechain network"); +export async function getDeployedGaugeMirrorAddressByTx(this: Curve, tx: ethers.ContractTransactionResponse): Promise { + if(this.chainId !== 1) throw Error("There is no getDeployedGaugeMirrorAddressByTx method on sidechain network"); const txInfo = await tx.wait(); if (!txInfo) throw Error("Can't get tx info"); - // @ts-ignore - return txInfo.logs[1].args[txInfo.logs[1].args.length - 1].toLowerCase(); + const log = txInfo.logs[1] as EventLog; + return log.args[log.args.length - 1].toLowerCase(); } -export const getDeployedGaugeMirrorAddress = async (chainId: number): Promise => { - if (curve.chainId !== 1) throw Error("There is no getDeployedGaugeMirrorAddress method on sidechain network"); - const rootGaugeFactory = chainId !== 42161? NETWORK_CONSTANTS[curve.chainId].ALIASES.root_gauge_factory: NETWORK_CONSTANTS[curve.chainId].ALIASES.root_gauge_factory_arbitrum; - const contract = curve.contracts[rootGaugeFactory].contract; +export async function getDeployedGaugeMirrorAddress(this: Curve, chainId: number): Promise { + if (this.chainId !== 1) throw Error("There is no getDeployedGaugeMirrorAddress method on sidechain network"); + const rootGaugeFactory = chainId !== 42161? NETWORK_CONSTANTS[this.chainId].ALIASES.root_gauge_factory: NETWORK_CONSTANTS[this.chainId].ALIASES.root_gauge_factory_arbitrum; + const contract = this.contracts[rootGaugeFactory].contract; const gaugeCount = await contract.get_gauge_count(chainId); const currentIndex: number = Number(gaugeCount) - 1; diff --git a/src/factory/factory-api.ts b/src/factory/factory-api.ts index 8760e540..34cf70cd 100644 --- a/src/factory/factory-api.ts +++ b/src/factory/factory-api.ts @@ -1,18 +1,21 @@ -import { curve } from "../curve.js"; -import { IDict, IFactoryPoolType, IPoolData, ICurve, IPoolDataFromApi } from "../interfaces"; -import factoryGaugeABI from "../constants/abis/gauge_factory.json" with { type: 'json' }; -import gaugeChildABI from "../constants/abis/gauge_child.json" with { type: 'json' }; -import ERC20ABI from "../constants/abis/ERC20.json" with { type: 'json' }; -import cryptoFactorySwapABI from "../constants/abis/factory-crypto/factory-crypto-pool-2.json" with { type: 'json' }; -import twocryptoFactorySwapABI from "../constants/abis/factory-twocrypto/factory-twocrypto-pool.json" with { type: 'json' }; -import tricryptoFactorySwapABI from "../constants/abis/factory-tricrypto/factory-tricrypto-pool.json" with { type: 'json' }; -import tricryptoFactoryEthDisabledSwapABI from "../constants/abis/factory-tricrypto/factory-tricrypto-pool-eth-disabled.json" with { type: 'json' }; -import { getPoolIdByAddress, setFactoryZapContracts } from "./common.js"; -import { _getPoolsFromApi } from "../cached.js"; +import {ICurve, IDict, IFactoryPoolType, IPoolData, IPoolDataFromApi} from "../interfaces"; +import factoryGaugeABI from "../constants/abis/gauge_factory.json" with {type: "json"}; +import gaugeChildABI from "../constants/abis/gauge_child.json" with {type: "json"}; +import ERC20ABI from "../constants/abis/ERC20.json" with {type: "json"}; +import cryptoFactorySwapABI from "../constants/abis/factory-crypto/factory-crypto-pool-2.json" with {type: "json"}; +import twocryptoFactorySwapABI + from "../constants/abis/factory-twocrypto/factory-twocrypto-pool.json" with {type: "json"}; +import tricryptoFactorySwapABI + from "../constants/abis/factory-tricrypto/factory-tricrypto-pool.json" with {type: "json"}; +import tricryptoFactoryEthDisabledSwapABI + from "../constants/abis/factory-tricrypto/factory-tricrypto-pool-eth-disabled.json" with {type: "json"}; +import {getPoolIdByAddress, setFactoryZapContracts} from "./common.js"; +import {_getPoolsFromApi} from "../cached.js"; import {assetTypeNameHandler, getPoolName, isStableNgPool} from "../utils.js"; -import StableNgBasePoolZapABI from "../constants/abis/stable-ng-base-pool-zap.json" with { type: 'json' }; -import MetaStableSwapNGABI from "../constants/abis/factory-stable-ng/meta-stableswap-ng.json" with { type: 'json' }; -import PlainStableSwapNGABI from "../constants/abis/factory-stable-ng/plain-stableswap-ng.json" with { type: 'json' }; +import StableNgBasePoolZapABI from "../constants/abis/stable-ng-base-pool-zap.json" with {type: "json"}; +import MetaStableSwapNGABI from "../constants/abis/factory-stable-ng/meta-stableswap-ng.json" with {type: "json"}; +import PlainStableSwapNGABI from "../constants/abis/factory-stable-ng/plain-stableswap-ng.json" with {type: "json"}; +import {type Curve} from "../curve"; export const lowerCasePoolDataAddresses = (poolsData: IPoolDataFromApi[]): IPoolDataFromApi[] => { for (const poolData of poolsData) { @@ -32,8 +35,8 @@ export const lowerCasePoolDataAddresses = (poolsData: IPoolDataFromApi[]): IPool return poolsData } -const getSwapAbiByFactoryType = (factoryType: IFactoryPoolType, pool: IPoolDataFromApi) => { - const isETHEnabled = pool.implementationAddress === curve.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.amm_native_transfers_enabled; +function getSwapAbiByFactoryType(this: ICurve, factoryType: IFactoryPoolType, pool: IPoolDataFromApi) { + const isETHEnabled = pool.implementationAddress === this.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.amm_native_transfers_enabled; const map: Record = { "factory-crypto": cryptoFactorySwapABI, "factory-twocrypto": twocryptoFactorySwapABI, @@ -46,7 +49,7 @@ const getSwapAbiByFactoryType = (factoryType: IFactoryPoolType, pool: IPoolDataF function setFactorySwapContracts(this: ICurve, rawPoolList: IPoolDataFromApi[], swapABIs: any, factoryType: IFactoryPoolType): void { if (["factory-crypto", "factory-twocrypto", "factory-tricrypto"].includes(factoryType)) { rawPoolList.forEach((pool) => { - this.setContract(pool.address, getSwapAbiByFactoryType(factoryType, pool)); + this.setContract(pool.address, getSwapAbiByFactoryType.call(this, factoryType, pool)); }); } else { rawPoolList.forEach((pool, i) => { @@ -78,7 +81,7 @@ function setFactoryCoinsContracts(this: ICurve, rawPoolList: IPoolDataFromApi[]) } } -export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFactoryPoolType): Promise> { +export async function getFactoryPoolsDataFromApi(this: Curve, factoryType: IFactoryPoolType): Promise> { const network = this.constants.NETWORK_NAME; const is_ng = ["factory-stable-ng", "factory-twocrypto", "factory-tricrypto"].includes(factoryType); const isCrypto = ["factory-crypto", "factory-twocrypto", "factory-tricrypto"].includes(factoryType); @@ -102,7 +105,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac const FACTORY_POOLS_DATA: IDict = {}; rawPoolList.forEach((pool, i) => { const nativeToken = this.constants.NATIVE_TOKEN; - const isETHEnabled = pool.implementationAddress === curve.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.amm_native_transfers_enabled; + const isETHEnabled = pool.implementationAddress === this.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations?.amm_native_transfers_enabled; let coinAddresses = pool.coins.map((c) => c.address); if (this.chainId === 137) { coinAddresses = coinAddresses.map((a) => a === "0x0000000000000000000000000000000000001010" ? nativeToken.wrappedAddress : a); @@ -159,7 +162,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac reference_asset: "CRYPTO", swap_address: pool.address, token_address: pool.lpTokenAddress as string, - gauge_address: pool.gaugeAddress ? pool.gaugeAddress : curve.constants.ZERO_ADDRESS, + gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS, deposit_address: basePoolZap.address, is_meta: true, is_crypto: true, @@ -185,7 +188,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac reference_asset: "CRYPTO", swap_address: pool.address, token_address: pool.lpTokenAddress as string, - gauge_address: pool.gaugeAddress ? pool.gaugeAddress : curve.constants.ZERO_ADDRESS, + gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS, is_crypto: true, is_plain: isPlain, is_factory: true, @@ -195,7 +198,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac wrapped_coin_addresses: coinAddresses, underlying_decimals: coinDecimals, wrapped_decimals: coinDecimals, - swap_abi: getSwapAbiByFactoryType(factoryType, pool), + swap_abi: getSwapAbiByFactoryType.call(this, factoryType, pool), gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI, in_api: true, is_ng, @@ -203,7 +206,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac } } else if (pool.isMetaPool) { const allPoolsData = {...this.constants.POOLS_DATA, ...FACTORY_POOLS_DATA}; - const basePoolId = getPoolIdByAddress(rawPoolList, pool.basePoolAddress as string); + const basePoolId = getPoolIdByAddress.call(this, rawPoolList, pool.basePoolAddress as string); this.constants.BASE_POOLS[basePoolId] = this.constants.BASE_POOLS[basePoolId] ? this.constants.BASE_POOLS[basePoolId] + 1: 1; const basePoolCoinNames = allPoolsData[basePoolId]?.underlying_coins; @@ -212,7 +215,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac const basePoolIdZapDict = this.constants.STABLE_FACTORY_CONSTANTS.basePoolIdZapDict ?? {}; - let deposit_address = this.constants.STABLE_FACTORY_CONSTANTS.stableNgBasePoolZap ?? curve.constants.ZERO_ADDRESS; + let deposit_address = this.constants.STABLE_FACTORY_CONSTANTS.stableNgBasePoolZap ?? this.constants.ZERO_ADDRESS; let deposit_abi = StableNgBasePoolZapABI; if (isStableNgPool(basePoolId)) { this.setContract(deposit_address, StableNgBasePoolZapABI); @@ -228,7 +231,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac reference_asset: assetTypeNameHandler(pool.assetTypeName), swap_address: pool.address, token_address: pool.address, - gauge_address: pool.gaugeAddress ? pool.gaugeAddress : curve.constants.ZERO_ADDRESS, + gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS, deposit_address, implementation_address: pool.implementationAddress, // Only for testing is_meta: true, @@ -254,7 +257,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve, factoryType: IFac reference_asset: assetTypeNameHandler(pool.assetTypeName), swap_address: pool.address, token_address: pool.address, - gauge_address: pool.gaugeAddress ? pool.gaugeAddress : curve.constants.ZERO_ADDRESS, + gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS, implementation_address: pool.implementationAddress, // Only for testing is_plain: true, is_factory: true, diff --git a/src/factory/factory-crypto.ts b/src/factory/factory-crypto.ts index 9685d18d..7571bac4 100644 --- a/src/factory/factory-crypto.ts +++ b/src/factory/factory-crypto.ts @@ -1,10 +1,9 @@ -import { IDict, IPoolData, ICurve } from "../interfaces"; -import { curve } from "../curve.js"; -import ERC20ABI from "../constants/abis/ERC20.json" with { type: 'json' }; -import cryptoFactorySwapABI from "../constants/abis/factory-crypto/factory-crypto-pool-2.json" with { type: 'json' }; -import factoryGaugeABI from "../constants/abis/gauge_factory.json" with { type: 'json' }; -import gaugeChildABI from "../constants/abis/gauge_child.json" with { type: 'json' }; -import { setFactoryZapContracts } from "./common.js"; +import {ICurve, IDict, IPoolData} from "../interfaces"; +import ERC20ABI from "../constants/abis/ERC20.json" with {type: "json"}; +import cryptoFactorySwapABI from "../constants/abis/factory-crypto/factory-crypto-pool-2.json" with {type: "json"}; +import factoryGaugeABI from "../constants/abis/gauge_factory.json" with {type: "json"}; +import gaugeChildABI from "../constants/abis/gauge_child.json" with {type: "json"}; +import {setFactoryZapContracts} from "./common.js"; const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); @@ -12,7 +11,7 @@ const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.is async function getRecentlyCreatedCryptoPoolId(this: ICurve, swapAddress: string): Promise { const factoryContract = this.contracts[this.constants.ALIASES.crypto_factory].contract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); for (let i = 1; i <= poolCount; i++) { const address: string = await factoryContract.pool_list(poolCount - i); if (address.toLowerCase() === swapAddress.toLowerCase()) return `factory-crypto-${poolCount - i}` @@ -25,7 +24,7 @@ async function getCryptoFactoryIdsAndSwapAddresses(this: ICurve, fromIdx = 0): P const factoryContract = this.contracts[this.constants.ALIASES.crypto_factory].contract; const factoryMulticallContract = this.contracts[this.constants.ALIASES.crypto_factory].multicallContract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); const calls = []; for (let i = fromIdx; i < poolCount; i++) { calls.push(factoryMulticallContract.pool_list(i)); @@ -71,7 +70,7 @@ async function _getLpTokenMap(this: ICurve,factorySwapAddresses: string[]): Prom async function getPoolsData(this: ICurve, factorySwapAddresses: string[]): Promise<[string[], string[], string[], string[][]]> { const factoryMulticallContract = this.contracts[this.constants.ALIASES.crypto_factory].multicallContract; - const isChildGaugeFactoryNull = curve.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === curve.constants.ZERO_ADDRESS; + const isChildGaugeFactoryNull = this.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === this.constants.ZERO_ADDRESS; const isChildGaugeFactoryOldNull = !("child_gauge_factory_old" in this.constants.ALIASES); const calls = []; @@ -100,8 +99,8 @@ async function getPoolsData(this: ICurve, factorySwapAddresses: string[]): Promi if(isChildGaugeFactoryNull || isChildGaugeFactoryOldNull) { for(let index = 0; index < res.length; index++) { - if(isChildGaugeFactoryNull && index % 4 == 1) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); - if(isChildGaugeFactoryOldNull && index % 4 == 2) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryNull && index % 4 == 1) res.splice(index, 0 , this.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryOldNull && index % 4 == 2) res.splice(index, 0 , this.constants.ZERO_ADDRESS); } } @@ -126,9 +125,9 @@ function setCryptoFactoryTokenContracts(this: ICurve, factoryTokenAddresses: str } function setCryptoFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]): void { - factoryGaugeAddresses.filter((addr) => addr !== curve.constants.ZERO_ADDRESS).forEach((addr, i) => { - this.setContract(addr, this.chainId === 1 ? factoryGaugeABI : gaugeChildABI); - }); + factoryGaugeAddresses.filter((addr) => addr !== this.constants.ZERO_ADDRESS).forEach((addr) => + this.setContract(addr, this.chainId === 1 ? factoryGaugeABI : gaugeChildABI) + ); } function setCryptoFactoryCoinsContracts(this: ICurve, coinAddresses: string[][]): void { @@ -207,7 +206,7 @@ async function getCoinsData( const res2 = res.slice(tokenAddresses.length * 2); const symbols = res2.filter((a, i) => i % 2 == 0) as string[]; - const decimals = (res2.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(curve.formatUnits(_d, 0))); + const decimals = (res2.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(this.formatUnits(_d, 0))); newCoinAddresses.forEach((addr, i) => { coinAddrNamesDict[addr] = symbols[i]; @@ -229,7 +228,7 @@ export async function getCryptoFactoryPoolData(this: ICurve, fromIdx = 0, swapAd const [tokenAddresses, rawGaugeAddresses, rawOldGaugeAddresses, coinAddresses] = await getPoolsData.call(this, swapAddresses); const gaugeAddresses: string[] = []; for (let i = 0; i < rawGaugeAddresses.length; i++) { - gaugeAddresses.push(rawGaugeAddresses[i] !== curve.constants.ZERO_ADDRESS ? rawGaugeAddresses[i] : rawOldGaugeAddresses[i]); + gaugeAddresses.push(rawGaugeAddresses[i] !== this.constants.ZERO_ADDRESS ? rawGaugeAddresses[i] : rawOldGaugeAddresses[i]); } setCryptoFactorySwapContracts.call(this, swapAddresses); setCryptoFactoryTokenContracts.call(this, tokenAddresses); diff --git a/src/factory/factory-tricrypto.ts b/src/factory/factory-tricrypto.ts index 007fdad9..d9e2ba47 100644 --- a/src/factory/factory-tricrypto.ts +++ b/src/factory/factory-tricrypto.ts @@ -1,18 +1,18 @@ -import { IDict, IPoolData, ICurve } from "../interfaces"; -import { curve } from "../curve.js"; -import ERC20ABI from "../constants/abis/ERC20.json" with { type: 'json' }; -import tricryptoFactorySwapABI from "../constants/abis/factory-tricrypto/factory-tricrypto-pool.json" with { type: 'json' }; -import tricryptoFactoryEthDisabledSwapABI from "../constants/abis/factory-tricrypto/factory-tricrypto-pool-eth-disabled.json" with { type: 'json' }; -import factoryGaugeABI from "../constants/abis/gauge_factory.json" with { type: 'json' }; -import gaugeChildABI from "../constants/abis/gauge_child.json" with { type: 'json' }; - +import {ICurve, IDict, IPoolData} from "../interfaces"; +import ERC20ABI from "../constants/abis/ERC20.json" with {type: "json"}; +import tricryptoFactorySwapABI + from "../constants/abis/factory-tricrypto/factory-tricrypto-pool.json" with {type: "json"}; +import tricryptoFactoryEthDisabledSwapABI + from "../constants/abis/factory-tricrypto/factory-tricrypto-pool-eth-disabled.json" with {type: "json"}; +import factoryGaugeABI from "../constants/abis/gauge_factory.json" with {type: "json"}; +import gaugeChildABI from "../constants/abis/gauge_child.json" with {type: "json"}; const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); async function getRecentlyCreatedCryptoPoolId(this: ICurve, swapAddress: string): Promise { const factoryContract = this.contracts[this.constants.ALIASES.tricrypto_factory].contract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); for (let i = 1; i <= poolCount; i++) { const address: string = await factoryContract.pool_list(poolCount - i); if (address.toLowerCase() === swapAddress.toLowerCase()) return `factory-tricrypto-${poolCount - i}` @@ -25,7 +25,7 @@ async function getCryptoFactoryIdsAndSwapAddresses(this: ICurve, fromIdx = 0): P const factoryContract = this.contracts[this.constants.ALIASES.tricrypto_factory].contract; const factoryMulticallContract = this.contracts[this.constants.ALIASES.tricrypto_factory].multicallContract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); const calls = []; for (let i = fromIdx; i < poolCount; i++) { calls.push(factoryMulticallContract.pool_list(i)); @@ -51,7 +51,7 @@ function _handleCoinAddresses(this: ICurve, coinAddresses: string[][]): string[] async function getPoolsData(this: ICurve, factorySwapAddresses: string[]): Promise<[string[], string[], string[][], string[]]> { const factoryMulticallContract = this.contracts[this.constants.ALIASES.tricrypto_factory].multicallContract; - const isChildGaugeFactoryNull = curve.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === curve.constants.ZERO_ADDRESS; + const isChildGaugeFactoryNull = this.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === this.constants.ZERO_ADDRESS; const isChildGaugeFactoryOldNull = !("child_gauge_factory_old" in this.constants.ALIASES); const calls = []; @@ -77,9 +77,9 @@ async function getPoolsData(this: ICurve, factorySwapAddresses: string[]): Promi if(isChildGaugeFactoryNull || isChildGaugeFactoryOldNull || this.chainId === 1) { for(let index = 0; index < res.length; index++) { - if(isChildGaugeFactoryNull && index % 4 == 0) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); - if(isChildGaugeFactoryOldNull && index % 4 == 1) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); - if(this.chainId === 1 && index % 4 == 3) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryNull && index % 4 == 0) res.splice(index, 0 , this.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryOldNull && index % 4 == 1) res.splice(index, 0 , this.constants.ZERO_ADDRESS); + if(this.chainId === 1 && index % 4 == 3) res.splice(index, 0 , this.constants.ZERO_ADDRESS); } } @@ -98,7 +98,7 @@ function setCryptoFactorySwapContracts(this: ICurve, factorySwapAddresses: strin } function setCryptoFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]): void { - factoryGaugeAddresses.filter((addr) => addr !== curve.constants.ZERO_ADDRESS).forEach((addr, i) => { + factoryGaugeAddresses.filter((addr) => addr !== this.constants.ZERO_ADDRESS).forEach((addr) => { this.setContract(addr, this.chainId === 1 ? factoryGaugeABI : gaugeChildABI); }); } @@ -174,7 +174,7 @@ async function getCoinsData( const res2 = res.slice(tokenAddresses.length * 2); const symbols = res2.filter((a, i) => i % 2 == 0) as string[]; - const decimals = (res2.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(curve.formatUnits(_d, 0))); + const decimals = (res2.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(this.formatUnits(_d, 0))); newCoinAddresses.forEach((addr, i) => { coinAddrNamesDict[addr] = symbols[i]; @@ -196,7 +196,7 @@ export async function getTricryptoFactoryPoolData(this: ICurve, fromIdx = 0, swa const [rawGaugeAddresses, rawOldGaugeAddresses, coinAddresses, implementationAddresses] = await getPoolsData.call(this, swapAddresses); const gaugeAddresses: string[] = []; for (let i = 0; i < rawGaugeAddresses.length; i++) { - gaugeAddresses.push(rawGaugeAddresses[i] !== curve.constants.ZERO_ADDRESS ? rawGaugeAddresses[i] : rawOldGaugeAddresses[i]); + gaugeAddresses.push(rawGaugeAddresses[i] !== this.constants.ZERO_ADDRESS ? rawGaugeAddresses[i] : rawOldGaugeAddresses[i]); } setCryptoFactorySwapContracts.call(this, swapAddresses); setCryptoFactoryGaugeContracts.call(this, gaugeAddresses); diff --git a/src/factory/factory-twocrypto.ts b/src/factory/factory-twocrypto.ts index 68bf5d3a..b4caabd9 100644 --- a/src/factory/factory-twocrypto.ts +++ b/src/factory/factory-twocrypto.ts @@ -1,9 +1,9 @@ -import { IDict, IPoolData, ICurve } from "../interfaces"; -import { curve } from "../curve.js"; -import ERC20ABI from "../constants/abis/ERC20.json" with { type: 'json' }; -import twocryptoFactorySwapABI from "../constants/abis/factory-twocrypto/factory-twocrypto-pool.json" with { type: 'json' }; -import factoryGaugeABI from "../constants/abis/gauge_factory.json" with { type: 'json' }; -import gaugeChildABI from "../constants/abis/gauge_child.json" with { type: 'json' }; +import {ICurve, IDict, IPoolData} from "../interfaces"; +import ERC20ABI from "../constants/abis/ERC20.json" with {type: "json"}; +import twocryptoFactorySwapABI + from "../constants/abis/factory-twocrypto/factory-twocrypto-pool.json" with {type: "json"}; +import factoryGaugeABI from "../constants/abis/gauge_factory.json" with {type: "json"}; +import gaugeChildABI from "../constants/abis/gauge_child.json" with {type: "json"}; const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); @@ -11,7 +11,7 @@ const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.is async function getRecentlyCreatedCryptoPoolId(this: ICurve, swapAddress: string): Promise { const factoryContract = this.contracts[this.constants.ALIASES.twocrypto_factory].contract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); for (let i = 1; i <= poolCount; i++) { const address: string = await factoryContract.pool_list(poolCount - i); if (address.toLowerCase() === swapAddress.toLowerCase()) return `factory-twocrypto-${poolCount - i}` @@ -24,7 +24,7 @@ async function getTwocryptoFactoryIdsAndSwapAddresses(this: ICurve, fromIdx = 0) const factoryContract = this.contracts[this.constants.ALIASES.twocrypto_factory].contract; const factoryMulticallContract = this.contracts[this.constants.ALIASES.twocrypto_factory].multicallContract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); const calls = []; for (let i = fromIdx; i < poolCount; i++) { calls.push(factoryMulticallContract.pool_list(i)); @@ -50,7 +50,7 @@ function _handleCoinAddresses(this: ICurve, coinAddresses: string[][]): string[] async function getPoolsData(this: ICurve, factorySwapAddresses: string[]): Promise<[string[], string[], string[][]]> { const factoryMulticallContract = this.contracts[this.constants.ALIASES.twocrypto_factory].multicallContract; - const isChildGaugeFactoryNull = curve.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === curve.constants.ZERO_ADDRESS; + const isChildGaugeFactoryNull = this.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === this.constants.ZERO_ADDRESS; const isChildGaugeFactoryOldNull = !("child_gauge_factory_old" in this.constants.ALIASES); const calls = []; @@ -76,8 +76,8 @@ async function getPoolsData(this: ICurve, factorySwapAddresses: string[]): Promi if(isChildGaugeFactoryNull || isChildGaugeFactoryOldNull) { for(let index = 0; index < res.length; index++) { - if(isChildGaugeFactoryNull && index % 3 == 0) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); - if(isChildGaugeFactoryOldNull && index % 3 == 1) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryNull && index % 3 == 0) res.splice(index, 0 , this.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryOldNull && index % 3 == 1) res.splice(index, 0 , this.constants.ZERO_ADDRESS); } } @@ -95,7 +95,7 @@ function setTwocryptoFactorySwapContracts(this: ICurve, factorySwapAddresses: st } function setTwocryptoFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]): void { - factoryGaugeAddresses.filter((addr) => addr !== curve.constants.ZERO_ADDRESS).forEach((addr, i) => { + factoryGaugeAddresses.filter((addr) => addr !== this.constants.ZERO_ADDRESS).forEach((addr) => { this.setContract(addr, this.chainId === 1 ? factoryGaugeABI : gaugeChildABI); }); } @@ -175,7 +175,7 @@ async function getCoinsData( const res2 = res.slice(tokenAddresses.length * 2); const symbols = res2.filter((a, i) => i % 2 == 0) as string[]; - const decimals = (res2.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(curve.formatUnits(_d, 0))); + const decimals = (res2.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(this.formatUnits(_d, 0))); newCoinAddresses.forEach((addr, i) => { coinAddrNamesDict[addr] = symbols[i]; @@ -197,7 +197,7 @@ export async function getTwocryptoFactoryPoolData(this: ICurve, fromIdx = 0, swa const [rawGaugeAddresses, rawOldGaugeAddresses, coinAddresses] = await getPoolsData.call(this, swapAddresses); const gaugeAddresses: string[] = []; for (let i = 0; i < rawGaugeAddresses.length; i++) { - gaugeAddresses.push(rawGaugeAddresses[i] !== curve.constants.ZERO_ADDRESS ? rawGaugeAddresses[i] : rawOldGaugeAddresses[i]); + gaugeAddresses.push(rawGaugeAddresses[i] !== this.constants.ZERO_ADDRESS ? rawGaugeAddresses[i] : rawOldGaugeAddresses[i]); } setTwocryptoFactorySwapContracts.call(this, swapAddresses); setTwocryptoFactoryGaugeContracts.call(this, gaugeAddresses); diff --git a/src/factory/factory.ts b/src/factory/factory.ts index 24856039..04b1ad24 100644 --- a/src/factory/factory.ts +++ b/src/factory/factory.ts @@ -1,14 +1,15 @@ -import { Contract as MulticallContract } from "@curvefi/ethcall"; -import { curve } from "../curve.js"; -import {IDict, IPoolData, ICurve, REFERENCE_ASSET, IPoolDataShort} from "../interfaces"; -import ERC20ABI from "../constants/abis/ERC20.json" with { type: 'json' }; -import PlainStableSwapNGABI from "../constants/abis/factory-stable-ng/plain-stableswap-ng.json" with { type: 'json' }; -import MetaStableSwapNGABI from "../constants/abis/factory-stable-ng/meta-stableswap-ng.json" with { type: 'json' }; -import factoryGaugeABI from "../constants/abis/gauge_factory.json" with { type: 'json' }; -import gaugeChildABI from "../constants/abis/gauge_child.json" with { type: 'json' }; -import StableNgBasePoolZapABI from "../constants/abis/stable-ng-base-pool-zap.json" with { type: 'json' }; -import { getPoolIdByAddress, setFactoryZapContracts } from "./common.js"; +import {Contract as MulticallContract} from "@curvefi/ethcall"; +import {ICurve, IDict, IPoolData, IPoolDataShort, REFERENCE_ASSET} from "../interfaces"; +import ERC20ABI from "../constants/abis/ERC20.json" with {type: "json"}; +import PlainStableSwapNGABI from "../constants/abis/factory-stable-ng/plain-stableswap-ng.json" with {type: "json"}; +import MetaStableSwapNGABI from "../constants/abis/factory-stable-ng/meta-stableswap-ng.json" with {type: "json"}; +import factoryGaugeABI from "../constants/abis/gauge_factory.json" with {type: "json"}; +import gaugeChildABI from "../constants/abis/gauge_child.json" with {type: "json"}; +import StableNgBasePoolZapABI from "../constants/abis/stable-ng-base-pool-zap.json" with {type: "json"}; +import {getPoolIdByAddress, setFactoryZapContracts} from "./common.js"; import {getPoolName, isStableNgPool} from "../utils.js"; +import {formatUnits} from "../constants/utils"; +import {Curve} from "../curve"; export const BLACK_LIST: { [index: number]: any } = { 1: [ @@ -27,7 +28,7 @@ export const BLACK_LIST: { [index: number]: any } = { const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); -export async function getBasePools(this: ICurve, factoryAddress: string, rawSwapAddresses: string[], tmpPools: IPoolDataShort[]): Promise<{ids: string[], addresses: string[]}> { +export async function getBasePools(this: Curve, factoryAddress: string, rawSwapAddresses: string[], tmpPools: IPoolDataShort[]): Promise<{ids: string[], addresses: string[]}> { const factoryMulticallContract = this.contracts[factoryAddress].multicallContract; const calls = []; @@ -42,7 +43,7 @@ export async function getBasePools(this: ICurve, factoryAddress: string, rawSwap result.forEach((item: string) => { if(item !== '0x0000000000000000000000000000000000000000') { - basePoolIds.push(getPoolIdByAddress(tmpPools, item)) + basePoolIds.push(getPoolIdByAddress.call(this, tmpPools, item)) basePoolAddresses.push(item) } else { basePoolIds.push('') @@ -61,7 +62,7 @@ async function getRecentlyCreatedPoolId(this: ICurve, swapAddress: string, facto const prefix = factoryAddress === this.constants.ALIASES.factory? 'factory-v2' : 'factory-stable-ng' - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); for (let i = 1; i <= poolCount; i++) { const address: string = await factoryContract.pool_list(poolCount - i); if (address.toLowerCase() === swapAddress.toLowerCase()) return `${prefix}-${poolCount - i}` @@ -74,7 +75,7 @@ async function getFactoryIdsAndSwapAddresses(this: ICurve, fromIdx = 0, factoryA const factoryContract = this.contracts[factoryAddress].contract; const factoryMulticallContract = this.contracts[factoryAddress].multicallContract; - const poolCount = Number(curve.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); + const poolCount = Number(this.formatUnits(await factoryContract.pool_count(this.constantOptions), 0)); const calls = []; for (let i = fromIdx; i < poolCount; i++) { @@ -101,21 +102,21 @@ function _handleReferenceAssets(referenceAssets: bigint[]): REFERENCE_ASSET[] { 0: "USD", 1: "ETH", 2: "BTC", - }[curve.formatUnits(t, 0)] || "OTHER" + }[formatUnits(t, 0)] || "OTHER" }) as REFERENCE_ASSET[]; } function _handleCoinAddresses(this: ICurve, coinAddresses: string[][]): string[][] { return coinAddresses.map( (addresses) => addresses - .filter((addr) => addr !== curve.constants.ZERO_ADDRESS) + .filter((addr) => addr !== this.constants.ZERO_ADDRESS) .map((addr) => this.chainId === 137 && addr === "0x0000000000000000000000000000000000001010" ? this.constants.NATIVE_TOKEN.address : addr.toLowerCase()) ); } async function getPoolsData(this: ICurve, factorySwapAddresses: string[], factoryAddress: string): Promise<[string[], string[], string[], REFERENCE_ASSET[], string[], string[], boolean[], string[][]]> { const factoryMulticallContract = this.contracts[factoryAddress].multicallContract; - const isChildGaugeFactoryNull = curve.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === curve.constants.ZERO_ADDRESS; + const isChildGaugeFactoryNull = this.chainId !== 1 && this.constants.ALIASES.child_gauge_factory === this.constants.ZERO_ADDRESS; const isChildGaugeFactoryOldNull = !("child_gauge_factory_old" in this.constants.ALIASES); const isStableNgFactory = factoryAddress === this.constants.ALIASES['stable_ng_factory']; @@ -148,8 +149,8 @@ async function getPoolsData(this: ICurve, factorySwapAddresses: string[], factor if(isChildGaugeFactoryNull || isChildGaugeFactoryOldNull || isStableNgFactory) { for(let index = 0; index < res.length; index++) { - if(isChildGaugeFactoryNull && index % 8 == 1) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); - if(isChildGaugeFactoryOldNull && index % 8 == 2) res.splice(index, 0 , curve.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryNull && index % 8 == 1) res.splice(index, 0 , this.constants.ZERO_ADDRESS); + if(isChildGaugeFactoryOldNull && index % 8 == 2) res.splice(index, 0 , this.constants.ZERO_ADDRESS); if(isStableNgFactory && index % 8 == 3) res.splice(index, 0 , -1); } } @@ -173,7 +174,7 @@ function setFactorySwapContracts(this: ICurve, factorySwapAddresses: string[], f } function setFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]): void { - factoryGaugeAddresses.filter((addr) => addr !== curve.constants.ZERO_ADDRESS).forEach((addr, i) => { + factoryGaugeAddresses.filter((addr) => addr !== this.constants.ZERO_ADDRESS).forEach((addr) => { this.setContract(addr, this.chainId === 1 ? factoryGaugeABI : gaugeChildABI); }); } @@ -235,7 +236,7 @@ async function getCoinsData( const res = await this.multicallProvider.all(calls); const symbols = res.filter((a, i) => i % 2 == 0) as string[]; - const decimals = (res.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(curve.formatUnits(_d, 0))); + const decimals = (res.filter((a, i) => i % 2 == 1) as bigint[]).map((_d) => Number(this.formatUnits(_d, 0))); newCoinAddresses.forEach((addr, i) => { coinAddrNamesDict[addr] = symbols[i]; @@ -246,13 +247,13 @@ async function getCoinsData( } -export async function getFactoryPoolData(this: ICurve, fromIdx = 0, swapAddress?: string, factoryAddress = curve.constants.ALIASES.factory): Promise> { +export async function getFactoryPoolData(this: Curve, fromIdx = 0, swapAddress?: string, factoryAddress = this.constants.ALIASES.factory): Promise> { const [rawPoolIds, rawSwapAddresses] = swapAddress ? [[await getRecentlyCreatedPoolId.call(this, swapAddress, factoryAddress)], [swapAddress.toLowerCase()]] : await getFactoryIdsAndSwapAddresses.call(this, fromIdx, factoryAddress); if (rawPoolIds.length === 0) return {}; - const is_ng = factoryAddress === curve.constants.ALIASES.stable_ng_factory; + const is_ng = factoryAddress === this.constants.ALIASES.stable_ng_factory; const [rawImplementations, rawGauges, rawOldGauges, rawReferenceAssets, rawPoolSymbols, rawPoolNames, rawIsMeta, rawCoinAddresses] = await getPoolsData.call(this, rawSwapAddresses, factoryAddress); const poolIds: string[] = []; @@ -270,7 +271,7 @@ export async function getFactoryPoolData(this: ICurve, fromIdx = 0, swapAddress? poolIds.push(rawPoolIds[i]); swapAddresses.push(rawSwapAddresses[i]); implementations.push(rawImplementations[i]); - gaugeAddresses.push(rawGauges[i] !== curve.constants.ZERO_ADDRESS ? rawGauges[i] : rawOldGauges[i]); + gaugeAddresses.push(rawGauges[i] !== this.constants.ZERO_ADDRESS ? rawGauges[i] : rawOldGauges[i]); referenceAssets.push(rawReferenceAssets[i]); poolSymbols.push(rawPoolSymbols[i]); poolNames.push(rawPoolNames[i]); @@ -324,20 +325,17 @@ export async function getFactoryPoolData(this: ICurve, fromIdx = 0, swapAddress? }; } else { const allPoolsData = {...this.constants.POOLS_DATA, ...this.constants.FACTORY_POOLS_DATA, ...this.constants.STABLE_NG_FACTORY_POOLS_DATA, ...FACTORY_POOLS_DATA}; - // @ts-ignore const basePoolIdCoinsDict = Object.fromEntries(basePools.ids.map( (poolId) => [poolId, allPoolsData[poolId]?.underlying_coins])); - // @ts-ignore const basePoolIdCoinAddressesDict = Object.fromEntries(basePools.ids.map( (poolId) => [poolId, allPoolsData[poolId]?.underlying_coin_addresses])); - // @ts-ignore const basePoolIdDecimalsDict = Object.fromEntries(basePools.ids.map( (poolId) => [poolId, allPoolsData[poolId]?.underlying_decimals])); const basePoolIdZapDict = this.constants.STABLE_FACTORY_CONSTANTS.basePoolIdZapDict ?? {}; this.constants.BASE_POOLS[basePools.ids[i]] = this.constants.BASE_POOLS[basePools.ids[i]] ? this.constants.BASE_POOLS[basePools.ids[i]] + 1: 1; - let deposit_address = this.constants.STABLE_FACTORY_CONSTANTS.stableNgBasePoolZap ?? curve.constants.ZERO_ADDRESS; + let deposit_address = this.constants.STABLE_FACTORY_CONSTANTS.stableNgBasePoolZap ?? this.constants.ZERO_ADDRESS; let deposit_abi = StableNgBasePoolZapABI; if (isStableNgPool(basePools.ids[i])) { this.setContract(deposit_address, StableNgBasePoolZapABI); diff --git a/src/index.ts b/src/index.ts index e325ac15..a123f444 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { ethers, Networkish } from "ethers"; +import { ethers } from "ethers"; import { PoolTemplate, getPool } from "./pools/index.js"; import { getUserPoolListByLiquidity, @@ -20,7 +20,7 @@ import { swap, getSwappedAmount, } from "./router.js"; -import { curve as _curve } from "./curve.js"; +import { Curve } from "./curve.js"; import { getCrv, getLockedAmountAndUnlockTime, @@ -140,287 +140,278 @@ import { isCanVoteExecute, } from "./dao.js"; -async function init ( - providerType: 'JsonRpc' | 'Web3' | 'Infura' | 'Alchemy' | 'NoRPC', - providerSettings: { url?: string, privateKey?: string, batchMaxCount? : number } | { externalProvider: ethers.Eip1193Provider } | { network?: Networkish, apiKey?: string } | 'NoRPC', - options: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number, chainId?: number } = {} -): Promise { - await _curve.init(providerType, providerSettings, options); - // @ts-ignore - this.signerAddress = _curve.signerAddress; - // @ts-ignore - this.chainId = _curve.chainId; - // @ts-ignore - this.isNoRPC = _curve.isNoRPC; -} - -function setCustomFeeData (customFeeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }): void { - _curve.setCustomFeeData(customFeeData); -} +export const createCurve = () => { + const _curve = new Curve(); + async function init (this: ReturnType, ...params: Parameters): Promise { + await _curve.init(...params); + this.signerAddress = _curve.signerAddress; + this.chainId = _curve.chainId; + this.isNoRPC = _curve.isNoRPC; + } -const curve = { - init, - chainId: 0, - signerAddress: '', - setCustomFeeData, - getPoolList: _curve.getPoolList, - getMainPoolList: _curve.getMainPoolList, - getUserPoolListByLiquidity, - getUserPoolListByClaimable, - getUserPoolList, - getUserLiquidityUSD, - getUserClaimable, - PoolTemplate, - getBasePools, - getPool, - getUsdRate, - getGasPriceFromL1, - getGasPriceFromL2, - getGasInfoForL2, - getGasPrice, - getTVL, - getBalances, - getAllowance, - hasAllowance, - ensureAllowance, - getCoinsData, - getVolume, - hasDepositAndStake, - hasRouter, - getCurveLiteNetworks, - getNetworkConstants: _curve.getNetworkConstants, - getIsLiteChain: _curve.getIsLiteChain, - isNoRPC: _curve.isNoRPC, - factory: { - fetchPools: _curve.fetchFactoryPools, - fetchNewPools: _curve.fetchNewFactoryPools, - getPoolList: _curve.getFactoryPoolList, - deployPlainPool: deployStablePlainPool, - setOracle, - deployMetaPool: deployStableMetaPool, - deployGauge: async (poolAddress: string): Promise => deployGauge(poolAddress, _curve.constants.ALIASES.factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror(chainId, salt), - getDeployedPlainPoolAddress: getDeployedStablePlainPoolAddress, - getDeployedMetaPoolAddress: getDeployedStableMetaPoolAddress, - getDeployedGaugeAddress: getDeployedGaugeAddress, - getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress, - getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx, - fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedFactoryPool, - gaugeImplementation: (): string => _curve.getGaugeImplementation("factory"), - estimateGas: { - deployPlainPool: deployStablePlainPoolEstimateGas, - setOracle: setOracleEstimateGas, - deployMetaPool: deployStableMetaPoolEstimateGas, - deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas(poolAddress, _curve.constants.ALIASES.factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas(chainId, salt), + return { + init, + chainId: 0, // until init is called + signerAddress: '', + setCustomFeeData: _curve.setCustomFeeData.bind(_curve), + getPoolList: _curve.getPoolList.bind(_curve), + getMainPoolList: _curve.getMainPoolList.bind(_curve), + getUserPoolListByLiquidity: getUserPoolListByLiquidity.bind(_curve), + getUserPoolListByClaimable: getUserPoolListByClaimable.bind(_curve), + getUserPoolList: getUserPoolList.bind(_curve), + getUserLiquidityUSD: getUserLiquidityUSD.bind(_curve), + getUserClaimable: getUserClaimable.bind(_curve), + PoolTemplate: PoolTemplate.bind(_curve), + getBasePools: getBasePools.bind(_curve), + getPool: getPool.bind(_curve), + getUsdRate: getUsdRate.bind(_curve), + getGasPriceFromL1: getGasPriceFromL1.bind(_curve), + getGasPriceFromL2: getGasPriceFromL2.bind(_curve), + getGasInfoForL2: getGasInfoForL2.bind(_curve), + getGasPrice: getGasPrice.bind(_curve), + getTVL: getTVL.bind(_curve), + getBalances: getBalances.bind(_curve), + getAllowance: getAllowance.bind(_curve), + hasAllowance: hasAllowance.bind(_curve), + ensureAllowance: ensureAllowance.bind(_curve), + getCoinsData: getCoinsData.bind(_curve), + getVolume: getVolume.bind(_curve), + hasDepositAndStake: hasDepositAndStake.bind(_curve), + hasRouter: hasRouter.bind(_curve), + getCurveLiteNetworks: getCurveLiteNetworks.bind(_curve), + getNetworkConstants: _curve.getNetworkConstants.bind(_curve), + getIsLiteChain: _curve.getIsLiteChain.bind(_curve), + isNoRPC: _curve.isNoRPC, + factory: { + fetchPools: _curve.fetchFactoryPools.bind(_curve), + fetchNewPools: _curve.fetchNewFactoryPools.bind(_curve), + getPoolList: _curve.getFactoryPoolList.bind(_curve), + deployPlainPool: deployStablePlainPool.bind(_curve), + setOracle: setOracle.bind(_curve), + deployMetaPool: deployStableMetaPool.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGauge.call(_curve, poolAddress, _curve.constants.ALIASES.factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror.call(_curve,chainId, salt), + getDeployedPlainPoolAddress: getDeployedStablePlainPoolAddress.bind(_curve), + getDeployedMetaPoolAddress: getDeployedStableMetaPoolAddress.bind(_curve), + getDeployedGaugeAddress: getDeployedGaugeAddress.bind(_curve), + getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress.bind(_curve), + getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx.bind(_curve), + fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedFactoryPool.bind(_curve), + gaugeImplementation: (): string => _curve.getGaugeImplementation("factory"), + estimateGas: { + deployPlainPool: deployStablePlainPoolEstimateGas.bind(_curve), + setOracle: setOracleEstimateGas.bind(_curve), + deployMetaPool: deployStableMetaPoolEstimateGas.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas.call(_curve,poolAddress, _curve.constants.ALIASES.factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas.call(_curve,chainId, salt), + }, }, - }, - crvUSDFactory: { - fetchPools: _curve.fetchCrvusdFactoryPools, - getPoolList: _curve.getCrvusdFactoryPoolList, - }, - EYWAFactory: { - fetchPools: _curve.fetchEywaFactoryPools, - getPoolList: _curve.getEywaFactoryPoolList, - }, - stableNgFactory: { - fetchPools: _curve.fetchStableNgFactoryPools, - fetchNewPools: _curve.fetchNewStableNgFactoryPools, - getPoolList: _curve.getStableNgFactoryPoolList, - deployPlainPool: deployStableNgPlainPool, - deployMetaPool: deployStableNgMetaPool, - deployGauge: async (poolAddress: string): Promise => deployGauge(poolAddress, _curve.constants.ALIASES.stable_ng_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror(chainId, salt), - getDeployedPlainPoolAddress: getDeployedStablePlainPoolAddress, - getDeployedMetaPoolAddress: getDeployedStableMetaPoolAddress, - getDeployedGaugeAddress: getDeployedGaugeAddress, - getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress, - getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx, - fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedStableNgFactoryPool, - estimateGas: { - deployPlainPool: deployStableNgPlainPoolEstimateGas, - deployMetaPool: deployStableNgMetaPoolEstimateGas, + crvUSDFactory: { + fetchPools: _curve.fetchCrvusdFactoryPools.bind(_curve), + getPoolList: _curve.getCrvusdFactoryPoolList.bind(_curve), }, - }, - cryptoFactory: { - fetchPools: _curve.fetchCryptoFactoryPools, - fetchNewPools: _curve.fetchNewCryptoFactoryPools, - getPoolList: _curve.getCryptoFactoryPoolList, - deployPool: deployCryptoPool, - deployGauge: async (poolAddress: string): Promise => deployGauge(poolAddress, _curve.constants.ALIASES.crypto_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror(chainId, salt), - getDeployedPoolAddress: getDeployedCryptoPoolAddress, - getDeployedGaugeAddress: getDeployedGaugeAddress, - getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress, - getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx, - fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedCryptoFactoryPool, - gaugeImplementation: (): string => _curve.getGaugeImplementation("factory-crypto"), - estimateGas: { - deployPool: deployCryptoPoolEstimateGas, - deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas(poolAddress, _curve.constants.ALIASES.crypto_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas(chainId, salt), + EYWAFactory: { + fetchPools: _curve.fetchEywaFactoryPools.bind(_curve), + getPoolList: _curve.getEywaFactoryPoolList.bind(_curve), }, - }, - twocryptoFactory: { - fetchPools: _curve.fetchTworyptoFactoryPools, - fetchNewPools: _curve.fetchNewTwocryptoFactoryPools, - getPoolList: _curve.getTworyptoFactoryPoolList, - deployPool: deployTwocryptoPool, - deployGauge: async (poolAddress: string): Promise => deployGauge(poolAddress, _curve.constants.ALIASES.twocrypto_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror(chainId, salt), - getDeployedPoolAddress: getDeployedTwocryptoPoolAddress, - getDeployedGaugeAddress: getDeployedGaugeAddress, - getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress, - getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx, - fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedTwocryptoFactoryPool, - gaugeImplementation: (): string => _curve.getGaugeImplementation("factory-twocrypto"), - estimateGas: { - deployPool: deployTwocryptoPoolEstimateGas, // - deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas(poolAddress, _curve.constants.ALIASES.twocrypto_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas(chainId, salt), + stableNgFactory: { + fetchPools: _curve.fetchStableNgFactoryPools.bind(_curve), + fetchNewPools: _curve.fetchNewStableNgFactoryPools.bind(_curve), + getPoolList: _curve.getStableNgFactoryPoolList.bind(_curve), + deployPlainPool: deployStableNgPlainPool.bind(_curve), + deployMetaPool: deployStableNgMetaPool.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGauge.call(_curve,poolAddress, _curve.constants.ALIASES.stable_ng_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror.call(_curve,chainId, salt), + getDeployedPlainPoolAddress: getDeployedStablePlainPoolAddress.bind(_curve), + getDeployedMetaPoolAddress: getDeployedStableMetaPoolAddress.bind(_curve), + getDeployedGaugeAddress: getDeployedGaugeAddress.bind(_curve), + getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress.bind(_curve), + getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx.bind(_curve), + fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedStableNgFactoryPool.bind(_curve), + estimateGas: { + deployPlainPool: deployStableNgPlainPoolEstimateGas.bind(_curve), + deployMetaPool: deployStableNgMetaPoolEstimateGas.bind(_curve), + }, }, - }, - tricryptoFactory: { - fetchPools: _curve.fetchTricryptoFactoryPools, - fetchNewPools: _curve.fetchNewTricryptoFactoryPools, - getPoolList: _curve.getTricryptoFactoryPoolList, - deployPool: deployTricryptoPool, - deployGauge: async (poolAddress: string): Promise => deployGauge(poolAddress, _curve.constants.ALIASES.tricrypto_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror(chainId, salt), - getDeployedPoolAddress: getDeployedTricryptoPoolAddress, - getDeployedGaugeAddress: getDeployedGaugeAddress, - getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress, - getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx, - fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedTricryptoFactoryPool, - gaugeImplementation: (): string => _curve.getGaugeImplementation("factory-tricrypto"), - estimateGas: { - deployPool: deployTricryptoPoolEstimateGas, - deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas(poolAddress, _curve.constants.ALIASES.tricrypto_factory), - deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas(poolAddress, salt), - deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas(chainId, salt), + cryptoFactory: { + fetchPools: _curve.fetchCryptoFactoryPools.bind(_curve), + fetchNewPools: _curve.fetchNewCryptoFactoryPools.bind(_curve), + getPoolList: _curve.getCryptoFactoryPoolList.bind(_curve), + deployPool: deployCryptoPool.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGauge.call(_curve,poolAddress, _curve.constants.ALIASES.crypto_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror.call(_curve,chainId, salt), + getDeployedPoolAddress: getDeployedCryptoPoolAddress.bind(_curve), + getDeployedGaugeAddress: getDeployedGaugeAddress.bind(_curve), + getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress.bind(_curve), + getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx.bind(_curve), + fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedCryptoFactoryPool.bind(_curve), + gaugeImplementation: (): string => _curve.getGaugeImplementation("factory-crypto"), + estimateGas: { + deployPool: deployCryptoPoolEstimateGas, + deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas.call(_curve,poolAddress, _curve.constants.ALIASES.crypto_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas.call(_curve,chainId, salt), + }, }, - }, - estimateGas: { - ensureAllowance: ensureAllowanceEstimateGas, - }, - boosting: { - getCrv, - getLockedAmountAndUnlockTime, - getVeCrv, - getVeCrvPct, - calcUnlockTime, - isApproved, - approve, - createLock, - increaseAmount, - increaseUnlockTime, - withdrawLockedCrv, - claimableFees, - claimFees, - claimableFeesCrvUSD, - claimFeesCrvUSD, - calculateVeCrv, - estimateGas: { - approve: approveEstimateGas, - createLock: createLockEstimateGas, - increaseAmount: increaseAmountEstimateGas, - increaseUnlockTime: increaseUnlockTimeEstimateGas, - withdrawLockedCrv: withdrawLockedCrvEstimateGas, - claimFees: claimFeesEstimateGas, - claimFeesCrvUSD: claimFeesCrvUSDEstimateGas, + twocryptoFactory: { + fetchPools: _curve.fetchTworyptoFactoryPools.bind(_curve), + fetchNewPools: _curve.fetchNewTwocryptoFactoryPools.bind(_curve), + getPoolList: _curve.getTworyptoFactoryPoolList.bind(_curve), + deployPool: deployTwocryptoPool.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGauge.call(_curve,poolAddress, _curve.constants.ALIASES.twocrypto_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror.call(_curve,chainId, salt), + getDeployedPoolAddress: getDeployedTwocryptoPoolAddress.bind(_curve), + getDeployedGaugeAddress: getDeployedGaugeAddress.bind(_curve), + getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress.bind(_curve), + getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx.bind(_curve), + fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedTwocryptoFactoryPool.bind(_curve), + gaugeImplementation: (): string => _curve.getGaugeImplementation("factory-twocrypto"), + estimateGas: { + deployPool: deployTwocryptoPoolEstimateGas, // + deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas.call(_curve,poolAddress, _curve.constants.ALIASES.twocrypto_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas.call(_curve,chainId, salt), + }, }, - sidechain: { - lastEthBlock, - getAnycallBalance, - topUpAnycall, - lastBlockSent, - blockToSend, - sendBlockhash, - submitProof, + tricryptoFactory: { + fetchPools: _curve.fetchTricryptoFactoryPools.bind(_curve), + fetchNewPools: _curve.fetchNewTricryptoFactoryPools.bind(_curve), + getPoolList: _curve.getTricryptoFactoryPoolList.bind(_curve), + deployPool: deployTricryptoPool.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGauge.call(_curve,poolAddress, _curve.constants.ALIASES.tricrypto_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechain.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirror.call(_curve,chainId, salt), + getDeployedPoolAddress: getDeployedTricryptoPoolAddress.bind(_curve), + getDeployedGaugeAddress: getDeployedGaugeAddress.bind(_curve), + getDeployedGaugeMirrorAddress: getDeployedGaugeMirrorAddress.bind(_curve), + getDeployedGaugeMirrorAddressByTx: getDeployedGaugeMirrorAddressByTx.bind(_curve), + fetchRecentlyDeployedPool: _curve.fetchRecentlyDeployedTricryptoFactoryPool.bind(_curve), + gaugeImplementation: (): string => _curve.getGaugeImplementation("factory-tricrypto"), estimateGas: { - topUpAnycall: topUpAnycallEstimateGas, - sendBlockhash: sendBlockhashEstimateGas, - submitProof: submitProofEstimateGas, + deployPool: deployTricryptoPoolEstimateGas.bind(_curve), + deployGauge: async (poolAddress: string): Promise => deployGaugeEstimateGas.call(_curve,poolAddress, _curve.constants.ALIASES.tricrypto_factory), + deployGaugeSidechain: async (poolAddress: string, salt: string): Promise => deployGaugeSidechainEstimateGas.call(_curve,poolAddress, salt), + deployGaugeMirror: async (chainId: number, salt: string): Promise => deployGaugeMirrorEstimateGas.call(_curve,chainId, salt), }, }, - }, - router: { - getBestRouteAndOutput, - getArgs, - expected: swapExpected, - required: swapRequired, - priceImpact: swapPriceImpact, - isApproved: swapIsApproved, - approve: swapApprove, - swap, - getSwappedAmount, estimateGas: { - approve: swapApproveEstimateGas, - swap: swapEstimateGas, + ensureAllowance: ensureAllowanceEstimateGas.bind(_curve), + }, + boosting: { + getCrv: getCrv.bind(_curve), + getLockedAmountAndUnlockTime: getLockedAmountAndUnlockTime.bind(_curve), + getVeCrv: getVeCrv.bind(_curve), + getVeCrvPct: getVeCrvPct.bind(_curve), + calcUnlockTime: calcUnlockTime.bind(_curve), + isApproved: isApproved.bind(_curve), + approve: approve.bind(_curve), + createLock: createLock.bind(_curve), + increaseAmount: increaseAmount.bind(_curve), + increaseUnlockTime: increaseUnlockTime.bind(_curve), + withdrawLockedCrv: withdrawLockedCrv.bind(_curve), + claimableFees: claimableFees.bind(_curve), + claimFees: claimFees.bind(_curve), + claimableFeesCrvUSD: claimableFeesCrvUSD.bind(_curve), + claimFeesCrvUSD: claimFeesCrvUSD.bind(_curve), + calculateVeCrv,estimateGas: { + approve: approveEstimateGas.bind(_curve), + createLock: createLockEstimateGas.bind(_curve), + increaseAmount: increaseAmountEstimateGas.bind(_curve), + increaseUnlockTime: increaseUnlockTimeEstimateGas.bind(_curve), + withdrawLockedCrv: withdrawLockedCrvEstimateGas.bind(_curve), + claimFees: claimFeesEstimateGas.bind(_curve), + claimFeesCrvUSD: claimFeesCrvUSDEstimateGas.bind(_curve), + }, + sidechain: { + lastEthBlock: lastEthBlock.bind(_curve), + getAnycallBalance: getAnycallBalance.bind(_curve), + topUpAnycall: topUpAnycall.bind(_curve), + lastBlockSent: lastBlockSent.bind(_curve), + blockToSend: blockToSend.bind(_curve), + sendBlockhash: sendBlockhash.bind(_curve), + submitProof: submitProof.bind(_curve), + estimateGas: { + topUpAnycall: topUpAnycallEstimateGas.bind(_curve), + sendBlockhash: sendBlockhashEstimateGas.bind(_curve), + submitProof: submitProofEstimateGas.bind(_curve), + }, + }, }, - }, - dao: { - // --- CRV lock --- + router: { + getBestRouteAndOutput: getBestRouteAndOutput.bind(_curve), + getArgs: getArgs.bind(_curve), + expected: swapExpected.bind(_curve), + required: swapRequired.bind(_curve), + priceImpact: swapPriceImpact.bind(_curve), + isApproved: swapIsApproved.bind(_curve), + approve: swapApprove.bind(_curve), + swap: swap.bind(_curve), + getSwappedAmount: getSwappedAmount.bind(_curve), + estimateGas: { + approve: swapApproveEstimateGas.bind(_curve), + swap: swapEstimateGas.bind(_curve), + }, + }, + dao: { + // --- CRV lock --- - // View methods - crvSupplyStats, - userCrv, - userVeCrv, - crvLockIsApproved, - calcCrvUnlockTime, - claimableFees: daoClaimableFees, - // Transaction methods - crvLockApprove, - createCrvLock, - increaseCrvLockedAmount, - increaseCrvUnlockTime, - withdrawLockedCrv: daoWithdrawLockedCrv, - claimFees: daoClaimFees, + // View methods + crvSupplyStats: crvSupplyStats.bind(_curve), + userCrv: userCrv.bind(_curve), + userVeCrv: userVeCrv.bind(_curve), + crvLockIsApproved: crvLockIsApproved.bind(_curve), + calcCrvUnlockTime: calcCrvUnlockTime.bind(_curve), + claimableFees: daoClaimableFees.bind(_curve), + // Transaction methods + crvLockApprove: crvLockApprove.bind(_curve), + createCrvLock: createCrvLock.bind(_curve), + increaseCrvLockedAmount: increaseCrvLockedAmount.bind(_curve), + increaseCrvUnlockTime: increaseCrvUnlockTime.bind(_curve), + withdrawLockedCrv: daoWithdrawLockedCrv.bind(_curve), + claimFees: daoClaimFees.bind(_curve), - // --- Gauge voting --- + // --- Gauge voting --- - // View methods - getVotingGaugeList, - userGaugeVotes, - voteForGaugeNextTime, - // Transaction methods - voteForGauge, + // View methods + getVotingGaugeList: getVotingGaugeList.bind(_curve), + userGaugeVotes: userGaugeVotes.bind(_curve), + voteForGaugeNextTime: voteForGaugeNextTime.bind(_curve), + // Transaction methods + voteForGauge: voteForGauge.bind(_curve), - // --- Proposal voting --- + // --- Proposal voting --- - // View methods - getProposalList, - getProposal, - userProposalVotes, - // Transaction methods - voteForProposal, - executeVote, - isCanVoteExecute, + // View methods + getProposalList: getProposalList.bind(_curve), + getProposal: getProposal.bind(_curve), + userProposalVotes: userProposalVotes.bind(_curve), + // Transaction methods + voteForProposal: voteForProposal.bind(_curve), + executeVote: executeVote.bind(_curve), + isCanVoteExecute: isCanVoteExecute.bind(_curve), - estimateGas: { - // --- CRV lock --- - crvLockApprove: crvLockApproveEstimateGas, - createCrvLock: createCrvLockEstimateGas, - increaseCrvLockedAmount: increaseCrvLockedAmountEstimateGas, - increaseCrvUnlockTime: increaseCrvUnlockTimeEstimateGas, - withdrawLockedCrv: daoWithdrawLockedCrvEstimateGas, - claimFees: daoClaimFeesEstimateGas, - // --- Gauge voting --- - voteForGauge: voteForGaugeEstimateGas, - // --- Proposal voting --- - voteForProposal: voteForProposalEstimateGas, - executeVote: executeVoteEstimateGas, + estimateGas: { + // --- CRV lock --- + crvLockApprove: crvLockApproveEstimateGas.bind(_curve), + createCrvLock: createCrvLockEstimateGas.bind(_curve), + increaseCrvLockedAmount: increaseCrvLockedAmountEstimateGas.bind(_curve), + increaseCrvUnlockTime: increaseCrvUnlockTimeEstimateGas.bind(_curve), + withdrawLockedCrv: daoWithdrawLockedCrvEstimateGas.bind(_curve), + claimFees: daoClaimFeesEstimateGas.bind(_curve), + // --- Gauge voting --- + voteForGauge: voteForGaugeEstimateGas.bind(_curve), + // --- Proposal voting --- + voteForProposal: voteForProposalEstimateGas.bind(_curve), + executeVote: executeVoteEstimateGas.bind(_curve), + }, }, - }, + } } -export default curve; +export default createCurve(); diff --git a/src/interfaces.ts b/src/interfaces.ts index a72c3d6a..50d544ab 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,5 +1,6 @@ import { Contract, ethers } from "ethers"; import { Contract as MulticallContract, Provider as MulticallProvider } from "@curvefi/ethcall"; +import {BigNumberish, Numeric} from "ethers"; export interface IDict { [index: string]: T, @@ -91,6 +92,7 @@ export interface ICurve { options: { gasPrice?: number | bigint, maxFeePerGas?: number | bigint, maxPriorityFeePerGas?: number | bigint }, constants: INetworkConstants, setContract: (address: string | undefined, abi: any) => void, + formatUnits(value: BigNumberish, unit?: string | Numeric): string } export interface ICoinFromPoolDataApi { diff --git a/src/pools/PoolTemplate.ts b/src/pools/PoolTemplate.ts index e3552f86..1483abbb 100644 --- a/src/pools/PoolTemplate.ts +++ b/src/pools/PoolTemplate.ts @@ -2,39 +2,40 @@ import BigNumber from 'bignumber.js'; import memoize from "memoizee"; import {_getAllGaugesFormatted} from '../external-api.js'; import { - _getCoinAddresses, + _cutZeros, _ensureAllowance, + _get_price_impact, + _get_small_x, + _getAddress, + _getCoinAddresses, + _getRewardsFromApi, _getUsdRate, - hasAllowance, - ensureAllowance, - ensureAllowanceEstimateGas, - BN, - toBN, - toStringFromBN, - parseUnits, - getEthIndex, - fromBN, - _cutZeros, _setContracts, - _get_small_x, - _get_price_impact, + BN, checkNumber, - _getRewardsFromApi, - mulBy1_3, - smartNumber, DIGas, - _getAddress, + ensureAllowance, + ensureAllowanceEstimateGas, findAbiFunction, + fromBN, + getEthIndex, + hasAllowance, + mulBy1_3, + parseUnits, PERIODS, + smartNumber, + toBN, + toStringFromBN, } from '../utils.js'; import {IDict, IProfit} from '../interfaces'; -import { curve, OLD_CHAINS } from "../curve.js"; -import ERC20Abi from '../constants/abis/ERC20.json' with { type: 'json' }; +import {Curve, OLD_CHAINS} from "../curve.js"; +import ERC20Abi from '../constants/abis/ERC20.json' with {type: 'json'}; import {CorePool} from "./subClasses/corePool.js"; import {StatsPool} from "./subClasses/statsPool.js"; import {WalletPool} from "./subClasses/walletPool.js"; import {checkVyperVulnerability} from "./utils.js"; + export class PoolTemplate extends CorePool { isGaugeKilled: () => Promise; gaugeStatus: () => Promise; @@ -69,8 +70,8 @@ export class PoolTemplate extends CorePool { stats: StatsPool; wallet: WalletPool; - constructor(id: string) { - super(id); + constructor(id: string, curve: Curve, poolData = curve.getPoolsData()[id]) { + super(id, poolData, curve); this.stats = new StatsPool(this); this.wallet = new WalletPool(this); @@ -108,16 +109,16 @@ export class PoolTemplate extends CorePool { public hasVyperVulnerability(): boolean { return checkVyperVulnerability( - curve.chainId, + this.curve.chainId, this.id, this.implementation ); } public rewardsOnly(): boolean { - if (curve.chainId === 2222 || curve.chainId === 324) return true; // TODO remove this for Kava and ZkSync - if (this.gauge.address === curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); - return !findAbiFunction(curve.contracts[this.gauge.address].abi, 'inflation_rate') + if (this.curve.chainId === 2222 || this.curve.chainId === 324) return true; // TODO remove this for Kava and ZkSync + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); + return !findAbiFunction(this.curve.contracts[this.gauge.address].abi, 'inflation_rate') .find((func) => ['', 'uint256'].includes(func.inputs.map((a) => `${a.type}`).join(','))) } @@ -126,28 +127,28 @@ export class PoolTemplate extends CorePool { if (Number(totalLiquidityUSD) === 0) return [0, 0]; let inflationRateBN, workingSupplyBN, totalSupplyBN; - if (curve.chainId !== 1) { - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; - const lpTokenContract = curve.contracts[this.lpToken].multicallContract; - const crvContract = curve.contracts[curve.constants.ALIASES.crv].contract; + if (this.curve.chainId !== 1) { + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; + const lpTokenContract = this.curve.contracts[this.lpToken].multicallContract; + const crvContract = this.curve.contracts[this.curve.constants.ALIASES.crv].contract; const currentWeek = Math.floor(Date.now() / 1000 / PERIODS.WEEK); - [inflationRateBN, workingSupplyBN, totalSupplyBN] = (await curve.multicallProvider.all([ + [inflationRateBN, workingSupplyBN, totalSupplyBN] = (await this.curve.multicallProvider.all([ gaugeContract.inflation_rate(currentWeek), gaugeContract.working_supply(), lpTokenContract.totalSupply(), ]) as bigint[]).map((value) => toBN(value)); if (inflationRateBN.eq(0)) { - inflationRateBN = toBN(await crvContract.balanceOf(this.gauge.address, curve.constantOptions)).div(PERIODS.WEEK); + inflationRateBN = toBN(await crvContract.balanceOf(this.gauge.address, this.curve.constantOptions)).div(PERIODS.WEEK); } } else { - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; - const lpTokenContract = curve.contracts[this.lpToken].multicallContract; - const gaugeControllerContract = curve.contracts[curve.constants.ALIASES.gauge_controller].multicallContract; + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; + const lpTokenContract = this.curve.contracts[this.lpToken].multicallContract; + const gaugeControllerContract = this.curve.contracts[this.curve.constants.ALIASES.gauge_controller].multicallContract; let weightBN; - [inflationRateBN, weightBN, workingSupplyBN, totalSupplyBN] = (await curve.multicallProvider.all([ + [inflationRateBN, weightBN, workingSupplyBN, totalSupplyBN] = (await this.curve.multicallProvider.all([ gaugeContract.inflation_rate(), gaugeControllerContract.gauge_relative_weight(this.gauge.address), gaugeContract.working_supply(), @@ -163,7 +164,7 @@ export class PoolTemplate extends CorePool { // If you added 1$ value of LP it would be 0.4$ of working LP. So your annual reward per 1$ in USD is: // (annual reward per working liquidity in $) * (0.4$ of working LP) const rateBN = inflationRateBN.times(31536000).div(workingSupplyBN).times(totalSupplyBN).div(Number(totalLiquidityUSD)).times(0.4); - const crvPrice = await _getUsdRate(curve.constants.ALIASES.crv); + const crvPrice = await _getUsdRate.call(this.curve, this.curve.constants.ALIASES.crv); const baseApyBN = rateBN.times(crvPrice); const boostedApyBN = baseApyBN.times(2.5); @@ -173,35 +174,35 @@ export class PoolTemplate extends CorePool { private async _pureCalcLpTokenAmount(_amounts: bigint[], isDeposit = true, useUnderlying = true): Promise { const calcContractAddress = this.isMeta && useUnderlying ? this.zap as string : this.address; const N_coins = useUnderlying ? this.underlyingCoins.length : this.wrappedCoins.length; - const contract = curve.contracts[calcContractAddress].contract; + const contract = this.curve.contracts[calcContractAddress].contract; if (this.isMetaFactory && useUnderlying) { if (`calc_token_amount(address,uint256[${N_coins}],bool)` in contract) { - return await contract.calc_token_amount(this.address, _amounts, isDeposit, curve.constantOptions); + return await contract.calc_token_amount(this.address, _amounts, isDeposit, this.curve.constantOptions); } - return await contract.calc_token_amount(this.address, _amounts, curve.constantOptions); + return await contract.calc_token_amount(this.address, _amounts, this.curve.constantOptions); } if (`calc_token_amount(uint256[${N_coins}],bool)` in contract) { - return await contract.calc_token_amount(_amounts, isDeposit, curve.constantOptions); + return await contract.calc_token_amount(_amounts, isDeposit, this.curve.constantOptions); } - return await contract.calc_token_amount(_amounts, curve.constantOptions); + return await contract.calc_token_amount(_amounts, this.curve.constantOptions); } - private _calcLpTokenAmount = memoize(async (_amounts: bigint[], isDeposit = true, useUnderlying = true): Promise => { + _calcLpTokenAmount = memoize(async (_amounts: bigint[], isDeposit = true, useUnderlying = true): Promise => { if (this.isCrypto) { try { return await this._pureCalcLpTokenAmount(_amounts, isDeposit, useUnderlying); } catch (e) { // Seeding - const lpContract = curve.contracts[this.lpToken].contract; - const _lpTotalSupply: bigint = await lpContract.totalSupply(curve.constantOptions); - if (_lpTotalSupply > curve.parseUnits("0")) throw e; // Already seeded + const lpContract = this.curve.contracts[this.lpToken].contract; + const _lpTotalSupply: bigint = await lpContract.totalSupply(this.curve.constantOptions); + if (_lpTotalSupply > this.curve.parseUnits("0")) throw e; // Already seeded if (this.isMeta && useUnderlying) throw Error("Initial deposit for crypto meta pools must be in wrapped coins"); const decimals = useUnderlying ? this.underlyingDecimals : this.wrappedDecimals; - const amounts = _amounts.map((_a, i) => curve.formatUnits(_a, decimals[i])); + const amounts = _amounts.map((_a, i) => this.curve.formatUnits(_a, decimals[i])); const seedAmounts = await this.getSeedAmounts(amounts[0]); // Checks N coins is 2 or 3 and amounts > 0 amounts.forEach((a, i) => { if (!BN(a).eq(BN(seedAmounts[i]))) throw Error(`Amounts must be = ${seedAmounts}`); @@ -215,11 +216,11 @@ export class PoolTemplate extends CorePool { if (this.isNg) return await this._pureCalcLpTokenAmount(_amounts, isDeposit, useUnderlying); if (this.isMeta) { - const basePool = new PoolTemplate(this.basePool); - return await curve.contracts[curve.constants.ALIASES.stable_calc].contract.calc_token_amount_meta( + const basePool = new PoolTemplate(this.basePool, this.curve); + return await this.curve.contracts[this.curve.constants.ALIASES.stable_calc].contract.calc_token_amount_meta( this.address, this.lpToken, - _amounts.concat(Array(10 - _amounts.length).fill(curve.parseUnits("0"))), + _amounts.concat(Array(10 - _amounts.length).fill(this.curve.parseUnits("0"))), _amounts.length, basePool.address, basePool.lpToken, @@ -227,10 +228,10 @@ export class PoolTemplate extends CorePool { useUnderlying ); } else { - return await curve.contracts[curve.constants.ALIASES.stable_calc].contract.calc_token_amount( + return await this.curve.contracts[this.curve.constants.ALIASES.stable_calc].contract.calc_token_amount( this.address, this.lpToken, - _amounts.concat(Array(10 - _amounts.length).fill(curve.parseUnits("0"))), + _amounts.concat(Array(10 - _amounts.length).fill(this.curve.parseUnits("0"))), _amounts.length, isDeposit, useUnderlying && this.isLending @@ -239,12 +240,12 @@ export class PoolTemplate extends CorePool { } catch (e: any) { // Seeding if (!isDeposit) throw e; // Seeding is only for deposit - const lpContract = curve.contracts[this.lpToken].contract; - const _lpTotalSupply: bigint = await lpContract.totalSupply(curve.constantOptions); - if (_lpTotalSupply > curve.parseUnits("0")) throw e; // Already seeded + const lpContract = this.curve.contracts[this.lpToken].contract; + const _lpTotalSupply: bigint = await lpContract.totalSupply(this.curve.constantOptions); + if (_lpTotalSupply > this.curve.parseUnits("0")) throw e; // Already seeded const decimals = useUnderlying ? this.underlyingDecimals : this.wrappedDecimals; - const amounts = _amounts.map((_a, i) => curve.formatUnits(_a, decimals[i])); + const amounts = _amounts.map((_a, i) => this.curve.formatUnits(_a, decimals[i])); const seedAmounts = await this.getSeedAmounts(amounts[0]); // Checks N coins == 2 and amounts > 0 amounts.forEach((a, i) => { @@ -270,7 +271,7 @@ export class PoolTemplate extends CorePool { const _underlyingAmounts: bigint[] = amounts.map((amount, i) => parseUnits(amount, this.underlyingDecimals[i])); const _expected = await this._calcLpTokenAmount(_underlyingAmounts, isDeposit, true); - return curve.formatUnits(_expected); + return this.curve.formatUnits(_expected); } private async calcLpTokenAmountWrapped(amounts: (number | string)[], isDeposit = true): Promise { @@ -285,7 +286,7 @@ export class PoolTemplate extends CorePool { const _amounts: bigint[] = amounts.map((amount, i) => parseUnits(amount, this.wrappedDecimals[i])); const _expected = await this._calcLpTokenAmount(_amounts, isDeposit, false); - return curve.formatUnits(_expected); + return this.curve.formatUnits(_expected); } @@ -299,12 +300,12 @@ export class PoolTemplate extends CorePool { const decimals = this.isMeta ? this.wrappedDecimals : this.underlyingDecimals; if (decimals.length === 2) { - const priceScaleBN = toBN(await curve.contracts[this.address].contract.price_scale(curve.constantOptions)); + const priceScaleBN = toBN(await this.curve.contracts[this.address].contract.price_scale(this.curve.constantOptions)); return [_cutZeros(amount1BN.toFixed(decimals[0])), _cutZeros(amount1BN.div(priceScaleBN).toFixed(decimals[1]))]; } else if (decimals.length === 3) { - const priceScaleBN = (await curve.multicallProvider.all([ - curve.contracts[this.address].multicallContract.price_scale(0), - curve.contracts[this.address].multicallContract.price_scale(1), + const priceScaleBN = (await this.curve.multicallProvider.all([ + this.curve.contracts[this.address].multicallContract.price_scale(0), + this.curve.contracts[this.address].multicallContract.price_scale(1), ]) as bigint[]).map((_p) => toBN(_p)); return [ _cutZeros(amount1BN.toFixed(decimals[0])), @@ -318,7 +319,7 @@ export class PoolTemplate extends CorePool { const amounts = [_cutZeros(amount1BN.toFixed(this.wrappedDecimals[0]))]; if (this.isMeta && useUnderlying) { - const basePool = new PoolTemplate(this.basePool); + const basePool = new PoolTemplate(this.basePool, this.curve); const basePoolBalancesBN = (await basePool.stats.underlyingBalances()).map(BN); const totalBN = basePoolBalancesBN.reduce((a, b) => a.plus(b)); for (let i = 1; i < this.underlyingDecimals.length; i++) { @@ -373,18 +374,18 @@ export class PoolTemplate extends CorePool { public async depositBonus(amounts: (number | string)[]): Promise { const amountsBN = amounts.map(BN); - let pricesBN: BigNumber[] = []; - const multicallContract = curve.contracts[this.address].multicallContract; + let pricesBN: BigNumber[]; + const multicallContract = this.curve.contracts[this.address].multicallContract; if(this.isCrypto || this.id === 'wsteth') { - if(curve.isLiteChain) { + if(this.curve.isLiteChain) { const prices = this.id.includes('twocrypto') ? [ 1, - Number(await curve.contracts[this.address].contract.price_oracle()) / (10 ** 18), + Number(await this.curve.contracts[this.address].contract.price_oracle()) / (10 ** 18), ] : [ 1, - ...(await curve.multicallProvider.all([ + ...(await this.curve.multicallProvider.all([ multicallContract.price_oracle(0), multicallContract.price_oracle(1), ])).map((value) => Number(value) / (10 ** 18)), @@ -406,15 +407,15 @@ export class PoolTemplate extends CorePool { } public async depositIsApproved(amounts: (number | string)[]): Promise { - return await hasAllowance(this.underlyingCoinAddresses, amounts, curve.signerAddress, this.zap || this.address); + return await hasAllowance.call(this.curve, this.underlyingCoinAddresses, amounts, this.curve.signerAddress, this.zap || this.address); } private async depositApproveEstimateGas(amounts: (number | string)[]): Promise { - return await ensureAllowanceEstimateGas(this.underlyingCoinAddresses, amounts, this.zap || this.address); + return await ensureAllowanceEstimateGas.call(this.curve, this.underlyingCoinAddresses, amounts, this.zap || this.address); } public async depositApprove(amounts: (number | string)[], isMax = true): Promise { - return await ensureAllowance(this.underlyingCoinAddresses, amounts, this.zap || this.address, isMax); + return await ensureAllowance.call(this.curve, this.underlyingCoinAddresses, amounts, this.zap || this.address, isMax); } // OVERRIDE @@ -458,7 +459,7 @@ export class PoolTemplate extends CorePool { throw Error(`depositWrappedIsApproved method doesn't exist for pool ${this.name} (id: ${this.name})`); } - return await hasAllowance(this.wrappedCoinAddresses, amounts, curve.signerAddress, this.address); + return await hasAllowance.call(this.curve, this.wrappedCoinAddresses, amounts, this.curve.signerAddress, this.address); } private async depositWrappedApproveEstimateGas(amounts: (number | string)[]): Promise { @@ -466,7 +467,7 @@ export class PoolTemplate extends CorePool { throw Error(`depositWrappedApprove method doesn't exist for pool ${this.name} (id: ${this.name})`); } - return await ensureAllowanceEstimateGas(this.wrappedCoinAddresses, amounts, this.address); + return await ensureAllowanceEstimateGas.call(this.curve, this.wrappedCoinAddresses, amounts, this.address); } public async depositWrappedApprove(amounts: (number | string)[]): Promise { @@ -474,7 +475,7 @@ export class PoolTemplate extends CorePool { throw Error(`depositWrappedApprove method doesn't exist for pool ${this.name} (id: ${this.name})`); } - return await ensureAllowance(this.wrappedCoinAddresses, amounts, this.address); + return await ensureAllowance.call(this.curve, this.wrappedCoinAddresses, amounts, this.address); } // OVERRIDE @@ -490,63 +491,63 @@ export class PoolTemplate extends CorePool { // ---------------- STAKING ---------------- public async stakeIsApproved(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`stakeIsApproved method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - return await hasAllowance([this.lpToken], [lpTokenAmount], curve.signerAddress, this.gauge.address); + return await hasAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.curve.signerAddress, this.gauge.address); } private async stakeApproveEstimateGas(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`stakeApproveEstimateGas method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - return await ensureAllowanceEstimateGas([this.lpToken], [lpTokenAmount], this.gauge.address); + return await ensureAllowanceEstimateGas.call(this.curve, [this.lpToken], [lpTokenAmount], this.gauge.address); } public async stakeApprove(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`stakeApprove method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - return await ensureAllowance([this.lpToken], [lpTokenAmount], this.gauge.address); + return await ensureAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.gauge.address); } private async stakeEstimateGas(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`stakeEstimateGas method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } const _lpTokenAmount = parseUnits(lpTokenAmount); - return smartNumber(await curve.contracts[this.gauge.address].contract.deposit.estimateGas(_lpTokenAmount, curve.constantOptions)); + return smartNumber(await this.curve.contracts[this.gauge.address].contract.deposit.estimateGas(_lpTokenAmount, this.curve.constantOptions)); } public async stake(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`stake method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } const _lpTokenAmount = parseUnits(lpTokenAmount); - await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.gauge.address) + await _ensureAllowance.call(this.curve, [this.lpToken], [_lpTokenAmount], this.gauge.address) - await curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await curve.contracts[this.gauge.address].contract.deposit.estimateGas(_lpTokenAmount, curve.constantOptions))); - return (await curve.contracts[this.gauge.address].contract.deposit(_lpTokenAmount, { ...curve.options, gasLimit })).hash; + await this.curve.updateFeeData(); + const gasLimit = mulBy1_3(DIGas(await this.curve.contracts[this.gauge.address].contract.deposit.estimateGas(_lpTokenAmount, this.curve.constantOptions))); + return (await this.curve.contracts[this.gauge.address].contract.deposit(_lpTokenAmount, { ...this.curve.options, gasLimit })).hash; } private async unstakeEstimateGas(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`unstakeEstimateGas method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } const _lpTokenAmount = parseUnits(lpTokenAmount); - return smartNumber(await curve.contracts[this.gauge.address].contract.withdraw.estimateGas(_lpTokenAmount, curve.constantOptions)); + return smartNumber(await this.curve.contracts[this.gauge.address].contract.withdraw.estimateGas(_lpTokenAmount, this.curve.constantOptions)); } public async unstake(lpTokenAmount: number | string): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`unstake method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } const _lpTokenAmount = parseUnits(lpTokenAmount); - await curve.updateFeeData(); - const gasLimit = DIGas((await curve.contracts[this.gauge.address].contract.withdraw.estimateGas(_lpTokenAmount, curve.constantOptions))) * curve.parseUnits("200", 0) / curve.parseUnits("100", 0); - return (await curve.contracts[this.gauge.address].contract.withdraw(_lpTokenAmount, { ...curve.options, gasLimit })).hash; + await this.curve.updateFeeData(); + const gasLimit = DIGas((await this.curve.contracts[this.gauge.address].contract.withdraw.estimateGas(_lpTokenAmount, this.curve.constantOptions))) * this.curve.parseUnits("200", 0) / this.curve.parseUnits("100", 0); + return (await this.curve.contracts[this.gauge.address].contract.withdraw(_lpTokenAmount, { ...this.curve.options, gasLimit })).hash; } // ---------------- CRV PROFIT, CLAIM, BOOSTING ---------------- @@ -554,30 +555,30 @@ export class PoolTemplate extends CorePool { public crvProfit = async (address = ""): Promise => { if (this.rewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use rewardsProfit instead`); - address = address || curve.signerAddress; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); let inflationRateBN, workingSupplyBN, workingBalanceBN; - if (curve.chainId !== 1) { - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; - const crvContract = curve.contracts[curve.constants.ALIASES.crv].contract; + if (this.curve.chainId !== 1) { + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; + const crvContract = this.curve.contracts[this.curve.constants.ALIASES.crv].contract; const currentWeek = Math.floor(Date.now() / 1000 / PERIODS.WEEK); - [inflationRateBN, workingBalanceBN, workingSupplyBN] = (await curve.multicallProvider.all([ + [inflationRateBN, workingBalanceBN, workingSupplyBN] = (await this.curve.multicallProvider.all([ gaugeContract.inflation_rate(currentWeek), gaugeContract.working_balances(address), gaugeContract.working_supply(), ]) as bigint[]).map((value) => toBN(value)); if (inflationRateBN.eq(0)) { - inflationRateBN = toBN(await crvContract.balanceOf(this.gauge.address, curve.constantOptions)).div(PERIODS.WEEK); + inflationRateBN = toBN(await crvContract.balanceOf(this.gauge.address, this.curve.constantOptions)).div(PERIODS.WEEK); } } else { - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; - const gaugeControllerContract = curve.contracts[curve.constants.ALIASES.gauge_controller].multicallContract; + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; + const gaugeControllerContract = this.curve.contracts[this.curve.constants.ALIASES.gauge_controller].multicallContract; let weightBN; - [inflationRateBN, weightBN, workingBalanceBN, workingSupplyBN] = (await curve.multicallProvider.all([ + [inflationRateBN, weightBN, workingBalanceBN, workingSupplyBN] = (await this.curve.multicallProvider.all([ gaugeContract.inflation_rate(), gaugeControllerContract.gauge_relative_weight(this.gauge.address), gaugeContract.working_balances(address), @@ -586,14 +587,14 @@ export class PoolTemplate extends CorePool { inflationRateBN = inflationRateBN.times(weightBN); } - const crvPrice = await _getUsdRate('CRV'); + const crvPrice = await _getUsdRate.call(this.curve, 'CRV'); if (workingSupplyBN.eq(0)) return { day: "0.0", week: "0.0", month: "0.0", year: "0.0", - token: curve.constants.ALIASES.crv, + token: this.curve.constants.ALIASES.crv, symbol: 'CRV', price: crvPrice, }; @@ -608,7 +609,7 @@ export class PoolTemplate extends CorePool { week: weeklyIncome.toString(), month: monthlyIncome.toString(), year: annualIncome.toString(), - token: curve.constants.ALIASES.crv, + token: this.curve.constants.ALIASES.crv, symbol: 'CRV', price: crvPrice, }; @@ -617,10 +618,10 @@ export class PoolTemplate extends CorePool { public async claimableCrv (address = ""): Promise { if (this.rewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use claimableRewards instead`); - address = address || curve.signerAddress; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); - return curve.formatUnits(await curve.contracts[this.gauge.address].contract.claimable_tokens(address, curve.constantOptions)); + return this.curve.formatUnits(await this.curve.contracts[this.gauge.address].contract.claimable_tokens(address, this.curve.constantOptions)); } public async claimCrvEstimateGas(): Promise { @@ -629,9 +630,9 @@ export class PoolTemplate extends CorePool { let isOldFactory = false; let contract; - if (curve.chainId !== 1) { - if (curve.constants.ALIASES.child_gauge_factory_old && curve.constants.ALIASES.child_gauge_factory_old !== curve.constants.ZERO_ADDRESS) { - const oldFactoryContract = curve.contracts[curve.constants.ALIASES.child_gauge_factory_old].contract; + if (this.curve.chainId !== 1) { + if (this.curve.constants.ALIASES.child_gauge_factory_old && this.curve.constants.ALIASES.child_gauge_factory_old !== this.curve.constants.ZERO_ADDRESS) { + const oldFactoryContract = this.curve.contracts[this.curve.constants.ALIASES.child_gauge_factory_old].contract; const gaugeAddress = await oldFactoryContract.get_gauge_from_lp_token(this.lpToken); isOldFactory = gaugeAddress.toLowerCase() === this.gauge.address.toLowerCase(); @@ -643,19 +644,19 @@ export class PoolTemplate extends CorePool { } if (!isOldFactory) { - contract = curve.chainId === 1 ? - curve.contracts[curve.constants.ALIASES.minter].contract : - curve.contracts[curve.constants.ALIASES.child_gauge_factory].contract; + contract = this.curve.chainId === 1 ? + this.curve.contracts[this.curve.constants.ALIASES.minter].contract : + this.curve.contracts[this.curve.constants.ALIASES.child_gauge_factory].contract; } if (!contract) { throw new Error("Failed to find the correct contract for estimating gas"); } - if (curve.chainId === 1) { - return Number(await contract.mint.estimateGas(this.gauge.address, curve.constantOptions)); + if (this.curve.chainId === 1) { + return Number(await contract.mint.estimateGas(this.gauge.address, this.curve.constantOptions)); } else { - return smartNumber(await contract.mint.estimateGas(this.gauge.address, curve.constantOptions)); + return smartNumber(await contract.mint.estimateGas(this.gauge.address, this.curve.constantOptions)); } } @@ -666,9 +667,9 @@ export class PoolTemplate extends CorePool { let isOldFactory = false; let contract; - if (curve.chainId !== 1) { - if (curve.constants.ALIASES.child_gauge_factory_old && curve.constants.ALIASES.child_gauge_factory_old !== curve.constants.ZERO_ADDRESS) { - const oldFactoryContract = curve.contracts[curve.constants.ALIASES.child_gauge_factory_old].contract; + if (this.curve.chainId !== 1) { + if (this.curve.constants.ALIASES.child_gauge_factory_old && this.curve.constants.ALIASES.child_gauge_factory_old !== this.curve.constants.ZERO_ADDRESS) { + const oldFactoryContract = this.curve.contracts[this.curve.constants.ALIASES.child_gauge_factory_old].contract; const gaugeAddress = await oldFactoryContract.get_gauge_from_lp_token(this.lpToken); isOldFactory = gaugeAddress.toLowerCase() === this.gauge.address.toLowerCase(); @@ -680,29 +681,29 @@ export class PoolTemplate extends CorePool { } if (!isOldFactory) { - contract = curve.chainId === 1 ? - curve.contracts[curve.constants.ALIASES.minter].contract : - curve.contracts[curve.constants.ALIASES.child_gauge_factory].contract; + contract = this.curve.chainId === 1 ? + this.curve.contracts[this.curve.constants.ALIASES.minter].contract : + this.curve.contracts[this.curve.constants.ALIASES.child_gauge_factory].contract; } if (!contract) { throw new Error("Failed to find the correct contract for minting"); } - await curve.updateFeeData(); + await this.curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await contract.mint.estimateGas(this.gauge.address, curve.constantOptions))); - return (await contract.mint(this.gauge.address, { ...curve.options, gasLimit })).hash; + const gasLimit = mulBy1_3(DIGas(await contract.mint.estimateGas(this.gauge.address, this.curve.constantOptions))); + return (await contract.mint(this.gauge.address, { ...this.curve.options, gasLimit })).hash; } public userBoost = async (address = ""): Promise => { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); if (this.rewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use stats.rewardsApy instead`); - address = _getAddress(address) + address = _getAddress.call(this.curve, address) - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; - const [workingBalanceBN, balanceBN] = (await curve.multicallProvider.all([ + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; + const [workingBalanceBN, balanceBN] = (await this.curve.multicallProvider.all([ gaugeContract.working_balances(address), gaugeContract.balanceOf(address), ]) as bigint[]).map((value: bigint) => toBN(value)); @@ -716,8 +717,8 @@ export class PoolTemplate extends CorePool { private _userFutureBoostAndWorkingSupply = async (address: string): Promise<[BigNumber, BigNumber]> => { // Calc future working balance - const veContractMulticall = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; - const gaugeContractMulticall = curve.contracts[this.gauge.address].multicallContract; + const veContractMulticall = this.curve.contracts[this.curve.constants.ALIASES.voting_escrow].multicallContract; + const gaugeContractMulticall = this.curve.contracts[this.gauge.address].multicallContract; const calls = [ veContractMulticall.balanceOf(address), veContractMulticall.totalSupply(), @@ -727,7 +728,7 @@ export class PoolTemplate extends CorePool { gaugeContractMulticall.working_supply(), ]; - const [_votingBalance, _votingTotal, _gaugeBalance, _gaugeTotal, _workingBalance, _workingSupply]: bigint[] = await curve.multicallProvider.all(calls); + const [_votingBalance, _votingTotal, _gaugeBalance, _gaugeTotal, _workingBalance, _workingSupply]: bigint[] = await this.curve.multicallProvider.all(calls); let _futureWorkingBalance = _gaugeBalance * BigInt(40) / BigInt(100); if (_votingTotal > BigInt(0)) { @@ -746,7 +747,7 @@ export class PoolTemplate extends CorePool { public userFutureBoost = async (address = ""): Promise => { if (this.rewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use stats.rewardsApy instead`); - address = _getAddress(address) + address = _getAddress.call(this.curve, address) const [boostBN] = await this._userFutureBoostAndWorkingSupply(address); if (boostBN.lt(1)) return '1.0'; if (boostBN.gt(2.5)) return '2.5'; @@ -756,7 +757,7 @@ export class PoolTemplate extends CorePool { public userCrvApy = async (address = ""): Promise => { if (this.rewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use stats.rewardsApy instead`); - address = _getAddress(address) + address = _getAddress.call(this.curve, address) const [minApy, maxApy] = await this.stats.tokenApy(); const boost = await this.userBoost(address); @@ -768,7 +769,7 @@ export class PoolTemplate extends CorePool { public userFutureCrvApy = async (address = ""): Promise => { if (this.rewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use stats.rewardsApy instead`); - address = _getAddress(address) + address = _getAddress.call(this.curve, address) const [boostBN, futureWorkingSupplyBN] = await this._userFutureBoostAndWorkingSupply(address); const [minApy, maxApy] = await this._calcTokenApy(futureWorkingSupplyBN); @@ -779,21 +780,21 @@ export class PoolTemplate extends CorePool { } public maxBoostedStake = async (...addresses: string[]): Promise | string> => { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); if (addresses.length == 1 && Array.isArray(addresses[0])) addresses = addresses[0]; - if (addresses.length === 0 && curve.signerAddress !== '') addresses = [curve.signerAddress]; + if (addresses.length === 0 && this.curve.signerAddress !== '') addresses = [this.curve.signerAddress]; if (addresses.length === 0) throw Error("Need to connect wallet or pass addresses into args"); - const votingEscrowContract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; + const votingEscrowContract = this.curve.contracts[this.curve.constants.ALIASES.voting_escrow].multicallContract; + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; const contractCalls = [votingEscrowContract.totalSupply(), gaugeContract.totalSupply()]; addresses.forEach((account: string) => { contractCalls.push(votingEscrowContract.balanceOf(account)); }); - const _response: bigint[] = await curve.multicallProvider.all(contractCalls); + const _response: bigint[] = await this.curve.multicallProvider.all(contractCalls); const responseBN: BigNumber[] = _response.map((value: bigint) => toBN(value)); const [veTotalSupplyBN, gaugeTotalSupplyBN] = responseBN.splice(0, 2); @@ -814,13 +815,14 @@ export class PoolTemplate extends CorePool { // ---------------- REWARDS PROFIT, CLAIM ---------------- public rewardTokens = memoize(async (useApi = true): Promise<{token: string, symbol: string, decimals: number}[]> => { + const curve = this.curve; if (this.gauge.address === curve.constants.ZERO_ADDRESS) return [] if (useApi) { - const rewards = await _getRewardsFromApi(); + const rewards = await _getRewardsFromApi.call(curve); if (!rewards[this.gauge.address]) return []; // Don't reset ABI if its already set, we might override an LP token ABI - rewards[this.gauge.address].forEach((r) => !curve.contracts[r.tokenAddress] && _setContracts(r.tokenAddress, ERC20Abi)); + rewards[this.gauge.address].forEach((r) => !curve.contracts[r.tokenAddress] && _setContracts.call(curve, r.tokenAddress, ERC20Abi)); return rewards[this.gauge.address].map((r) => ({ token: r.tokenAddress, symbol: r.symbol, decimals: Number(r.decimals) })); } @@ -844,7 +846,7 @@ export class PoolTemplate extends CorePool { const tokenInfoCalls = []; for (const token of tokens) { // Don't reset ABI if its already set, we might override an LP token ABI - const { multicallContract } = curve.contracts[token] || _setContracts(token, ERC20Abi) + const { multicallContract } = curve.contracts[token] || _setContracts.call(curve, token, ERC20Abi) tokenInfoCalls.push(multicallContract.symbol(), multicallContract.decimals()); } const tokenInfo = await curve.multicallProvider.all(tokenInfoCalls); @@ -857,7 +859,7 @@ export class PoolTemplate extends CorePool { const rewardContract = curve.contracts[this.sRewardContract as string].contract; const method = "snx()" in rewardContract ? "snx" : "rewardsToken" // susd, tbtc : dusd, musd, rsv, sbtc const token = (await rewardContract[method](curve.constantOptions) as string).toLowerCase(); - _setContracts(token, ERC20Abi); + _setContracts.call(curve, token, ERC20Abi); const tokenMulticallContract = curve.contracts[token].multicallContract; const res = await curve.multicallProvider.all([ tokenMulticallContract.symbol(), @@ -877,29 +879,29 @@ export class PoolTemplate extends CorePool { }); public rewardsProfit = async (address = ""): Promise => { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); - address = address || curve.signerAddress; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); const rewardTokens = await this.rewardTokens(); - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; const result = []; - if ('reward_data(address)' in curve.contracts[this.gauge.address].contract) { + if ('reward_data(address)' in this.curve.contracts[this.gauge.address].contract) { const calls = [gaugeContract.balanceOf(address), gaugeContract.totalSupply()]; for (const rewardToken of rewardTokens) { calls.push(gaugeContract.reward_data(rewardToken.token)); } - const res = await curve.multicallProvider.all(calls); + const res = await this.curve.multicallProvider.all(calls); const balanceBN = toBN(res.shift() as bigint); const totalSupplyBN = toBN(res.shift() as bigint); for (const rewardToken of rewardTokens) { const _rewardData = res.shift() as { period_finish: bigint, rate: bigint }; - const periodFinish = Number(curve.formatUnits(_rewardData.period_finish, 0)) * 1000; + const periodFinish = Number(this.curve.formatUnits(_rewardData.period_finish, 0)) * 1000; const inflationRateBN = periodFinish > Date.now() ? toBN(_rewardData.rate, rewardToken.decimals) : BN(0); - const tokenPrice = await _getUsdRate(rewardToken.token); + const tokenPrice = await _getUsdRate.call(this.curve, rewardToken.token); result.push( { @@ -913,10 +915,10 @@ export class PoolTemplate extends CorePool { } ) } - } else if (this.sRewardContract && "rewardRate()" in curve.contracts[this.sRewardContract].contract && "periodFinish()" && rewardTokens.length === 1) { + } else if (this.sRewardContract && "rewardRate()" in this.curve.contracts[this.sRewardContract].contract && "periodFinish()" && rewardTokens.length === 1) { const rewardToken = rewardTokens[0]; - const sRewardContract = curve.contracts[this.sRewardContract].multicallContract; - const [_inflationRate, _periodFinish, _balance, _totalSupply] = await curve.multicallProvider.all([ + const sRewardContract = this.curve.contracts[this.sRewardContract].multicallContract; + const [_inflationRate, _periodFinish, _balance, _totalSupply] = await this.curve.multicallProvider.all([ sRewardContract.rewardRate(), sRewardContract.periodFinish(), gaugeContract.balanceOf(address), @@ -927,7 +929,7 @@ export class PoolTemplate extends CorePool { const inflationRateBN = periodFinish > Date.now() ? toBN(_inflationRate, rewardToken.decimals) : BN(0); const balanceBN = toBN(_balance); const totalSupplyBN = toBN(_totalSupply); - const tokenPrice = await _getUsdRate(rewardToken.token); + const tokenPrice = await _getUsdRate.call(this.curve, rewardToken.token); result.push( { @@ -942,7 +944,7 @@ export class PoolTemplate extends CorePool { ) } else if (['aave', 'saave', 'ankreth'].includes(this.id)) { for (const rewardToken of rewardTokens) { - const tokenPrice = await _getUsdRate(rewardToken.token); + const tokenPrice = await _getUsdRate.call(this.curve, rewardToken.token); result.push( { day: "0", @@ -962,32 +964,32 @@ export class PoolTemplate extends CorePool { // TODO 1. Fix aave and saave error public async claimableRewards(address = ""): Promise<{token: string, symbol: string, amount: string}[]> { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`claimableRewards method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - address = address || curve.signerAddress; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; const rewardTokens = await this.rewardTokens(); const rewards = []; if ('claimable_reward(address,address)' in gaugeContract) { for (const rewardToken of rewardTokens) { - const _amount = await gaugeContract.claimable_reward(address, rewardToken.token, curve.constantOptions); + const _amount = await gaugeContract.claimable_reward(address, rewardToken.token, this.curve.constantOptions); rewards.push({ token: rewardToken.token, symbol: rewardToken.symbol, - amount: curve.formatUnits(_amount, rewardToken.decimals), + amount: this.curve.formatUnits(_amount, rewardToken.decimals), }); } } else if ('claimable_reward(address)' in gaugeContract && rewardTokens.length > 0) { // Synthetix Gauge const rewardToken = rewardTokens[0]; - const _totalAmount = await gaugeContract.claimable_reward(address, curve.constantOptions); - const _claimedAmount = await gaugeContract.claimed_rewards_for(address, curve.constantOptions); + const _totalAmount = await gaugeContract.claimable_reward(address, this.curve.constantOptions); + const _claimedAmount = await gaugeContract.claimed_rewards_for(address, this.curve.constantOptions); rewards.push({ token: rewardToken.token, symbol: rewardToken.symbol, - amount: curve.formatUnits(_totalAmount.sub(_claimedAmount), rewardToken.decimals), + amount: this.curve.formatUnits(_totalAmount.sub(_claimedAmount), rewardToken.decimals), }) } @@ -995,32 +997,32 @@ export class PoolTemplate extends CorePool { } public async claimRewardsEstimateGas(): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`claimRewards method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if (!("claim_rewards()" in gaugeContract)) throw Error (`${this.name} pool doesn't have such method`); - return smartNumber(await gaugeContract.claim_rewards.estimateGas(curve.constantOptions)); + return smartNumber(await gaugeContract.claim_rewards.estimateGas(this.curve.constantOptions)); } public async claimRewards(): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`claimRewards method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if (!("claim_rewards()" in gaugeContract)) throw Error (`${this.name} pool doesn't have such method`); - await curve.updateFeeData(); + await this.curve.updateFeeData(); - const gasLimit = mulBy1_3(DIGas(await gaugeContract.claim_rewards.estimateGas(curve.constantOptions))); - return (await gaugeContract.claim_rewards({ ...curve.options, gasLimit })).hash; + const gasLimit = mulBy1_3(DIGas(await gaugeContract.claim_rewards.estimateGas(this.curve.constantOptions))); + return (await gaugeContract.claim_rewards({ ...this.curve.options, gasLimit })).hash; } // ---------------- DEPOSIT & STAKE ---------------- public async depositAndStakeExpected(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeExpected method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } @@ -1028,7 +1030,7 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeBonus(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeBonus method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } @@ -1036,14 +1038,14 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeIsApproved(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeIsApproved method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - const coinsAllowance: boolean = await hasAllowance(this.underlyingCoinAddresses, amounts, curve.signerAddress, curve.constants.ALIASES.deposit_and_stake); + const coinsAllowance: boolean = await hasAllowance.call(this.curve, this.underlyingCoinAddresses, amounts, this.curve.signerAddress, this.curve.constants.ALIASES.deposit_and_stake); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if ('approved_to_deposit' in gaugeContract) { - const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(curve.constants.ALIASES.deposit_and_stake, curve.signerAddress, curve.constantOptions); + const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(this.curve.constants.ALIASES.deposit_and_stake, this.curve.signerAddress, this.curve.constantOptions); return coinsAllowance && gaugeAllowance } @@ -1051,16 +1053,16 @@ export class PoolTemplate extends CorePool { } private async depositAndStakeApproveEstimateGas(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeApprove method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - const approveCoinsGas: number | number[] = await ensureAllowanceEstimateGas(this.underlyingCoinAddresses, amounts, curve.constants.ALIASES.deposit_and_stake); + const approveCoinsGas: number | number[] = await ensureAllowanceEstimateGas.call(this.curve, this.underlyingCoinAddresses, amounts, this.curve.constants.ALIASES.deposit_and_stake); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if ('approved_to_deposit' in gaugeContract) { - const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(curve.constants.ALIASES.deposit_and_stake, curve.signerAddress, curve.constantOptions); + const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(this.curve.constants.ALIASES.deposit_and_stake, this.curve.signerAddress, this.curve.constantOptions); if (!gaugeAllowance) { - const approveGaugeGas = smartNumber(await gaugeContract.set_approve_deposit.estimateGas(curve.constants.ALIASES.deposit_and_stake, true, curve.constantOptions)); + const approveGaugeGas = smartNumber(await gaugeContract.set_approve_deposit.estimateGas(this.curve.constants.ALIASES.deposit_and_stake, true, this.curve.constantOptions)); if(Array.isArray(approveCoinsGas) && Array.isArray(approveGaugeGas)) { return [approveCoinsGas[0] + approveGaugeGas[0], approveCoinsGas[1] + approveGaugeGas[1]]; } @@ -1074,17 +1076,17 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeApprove(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeApprove method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } - const approveCoinsTx: string[] = await ensureAllowance(this.underlyingCoinAddresses, amounts, curve.constants.ALIASES.deposit_and_stake); + const approveCoinsTx: string[] = await ensureAllowance.call(this.curve, this.underlyingCoinAddresses, amounts, this.curve.constants.ALIASES.deposit_and_stake); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if ('approved_to_deposit' in gaugeContract) { - const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(curve.constants.ALIASES.deposit_and_stake, curve.signerAddress, curve.constantOptions); + const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(this.curve.constants.ALIASES.deposit_and_stake, this.curve.signerAddress, this.curve.constantOptions); if (!gaugeAllowance) { - const gasLimit = mulBy1_3(await gaugeContract.set_approve_deposit.estimateGas(curve.constants.ALIASES.deposit_and_stake, true, curve.constantOptions)); - const approveGaugeTx: string = (await gaugeContract.set_approve_deposit(curve.constants.ALIASES.deposit_and_stake, true, { ...curve.options, gasLimit })).hash; + const gasLimit = mulBy1_3(await gaugeContract.set_approve_deposit.estimateGas(this.curve.constants.ALIASES.deposit_and_stake, true, this.curve.constantOptions)); + const approveGaugeTx: string = (await gaugeContract.set_approve_deposit(this.curve.constants.ALIASES.deposit_and_stake, true, { ...this.curve.options, gasLimit })).hash; return [...approveCoinsTx, approveGaugeTx]; } } @@ -1093,7 +1095,7 @@ export class PoolTemplate extends CorePool { } private async depositAndStakeEstimateGas(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStake method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } @@ -1101,7 +1103,7 @@ export class PoolTemplate extends CorePool { } public async depositAndStake(amounts: (number | string)[], slippage = 0.1): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStake method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } @@ -1111,7 +1113,7 @@ export class PoolTemplate extends CorePool { // ---------------- DEPOSIT & STAKE WRAPPED ---------------- public async depositAndStakeWrappedExpected(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrappedExpected method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrappedExpected method doesn't exist for pool ${this.name} (id: ${this.name})`); @@ -1120,7 +1122,7 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeWrappedBonus(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrappedBonus method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrappedBonus method doesn't exist for pool ${this.name} (id: ${this.name})`); @@ -1129,16 +1131,16 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeWrappedIsApproved(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrappedIsApproved method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrappedIsApproved method doesn't exist for pool ${this.name} (id: ${this.name})`); - const coinsAllowance: boolean = await hasAllowance(this.wrappedCoinAddresses, amounts, curve.signerAddress, curve.constants.ALIASES.deposit_and_stake); + const coinsAllowance: boolean = await hasAllowance.call(this.curve, this.wrappedCoinAddresses, amounts, this.curve.signerAddress, this.curve.constants.ALIASES.deposit_and_stake); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if ('approved_to_deposit' in gaugeContract) { - const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(curve.constants.ALIASES.deposit_and_stake, curve.signerAddress, curve.constantOptions); + const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(this.curve.constants.ALIASES.deposit_and_stake, this.curve.signerAddress, this.curve.constantOptions); return coinsAllowance && gaugeAllowance; } @@ -1146,18 +1148,18 @@ export class PoolTemplate extends CorePool { } private async depositAndStakeWrappedApproveEstimateGas(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrappedApprove method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrappedApprove method doesn't exist for pool ${this.name} (id: ${this.name})`); - const approveCoinsGas: number | number[] = await ensureAllowanceEstimateGas(this.wrappedCoinAddresses, amounts, curve.constants.ALIASES.deposit_and_stake); + const approveCoinsGas: number | number[] = await ensureAllowanceEstimateGas.call(this.curve, this.wrappedCoinAddresses, amounts, this.curve.constants.ALIASES.deposit_and_stake); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if ('approved_to_deposit' in gaugeContract) { - const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(curve.constants.ALIASES.deposit_and_stake, curve.signerAddress, curve.constantOptions); + const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(this.curve.constants.ALIASES.deposit_and_stake, this.curve.signerAddress, this.curve.constantOptions); if (!gaugeAllowance) { - const approveGaugeGas = Number(await gaugeContract.set_approve_deposit.estimateGas(curve.constants.ALIASES.deposit_and_stake, true, curve.constantOptions)); + const approveGaugeGas = Number(await gaugeContract.set_approve_deposit.estimateGas(this.curve.constants.ALIASES.deposit_and_stake, true, this.curve.constantOptions)); if(Array.isArray(approveCoinsGas) && Array.isArray(approveGaugeGas)) { return [approveCoinsGas[0] + approveGaugeGas[0], approveCoinsGas[1] + approveGaugeGas[1]]; } @@ -1171,19 +1173,19 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeWrappedApprove(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrappedApprove method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrappedApprove method doesn't exist for pool ${this.name} (id: ${this.name})`); - const approveCoinsTx: string[] = await ensureAllowance(this.wrappedCoinAddresses, amounts, curve.constants.ALIASES.deposit_and_stake); + const approveCoinsTx: string[] = await ensureAllowance.call(this.curve, this.wrappedCoinAddresses, amounts, this.curve.constants.ALIASES.deposit_and_stake); - const gaugeContract = curve.contracts[this.gauge.address].contract; + const gaugeContract = this.curve.contracts[this.gauge.address].contract; if ('approved_to_deposit' in gaugeContract) { - const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(curve.constants.ALIASES.deposit_and_stake, curve.signerAddress, curve.constantOptions); + const gaugeAllowance: boolean = await gaugeContract.approved_to_deposit(this.curve.constants.ALIASES.deposit_and_stake, this.curve.signerAddress, this.curve.constantOptions); if (!gaugeAllowance) { - const gasLimit = mulBy1_3(await gaugeContract.set_approve_deposit.estimateGas(curve.constants.ALIASES.deposit_and_stake, true, curve.constantOptions)); - const approveGaugeTx: string = (await gaugeContract.set_approve_deposit(curve.constants.ALIASES.deposit_and_stake, true, { ...curve.options, gasLimit })).hash; + const gasLimit = mulBy1_3(await gaugeContract.set_approve_deposit.estimateGas(this.curve.constants.ALIASES.deposit_and_stake, true, this.curve.constantOptions)); + const approveGaugeTx: string = (await gaugeContract.set_approve_deposit(this.curve.constants.ALIASES.deposit_and_stake, true, { ...this.curve.options, gasLimit })).hash; return [...approveCoinsTx, approveGaugeTx]; } } @@ -1192,7 +1194,7 @@ export class PoolTemplate extends CorePool { } private async depositAndStakeWrappedEstimateGas(amounts: (number | string)[]): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrapped method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrapped method doesn't exist for pool ${this.name} (id: ${this.name})`); @@ -1201,7 +1203,7 @@ export class PoolTemplate extends CorePool { } public async depositAndStakeWrapped(amounts: (number | string)[], slippage = 0.1): Promise { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) { throw Error(`depositAndStakeWrapped method doesn't exist for pool ${this.name} (id: ${this.name}). There is no gauge`); } if (this.isPlain || this.isFake) throw Error(`depositAndStakeWrapped method doesn't exist for pool ${this.name} (id: ${this.name})`); @@ -1241,52 +1243,47 @@ export class PoolTemplate extends CorePool { const _amounts: bigint[] = amounts.map((amount, i) => parseUnits(amount, decimals[i])); - const contract = curve.contracts[curve.constants.ALIASES.deposit_and_stake].contract; + const contract = this.curve.contracts[this.curve.constants.ALIASES.deposit_and_stake].contract; const useUnderlying = isUnderlying && (this.isLending || (this.isCrypto && !this.isPlain)) && (!this.zap || this.id == 'avaxcrypto'); - const useDynarray = (!this.isCrypto && this.isNg && this.isPlain) || (isUnderlying && this.isMeta && (new PoolTemplate(this.basePool)).isNg); + const useDynarray = (!this.isCrypto && this.isNg && this.isPlain) || (isUnderlying && this.isMeta && (new PoolTemplate(this.basePool, this.curve)).isNg); const _expectedLpTokenAmount = isUnderlying ? - curve.parseUnits(await this.depositAndStakeExpected(amounts)) : - curve.parseUnits(await this.depositAndStakeWrappedExpected(amounts)); + this.curve.parseUnits(await this.depositAndStakeExpected(amounts)) : + this.curve.parseUnits(await this.depositAndStakeWrappedExpected(amounts)); const minAmountBN = toBN(_expectedLpTokenAmount).times(100 - slippage).div(100); const _minMintAmount = fromBN(minAmountBN); const ethIndex = getEthIndex(coinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - - let _gas = BigInt(0) - if (OLD_CHAINS.includes(curve.chainId)) { - _gas = (await contract.deposit_and_stake.estimateGas( - depositAddress, - this.lpToken, - this.gauge.address, - coins.length, - coinAddresses, - _amounts, - _minMintAmount, - useUnderlying, // <--- DIFFERENCE - useDynarray, - this.isMetaFactory && isUnderlying ? this.address : curve.constants.ZERO_ADDRESS, - {...curve.constantOptions, value} - )) - } else { - _gas = (await contract.deposit_and_stake.estimateGas( - depositAddress, - this.lpToken, - this.gauge.address, - coins.length, - coinAddresses, - _amounts, - _minMintAmount, - useDynarray, - this.isMetaFactory && isUnderlying ? this.address : curve.constants.ZERO_ADDRESS, - {...curve.constantOptions, value} - )) - } + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + + const _gas = OLD_CHAINS.includes(this.curve.chainId) ? (await contract.deposit_and_stake.estimateGas( + depositAddress, + this.lpToken, + this.gauge.address, + coins.length, + coinAddresses, + _amounts, + _minMintAmount, + useUnderlying, // <--- DIFFERENCE + useDynarray, + this.isMetaFactory && isUnderlying ? this.address : this.curve.constants.ZERO_ADDRESS, + {...this.curve.constantOptions, value} + )) : (await contract.deposit_and_stake.estimateGas( + depositAddress, + this.lpToken, + this.gauge.address, + coins.length, + coinAddresses, + _amounts, + _minMintAmount, + useDynarray, + this.isMetaFactory && isUnderlying ? this.address : this.curve.constants.ZERO_ADDRESS, + {...this.curve.constantOptions, value} + )); if (estimateGas) return smartNumber(_gas) - await curve.updateFeeData(); - const gasLimit = DIGas(_gas) * curve.parseUnits("200", 0) / curve.parseUnits("100", 0); - if (OLD_CHAINS.includes(curve.chainId)) { + await this.curve.updateFeeData(); + const gasLimit = DIGas(_gas) * this.curve.parseUnits("200", 0) / this.curve.parseUnits("100", 0); + if (OLD_CHAINS.includes(this.curve.chainId)) { return (await contract.deposit_and_stake( depositAddress, this.lpToken, @@ -1297,8 +1294,8 @@ export class PoolTemplate extends CorePool { _minMintAmount, useUnderlying, // <--- DIFFERENCE useDynarray, - this.isMetaFactory && isUnderlying ? this.address : curve.constants.ZERO_ADDRESS, - {...curve.options, gasLimit, value} + this.isMetaFactory && isUnderlying ? this.address : this.curve.constants.ZERO_ADDRESS, + {...this.curve.options, gasLimit, value} )).hash } else { return (await contract.deposit_and_stake( @@ -1310,8 +1307,8 @@ export class PoolTemplate extends CorePool { _amounts, _minMintAmount, useDynarray, - this.isMetaFactory && isUnderlying ? this.address : curve.constants.ZERO_ADDRESS, - {...curve.options, gasLimit, value} + this.isMetaFactory && isUnderlying ? this.address : this.curve.constants.ZERO_ADDRESS, + {...this.curve.options, gasLimit, value} )).hash } } @@ -1325,17 +1322,17 @@ export class PoolTemplate extends CorePool { public async withdrawIsApproved(lpTokenAmount: number | string): Promise { if (!this.zap) return true - return await hasAllowance([this.lpToken], [lpTokenAmount], curve.signerAddress, this.zap as string); + return await hasAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.curve.signerAddress, this.zap as string); } private async withdrawApproveEstimateGas(lpTokenAmount: number | string): Promise { if (!this.zap) return 0; - return await ensureAllowanceEstimateGas([this.lpToken], [lpTokenAmount], this.zap as string); + return await ensureAllowanceEstimateGas.call(this.curve, [this.lpToken], [lpTokenAmount], this.zap as string); } public async withdrawApprove(lpTokenAmount: number | string): Promise { if (!this.zap) return []; - return await ensureAllowance([this.lpToken], [lpTokenAmount], this.zap as string); + return await ensureAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.zap as string); } // OVERRIDE @@ -1375,17 +1372,17 @@ export class PoolTemplate extends CorePool { public async withdrawImbalanceBonus(amounts: (number | string)[]): Promise { let pricesBN: BigNumber[] = []; - const multicallContract = curve.contracts[this.address].multicallContract; + const multicallContract = this.curve.contracts[this.address].multicallContract; if(this.isCrypto || this.id === 'wsteth') { - if(curve.isLiteChain) { + if(this.curve.isLiteChain) { const prices = this.id.includes('twocrypto') ? [ 1, - Number(await curve.contracts[this.address].contract.price_oracle()) / (10 ** 18), + Number(await this.curve.contracts[this.address].contract.price_oracle()) / (10 ** 18), ] : [ 1, - ...(await curve.multicallProvider.all([ + ...(await this.curve.multicallProvider.all([ multicallContract.price_oracle(0), multicallContract.price_oracle(1), ])).map((value) => Number(value) / (10 ** 18)), @@ -1412,8 +1409,8 @@ export class PoolTemplate extends CorePool { if (this.zap) { const _amounts: bigint[] = amounts.map((amount, i) => parseUnits(amount, this.underlyingDecimals[i])); - const _maxBurnAmount = (await this._calcLpTokenAmount(_amounts, false)) * curve.parseUnits("101", 0) / curve.parseUnits("100", 0); - return await hasAllowance([this.lpToken], [curve.formatUnits(_maxBurnAmount, 18)], curve.signerAddress, this.zap as string); + const _maxBurnAmount = (await this._calcLpTokenAmount(_amounts, false)) * this.curve.parseUnits("101", 0) / this.curve.parseUnits("100", 0); + return await hasAllowance.call(this.curve, [this.lpToken], [this.curve.formatUnits(_maxBurnAmount, 18)], this.curve.signerAddress, this.zap as string); } return true; @@ -1424,8 +1421,8 @@ export class PoolTemplate extends CorePool { if (this.zap) { const _amounts: bigint[] = amounts.map((amount, i) => parseUnits(amount, this.underlyingDecimals[i])); - const _maxBurnAmount = (await this._calcLpTokenAmount(_amounts, false)) * curve.parseUnits("101", 0) / curve.parseUnits("100", 0); - return await ensureAllowanceEstimateGas([this.lpToken], [curve.formatUnits(_maxBurnAmount, 18)], this.zap as string); + const _maxBurnAmount = (await this._calcLpTokenAmount(_amounts, false)) * this.curve.parseUnits("101", 0) / this.curve.parseUnits("100", 0); + return await ensureAllowanceEstimateGas.call(this.curve, [this.lpToken], [this.curve.formatUnits(_maxBurnAmount, 18)], this.zap as string); } return 0; @@ -1436,8 +1433,8 @@ export class PoolTemplate extends CorePool { if (this.zap) { const _amounts: bigint[] = amounts.map((amount, i) => parseUnits(amount, this.underlyingDecimals[i])); - const _maxBurnAmount = (await this._calcLpTokenAmount(_amounts, false)) * curve.parseUnits("101", 0) / curve.parseUnits("100", 0); - return await ensureAllowance([this.lpToken], [curve.formatUnits(_maxBurnAmount, 18)], this.zap as string); + const _maxBurnAmount = (await this._calcLpTokenAmount(_amounts, false)) * this.curve.parseUnits("101", 0) / this.curve.parseUnits("100", 0); + return await ensureAllowance.call(this.curve, [this.lpToken], [this.curve.formatUnits(_maxBurnAmount, 18)], this.zap as string); } return []; @@ -1486,7 +1483,7 @@ export class PoolTemplate extends CorePool { // ---------------- WITHDRAW ONE COIN ---------------- // OVERRIDE - private async _withdrawOneCoinExpected(_lpTokenAmount: bigint, i: number): Promise { + async _withdrawOneCoinExpected(_lpTokenAmount: bigint, i: number): Promise { throw Error(`withdrawOneCoinExpected method doesn't exist for pool ${this.name} (id: ${this.name})`); } @@ -1495,23 +1492,23 @@ export class PoolTemplate extends CorePool { const _lpTokenAmount = parseUnits(lpTokenAmount); const _expected = await this._withdrawOneCoinExpected(_lpTokenAmount, i); - return curve.formatUnits(_expected, this.underlyingDecimals[i]); + return this.curve.formatUnits(_expected, this.underlyingDecimals[i]); } public async withdrawOneCoinBonus(lpTokenAmount: number | string, coin: string | number): Promise { let pricesBN: BigNumber[] = []; - const multicallContract = curve.contracts[this.address].multicallContract; + const multicallContract = this.curve.contracts[this.address].multicallContract; if(this.isCrypto || this.id === 'wsteth') { - if(curve.isLiteChain) { + if(this.curve.isLiteChain) { const prices = this.id.includes('twocrypto') ? [ 1, - Number(await curve.contracts[this.address].contract.price_oracle()) / (10 ** 18), + Number(await this.curve.contracts[this.address].contract.price_oracle()) / (10 ** 18), ] : [ 1, - ...(await curve.multicallProvider.all([ + ...(await this.curve.multicallProvider.all([ multicallContract.price_oracle(0), multicallContract.price_oracle(1), ])).map((value) => Number(value) / (10 ** 18)), @@ -1537,17 +1534,17 @@ export class PoolTemplate extends CorePool { public async withdrawOneCoinIsApproved(lpTokenAmount: number | string): Promise { if (!this.zap) return true - return await hasAllowance([this.lpToken], [lpTokenAmount], curve.signerAddress, this.zap as string); + return await hasAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.curve.signerAddress, this.zap as string); } private async withdrawOneCoinApproveEstimateGas(lpTokenAmount: number | string): Promise { if (!this.zap) return 0 - return await ensureAllowanceEstimateGas([this.lpToken], [lpTokenAmount], this.zap as string); + return await ensureAllowanceEstimateGas.call(this.curve, [this.lpToken], [lpTokenAmount], this.zap as string); } public async withdrawOneCoinApprove(lpTokenAmount: number | string): Promise { if (!this.zap) return [] - return await ensureAllowance([this.lpToken], [lpTokenAmount], this.zap as string); + return await ensureAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.zap as string); } // OVERRIDE @@ -1563,7 +1560,7 @@ export class PoolTemplate extends CorePool { // ---------------- WITHDRAW ONE COIN WRAPPED ---------------- // OVERRIDE - private async _withdrawOneCoinWrappedExpected(_lpTokenAmount: bigint, i: number): Promise { + async _withdrawOneCoinWrappedExpected(_lpTokenAmount: bigint, i: number): Promise { throw Error(`withdrawOneCoinWrappedExpected method doesn't exist for pool ${this.name} (id: ${this.name})`); } @@ -1573,7 +1570,7 @@ export class PoolTemplate extends CorePool { const _expected = await this._withdrawOneCoinWrappedExpected(_lpTokenAmount, i); - return curve.formatUnits(_expected, this.wrappedDecimals[i]); + return this.curve.formatUnits(_expected, this.wrappedDecimals[i]); } public async withdrawOneCoinWrappedBonus(lpTokenAmount: number | string, coin: string | number): Promise { @@ -1611,7 +1608,7 @@ export class PoolTemplate extends CorePool { } public async userBalances(address = ""): Promise { - address = address || curve.signerAddress; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); const lpTotalBalanceBN = await this._userLpTotalBalance(address); @@ -1621,7 +1618,7 @@ export class PoolTemplate extends CorePool { } public async userWrappedBalances(address = ""): Promise { - address = address || curve.signerAddress; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); const lpTotalBalanceBN = await this._userLpTotalBalance(address); @@ -1632,7 +1629,7 @@ export class PoolTemplate extends CorePool { public async userLiquidityUSD(address = ""): Promise { const lpBalanceBN = await this._userLpTotalBalance(address); - const lpPrice = await _getUsdRate(this.lpToken); + const lpPrice = await _getUsdRate.call(this.curve, this.lpToken); return lpBalanceBN.times(lpPrice).toFixed(8) } @@ -1660,8 +1657,8 @@ export class PoolTemplate extends CorePool { public async userShare(address = ""): Promise<{ lpUser: string, lpTotal: string, lpShare: string, gaugeUser?: string, gaugeTotal?: string, gaugeShare?: string }> { - const withGauge = this.gauge.address !== curve.constants.ZERO_ADDRESS; - address = address || curve.signerAddress; + const withGauge = this.gauge.address !== this.curve.constants.ZERO_ADDRESS; + address = address || this.curve.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); const userLpBalance = await this.wallet.lpTokenBalances(address) as IDict; @@ -1670,12 +1667,12 @@ export class PoolTemplate extends CorePool { let totalLp, gaugeLp; if (withGauge) { - [totalLp, gaugeLp] = (await curve.multicallProvider.all([ - curve.contracts[this.lpToken].multicallContract.totalSupply(), - curve.contracts[this.gauge.address].multicallContract.totalSupply(), - ]) as bigint[]).map((_supply) => curve.formatUnits(_supply)); + [totalLp, gaugeLp] = (await this.curve.multicallProvider.all([ + this.curve.contracts[this.lpToken].multicallContract.totalSupply(), + this.curve.contracts[this.gauge.address].multicallContract.totalSupply(), + ]) as bigint[]).map((_supply) => this.curve.formatUnits(_supply)); } else { - totalLp = curve.formatUnits(await curve.contracts[this.lpToken].contract.totalSupply(curve.constantOptions)); + totalLp = this.curve.formatUnits(await this.curve.contracts[this.lpToken].contract.totalSupply(this.curve.constantOptions)); } return { @@ -1690,16 +1687,16 @@ export class PoolTemplate extends CorePool { // ---------------- SWAP ---------------- - private async _swapExpected(i: number, j: number, _amount: bigint): Promise { + async _swapExpected(i: number, j: number, _amount: bigint): Promise { const contractAddress = this.isCrypto && this.isMeta ? this.zap as string : this.address; - const contract = curve.contracts[contractAddress].contract; + const contract = this.curve.contracts[contractAddress].contract; if ('get_dy_underlying' in contract) { - return await contract.get_dy_underlying(i, j, _amount, curve.constantOptions) + return await contract.get_dy_underlying(i, j, _amount, this.curve.constantOptions) } else { if ('get_dy(address,uint256,uint256,uint256)' in contract) { // atricrypto3 based metapools - return await contract.get_dy(this.address, i, j, _amount, curve.constantOptions); + return await contract.get_dy(this.address, i, j, _amount, this.curve.constantOptions); } - return await contract.get_dy(i, j, _amount, curve.constantOptions); + return await contract.get_dy(i, j, _amount, this.curve.constantOptions); } } @@ -1709,54 +1706,54 @@ export class PoolTemplate extends CorePool { const _amount = parseUnits(amount, this.underlyingDecimals[i]); const _expected = await this._swapExpected(i, j, _amount); - return curve.formatUnits(_expected, this.underlyingDecimals[j]) + return this.curve.formatUnits(_expected, this.underlyingDecimals[j]) } - private async _swapRequired(i: number, j: number, _amount: bigint, isUnderlying: boolean): Promise { + async _swapRequired(i: number, j: number, _amount: bigint, isUnderlying: boolean): Promise { if(this.isCrypto) { - if (this.isNg) return await curve.contracts[this.address].contract.get_dx(i, j, _amount, curve.constantOptions); + if (this.isNg) return await this.curve.contracts[this.address].contract.get_dx(i, j, _amount, this.curve.constantOptions); - const contract = curve.contracts[curve.constants.ALIASES.crypto_calc].contract; + const contract = this.curve.contracts[this.curve.constants.ALIASES.crypto_calc].contract; if(this.isMeta && isUnderlying) { - const basePool = new PoolTemplate(this.basePool); + const basePool = new PoolTemplate(this.basePool, this.curve); if(this.wrappedCoins.length === 3) { - return await contract.get_dx_tricrypto_meta_underlying(this.address, i, j, _amount, this.wrappedCoins.length, basePool.address, basePool.lpToken, curve.constantOptions) + return await contract.get_dx_tricrypto_meta_underlying(this.address, i, j, _amount, this.wrappedCoins.length, basePool.address, basePool.lpToken, this.curve.constantOptions) } if(basePool.isFake) { - const secondPool = new PoolTemplate(basePool.basePool) - return await contract.get_dx_double_meta_underlying(this.address, i, j, _amount, basePool.address, basePool.zap, secondPool.address, secondPool.lpToken, curve.constantOptions) + const secondPool = new PoolTemplate(basePool.basePool, this.curve) + return await contract.get_dx_double_meta_underlying(this.address, i, j, _amount, basePool.address, basePool.zap, secondPool.address, secondPool.lpToken, this.curve.constantOptions) } - return await contract.get_dx_meta_underlying(this.address, i, j, _amount, this.underlyingCoins.length, basePool.address, basePool.lpToken, curve.constantOptions) + return await contract.get_dx_meta_underlying(this.address, i, j, _amount, this.underlyingCoins.length, basePool.address, basePool.lpToken, this.curve.constantOptions) } else { - return await contract.get_dx(this.address, i, j, _amount, this.wrappedCoins.length, curve.constantOptions) + return await contract.get_dx(this.address, i, j, _amount, this.wrappedCoins.length, this.curve.constantOptions) } } else { if (this.isNg) { - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; if (this.isMeta) { if (isUnderlying) { - return await contract.get_dx_underlying(i, j, _amount, curve.constantOptions); + return await contract.get_dx_underlying(i, j, _amount, this.curve.constantOptions); } else { - return await contract.get_dx(i, j, _amount, curve.constantOptions); + return await contract.get_dx(i, j, _amount, this.curve.constantOptions); } } else { - return await contract.get_dx(i, j, _amount, curve.constantOptions) + return await contract.get_dx(i, j, _amount, this.curve.constantOptions) } } - const contract = curve.contracts[curve.constants.ALIASES.stable_calc].contract; + const contract = this.curve.contracts[this.curve.constants.ALIASES.stable_calc].contract; if(this.isMeta) { - const basePool = new PoolTemplate(this.basePool); + const basePool = new PoolTemplate(this.basePool, this.curve); if(isUnderlying) { - return await contract.get_dx_meta_underlying(this.address, i, j, _amount, this.underlyingCoins.length, basePool.address, basePool.lpToken, curve.constantOptions) + return await contract.get_dx_meta_underlying(this.address, i, j, _amount, this.underlyingCoins.length, basePool.address, basePool.lpToken, this.curve.constantOptions) } else { - return await contract.get_dx_meta(this.address, i, j, _amount, this.wrappedCoins.length, basePool.address, curve.constantOptions) + return await contract.get_dx_meta(this.address, i, j, _amount, this.wrappedCoins.length, basePool.address, this.curve.constantOptions) } } else { if(isUnderlying && this.isLending) { - return await contract.get_dx_underlying(this.address, i, j, _amount, this.underlyingCoins.length, curve.constantOptions) + return await contract.get_dx_underlying(this.address, i, j, _amount, this.underlyingCoins.length, this.curve.constantOptions) } else { - return await contract.get_dx(this.address, i, j, _amount, this.wrappedCoins.length, curve.constantOptions) + return await contract.get_dx(this.address, i, j, _amount, this.wrappedCoins.length, this.curve.constantOptions) } } } @@ -1768,7 +1765,7 @@ export class PoolTemplate extends CorePool { const _amount = parseUnits(amount, this.underlyingDecimals[j]); const _required = await this._swapRequired(i, j, _amount, true); - return curve.formatUnits(_required, this.underlyingDecimals[i]) + return this.curve.formatUnits(_required, this.underlyingDecimals[i]) } // OVERRIDE @@ -1794,26 +1791,26 @@ export class PoolTemplate extends CorePool { return Number(_cutZeros(priceImpactBN.toFixed(4))) } - private _swapContractAddress(): string { - return (this.isCrypto && this.isMeta) || (this.isMetaFactory && (new PoolTemplate(this.basePool).isLending)) ? this.zap as string : this.address; + _swapContractAddress(): string { + return (this.isCrypto && this.isMeta) || (this.isMetaFactory && (new PoolTemplate(this.basePool, this.curve).isLending)) ? this.zap as string : this.address; } public async swapIsApproved(inputCoin: string | number, amount: number | string): Promise { const contractAddress = this._swapContractAddress(); const i = this._getCoinIdx(inputCoin); - return await hasAllowance([this.underlyingCoinAddresses[i]], [amount], curve.signerAddress, contractAddress); + return await hasAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [amount], this.curve.signerAddress, contractAddress); } private async swapApproveEstimateGas (inputCoin: string | number, amount: number | string): Promise { const contractAddress = this._swapContractAddress(); const i = this._getCoinIdx(inputCoin); - return await ensureAllowanceEstimateGas([this.underlyingCoinAddresses[i]], [amount], contractAddress); + return await ensureAllowanceEstimateGas.call(this.curve, [this.underlyingCoinAddresses[i]], [amount], contractAddress); } public async swapApprove(inputCoin: string | number, amount: number | string): Promise { const contractAddress = this._swapContractAddress(); const i = this._getCoinIdx(inputCoin); - return await ensureAllowance([this.underlyingCoinAddresses[i]], [amount], contractAddress); + return await ensureAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [amount], contractAddress); } // OVERRIDE @@ -1828,8 +1825,8 @@ export class PoolTemplate extends CorePool { // ---------------- SWAP WRAPPED ---------------- - private async _swapWrappedExpected(i: number, j: number, _amount: bigint): Promise { - return await curve.contracts[this.address].contract.get_dy(i, j, _amount, curve.constantOptions); + async _swapWrappedExpected(i: number, j: number, _amount: bigint): Promise { + return await this.curve.contracts[this.address].contract.get_dy(i, j, _amount, this.curve.constantOptions); } // OVERRIDE @@ -1887,12 +1884,12 @@ export class PoolTemplate extends CorePool { // ---------------- ... ---------------- public gaugeOptimalDeposits = async (...accounts: string[]): Promise> => { - if (this.gauge.address === curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); + if (this.gauge.address === this.curve.constants.ZERO_ADDRESS) throw Error(`${this.name} doesn't have gauge`); if (accounts.length == 1 && Array.isArray(accounts[0])) accounts = accounts[0]; - const votingEscrowContract = curve.contracts[curve.constants.ALIASES.voting_escrow].multicallContract; - const lpTokenContract = curve.contracts[this.lpToken].multicallContract; - const gaugeContract = curve.contracts[this.gauge.address].multicallContract; + const votingEscrowContract = this.curve.contracts[this.curve.constants.ALIASES.voting_escrow].multicallContract; + const lpTokenContract = this.curve.contracts[this.lpToken].multicallContract; + const gaugeContract = this.curve.contracts[this.gauge.address].multicallContract; const contractCalls = [votingEscrowContract.totalSupply(), gaugeContract.totalSupply()]; accounts.forEach((account: string) => { contractCalls.push( @@ -1902,7 +1899,7 @@ export class PoolTemplate extends CorePool { ) }); - const _response: bigint[] = await curve.multicallProvider.all(contractCalls); + const _response: bigint[] = await this.curve.multicallProvider.all(contractCalls); const response: BigNumber[] = _response.map((value: bigint) => toBN(value)); const [veTotalSupply, gaugeTotalSupply] = response.splice(0,2); @@ -1916,8 +1913,7 @@ export class PoolTemplate extends CorePool { } const totalPower = Object.values(votingPower).reduce((sum, item) => sum.plus(item)); - // @ts-ignore - const optimalBN: IDict = Object.fromEntries(accounts.map((acc) => [acc, BN(0)])); + const optimalBN = Object.fromEntries(accounts.map((acc) => [acc, BN(0)])) as IDict; if (totalBalance.lt(gaugeTotalSupply.times(totalPower).div(veTotalSupply))) { for (const acct of accounts) { // min(voting, lp) @@ -1946,7 +1942,7 @@ export class PoolTemplate extends CorePool { return optimal } - private _getCoinIdx = (coin: string | number, useUnderlying = true): number => { + _getCoinIdx = (coin: string | number, useUnderlying = true): number => { if (typeof coin === 'number') { const coins_N = useUnderlying ? this.underlyingCoins.length : this.wrappedCoins.length; const idx = coin; @@ -1963,7 +1959,7 @@ export class PoolTemplate extends CorePool { return idx } - const [coinAddress] = _getCoinAddresses(coin); + const [coinAddress] = _getCoinAddresses.call(this.curve, coin); const lowerCaseCoinAddresses = useUnderlying ? this.underlyingCoinAddresses.map((c) => c.toLowerCase()) : this.wrappedCoinAddresses.map((c) => c.toLowerCase()); @@ -1977,20 +1973,20 @@ export class PoolTemplate extends CorePool { } // Used by mixins - private _getRates = async(): Promise => { + _getRates = async(): Promise => { const _rates: bigint[] = []; for (let i = 0; i < this.wrappedCoinAddresses.length; i++) { const addr = this.wrappedCoinAddresses[i]; if (this.useLending[i]) { if (['compound', 'usdt', 'ib'].includes(this.id)) { - _rates.push(await curve.contracts[addr].contract.exchangeRateStored()); + _rates.push(await this.curve.contracts[addr].contract.exchangeRateStored()); } else if (['y', 'busd', 'pax'].includes(this.id)) { - _rates.push(await curve.contracts[addr].contract.getPricePerFullShare()); + _rates.push(await this.curve.contracts[addr].contract.getPricePerFullShare()); } else { - _rates.push(curve.parseUnits(String(10**18), 0)); // Aave ratio 1:1 + _rates.push(this.curve.parseUnits(String(10**18), 0)); // Aave ratio 1:1 } } else { - _rates.push(curve.parseUnits(String(10**18), 0)); + _rates.push(this.curve.parseUnits(String(10**18), 0)); } } @@ -2001,33 +1997,33 @@ export class PoolTemplate extends CorePool { if (this.isMeta) { if (useUnderlying) return this.underlyingCoins.map(() => BN(1)); - const _vp = await curve.contracts[curve.getPoolsData()[this.basePool].swap_address].contract.get_virtual_price(); + const _vp = await this.curve.contracts[this.curve.getPoolsData()[this.basePool].swap_address].contract.get_virtual_price(); return [BN(1), toBN(_vp)] } //for crvusd and stable-ng implementations - if (findAbiFunction(curve.contracts[this.address].abi, 'stored_rates').length > 0 && this.isPlain) { - const _stored_rates: bigint[] = await curve.contracts[this.address].contract.stored_rates(); + if (findAbiFunction(this.curve.contracts[this.address].abi, 'stored_rates').length > 0 && this.isPlain) { + const _stored_rates: bigint[] = await this.curve.contracts[this.address].contract.stored_rates(); return _stored_rates.map((_r, i) => toBN(_r, 36 - this.wrappedDecimals[i])); } return this.wrappedCoins.map(() => BN(1)) } - private _underlyingPrices = async (): Promise => { + _underlyingPrices = async (): Promise => { const promises = []; for (const addr of this.underlyingCoinAddresses) { - promises.push(_getUsdRate(addr)) + promises.push(_getUsdRate.call(this.curve, addr)) } return await Promise.all(promises) } // NOTE! It may crash! - private _wrappedPrices = async (): Promise => { + _wrappedPrices = async (): Promise => { const promises = []; for (const addr of this.wrappedCoinAddresses) { - promises.push(_getUsdRate(addr)) + promises.push(_getUsdRate.call(this.curve, addr)) } return await Promise.all(promises) diff --git a/src/pools/mixins/common.ts b/src/pools/mixins/common.ts index 0e4c030b..09ab253c 100644 --- a/src/pools/mixins/common.ts +++ b/src/pools/mixins/common.ts @@ -1,9 +1,9 @@ import BigNumber from "bignumber.js"; import { PoolTemplate } from "../PoolTemplate.js"; -import { curve } from "../../curve.js"; import { fromBN, toBN } from "../../utils.js"; export async function _calcExpectedAmounts(this: PoolTemplate, _lpTokenAmount: bigint): Promise { + const {curve} = this const coinBalancesBN: BigNumber[] = []; for (let i = 0; i < this.wrappedCoinAddresses.length; i++) { const _balance: bigint = await curve.contracts[this.address].contract.balances(i, curve.constantOptions); @@ -23,7 +23,7 @@ export async function _calcExpectedUnderlyingAmountsMeta(this: PoolTemplate, _lp const _expectedWrappedAmounts = await _calcExpectedAmounts.call(this, _lpTokenAmount); const [_expectedMetaCoinAmount] = _expectedWrappedAmounts.splice(this.metaCoinIdx, 1); const _expectedUnderlyingAmounts = _expectedWrappedAmounts; - const basePool = new PoolTemplate(this.basePool); + const basePool = new PoolTemplate(this.basePool, this.curve); const _basePoolExpectedAmounts = basePool.isMeta ? await _calcExpectedUnderlyingAmountsMeta.call(basePool, _expectedMetaCoinAmount) : await _calcExpectedAmounts.call(basePool, _expectedMetaCoinAmount); diff --git a/src/pools/mixins/depositBalancedAmountsMixins.ts b/src/pools/mixins/depositBalancedAmountsMixins.ts index 121e7376..7de2e6f6 100644 --- a/src/pools/mixins/depositBalancedAmountsMixins.ts +++ b/src/pools/mixins/depositBalancedAmountsMixins.ts @@ -29,12 +29,9 @@ function _depositBalancedAmounts(poolBalances: string[], walletBalances: string[ return bestScenario.map((a, i) => walletBalancesBN[i].isZero() ? "0" : a.toFixed(decimals[i])) } -// @ts-ignore -export const depositBalancedAmountsMixin: PoolTemplate = { - async depositBalancedAmounts(): Promise { - // @ts-ignore +export const depositBalancedAmountsMixin = { + async depositBalancedAmounts(this: PoolTemplate): Promise { const poolBalances = await this.stats.underlyingBalances(); - // @ts-ignore const walletBalances = Object.values(await this.wallet.underlyingCoinBalances()); const balancedAmountsBN = (_depositBalancedAmounts(poolBalances, walletBalances, this.underlyingDecimals)); @@ -42,14 +39,10 @@ export const depositBalancedAmountsMixin: PoolTemplate = { }, } -// @ts-ignore -export const depositBalancedAmountsCryptoMixin: PoolTemplate = { - async depositBalancedAmounts(): Promise { - // @ts-ignore +export const depositBalancedAmountsCryptoMixin = { + async depositBalancedAmounts(this: PoolTemplate): Promise { const poolBalances = await this.stats.underlyingBalances(); - // @ts-ignore const walletBalances = Object.values(await this.wallet.underlyingCoinBalances()); - // @ts-ignore const prices = await this._underlyingPrices(); const poolBalancesUSD = poolBalances.map((b, i) => BN(b).times(prices[i]).toString()); const walletBalancesUSD = walletBalances.map((b, i) => BN(b).times(prices[i]).toString()); @@ -59,12 +52,9 @@ export const depositBalancedAmountsCryptoMixin: PoolTemplate = { }, } -// @ts-ignore -export const depositWrappedBalancedAmountsMixin: PoolTemplate = { - async depositWrappedBalancedAmounts(): Promise { - // @ts-ignore +export const depositWrappedBalancedAmountsMixin = { + async depositWrappedBalancedAmounts(this: PoolTemplate): Promise { const poolBalances = await this.stats.wrappedBalances(); - // @ts-ignore const walletBalances = Object.values(await this.wallet.wrappedCoinBalances()); const balancedAmountsBN = (_depositBalancedAmounts(poolBalances, walletBalances, this.underlyingDecimals)); @@ -72,14 +62,10 @@ export const depositWrappedBalancedAmountsMixin: PoolTemplate = { }, } -// @ts-ignore -export const depositWrappedBalancedAmountsCryptoMixin: PoolTemplate = { - async depositWrappedBalancedAmounts(): Promise { - // @ts-ignore +export const depositWrappedBalancedAmountsCryptoMixin = { + async depositWrappedBalancedAmounts(this: PoolTemplate): Promise { const poolBalances = (await this.stats.wrappedBalances()).map(Number); - // @ts-ignore - const walletBalances = Object.values(await this.walletWrappedCoinBalances()).map(Number); - // @ts-ignore + const walletBalances = Object.values(await this.wallet.wrappedCoinBalances()).map(Number); const prices = await this._wrappedPrices(); const poolBalancesUSD = poolBalances.map((b, i) => BN(b).times(prices[i]).toString()); const walletBalancesUSD = walletBalances.map((b, i) => BN(b).times(prices[i]).toString()); diff --git a/src/pools/mixins/depositMixins.ts b/src/pools/mixins/depositMixins.ts index a783acd0..fbc43845 100644 --- a/src/pools/mixins/depositMixins.ts +++ b/src/pools/mixins/depositMixins.ts @@ -1,8 +1,16 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { _ensureAllowance, fromBN, getEthIndex, hasAllowance, toBN, parseUnits, mulBy1_3, DIGas, smartNumber } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import { + _ensureAllowance, + DIGas, + fromBN, + getEthIndex, + hasAllowance, + mulBy1_3, + parseUnits, + smartNumber, + toBN, +} from '../../utils.js'; -// @ts-ignore async function _depositCheck(this: PoolTemplate, amounts: (number | string)[], estimateGas = false): Promise { if (amounts.length !== this.underlyingCoinAddresses.length) { throw Error(`${this.name} pool has ${this.underlyingCoinAddresses.length} coins (amounts provided for ${amounts.length})`); @@ -15,200 +23,153 @@ async function _depositCheck(this: PoolTemplate, amounts: (number | string)[], e } } - if (estimateGas && !(await hasAllowance(this.underlyingCoinAddresses, amounts, curve.signerAddress, this.zap || this.address))) { + if (estimateGas && !(await hasAllowance.call(this.curve, this.underlyingCoinAddresses, amounts, this.curve.signerAddress, this.zap || this.address))) { throw Error("Token allowance is needed to estimate gas") } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); return amounts.map((amount, i) => parseUnits(amount, this.underlyingDecimals[i])); } async function _depositMinAmount(this: PoolTemplate, _amounts: bigint[], slippage = 0.5): Promise { - // @ts-ignore const _expectedLpTokenAmount = await this._calcLpTokenAmount(_amounts); const minAmountBN = toBN(_expectedLpTokenAmount).times(100 - slippage).div(100); - return fromBN(minAmountBN); } -// @ts-ignore -export const depositMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _deposit(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.underlyingCoinAddresses, _amounts, this.zap as string); +export const depositMetaFactoryMixin = { + async _deposit(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.underlyingCoinAddresses, _amounts, this.zap as string); - // @ts-ignore const _minMintAmount = await _depositMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.underlyingCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.zap as string].contract; + const value = _amounts[ethIndex] || parseUnits("0"); + const contract = this.curve.contracts[this.zap as string].contract; - const gas = await contract.add_liquidity.estimateGas(this.address, _amounts, _minMintAmount, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(this.address, _amounts, _minMintAmount, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(this.address, _amounts, _minMintAmount, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(this.address, _amounts, _minMintAmount, { ...this.curve.options, gasLimit, value })).hash; }, - async depositEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositEstimateGas(this: PoolTemplate, amounts: (number | string)[]) { const _amounts = await _depositCheck.call(this, amounts, true); - - // @ts-ignore - return await this._deposit(_amounts, 0.1, true); + return await depositMetaFactoryMixin._deposit.call(this, _amounts, 0.1, true); }, - async deposit(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async deposit(this: PoolTemplate, amounts: (number | string)[], slippage?: number) { const _amounts = await _depositCheck.call(this, amounts); - - // @ts-ignore - return await this._deposit(_amounts, slippage); + return await depositMetaFactoryMixin._deposit.call(this, _amounts, slippage); }, } -// @ts-ignore -export const depositCryptoMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _deposit(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.underlyingCoinAddresses, _amounts, this.zap as string); +export const depositCryptoMetaFactoryMixin = { + async _deposit(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.underlyingCoinAddresses, _amounts, this.zap as string); - // @ts-ignore const _minMintAmount = await _depositMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.underlyingCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.zap as string].contract; + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + const contract = this.curve.contracts[this.zap as string].contract; - const gas = await contract.add_liquidity.estimateGas(this.address, _amounts, _minMintAmount, true, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(this.address, _amounts, _minMintAmount, true, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(this.address, _amounts, _minMintAmount, true, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(this.address, _amounts, _minMintAmount, true, { ...this.curve.options, gasLimit, value })).hash; }, - async depositEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _depositCheck.call(this, amounts, true); - - // @ts-ignore - return await this._deposit(_amounts, 0.1, true); + return await depositCryptoMetaFactoryMixin._deposit.call(this, _amounts, 0.1, true) as number | number[]; }, - async deposit(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async deposit(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _depositCheck.call(this, amounts); - - // @ts-ignore - return await this._deposit(_amounts, slippage); + return await depositCryptoMetaFactoryMixin._deposit.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const depositZapMixin: PoolTemplate = { - // @ts-ignore - async _deposit(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.underlyingCoinAddresses, _amounts, this.zap as string); +export const depositZapMixin = { + async _deposit(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.underlyingCoinAddresses, _amounts, this.zap as string); - // @ts-ignore const _minMintAmount = await _depositMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.underlyingCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.zap as string].contract; + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + const contract = this.curve.contracts[this.zap as string].contract; const args: any[] = [_amounts, _minMintAmount]; if (`add_liquidity(uint256[${this.underlyingCoinAddresses.length}],uint256,bool)` in contract) args.push(true); - const gas = await contract.add_liquidity.estimateGas(...args, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(...args, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(...args, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(...args, { ...this.curve.options, gasLimit, value })).hash; }, - async depositEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _depositCheck.call(this, amounts, true); - - // @ts-ignore - return await this._deposit(_amounts, 0.1, true); + return await depositZapMixin._deposit.call(this, _amounts, 0.1, true) as number | number[]; }, - async deposit(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async deposit(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _depositCheck.call(this, amounts); - - // @ts-ignore - return await this._deposit(_amounts, slippage); + return await depositZapMixin._deposit.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const depositLendingOrCryptoMixin: PoolTemplate = { - // @ts-ignore - async _deposit(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.underlyingCoinAddresses, _amounts, this.address); +export const depositLendingOrCryptoMixin = { + async _deposit(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.underlyingCoinAddresses, _amounts, this.address); - // @ts-ignore const _minMintAmount = await _depositMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.underlyingCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.address].contract; + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, true, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, true, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(_amounts, _minMintAmount, true, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(_amounts, _minMintAmount, true, { ...this.curve.options, gasLimit, value })).hash; }, - async depositEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _depositCheck.call(this, amounts, true); - - // @ts-ignore - return await this._deposit(_amounts, 0.1, true); + return await depositLendingOrCryptoMixin._deposit.call(this, _amounts, 0.1, true) as number | number[]; }, - async deposit(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async deposit(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _depositCheck.call(this, amounts); - - // @ts-ignore - return await this._deposit(_amounts, slippage); + return await depositLendingOrCryptoMixin._deposit.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const depositPlainMixin: PoolTemplate = { - // @ts-ignore - async _deposit(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.wrappedCoinAddresses, _amounts, this.address); - // @ts-ignore +export const depositPlainMixin = { + async _deposit(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.wrappedCoinAddresses, _amounts, this.address); const _minMintAmount = await _depositMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.wrappedCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.address].contract; + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(_amounts, _minMintAmount, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(_amounts, _minMintAmount, { ...this.curve.options, gasLimit, value })).hash; }, - async depositEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _depositCheck.call(this, amounts, true); - - // @ts-ignore - return await this._deposit(_amounts, 0.1, true); + return await depositPlainMixin._deposit.call(this, _amounts, 0.1, true) as number | number[]; }, - async deposit(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async deposit(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _depositCheck.call(this, amounts); - - // @ts-ignore - return await this._deposit(_amounts, slippage); + return await depositPlainMixin._deposit.call(this, _amounts, slippage) as string }, } \ No newline at end of file diff --git a/src/pools/mixins/depositWrappedMixins.ts b/src/pools/mixins/depositWrappedMixins.ts index 9b116df3..642714ee 100644 --- a/src/pools/mixins/depositWrappedMixins.ts +++ b/src/pools/mixins/depositWrappedMixins.ts @@ -1,6 +1,15 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { _ensureAllowance, fromBN, getEthIndex, hasAllowance, toBN, parseUnits, mulBy1_3, DIGas, smartNumber } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import { + _ensureAllowance, + DIGas, + fromBN, + getEthIndex, + hasAllowance, + mulBy1_3, + parseUnits, + smartNumber, + toBN, +} from '../../utils.js'; async function _depositWrappedCheck(this: PoolTemplate, amounts: (number | string)[], estimateGas = false): Promise { if (this.isFake) { @@ -18,91 +27,72 @@ async function _depositWrappedCheck(this: PoolTemplate, amounts: (number | strin } } - if (estimateGas && !(await hasAllowance(this.wrappedCoinAddresses, amounts, curve.signerAddress, this.address))) { + if (estimateGas && !(await hasAllowance.call(this.curve, this.wrappedCoinAddresses, amounts, this.curve.signerAddress, this.address))) { throw Error("Token allowance is needed to estimate gas") } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); return amounts.map((amount, i) => parseUnits(amount, this.wrappedDecimals[i])); } async function _depositWrappedMinAmount(this: PoolTemplate, _amounts: bigint[], slippage = 0.5): Promise { - // @ts-ignore const _expectedLpTokenAmount = await this._calcLpTokenAmount(_amounts, true, false); const minAmountBN = toBN(_expectedLpTokenAmount).times(100 - slippage).div(100); return fromBN(minAmountBN); } -// @ts-ignore -export const depositWrapped2argsMixin: PoolTemplate = { - // @ts-ignore - async _depositWrapped(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.wrappedCoinAddresses, _amounts, this.address); +export const depositWrapped2argsMixin = { + async _depositWrapped(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.wrappedCoinAddresses, _amounts, this.address); - // @ts-ignore const _minMintAmount = await _depositWrappedMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.wrappedCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.address].contract; + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(_amounts, _minMintAmount, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(_amounts, _minMintAmount, { ...this.curve.options, gasLimit, value })).hash; }, - async depositWrappedEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositWrappedEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _depositWrappedCheck.call(this, amounts, true); - - // @ts-ignore - return await this._depositWrapped(_amounts, 0.1, true); + return await depositWrapped2argsMixin._depositWrapped.call(this, _amounts, 0.1, true) as number; }, - async depositWrapped(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async depositWrapped(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _depositWrappedCheck.call(this, amounts); - - // @ts-ignore - return await this._depositWrapped(_amounts, slippage); + return await depositWrapped2argsMixin._depositWrapped.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const depositWrapped3argsMixin: PoolTemplate = { - // @ts-ignore - async _depositWrapped(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance(this.wrappedCoinAddresses, _amounts, this.address); +export const depositWrapped3argsMixin = { + async _depositWrapped(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, this.wrappedCoinAddresses, _amounts, this.address); - // @ts-ignore const _minMintAmount = await _depositWrappedMinAmount.call(this, _amounts, slippage); const ethIndex = getEthIndex(this.wrappedCoinAddresses); - const value = _amounts[ethIndex] || curve.parseUnits("0"); - const contract = curve.contracts[this.address].contract; + const value = _amounts[ethIndex] || this.curve.parseUnits("0"); + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, false, { ...curve.constantOptions, value }); + const gas = await contract.add_liquidity.estimateGas(_amounts, _minMintAmount, false, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.add_liquidity(_amounts, _minMintAmount, false, { ...curve.options, gasLimit, value })).hash; + return (await contract.add_liquidity(_amounts, _minMintAmount, false, { ...this.curve.options, gasLimit, value })).hash; }, - async depositWrappedEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async depositWrappedEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _depositWrappedCheck.call(this, amounts, true); - - // @ts-ignore - return await this._depositWrapped(_amounts, 0.1, true); + return await depositWrapped3argsMixin._depositWrapped.call(this, _amounts, 0.1, true) as number; }, - async depositWrapped(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async depositWrapped(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _depositWrappedCheck.call(this, amounts); - - // @ts-ignore - return await this._depositWrapped(_amounts, slippage); + return await depositWrapped3argsMixin._depositWrapped.call(this, _amounts, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/mixins/poolBalancesMixin.ts b/src/pools/mixins/poolBalancesMixin.ts index 18408bf8..076d7e36 100644 --- a/src/pools/mixins/poolBalancesMixin.ts +++ b/src/pools/mixins/poolBalancesMixin.ts @@ -1,18 +1,17 @@ -import { curve } from "../../curve.js"; import { PoolTemplate } from "../PoolTemplate.js"; import { _calcExpectedAmounts, _calcExpectedUnderlyingAmountsMeta } from "./common.js"; import {IStatsPool} from "../subClasses/statsPool"; -// @ts-ignore -export const poolBalancesMetaMixin: IStatsPool = { - async underlyingBalances(): Promise { +export const poolBalancesMetaMixin = { + async underlyingBalances(this: IStatsPool): Promise { + const curve = this.pool.curve; const swapContract = curve.contracts[this.pool.address].multicallContract; const contractCalls = this.pool.wrappedCoins.map((_, i) => swapContract.balances(i)); const _poolWrappedBalances: bigint[] = await curve.multicallProvider.all(contractCalls); const [_poolMetaCoinBalance] = _poolWrappedBalances.splice(this.pool.metaCoinIdx, 1); const _poolUnderlyingBalances = _poolWrappedBalances; - const basePool = new PoolTemplate(this.pool.basePool); + const basePool = new PoolTemplate(this.pool.basePool, curve); const _basePoolExpectedAmounts = basePool.isMeta ? await _calcExpectedUnderlyingAmountsMeta.call(basePool, _poolMetaCoinBalance) : await _calcExpectedAmounts.call(basePool, _poolMetaCoinBalance); @@ -22,14 +21,13 @@ export const poolBalancesMetaMixin: IStatsPool = { }, } -// @ts-ignore -export const poolBalancesLendingMixin: IStatsPool = { - async underlyingBalances(): Promise { +export const poolBalancesLendingMixin = { + async underlyingBalances(this: IStatsPool): Promise { + const curve = this.pool.curve; const swapContract = curve.contracts[this.pool.address].multicallContract; const contractCalls = this.pool.wrappedCoins.map((_, i) => swapContract.balances(i)); const _poolWrappedBalances: bigint[] = await curve.multicallProvider.all(contractCalls); - // @ts-ignore const _rates: bigint[] = await this.pool._getRates(); const _poolUnderlyingBalances = _poolWrappedBalances.map( (_b: bigint, i: number) => _b * _rates[i] / curve.parseUnits(String(10**18), 0)); diff --git a/src/pools/mixins/swapMixins.ts b/src/pools/mixins/swapMixins.ts index 3c58c710..1935dba5 100644 --- a/src/pools/mixins/swapMixins.ts +++ b/src/pools/mixins/swapMixins.ts @@ -1,9 +1,18 @@ import BigNumber from "bignumber.js"; -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { _ensureAllowance, _getCoinDecimals, fromBN, hasAllowance, isEth, toBN, parseUnits, mulBy1_3, DIGas, smartNumber } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import { + _ensureAllowance, + _getCoinDecimals, + DIGas, + fromBN, + hasAllowance, + isEth, + mulBy1_3, + parseUnits, + smartNumber, + toBN, +} from '../../utils.js'; -// @ts-ignore async function _swapCheck( this: PoolTemplate, inputCoin: string | number, @@ -11,11 +20,8 @@ async function _swapCheck( amount: number | string, estimateGas = false ): Promise<[number, number, bigint]> { - // @ts-ignore const contractAddress = this._swapContractAddress(); - // @ts-ignore const i = this._getCoinIdx(inputCoin); - // @ts-ignore const j = this._getCoinIdx(outputCoin); const inputCoinBalance = Object.values(await this.wallet.underlyingCoinBalances())[i]; @@ -23,11 +29,11 @@ async function _swapCheck( throw Error(`Not enough ${this.underlyingCoins[i]}. Actual: ${inputCoinBalance}, required: ${amount}`); } - if (estimateGas && !(await hasAllowance([this.underlyingCoinAddresses[i]], [amount], curve.signerAddress, contractAddress))) { + if (estimateGas && !(await hasAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [amount], this.curve.signerAddress, contractAddress))) { throw Error("Token allowance is needed to estimate gas") } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); const _amount = parseUnits(amount, this.underlyingDecimals[i]); @@ -35,159 +41,122 @@ async function _swapCheck( } async function _swapMinAmount(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage = 0.5): Promise { - // @ts-ignore const _expected: bigint = await this._swapExpected(i, j, _amount); - const [outputCoinDecimals] = _getCoinDecimals(this.underlyingCoinAddresses[j]); + const [outputCoinDecimals] = _getCoinDecimals.call(this.curve, this.underlyingCoinAddresses[j]); const minAmountBN: BigNumber = toBN(_expected, outputCoinDecimals).times(100 - slippage).div(100); return fromBN(minAmountBN, outputCoinDecimals); } -// @ts-ignore -export const swapTricrypto2Mixin: PoolTemplate = { - // @ts-ignore - async _swap(i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { - // @ts-ignore +export const swapTricrypto2Mixin = { + async _swap(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { const contractAddress = this._swapContractAddress(); - if (!estimateGas) await _ensureAllowance([this.underlyingCoinAddresses[i]], [_amount], contractAddress); + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [_amount], contractAddress); const _minRecvAmount = await _swapMinAmount.call(this, i, j, _amount, slippage); - const contract = curve.contracts[contractAddress].contract; + const contract = this.curve.contracts[contractAddress].contract; const exchangeMethod = 'exchange_underlying' in contract ? 'exchange_underlying' : 'exchange'; - const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : curve.parseUnits("0"); + const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : this.curve.parseUnits("0"); - const gas = await contract[exchangeMethod].estimateGas(i, j, _amount, _minRecvAmount, true, { ...curve.constantOptions, value }); + const gas = await contract[exchangeMethod].estimateGas(i, j, _amount, _minRecvAmount, true, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.options, value, gasLimit })).hash + return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...this.curve.options, value, gasLimit })).hash }, - async swapEstimateGas(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore + async swapEstimateGas(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount, true); - - // @ts-ignore - return await this._swap(i, j, _amount, 0.1, true); + return await swapTricrypto2Mixin._swap.call(this, i, j, _amount, 0.1, true) as number }, - async swap(inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { - // @ts-ignore + async swap(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount); - - // @ts-ignore - return await this._swap(i, j, _amount, slippage); + return await swapTricrypto2Mixin._swap.call(this, i, j, _amount, slippage) as string }, } -// @ts-ignore -export const swapMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _swap(i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { - // @ts-ignore +export const swapMetaFactoryMixin = { + async _swap(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { const contractAddress = this._swapContractAddress(); - if (!estimateGas) await _ensureAllowance([this.underlyingCoinAddresses[i]], [_amount], contractAddress); + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [_amount], contractAddress); const _minRecvAmount = await _swapMinAmount.call(this, i, j, _amount, slippage); - const contract = curve.contracts[contractAddress].contract; + const contract = this.curve.contracts[contractAddress].contract; const exchangeMethod = 'exchange_underlying' in contract ? 'exchange_underlying' : 'exchange'; - const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : curve.parseUnits("0"); + const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : this.curve.parseUnits("0"); - const gas = await contract[exchangeMethod].estimateGas(this.address, i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value }); + const gas = await contract[exchangeMethod].estimateGas(this.address, i, j, _amount, _minRecvAmount, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); - const gasLimit = DIGas(gas) * curve.parseUnits("140", 0) / curve.parseUnits("100", 0); - return (await contract[exchangeMethod](this.address, i, j, _amount, _minRecvAmount, { ...curve.options, value, gasLimit })).hash + const gasLimit = DIGas(gas) * this.curve.parseUnits("140", 0) / this.curve.parseUnits("100", 0); + return (await contract[exchangeMethod](this.address, i, j, _amount, _minRecvAmount, { ...this.curve.options, value, gasLimit })).hash }, - async swapEstimateGas(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore + async swapEstimateGas(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount, true); - - // @ts-ignore - return await this._swap(i, j, _amount, 0.1, true); + return await swapMetaFactoryMixin._swap.call(this, i, j, _amount, 0.1, true) as number; }, - async swap(inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { - // @ts-ignore + async swap(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount); - - // @ts-ignore - return await this._swap(i, j, _amount, slippage); + return await swapMetaFactoryMixin._swap.call(this, i, j, _amount, slippage) as string; }, } -// @ts-ignore -export const swapCryptoMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _swap(i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { - // @ts-ignore +export const swapCryptoMetaFactoryMixin = { + async _swap(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { const contractAddress = this._swapContractAddress(); - if (!estimateGas) await _ensureAllowance([this.underlyingCoinAddresses[i]], [_amount], contractAddress); + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [_amount], contractAddress); const _minRecvAmount = await _swapMinAmount.call(this, i, j, _amount, slippage); - const contract = curve.contracts[contractAddress].contract; + const contract = this.curve.contracts[contractAddress].contract; const exchangeMethod = 'exchange_underlying' in contract ? 'exchange_underlying' : 'exchange'; - const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : curve.parseUnits("0"); + const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : this.curve.parseUnits("0"); - const gas = await contract[exchangeMethod].estimateGas(this.address, i, j, _amount, _minRecvAmount, true, { ...curve.constantOptions, value }); + const gas = await contract[exchangeMethod].estimateGas(this.address, i, j, _amount, _minRecvAmount, true, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); - const gasLimit = DIGas(gas) * curve.parseUnits("140", 0) / curve.parseUnits("100", 0); - return (await contract[exchangeMethod](this.address, i, j, _amount, _minRecvAmount, true, { ...curve.options, value, gasLimit })).hash + const gasLimit = DIGas(gas) * this.curve.parseUnits("140", 0) / this.curve.parseUnits("100", 0); + return (await contract[exchangeMethod](this.address, i, j, _amount, _minRecvAmount, true, { ...this.curve.options, value, gasLimit })).hash }, - async swapEstimateGas(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore + async swapEstimateGas(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount, true); - - // @ts-ignore - return await this._swap(i, j, _amount, 0.1, true); + return await swapCryptoMetaFactoryMixin._swap.call(this, i, j, _amount, 0.1, true) as number; }, - async swap(inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { - // @ts-ignore + async swap(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount); - - // @ts-ignore - return await this._swap(i, j, _amount, slippage); + return await swapCryptoMetaFactoryMixin._swap.call(this, i, j, _amount, slippage) as string; }, } -// @ts-ignore -export const swapMixin: PoolTemplate = { - // @ts-ignore - async _swap(i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { - // @ts-ignore +export const swapMixin = { + async _swap(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { const contractAddress = this._swapContractAddress(); - if (!estimateGas) await _ensureAllowance([this.underlyingCoinAddresses[i]], [_amount], contractAddress); + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.underlyingCoinAddresses[i]], [_amount], contractAddress); const _minRecvAmount = await _swapMinAmount.call(this, i, j, _amount, slippage); - const contract = curve.contracts[contractAddress].contract; + const contract = this.curve.contracts[contractAddress].contract; const exchangeMethod = 'exchange_underlying' in contract ? 'exchange_underlying' : 'exchange'; - const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : curve.parseUnits("0"); + const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : this.curve.parseUnits("0"); - const gas = await contract[exchangeMethod].estimateGas(i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value }); + const gas = await contract[exchangeMethod].estimateGas(i, j, _amount, _minRecvAmount, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); - await curve.updateFeeData(); - const gasLimit = curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * curve.parseUnits("160", 0) / curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); - return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, { ...curve.options, value, gasLimit })).hash + await this.curve.updateFeeData(); + const gasLimit = this.curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * this.curve.parseUnits("160", 0) / this.curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); + return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, { ...this.curve.options, value, gasLimit })).hash }, - async swapEstimateGas(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore + async swapEstimateGas(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount, true); - - // @ts-ignore - return await this._swap(i, j, _amount, 0.1, true); + return await swapMixin._swap.call(this, i, j, _amount, 0.1, true) as number; }, - async swap(inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { - // @ts-ignore + async swap(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { const [i, j, _amount] = await _swapCheck.call(this, inputCoin, outputCoin, amount); - - // @ts-ignore - return await this._swap(i, j, _amount, slippage); + return await swapMixin._swap.call(this, i, j, _amount, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/mixins/swapWrappedMixins.ts b/src/pools/mixins/swapWrappedMixins.ts index 6bd6d9c1..371f37a2 100644 --- a/src/pools/mixins/swapWrappedMixins.ts +++ b/src/pools/mixins/swapWrappedMixins.ts @@ -1,21 +1,20 @@ import BigNumber from "bignumber.js"; -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; +import {PoolTemplate} from "../PoolTemplate.js"; import { _ensureAllowance, _getCoinDecimals, + DIGas, ensureAllowance, ensureAllowanceEstimateGas, fromBN, hasAllowance, isEth, - toBN, - parseUnits, mulBy1_3, - DIGas, - smartNumber } from '../../utils.js'; + parseUnits, + smartNumber, + toBN, +} from '../../utils.js'; -// @ts-ignore async function _swapWrappedCheck( this: PoolTemplate, inputCoin: string | number, @@ -23,9 +22,7 @@ async function _swapWrappedCheck( amount: number | string, estimateGas = false ): Promise<[number, number, bigint]> { - // @ts-ignore const i = this._getCoinIdx(inputCoin, false); - // @ts-ignore const j = this._getCoinIdx(outputCoin, false); const inputCoinBalance = Object.values(await this.wallet.wrappedCoinBalances())[i]; @@ -33,11 +30,11 @@ async function _swapWrappedCheck( throw Error(`Not enough ${this.wrappedCoins[i]}. Actual: ${inputCoinBalance}, required: ${amount}`); } - if (estimateGas && !(await hasAllowance([this.wrappedCoinAddresses[i]], [amount], curve.signerAddress, this.address))) { + if (estimateGas && !(await hasAllowance.call(this.curve, [this.wrappedCoinAddresses[i]], [amount], this.curve.signerAddress, this.address))) { throw Error("Token allowance is needed to estimate gas") } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); const _amount = parseUnits(amount, this.wrappedDecimals[i]); @@ -45,126 +42,97 @@ async function _swapWrappedCheck( } async function _swapWrappedMinAmount(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage = 0.5): Promise { - // @ts-ignore - const _expected: bigint = await this._swapWrappedExpected(i, j, _amount); - const [outputCoinDecimals] = _getCoinDecimals(this.wrappedCoinAddresses[j]); + const _expected: bigint = await this._swapWrappedExpected.call(this, i, j, _amount); + const [outputCoinDecimals] = _getCoinDecimals.call(this.curve, this.wrappedCoinAddresses[j]); const minAmountBN: BigNumber = toBN(_expected, outputCoinDecimals).times(100 - slippage).div(100); return fromBN(minAmountBN, outputCoinDecimals); } -// @ts-ignore -export const swapWrappedTricrypto2Mixin: PoolTemplate = { - // @ts-ignore - async _swapWrapped(i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.wrappedCoinAddresses[i]], [_amount], this.address); +export const swapWrappedTricrypto2Mixin= { + async _swapWrapped(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.wrappedCoinAddresses[i]], [_amount], this.address); const _minRecvAmount = await _swapWrappedMinAmount.call(this, i, j, _amount, slippage); - const contract = curve.contracts[this.address].contract; - const value = isEth(this.wrappedCoinAddresses[i]) ? _amount : curve.parseUnits("0"); + const contract = this.curve.contracts[this.address].contract; + const value = isEth(this.wrappedCoinAddresses[i]) ? _amount : this.curve.parseUnits("0"); - const gas = await contract.exchange.estimateGas(i, j, _amount, _minRecvAmount, false, { ...curve.constantOptions, value }); + const gas = await contract.exchange.estimateGas(i, j, _amount, _minRecvAmount, false, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.exchange(i, j, _amount, _minRecvAmount, false, { ...curve.options, value, gasLimit })).hash + return (await contract.exchange(i, j, _amount, _minRecvAmount, false, { ...this.curve.options, value, gasLimit })).hash }, - async swapWrappedEstimateGas(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore + async swapWrappedEstimateGas(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const [i, j, _amount] = await _swapWrappedCheck.call(this, inputCoin, outputCoin, amount, true); - - // @ts-ignore - return await this._swapWrapped(i, j, _amount, 0.1, true); + return await swapWrappedTricrypto2Mixin._swapWrapped.call(this, i, j, _amount, 0.1, true) as number; }, - async swapWrapped(inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { - // @ts-ignore + async swapWrapped(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { const [i, j, _amount] = await _swapWrappedCheck.call(this, inputCoin, outputCoin, amount); - - // @ts-ignore - return await this._swapWrapped(i, j, _amount, slippage); + return await swapWrappedTricrypto2Mixin._swapWrapped.call(this, i, j, _amount, slippage) as string; }, } -// @ts-ignore -export const swapWrappedMixin: PoolTemplate = { - // @ts-ignore - async _swapWrapped(i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.wrappedCoinAddresses[i]], [_amount], this.address); +export const swapWrappedMixin= { + async _swapWrapped(this: PoolTemplate, i: number, j: number, _amount: bigint, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.wrappedCoinAddresses[i]], [_amount], this.address); const _minRecvAmount = await _swapWrappedMinAmount.call(this, i, j, _amount, slippage); - const contract = curve.contracts[this.address].contract; - const value = isEth(this.wrappedCoinAddresses[i]) ? _amount : curve.parseUnits("0"); + const contract = this.curve.contracts[this.address].contract; + const value = isEth(this.wrappedCoinAddresses[i]) ? _amount : this.curve.parseUnits("0"); - const gas = await contract.exchange.estimateGas(i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value }); + const gas = await contract.exchange.estimateGas(i, j, _amount, _minRecvAmount, { ...this.curve.constantOptions, value }); if (estimateGas) return smartNumber(gas); - const gasLimit = curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * curve.parseUnits("140", 0) / curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); - return (await contract.exchange(i, j, _amount, _minRecvAmount, { ...curve.options, value, gasLimit })).hash + const gasLimit = this.curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * this.curve.parseUnits("140", 0) / this.curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); + return (await contract.exchange(i, j, _amount, _minRecvAmount, { ...this.curve.options, value, gasLimit })).hash }, - async swapWrappedEstimateGas(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore + async swapWrappedEstimateGas(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const [i, j, _amount] = await _swapWrappedCheck.call(this, inputCoin, outputCoin, amount, true); - - // @ts-ignore - return await this._swapWrapped(i, j, _amount, 0.1, true); + return await swapWrappedMixin._swapWrapped.call(this, i, j, _amount, 0.1, true) as number; }, - async swapWrapped(inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { - // @ts-ignore + async swapWrapped(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string, slippage?: number): Promise { const [i, j, _amount] = await _swapWrappedCheck.call(this, inputCoin, outputCoin, amount); - - // @ts-ignore - return await this._swapWrapped(i, j, _amount, slippage); + return await swapWrappedMixin._swapWrapped.call(this, i, j, _amount, slippage) as string; }, } -// @ts-ignore -export const swapWrappedExpectedAndApproveMixin: PoolTemplate = { - async swapWrappedExpected(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore +export const swapWrappedExpectedAndApproveMixin = { + async swapWrappedExpected(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { const i = this._getCoinIdx(inputCoin, false); - // @ts-ignore const j = this._getCoinIdx(outputCoin, false); const _amount = parseUnits(amount, this.wrappedDecimals[i]); - // @ts-ignore - const _expected = await this._swapWrappedExpected(i, j, _amount); + const _expected = await this._swapWrappedExpected.call(this, i, j, _amount); - return curve.formatUnits(_expected, this.wrappedDecimals[j]) + return this.curve.formatUnits(_expected, this.wrappedDecimals[j]) }, - async swapWrappedIsApproved(inputCoin: string | number, amount: number | string): Promise { - // @ts-ignore - const i = this._getCoinIdx(inputCoin, false); - return await hasAllowance([this.wrappedCoinAddresses[i]], [amount], curve.signerAddress, this.address); + async swapWrappedIsApproved(this: PoolTemplate, inputCoin: string | number, amount: number | string): Promise { + const i = this._getCoinIdx.call(this, inputCoin, false); + return await hasAllowance.call(this.curve, [this.wrappedCoinAddresses[i]], [amount], this.curve.signerAddress, this.address); }, - async swapWrappedApproveEstimateGas(inputCoin: string | number, amount: number | string): Promise { - // @ts-ignore - const i = this._getCoinIdx(inputCoin, false); - return await ensureAllowanceEstimateGas([this.wrappedCoinAddresses[i]], [amount], this.address); + async swapWrappedApproveEstimateGas(this: PoolTemplate, inputCoin: string | number, amount: number | string): Promise { + const i = this._getCoinIdx.call(this, inputCoin, false); + return await ensureAllowanceEstimateGas.call(this.curve, [this.wrappedCoinAddresses[i]], [amount], this.address); }, - async swapWrappedApprove(inputCoin: string | number, amount: number | string): Promise { - // @ts-ignore - const i = this._getCoinIdx(inputCoin, false); - return await ensureAllowance([this.wrappedCoinAddresses[i]], [amount], this.address); + async swapWrappedApprove(this: PoolTemplate, inputCoin: string | number, amount: number | string): Promise { + const i = this._getCoinIdx.call(this, inputCoin, false); + return await ensureAllowance.call(this.curve, [this.wrappedCoinAddresses[i]], [amount], this.address); }, } -// @ts-ignore -export const swapWrappedRequiredMixin: PoolTemplate = { - async swapWrappedRequired(inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { - // @ts-ignore - const i = this._getCoinIdx(inputCoin, false); - // @ts-ignore - const j = this._getCoinIdx(outputCoin, false); +export const swapWrappedRequiredMixin = { + async swapWrappedRequired(this: PoolTemplate, inputCoin: string | number, outputCoin: string | number, amount: number | string): Promise { + const i = this._getCoinIdx.call(this, inputCoin, false); + const j = this._getCoinIdx.call(this, outputCoin, false); const _amount = parseUnits(amount, this.wrappedDecimals[j]); - // @ts-ignore - const _required = await this._swapRequired(i, j, _amount, false); - - return curve.formatUnits(_required, this.wrappedDecimals[i]) + const _required = await this._swapRequired.call(this, i, j, _amount, false); + return this.curve.formatUnits(_required, this.wrappedDecimals[i]) }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawExpectedMixins.ts b/src/pools/mixins/withdrawExpectedMixins.ts index 503aa823..7267c8f6 100644 --- a/src/pools/mixins/withdrawExpectedMixins.ts +++ b/src/pools/mixins/withdrawExpectedMixins.ts @@ -1,47 +1,40 @@ -import { curve } from "../../curve.js"; import { PoolTemplate } from "../PoolTemplate.js"; import { parseUnits } from "../../utils.js"; import { _calcExpectedAmounts, _calcExpectedUnderlyingAmountsMeta } from "./common.js"; +import {formatUnits} from "../../constants/utils"; -// @ts-ignore -export const withdrawExpectedMixin: PoolTemplate = { - async withdrawExpected(lpTokenAmount: number | string): Promise { +export const withdrawExpectedMixin = { + async withdrawExpected(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = parseUnits(lpTokenAmount); const _expected = await _calcExpectedAmounts.call(this, _lpTokenAmount); - - return _expected.map((amount: bigint, i: number) => curve.formatUnits(amount, this.underlyingDecimals[i])); + return _expected.map((amount: bigint, i: number) => formatUnits(amount, this.underlyingDecimals[i])); }, } -// @ts-ignore -export const withdrawExpectedLendingOrCryptoMixin: PoolTemplate = { - async withdrawExpected(lpTokenAmount: number | string): Promise { +export const withdrawExpectedLendingOrCryptoMixin = { + async withdrawExpected(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = parseUnits(lpTokenAmount); const _expectedAmounts = await _calcExpectedAmounts.call(this, _lpTokenAmount); - // @ts-ignore const _rates: bigint[] = await this._getRates(); - const _expected = _expectedAmounts.map((_amount: bigint, i: number) => _amount * _rates[i] / curve.parseUnits(String(10**18), 0)); + const _expected = _expectedAmounts.map((_amount: bigint, i: number) => _amount * _rates[i] / parseUnits(String(10**18), 0)); - return _expected.map((amount: bigint, i: number) => curve.formatUnits(amount, this.underlyingDecimals[i])); + return _expected.map((amount: bigint, i: number) => formatUnits(amount, this.underlyingDecimals[i])); }, } -// @ts-ignore -export const withdrawExpectedMetaMixin: PoolTemplate = { - async withdrawExpected(lpTokenAmount: number | string): Promise { +export const withdrawExpectedMetaMixin = { + async withdrawExpected(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = parseUnits(lpTokenAmount); const _expected = await _calcExpectedUnderlyingAmountsMeta.call(this, _lpTokenAmount) - return _expected.map((amount: bigint, i: number) => curve.formatUnits(amount, this.underlyingDecimals[i])); + return _expected.map((amount: bigint, i: number) => formatUnits(amount, this.underlyingDecimals[i])); }, } -// @ts-ignore -export const withdrawWrappedExpectedMixin: PoolTemplate = { - async withdrawWrappedExpected(lpTokenAmount: number | string): Promise { +export const withdrawWrappedExpectedMixin = { + async withdrawWrappedExpected(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = parseUnits(lpTokenAmount); const _expected = await _calcExpectedAmounts.call(this, _lpTokenAmount) - - return _expected.map((amount: bigint, i: number) => curve.formatUnits(amount, this.wrappedDecimals[i])); + return _expected.map((amount: bigint, i: number) => formatUnits(amount, this.wrappedDecimals[i])); }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawImbalanceMixins.ts b/src/pools/mixins/withdrawImbalanceMixins.ts index adcdfbd3..6640509f 100644 --- a/src/pools/mixins/withdrawImbalanceMixins.ts +++ b/src/pools/mixins/withdrawImbalanceMixins.ts @@ -1,8 +1,6 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { _ensureAllowance, fromBN, hasAllowance, toBN, parseUnits, mulBy1_3, smartNumber, DIGas } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import {_ensureAllowance, DIGas, fromBN, hasAllowance, mulBy1_3, parseUnits, smartNumber, toBN} from '../../utils.js'; -// @ts-ignore async function _withdrawImbalanceCheck(this: PoolTemplate, amounts: (number | string)[], estimateGas = false): Promise { const lpTokenAmount = await this.withdrawImbalanceExpected(amounts); const lpTokenBalance = (await this.wallet.lpTokenBalances())['lpToken']; @@ -10,145 +8,112 @@ async function _withdrawImbalanceCheck(this: PoolTemplate, amounts: (number | st throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - if (estimateGas && this.zap && !(await hasAllowance([this.lpToken], [lpTokenAmount], curve.signerAddress, this.zap))) { + if (estimateGas && this.zap && !(await hasAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.curve.signerAddress, this.zap))) { throw Error("Token allowance is needed to estimate gas") } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); return amounts.map((amount, i) => parseUnits(amount, this.underlyingDecimals[i])); } async function _withdrawImbalanceMaxBurnAmount(this: PoolTemplate, _amounts: bigint[], slippage = 0.5): Promise { - // @ts-ignore const _expectedLpTokenAmount = await this._calcLpTokenAmount(_amounts, false); const maxBurnAmountBN = toBN(_expectedLpTokenAmount).times(100 + slippage).div(100); return fromBN(maxBurnAmountBN); } -// @ts-ignore -export const withdrawImbalanceMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _withdrawImbalance(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { +export const withdrawImbalanceMetaFactoryMixin = { + async _withdrawImbalance(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { const _maxBurnAmount = await _withdrawImbalanceMaxBurnAmount.call(this, _amounts, slippage); - if (!estimateGas) await _ensureAllowance([this.lpToken], [_maxBurnAmount], this.zap as string); + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.lpToken], [_maxBurnAmount], this.zap as string); - const contract = curve.contracts[this.zap as string].contract; - const gas = await contract.remove_liquidity_imbalance.estimateGas(this.address, _amounts, _maxBurnAmount, curve.constantOptions); + const contract = this.curve.contracts[this.zap as string].contract; + const gas = await contract.remove_liquidity_imbalance.estimateGas(this.address, _amounts, _maxBurnAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_imbalance(this.address, _amounts, _maxBurnAmount, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity_imbalance(this.address, _amounts, _maxBurnAmount, { ...this.curve.options, gasLimit })).hash; }, - async withdrawImbalanceEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async withdrawImbalanceEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts, true); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, 0.1, true); + return await withdrawImbalanceMetaFactoryMixin._withdrawImbalance.call(this, _amounts, 0.1, true) as number; }, - async withdrawImbalance(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async withdrawImbalance(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, slippage); + return await withdrawImbalanceMetaFactoryMixin._withdrawImbalance.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const withdrawImbalanceZapMixin: PoolTemplate = { - // @ts-ignore - async _withdrawImbalance(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { +export const withdrawImbalanceZapMixin = { + async _withdrawImbalance(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { const _maxBurnAmount = await _withdrawImbalanceMaxBurnAmount.call(this, _amounts, slippage); - if (!estimateGas) await _ensureAllowance([this.lpToken], [_maxBurnAmount], this.zap as string); + if (!estimateGas) await _ensureAllowance.call(this.curve, [this.lpToken], [_maxBurnAmount], this.zap as string); - const contract = curve.contracts[this.zap as string].contract; - const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, curve.constantOptions); + const contract = this.curve.contracts[this.zap as string].contract; + const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, { ...this.curve.options, gasLimit })).hash; }, - async withdrawImbalanceEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async withdrawImbalanceEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts, true); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, 0.1, true); + return await withdrawImbalanceZapMixin._withdrawImbalance.call(this, _amounts, 0.1, true) as number; }, - async withdrawImbalance(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async withdrawImbalance(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, slippage); + return await withdrawImbalanceZapMixin._withdrawImbalance.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const withdrawImbalanceLendingMixin: PoolTemplate = { - // @ts-ignore - async _withdrawImbalance(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { +export const withdrawImbalanceLendingMixin = { + async _withdrawImbalance(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { const _maxBurnAmount = await _withdrawImbalanceMaxBurnAmount.call(this, _amounts, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, true, curve.constantOptions); + const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, true, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); - const gasLimit = curve.chainId === 137 && this.id === 'ren' ? gas * curve.parseUnits("140", 0) / curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, true, { ...curve.options, gasLimit })).hash; + const gasLimit = this.curve.chainId === 137 && this.id === 'ren' ? gas * this.curve.parseUnits("140", 0) / this.curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); + return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, true, { ...this.curve.options, gasLimit })).hash; }, - async withdrawImbalanceEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async withdrawImbalanceEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts, true); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, 0.1, true); + return await withdrawImbalanceLendingMixin._withdrawImbalance.call(this, _amounts, 0.1, true) as number; }, - async withdrawImbalance(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async withdrawImbalance(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, slippage); + return await withdrawImbalanceLendingMixin._withdrawImbalance.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const withdrawImbalancePlainMixin: PoolTemplate = { - // @ts-ignore - async _withdrawImbalance(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { +export const withdrawImbalancePlainMixin = { + async _withdrawImbalance(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { const _maxBurnAmount = await _withdrawImbalanceMaxBurnAmount.call(this, _amounts, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, curve.constantOptions); + const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, { ...this.curve.options, gasLimit })).hash; }, - async withdrawImbalanceEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async withdrawImbalanceEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts, true); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, 0.1, true); + return await withdrawImbalancePlainMixin._withdrawImbalance.call(this, _amounts, 0.1, true) as number; }, - async withdrawImbalance(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async withdrawImbalance(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _withdrawImbalanceCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalance(_amounts, slippage); + return await withdrawImbalancePlainMixin._withdrawImbalance.call(this, _amounts, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawImbalanceWrappedMixins.ts b/src/pools/mixins/withdrawImbalanceWrappedMixins.ts index 995d3e9a..73993db4 100644 --- a/src/pools/mixins/withdrawImbalanceWrappedMixins.ts +++ b/src/pools/mixins/withdrawImbalanceWrappedMixins.ts @@ -1,87 +1,67 @@ -import { ethers } from "ethers"; -import { curve } from "../../curve.js"; import { PoolTemplate } from "../PoolTemplate.js"; import { fromBN, toBN, parseUnits, mulBy1_3, smartNumber, DIGas } from '../../utils.js'; -// @ts-ignore -async function _withdrawImbalanceWrappedCheck(this: PoolTemplate, amounts: (number | string)[]): Promise { +async function _withdrawImbalanceWrappedCheck(this: PoolTemplate, amounts: (number | string)[]): Promise { const lpTokenAmount = await this.withdrawImbalanceWrappedExpected(amounts); const lpTokenBalance = (await this.wallet.lpTokenBalances())['lpToken']; if (Number(lpTokenBalance) < Number(lpTokenAmount)) { throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - await curve.updateFeeData(); + await this.curve.updateFeeData(); return amounts.map((amount, i) => parseUnits(amount, this.wrappedDecimals[i])); } async function _withdrawImbalanceWrappedMaxBurnAmount(this: PoolTemplate, _amounts: bigint[], slippage = 0.5): Promise { - // @ts-ignore const _expectedLpTokenAmount = await this._calcLpTokenAmount(_amounts, false, false); const maxBurnAmountBN = toBN(_expectedLpTokenAmount).times(100 + slippage).div(100); return fromBN(maxBurnAmountBN); } -// @ts-ignore -export const withdrawImbalanceWrapped2argsMixin: PoolTemplate = { - // @ts-ignore - async _withdrawImbalanceWrapped(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { +export const withdrawImbalanceWrapped2argsMixin = { + async _withdrawImbalanceWrapped(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { const _maxBurnAmount = await _withdrawImbalanceWrappedMaxBurnAmount.call(this, _amounts, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, curve.constantOptions); + const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, { ...this.curve.options, gasLimit })).hash; }, - async withdrawImbalanceWrappedEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async withdrawImbalanceWrappedEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _withdrawImbalanceWrappedCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalanceWrapped(_amounts, 0.1, true); + return await withdrawImbalanceWrapped2argsMixin._withdrawImbalanceWrapped.call(this, _amounts, 0.1, true) as number; }, - async withdrawImbalanceWrapped(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async withdrawImbalanceWrapped(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _withdrawImbalanceWrappedCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalanceWrapped(_amounts, slippage); + return await withdrawImbalanceWrapped2argsMixin._withdrawImbalanceWrapped.call(this, _amounts, slippage) as string; }, } -// @ts-ignore -export const withdrawImbalanceWrapped3argsMixin: PoolTemplate = { - // @ts-ignore - async _withdrawImbalanceWrapped(_amounts: bigint[], slippage?: number, estimateGas = false): Promise { +export const withdrawImbalanceWrapped3argsMixin = { + async _withdrawImbalanceWrapped(this: PoolTemplate, _amounts: bigint[], slippage?: number, estimateGas = false): Promise { const _maxBurnAmount = await _withdrawImbalanceWrappedMaxBurnAmount.call(this, _amounts, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, false, curve.constantOptions); + const gas = await contract.remove_liquidity_imbalance.estimateGas(_amounts, _maxBurnAmount, false, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); - const gasLimit = curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * curve.parseUnits("140", 0) / curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, false, { ...curve.options, gasLimit })).hash; + const gasLimit = this.curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * this.curve.parseUnits("140", 0) / this.curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); + return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, false, { ...this.curve.options, gasLimit })).hash; }, - async withdrawImbalanceWrappedEstimateGas(amounts: (number | string)[]): Promise { - // @ts-ignore + async withdrawImbalanceWrappedEstimateGas(this: PoolTemplate, amounts: (number | string)[]): Promise { const _amounts = await _withdrawImbalanceWrappedCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalanceWrapped(_amounts, 0.1, true); + return await withdrawImbalanceWrapped3argsMixin._withdrawImbalanceWrapped.call(this, _amounts, 0.1, true) as number; }, - async withdrawImbalanceWrapped(amounts: (number | string)[], slippage?: number): Promise { - // @ts-ignore + async withdrawImbalanceWrapped(this: PoolTemplate, amounts: (number | string)[], slippage?: number): Promise { const _amounts = await _withdrawImbalanceWrappedCheck.call(this, amounts); - - // @ts-ignore - return await this._withdrawImbalanceWrapped(_amounts, slippage); + return await withdrawImbalanceWrapped3argsMixin._withdrawImbalanceWrapped.call(this, _amounts, slippage) as string; }, } diff --git a/src/pools/mixins/withdrawMixins.ts b/src/pools/mixins/withdrawMixins.ts index c8e8d7ab..489bf77a 100644 --- a/src/pools/mixins/withdrawMixins.ts +++ b/src/pools/mixins/withdrawMixins.ts @@ -1,192 +1,150 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { _ensureAllowance, fromBN, hasAllowance, toBN, parseUnits, mulBy1_3, smartNumber, DIGas } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import {_ensureAllowance, DIGas, fromBN, hasAllowance, mulBy1_3, parseUnits, smartNumber, toBN} from '../../utils.js'; -// @ts-ignore async function _withdrawCheck(this: PoolTemplate, lpTokenAmount: number | string, estimateGas = false): Promise { const lpTokenBalance = (await this.wallet.lpTokenBalances())['lpToken']; if (Number(lpTokenBalance) < Number(lpTokenAmount)) { throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - if (estimateGas && this.zap && !(await hasAllowance([this.lpToken], [lpTokenAmount], curve.signerAddress, this.zap))) { + if (estimateGas && this.zap && !(await hasAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.curve.signerAddress, this.zap))) { throw Error("Token allowance is needed to estimate gas") } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); return parseUnits(lpTokenAmount); } async function _withdrawMinAmounts(this: PoolTemplate, _lpTokenAmount: bigint, slippage = 0.5): Promise { - const expectedAmounts = await this.withdrawExpected(curve.formatUnits(_lpTokenAmount)); - const _expectedAmounts = expectedAmounts.map((a, i) => curve.parseUnits(a, this.underlyingDecimals[i])); + const expectedAmounts = await this.withdrawExpected(this.curve.formatUnits(_lpTokenAmount)); + const _expectedAmounts = expectedAmounts.map((a, i) => this.curve.parseUnits(a, this.underlyingDecimals[i])); const minRecvAmountsBN = _expectedAmounts.map((_a, i) => toBN(_a, this.underlyingDecimals[i]).times(100 - slippage).div(100)); return minRecvAmountsBN.map((a, i) => fromBN(a, this.underlyingDecimals[i])); } -// @ts-ignore -export const withdrawMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _withdraw(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); +export const withdrawMetaFactoryMixin = { + async _withdraw(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.bind(this.curve, [this.lpToken], [_lpTokenAmount], this.zap as string); const _minAmounts = await _withdrawMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.zap as string].contract; + const contract = this.curve.contracts[this.zap as string].contract; - const gas = await contract.remove_liquidity.estimateGas(this.address, _lpTokenAmount, _minAmounts, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(this.address, _lpTokenAmount, _minAmounts, this.curve.constantOptions); if (estimateGas) return smartNumber(gas) const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(this.address, _lpTokenAmount, _minAmounts, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(this.address, _lpTokenAmount, _minAmounts, { ...this.curve.options, gasLimit })).hash; }, - async withdrawEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount, true); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, 0.1, true); + return await withdrawMetaFactoryMixin._withdraw.call(this, _lpTokenAmount, 0.1, true) as number | number[]; }, - async withdraw(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdraw(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, slippage); + return await withdrawMetaFactoryMixin._withdraw.call(this, _lpTokenAmount, slippage) as string; }, } -// @ts-ignore -export const withdrawCryptoMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _withdraw(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); +export const withdrawCryptoMetaFactoryMixin = { + async _withdraw(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.bind(this.curve, [this.lpToken], [_lpTokenAmount], this.zap as string); const _minAmounts = await _withdrawMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.zap as string].contract; + const contract = this.curve.contracts[this.zap as string].contract; - const gas = await contract.remove_liquidity.estimateGas(this.address, _lpTokenAmount, _minAmounts, true, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(this.address, _lpTokenAmount, _minAmounts, true, this.curve.constantOptions); if (estimateGas) return smartNumber(gas) const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(this.address, _lpTokenAmount, _minAmounts, true, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(this.address, _lpTokenAmount, _minAmounts, true, { ...this.curve.options, gasLimit })).hash; }, - async withdrawEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount, true); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, 0.1, true); + return await withdrawCryptoMetaFactoryMixin._withdraw.call(this, _lpTokenAmount, 0.1, true) as number | number[]; }, - async withdraw(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdraw(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, slippage); + return await withdrawCryptoMetaFactoryMixin._withdraw.call(this, _lpTokenAmount, slippage) as string; }, } -// @ts-ignore -export const withdrawZapMixin: PoolTemplate = { - // @ts-ignore - async _withdraw(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); +export const withdrawZapMixin = { + async _withdraw(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.bind(this.curve, [this.lpToken], [_lpTokenAmount], this.zap as string); - // @ts-ignore const _minAmounts = await _withdrawMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.zap as string].contract; + const contract = this.curve.contracts[this.zap as string].contract; const args: any[] = [_lpTokenAmount, _minAmounts]; if (`remove_liquidity(uint256,uint256[${this.underlyingCoinAddresses.length}],bool)` in contract) args.push(true); - const gas = await contract.remove_liquidity.estimateGas(...args, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(...args, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(...args, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(...args, { ...this.curve.options, gasLimit })).hash; }, - async withdrawEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount, true); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, 0.1, true); + return await withdrawZapMixin._withdraw.call(this, _lpTokenAmount, 0.1, true) as number | number[]; }, - async withdraw(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdraw(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, slippage); + return await withdrawZapMixin._withdraw.call(this, _lpTokenAmount, slippage) as string; }, } -// @ts-ignore -export const withdrawLendingOrCryptoMixin: PoolTemplate = { - // @ts-ignore - async _withdraw(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { +export const withdrawLendingOrCryptoMixin = { + async _withdraw(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { const _minAmounts = await _withdrawMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, true, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, true, this.curve.constantOptions); if (estimateGas) return smartNumber(gas) const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, true, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, true, { ...this.curve.options, gasLimit })).hash; }, - async withdrawEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount, true); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, 0.1, true); + return await withdrawLendingOrCryptoMixin._withdraw.call(this, _lpTokenAmount, 0.1, true) as number | number[]; }, - async withdraw(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdraw(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdraw(_lpTokenAmount, slippage); + return await withdrawLendingOrCryptoMixin._withdraw.call(this, _lpTokenAmount, slippage) as string; }, } -// @ts-ignore -export const withdrawPlainMixin: PoolTemplate = { - // @ts-ignore - async _withdraw(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { - // @ts-ignore +export const withdrawPlainMixin = { + async _withdraw(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { const _minAmounts = await _withdrawMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, { ...this.curve.options, gasLimit })).hash; }, - async withdrawEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount, true); - // @ts-ignore - return await this._withdraw(_lpTokenAmount, 0.1, true); + return await withdrawPlainMixin._withdraw.call(this, _lpTokenAmount, 0.1, true) as number | number[]; }, - async withdraw(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdraw(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawCheck.call(this, lpTokenAmount); - // @ts-ignore - return await this._withdraw(_lpTokenAmount, slippage); + return await withdrawPlainMixin._withdraw.call(this, _lpTokenAmount, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawOneCoinExpectedMixins.ts b/src/pools/mixins/withdrawOneCoinExpectedMixins.ts index b94009a4..53e7e310 100644 --- a/src/pools/mixins/withdrawOneCoinExpectedMixins.ts +++ b/src/pools/mixins/withdrawOneCoinExpectedMixins.ts @@ -1,34 +1,29 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; +import {PoolTemplate} from "../PoolTemplate.js"; -// @ts-ignore -export const withdrawOneCoinExpectedMetaFactoryMixin: PoolTemplate = { - async _withdrawOneCoinExpected(_lpTokenAmount: bigint, i: number): Promise { - const contract = curve.contracts[this.zap as string].contract; - return await contract.calc_withdraw_one_coin(this.address, _lpTokenAmount, i, curve.constantOptions); +export const withdrawOneCoinExpectedMetaFactoryMixin = { + async _withdrawOneCoinExpected(this: PoolTemplate,_lpTokenAmount: bigint, i: number): Promise { + const contract = this.curve.contracts[this.zap as string].contract; + return await contract.calc_withdraw_one_coin(this.address, _lpTokenAmount, i, this.curve.constantOptions); }, } -// @ts-ignore -export const withdrawOneCoinExpectedZapMixin: PoolTemplate = { - async _withdrawOneCoinExpected(_lpTokenAmount: bigint, i: number): Promise { - const contract = curve.contracts[this.zap as string].contract; - return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, curve.constantOptions); +export const withdrawOneCoinExpectedZapMixin = { + async _withdrawOneCoinExpected(this: PoolTemplate,_lpTokenAmount: bigint, i: number): Promise { + const contract = this.curve.contracts[this.zap as string].contract; + return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, this.curve.constantOptions); }, } -// @ts-ignore -export const withdrawOneCoinExpected3argsMixin: PoolTemplate = { - async _withdrawOneCoinExpected(_lpTokenAmount: bigint, i: number): Promise { - const contract = curve.contracts[this.address].contract; - return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, true, curve.constantOptions); +export const withdrawOneCoinExpected3argsMixin = { + async _withdrawOneCoinExpected(this: PoolTemplate,_lpTokenAmount: bigint, i: number): Promise { + const contract = this.curve.contracts[this.address].contract; + return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, true, this.curve.constantOptions); }, } -// @ts-ignore -export const withdrawOneCoinExpected2argsMixin: PoolTemplate = { - async _withdrawOneCoinExpected(_lpTokenAmount: bigint, i: number): Promise { - const contract = curve.contracts[this.address].contract; - return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, curve.constantOptions); +export const withdrawOneCoinExpected2argsMixin = { + async _withdrawOneCoinExpected(this: PoolTemplate,_lpTokenAmount: bigint, i: number): Promise { + const contract = this.curve.contracts[this.address].contract; + return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, this.curve.constantOptions); }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawOneCoinMixins.ts b/src/pools/mixins/withdrawOneCoinMixins.ts index 21153c48..e3f8de02 100644 --- a/src/pools/mixins/withdrawOneCoinMixins.ts +++ b/src/pools/mixins/withdrawOneCoinMixins.ts @@ -1,9 +1,6 @@ -import { ethers } from "ethers"; -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { _ensureAllowance, fromBN, hasAllowance, toBN, parseUnits, mulBy1_3, smartNumber, DIGas } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import {_ensureAllowance, DIGas, fromBN, hasAllowance, mulBy1_3, parseUnits, smartNumber, toBN} from '../../utils.js'; -// @ts-ignore async function _withdrawOneCoinCheck(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, estimateGas = false): Promise<[bigint, number]> { @@ -12,13 +9,12 @@ async function _withdrawOneCoinCheck(this: PoolTemplate, lpTokenAmount: number | throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - if (estimateGas && this.zap && !(await hasAllowance([this.lpToken], [lpTokenAmount], curve.signerAddress, this.zap))) { + if (estimateGas && this.zap && !(await hasAllowance.call(this.curve, [this.lpToken], [lpTokenAmount], this.curve.signerAddress, this.zap))) { throw Error("Token allowance is needed to estimate gas"); } - if (!estimateGas) await curve.updateFeeData(); + if (!estimateGas) await this.curve.updateFeeData(); - // @ts-ignore const i = this._getCoinIdx(coin); const _lpTokenAmount = parseUnits(lpTokenAmount); @@ -26,172 +22,130 @@ async function _withdrawOneCoinCheck(this: PoolTemplate, lpTokenAmount: number | } async function _withdrawOneCoinMinAmount(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage = 0.5): Promise { - // @ts-ignore const _expectedLpTokenAmount = await this._withdrawOneCoinExpected(_lpTokenAmount, i); const minAmountBN = toBN(_expectedLpTokenAmount).times(100 - slippage).div(100); - return fromBN(minAmountBN); } -// @ts-ignore -export const withdrawOneCoinMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoin(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); +export const withdrawOneCoinMetaFactoryMixin = { + async _withdrawOneCoin(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.bind(this.curve, [this.lpToken], [_lpTokenAmount], this.zap as string); const _minAmount = await _withdrawOneCoinMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.zap as string].contract; + const contract = this.curve.contracts[this.zap as string].contract; - const gas = await contract.remove_liquidity_one_coin.estimateGas(this.address, _lpTokenAmount, i, _minAmount, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(this.address, _lpTokenAmount, i, _minAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas) const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(this.address, _lpTokenAmount, i, _minAmount, { ...curve.options, gasLimit })).hash + return (await contract.remove_liquidity_one_coin(this.address, _lpTokenAmount, i, _minAmount, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin, true); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinMetaFactoryMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, 0.1, true) as number | number[]; }, - async withdrawOneCoin(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoin(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, slippage); + return await withdrawOneCoinMetaFactoryMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, slippage) as string; }, } -// @ts-ignore -export const withdrawOneCoinCryptoMetaFactoryMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoin(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); +export const withdrawOneCoinCryptoMetaFactoryMixin = { + async _withdrawOneCoin(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.bind(this.curve, [this.lpToken], [_lpTokenAmount], this.zap as string); const _minAmount = await _withdrawOneCoinMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.zap as string].contract; + const contract = this.curve.contracts[this.zap as string].contract; - const gas = await contract.remove_liquidity_one_coin.estimateGas(this.address, _lpTokenAmount, i, _minAmount, true, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(this.address, _lpTokenAmount, i, _minAmount, true, this.curve.constantOptions); if (estimateGas) return smartNumber(gas) const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(this.address, _lpTokenAmount, i, _minAmount, true, { ...curve.options, gasLimit })).hash + return (await contract.remove_liquidity_one_coin(this.address, _lpTokenAmount, i, _minAmount, true, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin, true); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinCryptoMetaFactoryMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, 0.1, true) as number | number[]; }, - async withdrawOneCoin(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoin(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, slippage); + return await withdrawOneCoinCryptoMetaFactoryMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, slippage) as string; }, } -// @ts-ignore -export const withdrawOneCoinZapMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoin(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { - if (!estimateGas) await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); +export const withdrawOneCoinZapMixin = { + async _withdrawOneCoin(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { + if (!estimateGas) await _ensureAllowance.bind(this.curve, [this.lpToken], [_lpTokenAmount], this.zap as string); const _minAmount = await _withdrawOneCoinMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.zap as string].contract; + const contract = this.curve.contracts[this.zap as string].contract; const args: any[] = [_lpTokenAmount, i, _minAmount]; if (`remove_liquidity_one_coin(uint256,uint256,uint256,bool)` in contract) args.push(true); - const gas = await contract.remove_liquidity_one_coin.estimateGas(...args, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(...args, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(...args, { ...curve.options, gasLimit })).hash + return (await contract.remove_liquidity_one_coin(...args, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin, true); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinZapMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, 0.1, true) as number | number[]; }, - async withdrawOneCoin(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoin(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, slippage); + return await withdrawOneCoinZapMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, slippage) as string; }, } -// @ts-ignore -export const withdrawOneCoinLendingOrCryptoMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoin(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { +export const withdrawOneCoinLendingOrCryptoMixin = { + async _withdrawOneCoin(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { const _minAmount = await _withdrawOneCoinMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, true, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, true, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); - const gasLimit = curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * curve.parseUnits("160", 0) / curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, true, { ...curve.options, gasLimit })).hash + const gasLimit = this.curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * this.curve.parseUnits("160", 0) / this.curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); + return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, true, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin, true); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinLendingOrCryptoMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, 0.1, true) as number | number[]; }, - async withdrawOneCoin(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoin(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, slippage); + return await withdrawOneCoinLendingOrCryptoMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, slippage) as string; }, } -// @ts-ignore -export const withdrawOneCoinPlainMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoin(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { +export const withdrawOneCoinPlainMixin = { + async _withdrawOneCoin(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { const _minAmount = await _withdrawOneCoinMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, { ...curve.options, gasLimit })).hash + return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin, true); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinPlainMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, 0.1, true) as number | number[]; }, - async withdrawOneCoin(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoin(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoin(_lpTokenAmount, i, slippage); + return await withdrawOneCoinPlainMixin._withdrawOneCoin.call(this, _lpTokenAmount, i, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawOneCoinWrappedExpectedMixins.ts b/src/pools/mixins/withdrawOneCoinWrappedExpectedMixins.ts index afea7bf9..79e52d6a 100644 --- a/src/pools/mixins/withdrawOneCoinWrappedExpectedMixins.ts +++ b/src/pools/mixins/withdrawOneCoinWrappedExpectedMixins.ts @@ -1,18 +1,15 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; +import {PoolTemplate} from "../PoolTemplate.js"; -// @ts-ignore -export const withdrawOneCoinWrappedExpected2argsMixin: PoolTemplate = { - async _withdrawOneCoinWrappedExpected(_lpTokenAmount: bigint, i: number): Promise { - const contract = curve.contracts[this.address].contract; - return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, curve.constantOptions); +export const withdrawOneCoinWrappedExpected2argsMixin = { + async _withdrawOneCoinWrappedExpected(this: PoolTemplate, _lpTokenAmount: bigint, i: number): Promise { + const contract = this.curve.contracts[this.address].contract; + return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, this.curve.constantOptions); }, } -// @ts-ignore -export const withdrawOneCoinWrappedExpected3argsMixin: PoolTemplate = { - async _withdrawOneCoinWrappedExpected(_lpTokenAmount: bigint, i: number): Promise { - const contract = curve.contracts[this.address].contract; - return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, false, curve.constantOptions); +export const withdrawOneCoinWrappedExpected3argsMixin = { + async _withdrawOneCoinWrappedExpected(this: PoolTemplate, _lpTokenAmount: bigint, i: number): Promise { + const contract = this.curve.contracts[this.address].contract; + return await contract.calc_withdraw_one_coin(_lpTokenAmount, i, false, this.curve.constantOptions); }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawOneCoinWrappedMixins.ts b/src/pools/mixins/withdrawOneCoinWrappedMixins.ts index 46ac3abb..1bf4be3c 100644 --- a/src/pools/mixins/withdrawOneCoinWrappedMixins.ts +++ b/src/pools/mixins/withdrawOneCoinWrappedMixins.ts @@ -1,8 +1,6 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { fromBN, toBN, parseUnits, mulBy1_3, smartNumber, DIGas } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import {DIGas, fromBN, mulBy1_3, parseUnits, smartNumber, toBN} from '../../utils.js'; -// @ts-ignore async function _withdrawOneCoinWrappedCheck(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise<[bigint, number]> { @@ -11,9 +9,8 @@ async function _withdrawOneCoinWrappedCheck(this: PoolTemplate, lpTokenAmount: n throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - await curve.updateFeeData(); + await this.curve.updateFeeData(); - // @ts-ignore const i = this._getCoinIdx(coin, false); const _lpTokenAmount = parseUnits(lpTokenAmount); @@ -21,71 +18,54 @@ async function _withdrawOneCoinWrappedCheck(this: PoolTemplate, lpTokenAmount: n } async function _withdrawOneCoinWrappedMinAmount(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage = 0.5): Promise { - // @ts-ignore const _expectedLpTokenAmount = await this._withdrawOneCoinWrappedExpected(_lpTokenAmount, i); const minAmountBN = toBN(_expectedLpTokenAmount).times(100 - slippage).div(100); return fromBN(minAmountBN); } -// @ts-ignore -export const withdrawOneCoinWrappedLendingOrCryptoMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoinWrapped(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { +export const withdrawOneCoinWrappedLendingOrCryptoMixin = { + async _withdrawOneCoinWrapped(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { const _minAmount = await _withdrawOneCoinWrappedMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, false, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, false, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); - const gasLimit = curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * curve.parseUnits("160", 0) / curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, false, { ...curve.options, gasLimit })).hash + const gasLimit = this.curve.chainId === 137 && this.id === 'ren' ? DIGas(gas) * this.curve.parseUnits("160", 0) / this.curve.parseUnits("100", 0) : mulBy1_3(DIGas(gas)); + return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, false, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinWrappedEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinWrappedEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinWrappedCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoinWrapped(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinWrappedLendingOrCryptoMixin._withdrawOneCoinWrapped.call(this, _lpTokenAmount, i, 0.1, true) as number; }, - async withdrawOneCoinWrapped(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoinWrapped(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinWrappedCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoinWrapped(_lpTokenAmount, i, slippage); + return await withdrawOneCoinWrappedLendingOrCryptoMixin._withdrawOneCoinWrapped.call(this, _lpTokenAmount, i, slippage) as string; }, } -// @ts-ignore -export const withdrawOneCoinWrappedMixin: PoolTemplate = { - // @ts-ignore - async _withdrawOneCoinWrapped(_lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { +export const withdrawOneCoinWrappedMixin = { + async _withdrawOneCoinWrapped(this: PoolTemplate, _lpTokenAmount: bigint, i: number, slippage?: number, estimateGas = false): Promise { const _minAmount = await _withdrawOneCoinWrappedMinAmount.call(this, _lpTokenAmount, i, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, curve.constantOptions); + const gas = await contract.remove_liquidity_one_coin.estimateGas(_lpTokenAmount, i, _minAmount, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, { ...curve.options, gasLimit })).hash + return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, { ...this.curve.options, gasLimit })).hash }, - async withdrawOneCoinWrappedEstimateGas(lpTokenAmount: number | string, coin: string | number): Promise { - // @ts-ignore + async withdrawOneCoinWrappedEstimateGas(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinWrappedCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoinWrapped(_lpTokenAmount, i, 0.1, true); + return await withdrawOneCoinWrappedMixin._withdrawOneCoinWrapped.call(this, _lpTokenAmount, i, 0.1, true) as number; }, - async withdrawOneCoinWrapped(lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { - // @ts-ignore + async withdrawOneCoinWrapped(this: PoolTemplate, lpTokenAmount: number | string, coin: string | number, slippage?: number): Promise { const [_lpTokenAmount, i] = await _withdrawOneCoinWrappedCheck.call(this, lpTokenAmount, coin); - - // @ts-ignore - return await this._withdrawOneCoinWrapped(_lpTokenAmount, i, slippage); + return await withdrawOneCoinWrappedMixin._withdrawOneCoinWrapped.call(this, _lpTokenAmount, i, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/mixins/withdrawWrappedMixins.ts b/src/pools/mixins/withdrawWrappedMixins.ts index eeeb294d..989dd45c 100644 --- a/src/pools/mixins/withdrawWrappedMixins.ts +++ b/src/pools/mixins/withdrawWrappedMixins.ts @@ -1,85 +1,67 @@ -import { curve } from "../../curve.js"; -import { PoolTemplate } from "../PoolTemplate.js"; -import { fromBN, toBN, parseUnits, mulBy1_3, smartNumber, DIGas } from '../../utils.js'; +import {PoolTemplate} from "../PoolTemplate.js"; +import {DIGas, fromBN, mulBy1_3, parseUnits, smartNumber, toBN} from '../../utils.js'; -// @ts-ignore async function _withdrawWrappedCheck(this: PoolTemplate, lpTokenAmount: number | string): Promise { const lpTokenBalance = (await this.wallet.lpTokenBalances())['lpToken']; if (Number(lpTokenBalance) < Number(lpTokenAmount)) { throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - await curve.updateFeeData(); + await this.curve.updateFeeData(); return parseUnits(lpTokenAmount); } async function _withdrawWrappedMinAmounts(this: PoolTemplate, _lpTokenAmount: bigint, slippage = 0.5): Promise { - const expectedAmounts = await this.withdrawWrappedExpected(curve.formatUnits(_lpTokenAmount)); - const _expectedAmounts = expectedAmounts.map((a, i) => curve.parseUnits(a, this.wrappedDecimals[i])); + const expectedAmounts = await this.withdrawWrappedExpected(this.curve.formatUnits(_lpTokenAmount)); + const _expectedAmounts = expectedAmounts.map((a, i) => this.curve.parseUnits(a, this.wrappedDecimals[i])); const minRecvAmountsBN = _expectedAmounts.map((_a, i) => toBN(_a, this.wrappedDecimals[i]).times(100 - slippage).div(100)); return minRecvAmountsBN.map((a, i) => fromBN(a, this.wrappedDecimals[i])); } -// @ts-ignore -export const withdrawWrapped2argsMixin: PoolTemplate = { - // @ts-ignore - async _withdrawWrapped(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { +export const withdrawWrapped2argsMixin = { + async _withdrawWrapped(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { const _minAmounts = await _withdrawWrappedMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, { ...this.curve.options, gasLimit })).hash; }, - async withdrawWrappedEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawWrappedEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawWrappedCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdrawWrapped(_lpTokenAmount, 0.1, true); + return await withdrawWrapped2argsMixin._withdrawWrapped.call(this, _lpTokenAmount, 0.1, true) as number; }, - async withdrawWrapped(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdrawWrapped(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawWrappedCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdrawWrapped(_lpTokenAmount, slippage); + return await withdrawWrapped2argsMixin._withdrawWrapped.call(this, _lpTokenAmount, slippage) as string; }, } -// @ts-ignore -export const withdrawWrapped3argsMixin: PoolTemplate = { - // @ts-ignore - async _withdrawWrapped(_lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { +export const withdrawWrapped3argsMixin = { + async _withdrawWrapped(this: PoolTemplate, _lpTokenAmount: bigint, slippage?: number, estimateGas = false): Promise { const _minAmounts = await _withdrawWrappedMinAmounts.call(this, _lpTokenAmount, slippage); - const contract = curve.contracts[this.address].contract; + const contract = this.curve.contracts[this.address].contract; - const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, false, curve.constantOptions); + const gas = await contract.remove_liquidity.estimateGas(_lpTokenAmount, _minAmounts, false, this.curve.constantOptions); if (estimateGas) return smartNumber(gas); const gasLimit = mulBy1_3(DIGas(gas)); - return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, false, { ...curve.options, gasLimit })).hash; + return (await contract.remove_liquidity(_lpTokenAmount, _minAmounts, false, { ...this.curve.options, gasLimit })).hash; }, - async withdrawWrappedEstimateGas(lpTokenAmount: number | string): Promise { - // @ts-ignore + async withdrawWrappedEstimateGas(this: PoolTemplate, lpTokenAmount: number | string): Promise { const _lpTokenAmount = await _withdrawWrappedCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdrawWrapped(_lpTokenAmount, 0.1, true); + return await withdrawWrapped3argsMixin._withdrawWrapped.call(this, _lpTokenAmount, 0.1, true) as number; }, - async withdrawWrapped(lpTokenAmount: number | string, slippage?: number): Promise { - // @ts-ignore + async withdrawWrapped(this: PoolTemplate, lpTokenAmount: number | string, slippage?: number): Promise { const _lpTokenAmount = await _withdrawWrappedCheck.call(this, lpTokenAmount); - - // @ts-ignore - return await this._withdrawWrapped(_lpTokenAmount, slippage); + return await withdrawWrapped3argsMixin._withdrawWrapped.call(this, _lpTokenAmount, slippage) as string; }, } \ No newline at end of file diff --git a/src/pools/poolConstructor.ts b/src/pools/poolConstructor.ts index 144cdb96..8050f27c 100644 --- a/src/pools/poolConstructor.ts +++ b/src/pools/poolConstructor.ts @@ -1,38 +1,85 @@ -import { curve } from "../curve.js"; -import { PoolTemplate } from "./PoolTemplate.js"; -import { poolBalancesMetaMixin, poolBalancesLendingMixin } from "./mixins/poolBalancesMixin.js"; -import { depositBalancedAmountsMixin, depositBalancedAmountsCryptoMixin, depositWrappedBalancedAmountsMixin, depositWrappedBalancedAmountsCryptoMixin } from "./mixins/depositBalancedAmountsMixins.js"; -import { depositMetaFactoryMixin, depositCryptoMetaFactoryMixin, depositZapMixin, depositLendingOrCryptoMixin, depositPlainMixin } from "./mixins/depositMixins.js"; -import { depositWrapped2argsMixin, depositWrapped3argsMixin } from "./mixins/depositWrappedMixins.js"; -import { withdrawExpectedMixin, withdrawExpectedLendingOrCryptoMixin, withdrawExpectedMetaMixin, withdrawWrappedExpectedMixin } from "./mixins/withdrawExpectedMixins.js"; -import { withdrawMetaFactoryMixin, withdrawCryptoMetaFactoryMixin, withdrawZapMixin, withdrawLendingOrCryptoMixin, withdrawPlainMixin } from "./mixins/withdrawMixins.js"; -import { withdrawWrapped2argsMixin, withdrawWrapped3argsMixin } from "./mixins/withdrawWrappedMixins.js"; -import { withdrawImbalanceMetaFactoryMixin, withdrawImbalanceZapMixin, withdrawImbalanceLendingMixin, withdrawImbalancePlainMixin } from "./mixins/withdrawImbalanceMixins.js"; -import { withdrawImbalanceWrapped2argsMixin, withdrawImbalanceWrapped3argsMixin } from "./mixins/withdrawImbalanceWrappedMixins.js"; -import { withdrawOneCoinExpectedMetaFactoryMixin, withdrawOneCoinExpectedZapMixin, withdrawOneCoinExpected3argsMixin, withdrawOneCoinExpected2argsMixin } from "./mixins/withdrawOneCoinExpectedMixins.js"; -import { withdrawOneCoinMetaFactoryMixin, withdrawOneCoinCryptoMetaFactoryMixin, withdrawOneCoinZapMixin, withdrawOneCoinLendingOrCryptoMixin, withdrawOneCoinPlainMixin } from "./mixins/withdrawOneCoinMixins.js"; -import { withdrawOneCoinWrappedExpected2argsMixin, withdrawOneCoinWrappedExpected3argsMixin } from "./mixins/withdrawOneCoinWrappedExpectedMixins.js"; -import { withdrawOneCoinWrappedLendingOrCryptoMixin, withdrawOneCoinWrappedMixin } from "./mixins/withdrawOneCoinWrappedMixins.js"; -import { swapTricrypto2Mixin, swapMetaFactoryMixin, swapCryptoMetaFactoryMixin, swapMixin } from "./mixins/swapMixins.js"; +import {type Curve} from "../curve.js"; +import {PoolTemplate} from "./PoolTemplate.js"; +import {poolBalancesLendingMixin, poolBalancesMetaMixin} from "./mixins/poolBalancesMixin.js"; +import { + depositBalancedAmountsCryptoMixin, + depositBalancedAmountsMixin, + depositWrappedBalancedAmountsCryptoMixin, + depositWrappedBalancedAmountsMixin, +} from "./mixins/depositBalancedAmountsMixins.js"; +import { + depositCryptoMetaFactoryMixin, + depositLendingOrCryptoMixin, + depositMetaFactoryMixin, + depositPlainMixin, + depositZapMixin, +} from "./mixins/depositMixins.js"; +import {depositWrapped2argsMixin, depositWrapped3argsMixin} from "./mixins/depositWrappedMixins.js"; +import { + withdrawExpectedLendingOrCryptoMixin, + withdrawExpectedMetaMixin, + withdrawExpectedMixin, + withdrawWrappedExpectedMixin, +} from "./mixins/withdrawExpectedMixins.js"; +import { + withdrawCryptoMetaFactoryMixin, + withdrawLendingOrCryptoMixin, + withdrawMetaFactoryMixin, + withdrawPlainMixin, + withdrawZapMixin, +} from "./mixins/withdrawMixins.js"; +import {withdrawWrapped2argsMixin, withdrawWrapped3argsMixin} from "./mixins/withdrawWrappedMixins.js"; +import { + withdrawImbalanceLendingMixin, + withdrawImbalanceMetaFactoryMixin, + withdrawImbalancePlainMixin, + withdrawImbalanceZapMixin, +} from "./mixins/withdrawImbalanceMixins.js"; +import { + withdrawImbalanceWrapped2argsMixin, + withdrawImbalanceWrapped3argsMixin, +} from "./mixins/withdrawImbalanceWrappedMixins.js"; +import { + withdrawOneCoinExpected2argsMixin, + withdrawOneCoinExpected3argsMixin, + withdrawOneCoinExpectedMetaFactoryMixin, + withdrawOneCoinExpectedZapMixin, +} from "./mixins/withdrawOneCoinExpectedMixins.js"; +import { + withdrawOneCoinCryptoMetaFactoryMixin, + withdrawOneCoinLendingOrCryptoMixin, + withdrawOneCoinMetaFactoryMixin, + withdrawOneCoinPlainMixin, + withdrawOneCoinZapMixin, +} from "./mixins/withdrawOneCoinMixins.js"; +import { + withdrawOneCoinWrappedExpected2argsMixin, + withdrawOneCoinWrappedExpected3argsMixin, +} from "./mixins/withdrawOneCoinWrappedExpectedMixins.js"; +import { + withdrawOneCoinWrappedLendingOrCryptoMixin, + withdrawOneCoinWrappedMixin, +} from "./mixins/withdrawOneCoinWrappedMixins.js"; +import {swapCryptoMetaFactoryMixin, swapMetaFactoryMixin, swapMixin, swapTricrypto2Mixin} from "./mixins/swapMixins.js"; import { swapWrappedExpectedAndApproveMixin, - swapWrappedTricrypto2Mixin, swapWrappedMixin, swapWrappedRequiredMixin, + swapWrappedTricrypto2Mixin, } from "./mixins/swapWrappedMixins.js"; -import { getCountArgsOfMethodByAbi, findAbiSignature } from "../utils.js"; +import {findAbiSignature, getCountArgsOfMethodByAbi} from "../utils.js"; import {StatsPool} from "./subClasses/statsPool.js"; -export const getPool = (poolId: string): PoolTemplate => { - const poolDummy = new PoolTemplate(poolId); +export function getPool(this: Curve, poolId: string): PoolTemplate { + const poolDummy = new PoolTemplate(poolId, this); + class Pool extends PoolTemplate { stats: StatsPool; - constructor(poolId: string) { - super(poolId); + constructor(poolId: string, curve: Curve) { + super(poolId, curve); this.stats = new StatsPool(this); - this.configureStats(poolDummy); } @@ -70,7 +117,7 @@ export const getPool = (poolId: string): PoolTemplate => { } } else if (poolDummy.zap && poolId !== 'susd') { Object.assign(Pool.prototype, depositZapMixin); - } else if (getCountArgsOfMethodByAbi(curve.contracts[poolDummy.address].abi, 'add_liquidity') > 2) { + } else if (getCountArgsOfMethodByAbi(this.contracts[poolDummy.address].abi, 'add_liquidity') > 2) { Object.assign(Pool.prototype, depositLendingOrCryptoMixin); } else { Object.assign(Pool.prototype, depositPlainMixin); @@ -103,7 +150,7 @@ export const getPool = (poolId: string): PoolTemplate => { } } else if (poolDummy.zap && poolId !== 'susd') { Object.assign(Pool.prototype, withdrawZapMixin); - } else if (getCountArgsOfMethodByAbi(curve.contracts[poolDummy.address].abi, 'remove_liquidity') > 2) { + } else if (getCountArgsOfMethodByAbi(this.contracts[poolDummy.address].abi, 'remove_liquidity') > 2) { Object.assign(Pool.prototype, withdrawLendingOrCryptoMixin); } else { Object.assign(Pool.prototype, withdrawPlainMixin); @@ -162,7 +209,7 @@ export const getPool = (poolId: string): PoolTemplate => { } } else if (poolDummy.zap) { // including susd Object.assign(Pool.prototype, withdrawOneCoinZapMixin); - } else if (getCountArgsOfMethodByAbi(curve.contracts[poolDummy.address].abi, 'remove_liquidity_one_coin') > 3) { + } else if (getCountArgsOfMethodByAbi(this.contracts[poolDummy.address].abi, 'remove_liquidity_one_coin') > 3) { Object.assign(Pool.prototype, withdrawOneCoinLendingOrCryptoMixin); } else { Object.assign(Pool.prototype, withdrawOneCoinPlainMixin); @@ -187,10 +234,10 @@ export const getPool = (poolId: string): PoolTemplate => { } // swap and swapEstimateGas - if (findAbiSignature(curve.contracts[poolDummy.address].abi, 'exchange', 'uint256,uint256,uint256,uint256,bool') && - !(curve.chainId === 100 && poolDummy.id === "tricrypto")) { // tricrypto2 (eth), tricrypto (arbitrum), avaxcrypto (avalanche); 100 is xDAI + if (findAbiSignature(this.contracts[poolDummy.address].abi, 'exchange', 'uint256,uint256,uint256,uint256,bool') && + !(this.chainId === 100 && poolDummy.id === "tricrypto")) { // tricrypto2 (eth), tricrypto (arbitrum), avaxcrypto (avalanche); 100 is xDAI Object.assign(Pool.prototype, swapTricrypto2Mixin); - } else if (poolDummy.isMetaFactory && (getPool(poolDummy.basePool).isLending || getPool(poolDummy.basePool).isFake || poolDummy.isCrypto)) { + } else if (poolDummy.isMetaFactory && (getPool.call(this, poolDummy.basePool).isLending || getPool.call(this, poolDummy.basePool).isFake || poolDummy.isCrypto)) { if (poolDummy.isCrypto) { Object.assign(Pool.prototype, swapCryptoMetaFactoryMixin); } else { @@ -204,12 +251,12 @@ export const getPool = (poolId: string): PoolTemplate => { if (!poolDummy.isPlain && !poolDummy.isFake) { Object.assign(Pool.prototype, swapWrappedExpectedAndApproveMixin); Object.assign(Pool.prototype, swapWrappedRequiredMixin); - if (findAbiSignature(curve.contracts[poolDummy.address].abi, 'exchange', 'uint256,uint256,uint256,uint256,bool')) { // tricrypto2 (eth), tricrypto (arbitrum) + if (findAbiSignature(this.contracts[poolDummy.address].abi, 'exchange', 'uint256,uint256,uint256,uint256,bool')) { // tricrypto2 (eth), tricrypto (arbitrum) Object.assign(Pool.prototype, swapWrappedTricrypto2Mixin); } else { Object.assign(Pool.prototype, swapWrappedMixin); } } - return new Pool(poolId); + return new Pool(poolId, this); } \ No newline at end of file diff --git a/src/pools/subClasses/corePool.ts b/src/pools/subClasses/corePool.ts index 1134dfd2..dd8870ff 100644 --- a/src/pools/subClasses/corePool.ts +++ b/src/pools/subClasses/corePool.ts @@ -1,5 +1,6 @@ -import {curve} from "../../curve.js"; +import {type Curve} from "../../curve.js"; import {GaugePool, IGaugePool} from "./gaugePool.js"; +import {IPoolData} from "../../interfaces"; export interface ICorePool { id: string; @@ -68,13 +69,10 @@ export class CorePool implements ICorePool { useLending: boolean[]; inApi: boolean; - constructor(id: string) { - const poolsData = curve.getPoolsData(); - if (!poolsData[id]) { - throw new Error(`Pool ${id} not found. Available pools: ${Object.keys(poolsData).join(', ')}`); + constructor(id: string, poolData: IPoolData, readonly curve: Curve) { + if (!poolData) { + throw new Error(`Pool data is required for pool ${id}`); } - const poolData = poolsData[id]; - this.id = id; this.name = poolData.name; this.fullName = poolData.full_name; @@ -82,7 +80,7 @@ export class CorePool implements ICorePool { this.referenceAsset = poolData.reference_asset; this.address = poolData.swap_address; this.lpToken = poolData.token_address; - this.gauge = new GaugePool(poolData.gauge_address, poolData.name); + this.gauge = new GaugePool(poolData.gauge_address, poolData.name, curve); this.zap = poolData.deposit_address || null; this.sRewardContract = poolData.sCurveRewards_address || null; this.rewardContract = poolData.reward_contract || null; diff --git a/src/pools/subClasses/gaugePool.ts b/src/pools/subClasses/gaugePool.ts index 178303c6..8f89c2c0 100644 --- a/src/pools/subClasses/gaugePool.ts +++ b/src/pools/subClasses/gaugePool.ts @@ -1,5 +1,5 @@ import {IDict} from '../../interfaces.js'; -import {curve} from "../../curve.js"; +import {type Curve} from "../../curve.js"; import { DIGas, ensureAllowance, @@ -32,11 +32,9 @@ export interface IGaugePool { } export class GaugePool implements IGaugePool { - address: string; - poolName: string; estimateGas; - constructor(address: string, poolName: string) { + constructor(readonly address: string, readonly poolName: string, readonly curve: Curve) { this.address = address; this.poolName = poolName; this.estimateGas = { @@ -48,29 +46,29 @@ export class GaugePool implements IGaugePool { public async gaugeManager(): Promise { + const curve = this.curve if(!this.address || this.address === curve.constants.ZERO_ADDRESS) { return curve.constants.ZERO_ADDRESS; } else { try { return await curve.contracts[this.address].contract.manager(); - } catch (e) { + } catch { return curve.constants.ZERO_ADDRESS; } } } public async gaugeDistributors(): Promise> { - const gaugeContract = await curve.contracts[this.address].contract; - const gaugeMulticallContract = await curve.contracts[this.address].multicallContract; + const { contract: gaugeContract, multicallContract: gaugeMulticallContract } = this.curve.contracts[this.address]; - const rewardCount = Number(curve.formatUnits(await gaugeContract.reward_count(curve.constantOptions), 0)); + const rewardCount = Number(this.curve.formatUnits(await gaugeContract.reward_count(this.curve.constantOptions), 0)); let calls = []; for (let i = 0; i < rewardCount; i++) { calls.push(gaugeMulticallContract.reward_tokens(i)); } - const rewardTokens = await curve.multicallProvider.all(calls) as string[] + const rewardTokens = await this.curve.multicallProvider.all(calls) as string[] calls = []; @@ -78,7 +76,7 @@ export class GaugePool implements IGaugePool { calls.push(gaugeMulticallContract.reward_data(rewardTokens[i])); } - const rewardData: Array<{distributor: string}> = await curve.multicallProvider.all(calls) + const rewardData: Array<{distributor: string}> = await this.curve.multicallProvider.all(calls) const gaugeDistributors: IDict = {}; for (let i = 0; i < rewardCount; i++) { @@ -89,18 +87,20 @@ export class GaugePool implements IGaugePool { } public async gaugeVersion(): Promise { + const curve = this.curve if(!this.address || this.address === curve.constants.ZERO_ADDRESS) { return null; } else { try { return await curve.contracts[this.address].contract.version(); - } catch (e) { + } catch { return null; } } } private async _addReward(_reward_token: string, _distributor: string, estimateGas = false): Promise { + const curve = this.curve if(this.address !== curve.constants.ZERO_ADDRESS && this.address) { const gas = await curve.contracts[this.address].contract.add_reward.estimateGas(_reward_token, _distributor, { ...curve.constantOptions }); if (estimateGas) return smartNumber(gas); @@ -114,13 +114,11 @@ export class GaugePool implements IGaugePool { } private async addRewardEstimateGas(rewardToken: string, distributor: string): Promise { - // @ts-ignore - return await this._addReward(rewardToken, distributor, true); + return await this._addReward(rewardToken, distributor, true) as number | number[]; } public async addReward(rewardToken: string, distributor: string): Promise { - // @ts-ignore - return await this._addReward(rewardToken, distributor); + return await this._addReward(rewardToken, distributor) as string; } public async isDepositRewardAvailable(): Promise { @@ -131,23 +129,24 @@ export class GaugePool implements IGaugePool { } public async depositRewardIsApproved(rewardToken: string, amount: number | string): Promise { - return await hasAllowance([rewardToken], [amount], curve.signerAddress, this.address); + return await hasAllowance.call(this.curve, [rewardToken], [amount], this.curve.signerAddress, this.address); } private async depositRewardApproveEstimateGas(rewardToken: string, amount: number | string): Promise { - return await ensureAllowanceEstimateGas([rewardToken], [amount], this.address); + return await ensureAllowanceEstimateGas.call(this.curve, [rewardToken], [amount], this.address); } public async depositRewardApprove(rewardToken: string, amount: number | string): Promise { - return await ensureAllowance([rewardToken], [amount], this.address); + return await ensureAllowance.call(this.curve, [rewardToken], [amount], this.address); } private async _depositReward(rewardToken: string, amount: string | number, epoch: string | number, estimateGas = false): Promise { - if (!estimateGas) await ensureAllowance([rewardToken], [amount], this.address); + const curve = this.curve; + if (!estimateGas) await ensureAllowance.call(curve, [rewardToken], [amount], this.address); const contract = curve.contracts[this.address].contract; - const decimals = (await getCoinsData(rewardToken))[0].decimals; + const decimals = (await getCoinsData.call(curve, rewardToken))[0].decimals; const _amount = parseUnits(amount, decimals); @@ -159,15 +158,11 @@ export class GaugePool implements IGaugePool { } async depositRewardEstimateGas(rewardToken: string, amount: string | number, epoch: string | number): Promise { - - // @ts-ignore - return await this._depositReward(rewardToken, amount, epoch, true); + return await this._depositReward(rewardToken, amount, epoch, true) as number | number[] } public async depositReward(rewardToken: string, amount: string | number, epoch: string | number): Promise { - - // @ts-ignore - return await this._depositReward(rewardToken, amount, epoch); + return await this._depositReward(rewardToken, amount, epoch) as string } } diff --git a/src/pools/subClasses/statsPool.ts b/src/pools/subClasses/statsPool.ts index 36b4e55b..651a1558 100644 --- a/src/pools/subClasses/statsPool.ts +++ b/src/pools/subClasses/statsPool.ts @@ -1,4 +1,3 @@ -import { curve } from "../../curve.js"; import {IPoolType, IReward} from '../../interfaces.js'; import {_getPoolsFromApi,_getCrvApyFromApi} from '../../cached.js'; import { @@ -9,6 +8,7 @@ import { getVolumeApiController, } from '../../utils.js'; import {PoolTemplate} from "../PoolTemplate.js"; +import memoize from "memoizee"; export interface IStatsParameters { lpTokenSupply: string, @@ -45,6 +45,7 @@ export class StatsPool implements IStatsPool { } public parameters = async (): Promise => { + const curve = this.pool.curve; const multicallContract = curve.contracts[this.pool.address].multicallContract; const lpMulticallContract = curve.contracts[this.pool.lpToken].multicallContract; @@ -83,7 +84,7 @@ export class StatsPool implements IStatsPool { let _prices, _adminFee, _A, _lpTokenSupply, _gamma; try { [_virtualPrice, _fee, _adminFee, _A, _lpTokenSupply, _gamma, ..._prices] = await curve.multicallProvider.all(calls) as bigint[]; - } catch (e) { // Empty pool + } catch { // Empty pool calls.shift(); if (this.pool.isCrypto) { calls.shift(); @@ -126,6 +127,7 @@ export class StatsPool implements IStatsPool { } public async wrappedBalances(): Promise { + const curve = this.pool.curve; const contract = curve.contracts[this.pool.address].multicallContract; const calls = []; for (let i = 0; i < this.pool.wrappedCoins.length; i++) calls.push(contract.balances(i)); @@ -139,6 +141,7 @@ export class StatsPool implements IStatsPool { } public totalLiquidity = async (useApi = true): Promise => { + const curve = this.pool.curve; if (curve.chainId === 1 && this.pool.id === "crveth") return "0" if (this.pool.isLlamma) { @@ -152,7 +155,7 @@ export class StatsPool implements IStatsPool { collateralContract.balanceOf(this.pool.address), ammContract.admin_fees_y(), ]); - const collateralRate = await _getUsdRate(this.pool.underlyingCoinAddresses[1]); + const collateralRate = await _getUsdRate.call(curve, this.pool.underlyingCoinAddresses[1]); const stablecoinTvlBN = toBN(_balance_x).minus(toBN(_fee_x)); const collateralTvlBN = toBN(_balance_y).minus(toBN(_fee_y)).times(collateralRate); @@ -167,7 +170,7 @@ export class StatsPool implements IStatsPool { poolType = this.pool.id.replace(/-\d+$/, ''); poolType = poolType.replace(/-v2$/, ''); } - const poolsData = (await _getPoolsFromApi(network, poolType as IPoolType)).poolData; + const poolsData = (await _getPoolsFromApi.call(curve, network, poolType as IPoolType)).poolData; try { const totalLiquidity = poolsData.filter((data) => data.address.toLowerCase() === this.pool.address.toLowerCase())[0].usdTotal; @@ -180,7 +183,7 @@ export class StatsPool implements IStatsPool { const balances = await this.underlyingBalances(); const promises = []; for (const addr of this.pool.underlyingCoinAddresses) { - promises.push(_getUsdRate(addr)) + promises.push(_getUsdRate.call(curve, addr)) } const prices = await Promise.all(promises); const totalLiquidity = (balances as string[]).reduce( @@ -189,14 +192,20 @@ export class StatsPool implements IStatsPool { return totalLiquidity.toFixed(8) } + totalLiquidityMemoized = memoize(this.totalLiquidity.bind(this), { + promise: true, + maxAge: 5 * 60 * 1000, // 5m + }); + public volume = async (): Promise => { + const curve = this.pool.curve; if(curve.isLiteChain && curve.chainId !== 146) { throw Error('This method is not supported for the lite version') } const network = curve.constants.NETWORK_NAME; - const {poolsData} = await getVolumeApiController(network); + const {poolsData} = await getVolumeApiController.call(curve, network); const poolData = poolsData.find((d) => d.address.toLowerCase() === this.pool.address); if(poolData) { @@ -207,12 +216,13 @@ export class StatsPool implements IStatsPool { } public baseApy = async (): Promise<{ day: string, week: string }> => { + const curve = this.pool.curve; if(curve.isLiteChain && curve.chainId !== 146) { throw Error('baseApy is not supported for the lite version') } const network = curve.constants.NETWORK_NAME; - const {poolsData} = await getVolumeApiController(network); + const {poolsData} = await getVolumeApiController.call(curve, network); const poolData = poolsData.find((d) => d.address.toLowerCase() === this.pool.address); if(poolData) { @@ -225,6 +235,7 @@ export class StatsPool implements IStatsPool { } public tokenApy = async (useApi = true): Promise<[baseApy: number, boostedApy: number]> => { + const curve = this.pool.curve; if(curve.isLiteChain && curve.chainId !== 146) { throw Error('tokenApy is not supported for the lite version') } @@ -233,7 +244,7 @@ export class StatsPool implements IStatsPool { const isDisabledChain = [1313161554].includes(curve.chainId); // Disable Aurora if (useApi && !isDisabledChain) { - const crvAPYs = await _getCrvApyFromApi(); + const crvAPYs = await _getCrvApyFromApi(curve.constants.NETWORK_NAME); const poolCrvApy = crvAPYs[this.pool.gauge.address] ?? [0, 0]; // new pools might be missing return [poolCrvApy[0], poolCrvApy[1]]; } @@ -242,11 +253,12 @@ export class StatsPool implements IStatsPool { } public rewardsApy = async (useApi = true): Promise => { + const curve = this.pool.curve; if (this.pool.gauge.address === curve.constants.ZERO_ADDRESS) return []; const isDisabledChain = [1313161554].includes(curve.chainId); // Disable Aurora if (useApi && !isDisabledChain) { - const rewards = await _getRewardsFromApi(); + const rewards = await _getRewardsFromApi.call(curve); if (!rewards[this.pool.gauge.address]) return []; return rewards[this.pool.gauge.address].map((r) => ({ gaugeAddress: r.gaugeAddress, tokenAddress: r.tokenAddress, symbol: r.symbol, apy: r.apy })); } @@ -259,7 +271,7 @@ export class StatsPool implements IStatsPool { const rewardContract = curve.contracts[this.pool.sRewardContract || this.pool.gauge.address].multicallContract; const totalLiquidityUSD = await this.totalLiquidity(); - const rewardRate = await _getUsdRate(rewardToken.token); + const rewardRate = await _getUsdRate.call(curve, rewardToken.token); const [rewardData, _stakedSupply, _totalSupply] = (await curve.multicallProvider.all([ rewardContract.reward_data(rewardToken.token), diff --git a/src/pools/subClasses/walletPool.ts b/src/pools/subClasses/walletPool.ts index b75495cd..8c938915 100644 --- a/src/pools/subClasses/walletPool.ts +++ b/src/pools/subClasses/walletPool.ts @@ -1,4 +1,3 @@ -import { curve } from "../../curve.js"; import {IDict} from '../../interfaces'; import { _prepareAddresses, @@ -17,7 +16,7 @@ export interface IWalletPool { export class WalletPool implements IWalletPool { private pool: PoolTemplate; - constructor(pool: PoolTemplate) { + constructor(pool: PoolTemplate, readonly curve = pool.curve) { this.pool = pool; } @@ -33,8 +32,8 @@ export class WalletPool implements IWalletPool { } } - addresses = _prepareAddresses(addresses); - const rawBalances: IDict = await _getBalances(coinAddresses, addresses); + addresses = _prepareAddresses.call(this.curve, addresses); + const rawBalances: IDict = await _getBalances.call(this.curve, coinAddresses, addresses); const balances: IDict> = {}; for (const address of addresses) { @@ -48,7 +47,7 @@ export class WalletPool implements IWalletPool { } public async balances(...addresses: string[] | string[][]): Promise> | IDict> { - if (this.pool.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.pool.gauge.address === this.curve.constants.ZERO_ADDRESS) { return await this._balances( ['lpToken', ...this.pool.underlyingCoinAddresses, ...this.pool.wrappedCoinAddresses], [this.pool.lpToken, ...this.pool.underlyingCoinAddresses, ...this.pool.wrappedCoinAddresses], @@ -64,7 +63,7 @@ export class WalletPool implements IWalletPool { } public async lpTokenBalances(...addresses: string[] | string[][]): Promise> | IDict> { - if (this.pool.gauge.address === curve.constants.ZERO_ADDRESS) { + if (this.pool.gauge.address === this.curve.constants.ZERO_ADDRESS) { return await this._balances(['lpToken'], [this.pool.lpToken], ...addresses); } else { return await this._balances(['lpToken', 'gauge'], [this.pool.lpToken, this.pool.gauge.address], ...addresses); diff --git a/src/pools/utils.ts b/src/pools/utils.ts index 8e026d6b..b09b4c86 100644 --- a/src/pools/utils.ts +++ b/src/pools/utils.ts @@ -1,44 +1,44 @@ -import { getPool } from "./poolConstructor.js"; -import { IDict } from "../interfaces"; -import { curve } from "../curve.js"; -import { _getRewardsFromApi, _getUsdRate, _setContracts, toBN } from "../utils.js"; -import { _getAllPoolsFromApi } from "../cached.js"; -import ERC20Abi from "../constants/abis/ERC20.json" with { type: 'json' }; +import {getPool} from "./poolConstructor.js"; +import {IDict} from "../interfaces"; +import {type Curve} from "../curve.js"; +import {_getRewardsFromApi, _getUsdRate, _setContracts, toBN} from "../utils.js"; +import {_getAllPoolsFromApi} from "../cached.js"; +import ERC20Abi from "../constants/abis/ERC20.json" with {type: "json"}; const BATCH_SIZE = 50; -const batchedMulticall = async (calls: any[]): Promise => { +async function batchedMulticall(this: Curve, calls: any[]): Promise { const results: bigint[] = []; for (let i = 0; i < calls.length; i += BATCH_SIZE) { const batch = calls.slice(i, i + BATCH_SIZE); - const res: bigint[] = await curve.multicallProvider.all(batch); - results.push(...res ); + const res: bigint[] = await this.multicallProvider.all(batch); + results.push(...res); } return results; -}; +} // _userLpBalance: { address: { poolId: { _lpBalance: 0, time: 0 } } } const _userLpBalanceCache: IDict> = {}; const _isUserLpBalanceCacheExpired = (address: string, poolId: string) => (_userLpBalanceCache[address]?.[poolId]?.time || 0) + 600000 < Date.now(); -const _getUserLpBalances = async (pools: string[], address: string, useCache: boolean): Promise => { +async function _getUserLpBalances(this: Curve, pools: string[], address: string, useCache: boolean): Promise { const poolsToFetch: string[] = useCache ? pools.filter((poolId) => _isUserLpBalanceCacheExpired(address as string, poolId)) : pools; if (poolsToFetch.length > 0) { const calls = []; for (const poolId of poolsToFetch) { - const pool = getPool(poolId); - calls.push(curve.contracts[pool.lpToken].multicallContract.balanceOf(address)); - if (pool.gauge.address && pool.gauge.address !== curve.constants.ZERO_ADDRESS) { - calls.push(curve.contracts[pool.gauge.address].multicallContract.balanceOf(address)); + const pool = getPool.call(this, poolId); + calls.push(this.contracts[pool.lpToken].multicallContract.balanceOf(address)); + if (pool.gauge.address && pool.gauge.address !== this.constants.ZERO_ADDRESS) { + calls.push(this.contracts[pool.gauge.address].multicallContract.balanceOf(address)); } } - const _rawBalances: bigint[] = (await batchedMulticall(calls as any[]) as bigint[]); + const _rawBalances: bigint[] = (await batchedMulticall.call(this, calls as any[]) as bigint[]); for (const poolId of poolsToFetch) { - const pool = getPool(poolId); + const pool = getPool.call(this, poolId); let _balance = _rawBalances.shift() as bigint; - if (pool.gauge.address && pool.gauge.address !== curve.constants.ZERO_ADDRESS) _balance = _balance + (_rawBalances.shift() as bigint); + if (pool.gauge.address && pool.gauge.address !== this.constants.ZERO_ADDRESS) _balance = _balance + (_rawBalances.shift() as bigint); if (!_userLpBalanceCache[address]) _userLpBalanceCache[address] = {}; _userLpBalanceCache[address][poolId] = {'_lpBalance': _balance, 'time': Date.now()} @@ -53,9 +53,9 @@ const _getUserLpBalances = async (pools: string[], address: string, useCache: bo return _lpBalances } -export const getUserPoolListByLiquidity = async (address = curve.signerAddress): Promise => { - const pools = curve.getPoolList(); - const _lpBalances = await _getUserLpBalances(pools, address, false); +export async function getUserPoolListByLiquidity(this: Curve, address = this.signerAddress): Promise { + const pools = this.getPoolList(); + const _lpBalances = await _getUserLpBalances.call(this, pools, address, false); const userPoolList: string[] = [] for (let i = 0; i < pools.length; i++) { @@ -67,13 +67,13 @@ export const getUserPoolListByLiquidity = async (address = curve.signerAddress): return userPoolList } -export const getUserLiquidityUSD = async (pools: string[], address = curve.signerAddress): Promise => { - const _lpBalances = await _getUserLpBalances(pools, address, true); +export async function getUserLiquidityUSD(this: Curve, pools: string[], address = this.signerAddress): Promise { + const _lpBalances = await _getUserLpBalances.call(this, pools, address, true); const userLiquidityUSD: string[] = [] for (let i = 0; i < pools.length; i++) { - const pool = getPool(pools[i]); - const price = await _getUsdRate(pool.lpToken); + const pool = getPool.call(this, pools[i]); + const price = await _getUsdRate.call(this, pool.lpToken); userLiquidityUSD.push(toBN(_lpBalances[i]).times(price).toFixed(8)); } @@ -84,23 +84,22 @@ export const getUserLiquidityUSD = async (pools: string[], address = curve.signe const _userClaimableCache: IDict> = {}; const _isUserClaimableCacheExpired = (address: string, poolId: string) => (_userClaimableCache[address]?.[poolId]?.time || 0) + 600000 < Date.now(); -const _getUserClaimable = async (pools: string[], address: string, useCache: boolean): - Promise<{ token: string, symbol: string, amount: string }[][]> => { +async function _getUserClaimable(this: Curve, pools: string[], address: string, useCache: boolean): + Promise<{ token: string, symbol: string, amount: string }[][]> { const poolsToFetch: string[] = useCache ? pools.filter((poolId) => _isUserClaimableCacheExpired(address as string, poolId)) : pools; if (poolsToFetch.length > 0) { // --- 1. CRV --- - const hasCrvReward: boolean[] = []; for (const poolId of poolsToFetch) { - const pool = getPool(poolId); - if (curve.chainId === 324 || curve.chainId === 2222 || pool.gauge.address === curve.constants.ZERO_ADDRESS) { // TODO remove this for ZkSync and Kava + const pool = getPool.call(this, poolId); + if (this.chainId === 324 || this.chainId === 2222 || pool.gauge.address === this.constants.ZERO_ADDRESS) { // TODO remove this for ZkSync and Kava hasCrvReward.push(false); continue; } - const gaugeContract = curve.contracts[pool.gauge.address].contract; + const gaugeContract = this.contracts[pool.gauge.address].contract; hasCrvReward.push('inflation_rate()' in gaugeContract || 'inflation_rate(uint256)' in gaugeContract); } @@ -108,13 +107,13 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo const rewardCount: number[] = []; for (const poolId of poolsToFetch) { - const pool = getPool(poolId); - if (pool.gauge.address === curve.constants.ZERO_ADDRESS) { + const pool = getPool.call(this, poolId); + if (pool.gauge.address === this.constants.ZERO_ADDRESS) { rewardCount.push(0); continue; } - const gaugeContract = curve.contracts[pool.gauge.address].contract; + const gaugeContract = this.contracts[pool.gauge.address].contract; if ("reward_tokens(uint256)" in gaugeContract) { // gauge_v2, gauge_v3, gauge_v4, gauge_v5, gauge_factory, gauge_rewards_only, gauge_child rewardCount.push(8); } else if ('claimable_reward(address)' in gaugeContract) { // gauge_synthetix @@ -128,29 +127,29 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo const rewardTokenCalls = []; for (let i = 0; i < poolsToFetch.length; i++) { - const pool = getPool(poolsToFetch[i]); + const pool = getPool.call(this, poolsToFetch[i]); if (rewardCount[i] !== -1) { // no_gauge, gauge, gauge_v2, gauge_v3, gauge_v4, gauge_v5, gauge_factory, gauge_rewards_only, gauge_child for (let count = 0; count < rewardCount[i]; count++) { - const gaugeContract = curve.contracts[pool.gauge.address].multicallContract; + const gaugeContract = this.contracts[pool.gauge.address].multicallContract; rewardTokenCalls.push(gaugeContract.reward_tokens(count)); } } else { // gauge_synthetix rewardCount[i] = 1; - const rewardContract = curve.contracts[pool.sRewardContract as string].contract; - const rewardMulticallContract = curve.contracts[pool.sRewardContract as string].multicallContract; + const rewardContract = this.contracts[pool.sRewardContract as string].contract; + const rewardMulticallContract = this.contracts[pool.sRewardContract as string].multicallContract; const method = "snx()" in rewardContract ? "snx" : "rewardsToken" // susd, tbtc : dusd, musd, rsv, sbtc rewardTokenCalls.push(rewardMulticallContract[method]()); } } - const rawRewardTokens: string[] = (await batchedMulticall(rewardTokenCalls) as string[]).map((t) => t.toLowerCase()); + const rawRewardTokens: string[] = (await batchedMulticall.call(this, rewardTokenCalls) as string[]).map((t) => t.toLowerCase()); const rewardTokens: IDict = {}; for (let i = 0; i < poolsToFetch.length; i++) { rewardTokens[poolsToFetch[i]] = []; for (let j = 0; j < rewardCount[i]; j++) { const rewardAddress = rawRewardTokens.shift(); - if (rewardAddress === curve.constants.ZERO_ADDRESS) continue; - if (curve.chainId !== 1 && rewardAddress === curve.constants.COINS.crv) continue; + if (rewardAddress === this.constants.ZERO_ADDRESS) continue; + if (this.chainId !== 1 && rewardAddress === this.constants.COINS.crv) continue; // REYIELD shitcoin which breaks things, because symbol() throws an error if (rewardAddress === "0xf228ec3476318aCB4E719D2b290bb2ef8B34DFfA".toLowerCase()) continue; rewardTokens[poolsToFetch[i]].push(rewardAddress as string); @@ -162,11 +161,11 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo const rewardInfoCalls = []; for (let i = 0; i < poolsToFetch.length; i++) { const poolId = poolsToFetch[i]; - const pool = getPool(poolId); - if (pool.gauge.address === curve.constants.ZERO_ADDRESS) continue; + const pool = getPool.call(this, poolId); + if (pool.gauge.address === this.constants.ZERO_ADDRESS) continue; - const gaugeContract = curve.contracts[pool.gauge.address].contract; - const gaugeMulticallContract = curve.contracts[pool.gauge.address].multicallContract; + const gaugeContract = this.contracts[pool.gauge.address].contract; + const gaugeMulticallContract = this.contracts[pool.gauge.address].multicallContract; if (hasCrvReward[i]) { rewardInfoCalls.push(gaugeMulticallContract.claimable_tokens(address)); @@ -174,7 +173,7 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo for (const token of rewardTokens[poolId]) { // Don't reset the reward ABI if the reward is the LP token itself, otherwise we lose LP contract functions - const { multicallContract } = token === pool.address ? curve.contracts[token] : _setContracts(token, ERC20Abi) + const { multicallContract } = token === pool.address ? this.contracts[token] : _setContracts.call(this, token, ERC20Abi) rewardInfoCalls.push(multicallContract.symbol(), multicallContract.decimals()); if ('claimable_reward(address,address)' in gaugeContract) { @@ -185,23 +184,23 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo } } - const rawRewardInfo = await batchedMulticall(rewardInfoCalls); + const rawRewardInfo = await batchedMulticall.call(this, rewardInfoCalls); for (let i = 0; i < poolsToFetch.length; i++) { const poolId = poolsToFetch[i]; - const pool = getPool(poolId); + const pool = getPool.call(this, poolId); if (!_userClaimableCache[address]) _userClaimableCache[address] = {}; _userClaimableCache[address][poolId] = { rewards: [], time: Date.now() }; - if (pool.gauge.address === curve.constants.ZERO_ADDRESS) continue; + if (pool.gauge.address === this.constants.ZERO_ADDRESS) continue; - const gaugeContract = curve.contracts[pool.gauge.address].contract; + const gaugeContract = this.contracts[pool.gauge.address].contract; if (hasCrvReward[i]) { - const token = curve.constants.ALIASES.crv; + const token = this.constants.ALIASES.crv; const symbol = 'CRV'; const decimals = 18; const _amount = rawRewardInfo.shift() as bigint; - const amount = curve.formatUnits(_amount, decimals); + const amount = this.formatUnits(_amount, decimals); if (Number(amount) > 0) _userClaimableCache[address][poolId].rewards.push({ token, symbol, amount }); } @@ -214,7 +213,7 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo const _claimedAmount = rawRewardInfo.shift() as bigint; _amount = _amount - _claimedAmount; } - const amount = curve.formatUnits(_amount, decimals); + const amount = this.formatUnits(_amount, decimals); if (Number(amount) > 0) _userClaimableCache[address][poolId].rewards.push({ token, symbol, amount }); } @@ -229,8 +228,8 @@ const _getUserClaimable = async (pools: string[], address: string, useCache: boo return _claimable } -const _getUserClaimableUseApi = async (pools: string[], address: string, useCache: boolean): - Promise<{ token: string, symbol: string, amount: string }[][]> => { +async function _getUserClaimableUseApi(this: Curve, pools: string[], address: string, useCache: boolean): + Promise<{ token: string, symbol: string, amount: string }[][]> { const poolsToFetch: string[] = useCache ? pools.filter((poolId) => _isUserClaimableCacheExpired(address as string, poolId)) : pools; if (poolsToFetch.length > 0) { @@ -239,13 +238,13 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach const hasCrvReward: boolean[] = []; for (const poolId of poolsToFetch) { - const pool = getPool(poolId); - if (curve.chainId === 324 || curve.chainId === 2222 || pool.gauge.address === curve.constants.ZERO_ADDRESS) { // TODO remove this for ZkSync and Kava + const pool = getPool.call(this, poolId); + if (this.chainId === 324 || this.chainId === 2222 || pool.gauge.address === this.constants.ZERO_ADDRESS) { // TODO remove this for ZkSync and Kava hasCrvReward.push(false); continue; } - const gaugeContract = curve.contracts[pool.gauge.address].contract; + const gaugeContract = this.contracts[pool.gauge.address].contract; hasCrvReward.push('inflation_rate()' in gaugeContract || 'inflation_rate(uint256)' in gaugeContract); } @@ -253,8 +252,8 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach const rewardTokens: IDict<{ token: string, symbol: string, decimals: number }[]> = {}; for (let i = 0; i < poolsToFetch.length; i++) { - const pool = getPool(poolsToFetch[i]); - const rewards = await _getRewardsFromApi(); + const pool = getPool.call(this, poolsToFetch[i]); + const rewards = await _getRewardsFromApi.call(this); rewardTokens[poolsToFetch[i]] = (rewards[pool.gauge.address] ?? []) .map((r) => ({ token: r.tokenAddress, symbol: r.symbol, decimals: Number(r.decimals)})); } @@ -264,11 +263,11 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach const rewardInfoCalls = []; for (let i = 0; i < poolsToFetch.length; i++) { const poolId = poolsToFetch[i]; - const pool = getPool(poolId); - if (pool.gauge.address === curve.constants.ZERO_ADDRESS) continue; + const pool = getPool.call(this, poolId); + if (pool.gauge.address === this.constants.ZERO_ADDRESS) continue; - const gaugeContract = curve.contracts[pool.gauge.address].contract; - const gaugeMulticallContract = curve.contracts[pool.gauge.address].multicallContract; + const gaugeContract = this.contracts[pool.gauge.address].contract; + const gaugeMulticallContract = this.contracts[pool.gauge.address].multicallContract; if (hasCrvReward[i]) { rewardInfoCalls.push(gaugeMulticallContract.claimable_tokens(address)); @@ -277,7 +276,7 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach for (const r of rewardTokens[poolId]) { // Don't reset the reward ABI if the reward is the LP token itself, otherwise we lose LP contract functions if (r.token !== pool.address) { - _setContracts(r.token, ERC20Abi) + _setContracts.call(this, r.token, ERC20Abi) } if ('claimable_reward(address,address)' in gaugeContract) { @@ -288,23 +287,23 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach } } - const rawRewardInfo = await batchedMulticall(rewardInfoCalls); + const rawRewardInfo = await batchedMulticall.call(this, rewardInfoCalls); for (let i = 0; i < poolsToFetch.length; i++) { const poolId = poolsToFetch[i]; - const pool = getPool(poolId); + const pool = getPool.call(this, poolId); if (!_userClaimableCache[address]) _userClaimableCache[address] = {}; _userClaimableCache[address][poolId] = { rewards: [], time: Date.now() }; - if (pool.gauge.address === curve.constants.ZERO_ADDRESS) continue; + if (pool.gauge.address === this.constants.ZERO_ADDRESS) continue; - const gaugeContract = curve.contracts[pool.gauge.address].contract; + const gaugeContract = this.contracts[pool.gauge.address].contract; if (hasCrvReward[i]) { - const token = curve.constants.ALIASES.crv; + const token = this.constants.ALIASES.crv; const symbol = 'CRV'; const decimals = 18; const _amount = rawRewardInfo.shift() as bigint; - const amount = curve.formatUnits(_amount, decimals); + const amount = this.formatUnits(_amount, decimals); if (Number(amount) > 0) _userClaimableCache[address][poolId].rewards.push({ token, symbol, amount }); } @@ -315,7 +314,7 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach const _claimedAmount = rawRewardInfo.shift() as bigint; _amount = _amount - _claimedAmount; } - const amount = curve.formatUnits(_amount, r.decimals); + const amount = this.formatUnits(_amount, r.decimals); if (Number(amount) > 0) _userClaimableCache[address][poolId].rewards.push({ token: r.token, symbol: r.symbol, amount }); } @@ -330,9 +329,9 @@ const _getUserClaimableUseApi = async (pools: string[], address: string, useCach return _claimable } -export const getUserPoolListByClaimable = async (address = curve.signerAddress): Promise => { - const pools = curve.getPoolList(); - const _claimable = await _getUserClaimable(pools, address, false); +export async function getUserPoolListByClaimable(this: Curve, address = this.signerAddress): Promise { + const pools = this.getPoolList(); + const _claimable = await _getUserClaimable.call(this, pools, address, false); const userPoolList: string[] = [] for (let i = 0; i < pools.length; i++) { @@ -344,15 +343,15 @@ export const getUserPoolListByClaimable = async (address = curve.signerAddress): return userPoolList } -export const getUserClaimable = async (pools: string[], address = curve.signerAddress): - Promise<{ token: string, symbol: string, amount: string, price: number }[][]> => { - const _claimable = await _getUserClaimable(pools, address, true); +export async function getUserClaimable(this: Curve, pools: string[], address = this.signerAddress): + Promise<{ token: string, symbol: string, amount: string, price: number }[][]> { + const _claimable = await _getUserClaimable.call(this, pools, address, true); const claimableWithPrice: { token: string, symbol: string, amount: string, price: number }[][] = [] for (let i = 0; i < pools.length; i++) { claimableWithPrice.push([]); for (const c of _claimable[i]) { - const price = await _getUsdRate(c.token); + const price = await _getUsdRate.call(this, c.token); claimableWithPrice[claimableWithPrice.length - 1].push({ ...c, price }) } } @@ -360,11 +359,11 @@ export const getUserClaimable = async (pools: string[], address = curve.signerAd return claimableWithPrice } -export const getUserPoolList = async (address = curve.signerAddress, useApi = true): Promise => { - const pools = curve.getPoolList(); +export async function getUserPoolList(this: Curve, address = this.signerAddress, useApi = true): Promise { + const pools = this.getPoolList(); const [_lpBalances, _claimable] = await Promise.all([ - _getUserLpBalances(pools, address, false), - useApi ? _getUserClaimableUseApi(pools, address, false) : _getUserClaimable(pools, address, false), + _getUserLpBalances.call(this, pools, address, false), + useApi ? _getUserClaimableUseApi.call(this, pools, address, false) : _getUserClaimable.call(this, pools, address, false), ]); const userPoolList: string[] = [] @@ -377,9 +376,9 @@ export const getUserPoolList = async (address = curve.signerAddress, useApi = tr return userPoolList } -export const _getAmplificationCoefficientsFromApi = async (): Promise> => { - const network = curve.constants.NETWORK_NAME; - const allTypesExtendedPoolData = await _getAllPoolsFromApi(network, curve.isLiteChain); +export async function _getAmplificationCoefficientsFromApi(this: Curve): Promise> { + const network = this.constants.NETWORK_NAME; + const allTypesExtendedPoolData = await _getAllPoolsFromApi(network, this.isLiteChain); const amplificationCoefficientDict: IDict = {}; for (const extendedPoolData of allTypesExtendedPoolData) { diff --git a/src/route-graph.worker.ts b/src/route-graph.worker.ts index 5a6651d9..770b912f 100644 --- a/src/route-graph.worker.ts +++ b/src/route-graph.worker.ts @@ -1,9 +1,9 @@ // important: only type imports, the worker needs to be standalone import type {IChainId, IDict, IPoolData, IRouteStep, ISwapType} from "./interfaces"; -import type {curve} from "./curve"; +import type {Curve} from "./curve"; export type IRouteGraphInput = { - constants: typeof curve['constants'], + constants: Curve['constants'], chainId: IChainId, isLiteChain: boolean, allPools: [string, IPoolData][], @@ -24,7 +24,6 @@ export function routeGraphWorker() { ].map((a) => a.toLowerCase()), }, } - const createRouteGraph = ({constants, chainId, isLiteChain, allPools, amplificationCoefficientDict, poolTvlDict}: IRouteGraphInput): IDict> => { const routerGraph: IDict> = {} // ETH <-> WETH (exclude Celo) @@ -231,17 +230,15 @@ export function routeGraphWorker() { // SNX swaps if (chainId in SNX) { - // @ts-ignore - for (const inCoin of SNX[chainId].coins) { - // @ts-ignore - for (const outCoin of SNX[chainId].coins) { + const chain = chainId as keyof typeof SNX; + for (const inCoin of SNX[chain].coins) { + for (const outCoin of SNX[chain].coins) { if (inCoin === outCoin) continue; if (!routerGraph[inCoin]) routerGraph[inCoin] = {}; routerGraph[inCoin][outCoin] = [{ poolId: "SNX exchanger", - // @ts-ignore - swapAddress: SNX[chainId].swap, + swapAddress: SNX[chain].swap, inputCoinAddress: inCoin, outputCoinAddress: outCoin, swapParams: [0, 0, 9, 0, 0], diff --git a/src/router.ts b/src/router.ts index 847229e3..11c2e48a 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,8 +1,7 @@ -import memoize from "memoizee"; import BigNumber from "bignumber.js"; import {ethers} from "ethers"; -import { curve, OLD_CHAINS } from "./curve.js"; -import {IDict, IRoute, IRouteOutputAndCost, IRouteStep, IChainId} from "./interfaces"; +import {type Curve, OLD_CHAINS} from "./curve.js"; +import {IChainId, IDict, IRoute, IRouteOutputAndCost, IRouteStep} from "./interfaces"; import { _cutZeros, _get_price_impact, @@ -30,16 +29,12 @@ import {_getAmplificationCoefficientsFromApi} from "./pools/utils.js"; import {L2Networks} from "./constants/L2Networks.js"; import {IRouterWorkerInput, routeFinderWorker, routeFinderWorkerCode} from "./route-finder.worker.js"; import {IRouteGraphInput, routeGraphWorker, routeGraphWorkerCode} from "./route-graph.worker.js"; +import {memoizeMethod} from "./constants/utils"; const MAX_STEPS = 5; const ROUTE_LENGTH = (MAX_STEPS * 2) + 1; -const _getTVL = memoize( - async (poolId: string) => Number(await (getPool(poolId)).stats.totalLiquidity()), - { - promise: true, - maxAge: 5 * 60 * 1000, // 5m - }); +async function _getTVL(this: Curve, poolId: string) { return Number(await getPool.call(this, poolId).stats.totalLiquidityMemoized()) } async function entriesToDictAsync(entries: [string, T][], mapper: (key: string, value: T) => Promise): Promise> { const result: IDict = {}; @@ -53,29 +48,26 @@ function mapDict(dict: IDict, mapper: (key: string, value: T) => U): ID return result; } -const _buildRouteGraph = memoize(async (chainId: IChainId, isLiteChain: boolean): Promise>> => { - const constants = curve.constants; - const allPools = Object.entries(curve.getPoolsData()).filter(([id]) => !["crveth", "y", "busd", "pax"].includes(id)); - const amplificationCoefficientDict = await _getAmplificationCoefficientsFromApi(); - const poolTvlDict: IDict = await entriesToDictAsync(allPools, _getTVL); - const input: IRouteGraphInput = {constants, chainId, isLiteChain, allPools, amplificationCoefficientDict, poolTvlDict}; +async function _buildRouteGraphImpl(this: Curve, chainId: IChainId, isLiteChain: boolean): Promise>> { + const constants = this.constants; + const allPools = Object.entries(this.getPoolsData()).filter(([id]) => !["crveth", "y", "busd", "pax"].includes(id)); + const amplificationCoefficientDict = await _getAmplificationCoefficientsFromApi.call(this); + const poolTvlDict: IDict = await entriesToDictAsync(allPools, _getTVL.bind(this)); + const input: IRouteGraphInput = { constants, chainId, isLiteChain, allPools, amplificationCoefficientDict, poolTvlDict }; return runWorker(routeGraphWorkerCode, routeGraphWorker, {type: 'createRouteGraph', ...input}); -}, -{ - promise: true, - maxAge: 5 * 60 * 1000, // 5m -}); - -const _findRoutes = async (inputCoinAddress: string, outputCoinAddress: string): Promise => { - const routerGraph = await _buildRouteGraph(curve.chainId, curve.isLiteChain); // It's important to pass chainId to not use cache from another network +} + +async function _findRoutes(this: Curve, inputCoinAddress: string, outputCoinAddress: string): Promise { + const _buildRouteGraph = memoizeMethod(this, '_buildRouteGraph', _buildRouteGraphImpl); + const routerGraph = await _buildRouteGraph.call(this, this.chainId, this.isLiteChain); // It's important to pass chainId to not use cache from another network // extract only the fields we need for the worker const poolData = mapDict( - curve.getPoolsData(), + this.getPoolsData(), (_, { is_lending, wrapped_coin_addresses, underlying_coin_addresses, token_address }) => ({ is_lending, wrapped_coin_addresses, underlying_coin_addresses, token_address }) ); const input: IRouterWorkerInput = {inputCoinAddress, outputCoinAddress, routerGraph, poolData}; return runWorker(routeFinderWorkerCode, routeFinderWorker, {type: 'findRoutes', ...input}); -}; +} const _getRouteKey = (route: IRoute, inputCoinAddress: string, outputCoinAddress: string): string => { const sortedCoins = [inputCoinAddress, outputCoinAddress].sort(); @@ -87,7 +79,7 @@ const _getRouteKey = (route: IRoute, inputCoinAddress: string, outputCoinAddress return key } -const _getExchangeArgs = (route: IRoute): { +function _getExchangeArgs(this: Curve, route: IRoute): { _route: string[], _swapParams: number[][], _pools?: string[], @@ -95,8 +87,8 @@ const _getExchangeArgs = (route: IRoute): { _baseTokens?: string[], _secondBasePools?: string[], _secondBaseTokens?: string[] -} => { - if (OLD_CHAINS.includes(curve.chainId)) { +} { + if (OLD_CHAINS.includes(this.chainId)) { let _route = []; if (route.length > 0) _route.push(route[0].inputCoinAddress); let _swapParams = []; @@ -114,13 +106,13 @@ const _getExchangeArgs = (route: IRoute): { _secondBasePools.push(routeStep.secondBasePool); _secondBaseTokens.push(routeStep.secondBaseToken); } - _route = _route.concat(Array(ROUTE_LENGTH - _route.length).fill(curve.constants.ZERO_ADDRESS)); + _route = _route.concat(Array(ROUTE_LENGTH - _route.length).fill(this.constants.ZERO_ADDRESS)); _swapParams = _swapParams.concat(Array(MAX_STEPS - _swapParams.length).fill([0, 0, 0, 0, 0])); - _pools = _pools.concat(Array(MAX_STEPS - _pools.length).fill(curve.constants.ZERO_ADDRESS)); - _basePools = _basePools.concat(Array(MAX_STEPS - _basePools.length).fill(curve.constants.ZERO_ADDRESS)); - _baseTokens = _baseTokens.concat(Array(MAX_STEPS - _baseTokens.length).fill(curve.constants.ZERO_ADDRESS)); - _secondBasePools = _secondBasePools.concat(Array(MAX_STEPS - _secondBasePools.length).fill(curve.constants.ZERO_ADDRESS)); - _secondBaseTokens = _secondBaseTokens.concat(Array(MAX_STEPS - _secondBaseTokens.length).fill(curve.constants.ZERO_ADDRESS)); + _pools = _pools.concat(Array(MAX_STEPS - _pools.length).fill(this.constants.ZERO_ADDRESS)); + _basePools = _basePools.concat(Array(MAX_STEPS - _basePools.length).fill(this.constants.ZERO_ADDRESS)); + _baseTokens = _baseTokens.concat(Array(MAX_STEPS - _baseTokens.length).fill(this.constants.ZERO_ADDRESS)); + _secondBasePools = _secondBasePools.concat(Array(MAX_STEPS - _secondBasePools.length).fill(this.constants.ZERO_ADDRESS)); + _secondBaseTokens = _secondBaseTokens.concat(Array(MAX_STEPS - _secondBaseTokens.length).fill(this.constants.ZERO_ADDRESS)); return {_route, _swapParams, _pools, _basePools, _baseTokens, _secondBasePools, _secondBaseTokens} } else { // RouterNgPoolsOnly @@ -131,32 +123,32 @@ const _getExchangeArgs = (route: IRoute): { _route.push(routeStep.swapAddress, routeStep.outputCoinAddress); _swapParams.push(routeStep.swapParams.slice(0, 4)); } - _route = _route.concat(Array(ROUTE_LENGTH - _route.length).fill(curve.constants.ZERO_ADDRESS)); + _route = _route.concat(Array(ROUTE_LENGTH - _route.length).fill(this.constants.ZERO_ADDRESS)); _swapParams = _swapParams.concat(Array(MAX_STEPS - _swapParams.length).fill([0, 0, 0, 0])); - return { _route, _swapParams } + return {_route, _swapParams} } } const _estimatedGasForDifferentRoutesCache: IDict<{ gas: bigint | bigint[], time: number }> = {}; -const _estimateGasForDifferentRoutes = async (routes: IRoute[], inputCoinAddress: string, outputCoinAddress: string, _amount: bigint): Promise> => { +async function _estimateGasForDifferentRoutes(this: Curve, routes: IRoute[], inputCoinAddress: string, outputCoinAddress: string, _amount: bigint): Promise> { inputCoinAddress = inputCoinAddress.toLowerCase(); outputCoinAddress = outputCoinAddress.toLowerCase(); - const contract = curve.contracts[curve.constants.ALIASES.router].contract; + const contract = this.contracts[this.constants.ALIASES.router].contract; const gasPromises: Promise[] = []; - const value = isEth(inputCoinAddress) ? _amount : curve.parseUnits("0"); + const value = isEth(inputCoinAddress) ? _amount : this.parseUnits("0"); for (const route of routes) { const routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress); let gasPromise: Promise; - const { _route, _swapParams, _pools } = _getExchangeArgs(route); + const {_route, _swapParams, _pools} = _getExchangeArgs.call(this, route); if ((_estimatedGasForDifferentRoutesCache[routeKey]?.time || 0) + 3600000 < Date.now()) { if (_pools) { - gasPromise = contract.exchange.estimateGas(_route, _swapParams, _amount, 0, _pools, { ...curve.constantOptions, value}); + gasPromise = contract.exchange.estimateGas(_route, _swapParams, _amount, 0, _pools, { ...this.constantOptions, value}); } else { - gasPromise = contract.exchange.estimateGas(_route, _swapParams, _amount, 0, { ...curve.constantOptions, value}); + gasPromise = contract.exchange.estimateGas(_route, _swapParams, _amount, 0, { ...this.constantOptions, value}); } } else { gasPromise = Promise.resolve(_estimatedGasForDifferentRoutesCache[routeKey].gas); @@ -169,167 +161,163 @@ const _estimateGasForDifferentRoutes = async (routes: IRoute[], inputCoinAddress routes.forEach((route, i: number) => { const routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress); - _estimatedGasForDifferentRoutesCache[routeKey] = { 'gas': _gasAmounts[i], 'time': Date.now() }; + _estimatedGasForDifferentRoutesCache[routeKey] = {'gas': _gasAmounts[i], 'time': Date.now()}; }) return _gasAmounts.map((_g) => smartNumber(_g)); - } catch (err) { // No allowance + } catch { // No allowance return routes.map(() => 0); } } -const _getBestRoute = memoize( - async (inputCoinAddress: string, outputCoinAddress: string, amount: number | string): Promise => { - const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress); - const _amount = parseUnits(amount, inputCoinDecimals); - if (_amount === curve.parseUnits("0")) return []; +async function _getBestRouteImpl(this: Curve, inputCoinAddress: string, outputCoinAddress: string, amount: number | string): Promise { + const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals.call(this, inputCoinAddress, outputCoinAddress); + const _amount = parseUnits(amount, inputCoinDecimals); + if (_amount === this.parseUnits("0")) return []; - const routesRaw: IRouteOutputAndCost[] = (await _findRoutes(inputCoinAddress, outputCoinAddress)).map( - (route) => ({ route, _output: curve.parseUnits("0"), outputUsd: 0, txCostUsd: 0 }) - ); - const routes: IRouteOutputAndCost[] = []; + const routesRaw: IRouteOutputAndCost[] = (await _findRoutes.call(this, inputCoinAddress, outputCoinAddress)).map( + (route) => ({route, _output: this.parseUnits("0"), outputUsd: 0, txCostUsd: 0}) + ); + const routes: IRouteOutputAndCost[] = []; - try { - const calls = []; - const multicallContract = curve.contracts[curve.constants.ALIASES.router].multicallContract; - for (const r of routesRaw) { - const { _route, _swapParams, _pools } = _getExchangeArgs(r.route); - if (_pools) { - calls.push(multicallContract.get_dy(_route, _swapParams, _amount, _pools)); - } else { - calls.push(multicallContract.get_dy(_route, _swapParams, _amount)); - } + try { + const calls = []; + const multicallContract = this.contracts[this.constants.ALIASES.router].multicallContract; + for (const r of routesRaw) { + const {_route, _swapParams, _pools} = _getExchangeArgs.call(this, r.route); + if (_pools) { + calls.push(multicallContract.get_dy(_route, _swapParams, _amount, _pools)); + } else { + calls.push(multicallContract.get_dy(_route, _swapParams, _amount)); } + } - const _outputAmounts = await curve.multicallProvider.all(calls) as bigint[]; + const _outputAmounts = await this.multicallProvider.all(calls) as bigint[]; - for (let i = 0; i < _outputAmounts.length; i++) { - routesRaw[i]._output = _outputAmounts[i]; - routes.push(routesRaw[i]); - } - } catch (err) { - // const promises = []; - // const contract = curve.contracts[curve.constants.ALIASES.router].contract; - // for (const r of routesRaw) { - // const { _route, _swapParams, _pools } = _getExchangeArgs(r.route); - // promises.push(contract.get_dy(_route, _swapParams, _amount, _pools, curve.constantOptions)); - // } - // - // const res = await Promise.allSettled(promises); - // - // for (let i = 0; i < res.length; i++) { - // if (res[i].status === 'rejected') { - // console.log(`Route ${(routesRaw[i].route.map((s) => s.poolId)).join(" --> ")} is unavailable`); - // continue; - // } - // routesRaw[i]._output = (res[i] as PromiseFulfilledResult).value; - // routes.push(routesRaw[i]); - // } - - const contract = curve.contracts[curve.constants.ALIASES.router].contract; - const _outputs = []; - for (const r of routesRaw) { - const { _route, _swapParams, _pools } = _getExchangeArgs(r.route); - try { - if (_pools) { - _outputs.push(await contract.get_dy(_route, _swapParams, _amount, _pools, curve.constantOptions)); - } else { - _outputs.push(await contract.get_dy(_route, _swapParams, _amount, curve.constantOptions)); - } - } catch (e) { - _outputs.push(curve.parseUnits('-1', 0)); + for (let i = 0; i < _outputAmounts.length; i++) { + routesRaw[i]._output = _outputAmounts[i]; + routes.push(routesRaw[i]); + } + } catch { + // const promises = []; + // const contract = this.contracts[this.constants.ALIASES.router].contract; + // for (const r of routesRaw) { + // const { _route, _swapParams, _pools } = _getExchangeArgs(r.route); + // promises.push(contract.get_dy(_route, _swapParams, _amount, _pools, this.constantOptions)); + // } + // + // const res = await Promise.allSettled(promises); + // + // for (let i = 0; i < res.length; i++) { + // if (res[i].status === 'rejected') { + // console.log(`Route ${(routesRaw[i].route.map((s) => s.poolId)).join(" --> ")} is unavailable`); + // continue; + // } + // routesRaw[i]._output = (res[i] as PromiseFulfilledResult).value; + // routes.push(routesRaw[i]); + // } + + const contract = this.contracts[this.constants.ALIASES.router].contract; + const _outputs = []; + for (const r of routesRaw) { + const {_route, _swapParams, _pools} = _getExchangeArgs.call(this, r.route); + try { + if (_pools) { + _outputs.push(await contract.get_dy(_route, _swapParams, _amount, _pools, this.constantOptions)); + } else { + _outputs.push(await contract.get_dy(_route, _swapParams, _amount, this.constantOptions)); } + } catch { + _outputs.push(this.parseUnits('-1', 0)); } + } - for (let i = 0; i < _outputs.length; i++) { - if (_outputs[i] < 0) { - console.log(`Route ${(routesRaw[i].route.map((s) => s.poolId)).join(" --> ")} is unavailable`); - continue; - } - routesRaw[i]._output = _outputs[i]; - routes.push(routesRaw[i]); + for (let i = 0; i < _outputs.length; i++) { + if (_outputs[i] < 0) { + console.log(`Route ${(routesRaw[i].route.map((s) => s.poolId)).join(" --> ")} is unavailable`); + continue; } + routesRaw[i]._output = _outputs[i]; + routes.push(routesRaw[i]); } - if (routes.length === 0) return []; - if (routes.length === 1) return routes[0].route; - - const [gasAmounts, outputCoinUsdRate, gasData, ethUsdRate] = await Promise.all([ - _estimateGasForDifferentRoutes(routes.map((r) => r.route), inputCoinAddress, outputCoinAddress, _amount), - _getUsdRate(outputCoinAddress), - fetch("https://api.curve.finance/api/getGas").then((res) => res.json()), - _getUsdRate(ETH_ADDRESS), - ]); - const gasPrice = gasData.data.gas.standard; - const expectedAmounts = (routes).map( - (route) => Number(curve.formatUnits(route._output, outputCoinDecimals)) - ); - - const expectedAmountsUsd = expectedAmounts.map((a) => a * outputCoinUsdRate); - - const L1GasPrice = L2Networks.includes(curve.chainId) ? await getGasPriceFromL1() : 0; - - const txCostsUsd = gasAmounts.map((a) => getTxCostsUsd(ethUsdRate, gasPrice, a, L1GasPrice)); - - routes.forEach((route, i) => { - route.outputUsd = expectedAmountsUsd[i]; - route.txCostUsd = txCostsUsd[i] - }); - - return routes.reduce((route1, route2) => { - const diff = (route1.outputUsd - route1.txCostUsd) - (route2.outputUsd - route2.txCostUsd); - if (diff > 0) return route1 - if (diff === 0 && route1.route.length < route2.route.length) return route1 - return route2 - }).route; - }, - { - promise: true, - maxAge: 5 * 60 * 1000, // 5m } -) + if (routes.length === 0) return []; + if (routes.length === 1) return routes[0].route; + + const [gasAmounts, outputCoinUsdRate, gasData, ethUsdRate] = await Promise.all([ + _estimateGasForDifferentRoutes.call(this, routes.map((r) => r.route), inputCoinAddress, outputCoinAddress, _amount), + _getUsdRate.call(this, outputCoinAddress), + fetch("https://api.curve.finance/api/getGas").then((res) => res.json()), + _getUsdRate.call(this, ETH_ADDRESS), + ]); + const gasPrice = gasData.data.gas.standard; + const expectedAmounts = (routes).map( + (route) => Number(this.formatUnits(route._output, outputCoinDecimals)) + ); -const _getOutputForRoute = memoize( - async (route: IRoute, _amount: bigint): Promise => { - const contract = curve.contracts[curve.constants.ALIASES.router].contract; - const { _route, _swapParams, _pools } = _getExchangeArgs(route); - if (_pools) { - return await contract.get_dy(_route, _swapParams, _amount, _pools, curve.constantOptions); - } else { - return await contract.get_dy(_route, _swapParams, _amount, curve.constantOptions); - } - }, - { - promise: true, - maxAge: 15 * 1000, // 15s + const expectedAmountsUsd = expectedAmounts.map((a) => a * outputCoinUsdRate); + + const L1GasPrice = L2Networks.includes(this.chainId) ? await getGasPriceFromL1.call(this) : 0; + + const txCostsUsd = gasAmounts.map((a) => getTxCostsUsd(ethUsdRate, gasPrice, a, L1GasPrice)); + + routes.forEach((route, i) => { + route.outputUsd = expectedAmountsUsd[i]; + route.txCostUsd = txCostsUsd[i] + }); + + return routes.reduce((route1, route2) => { + const diff = (route1.outputUsd - route1.txCostUsd) - (route2.outputUsd - route2.txCostUsd); + if (diff > 0) return route1 + if (diff === 0 && route1.route.length < route2.route.length) return route1 + return route2 + }).route; +} + +async function _getBestRoute(this: Curve, inputCoinAddress: string, outputCoinAddress: string, amount: number | string): Promise { + return memoizeMethod(this, '_getBestRoute', _getBestRouteImpl).call(this, inputCoinAddress, outputCoinAddress, amount); +} + +async function _getOutputForRouteImpl(this: Curve, route: IRoute, _amount: bigint): Promise { + const contract = this.contracts[this.constants.ALIASES.router].contract; + const { _route, _swapParams, _pools } = _getExchangeArgs.call(this, route); + if (_pools) { + return await contract.get_dy(_route, _swapParams, _amount, _pools, this.constantOptions); + } else { + return await contract.get_dy(_route, _swapParams, _amount, this.constantOptions); } -); +} + +async function _getOutputForRoute(this: Curve, route: IRoute, _amount: bigint): Promise { + return memoizeMethod(this, '_getOutputForRoute', _getOutputForRouteImpl).call(this, route, _amount); +} const _routesCache: IDict<{ route: IRoute, output: string, timestamp: number }> = {}; -const _getBestRouteAndOutput = (inputCoin: string, outputCoin: string, amount: number | string): { route: IRoute, output: string, timestamp: number } => { - const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin); +function _getBestRouteAndOutput(this: Curve, inputCoin: string, outputCoin: string, amount: number | string): { route: IRoute, output: string, timestamp: number } { + const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses.call(this, inputCoin, outputCoin); const key = `${inputCoinAddress}-${outputCoinAddress}-${amount}` if (!(key in _routesCache)) throw Error("You must call getBestRouteAndOutput first"); - return _routesCache[key] } -export const getBestRouteAndOutput = async (inputCoin: string, outputCoin: string, amount: number | string): Promise<{ route: IRoute, output: string }> => { - const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin); - const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress); - const route = await _getBestRoute(inputCoinAddress, outputCoinAddress, amount); // 5 minutes cache +export async function getBestRouteAndOutput(this: Curve, inputCoin: string, outputCoin: string, amount: number | string): Promise<{ route: IRoute, output: string }> { + const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses.call(this, inputCoin, outputCoin); + const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals.call(this, inputCoinAddress, outputCoinAddress); + + const route = await _getBestRoute.call(this, inputCoinAddress, outputCoinAddress, amount); // 5 minutes cache if (route.length === 0) return { route, output: '0.0' }; - const _output = await _getOutputForRoute(route, parseUnits(amount, inputCoinDecimals)); // 15 seconds cache, so we call it to get fresh output estimation + const _output = await _getOutputForRoute.call(this, route, parseUnits(amount, inputCoinDecimals)); // 15 seconds cache, so we call it to get fresh output estimation _routesCache[`${inputCoinAddress}-${outputCoinAddress}-${amount}`] = { route, - output: curve.formatUnits(_output + BigInt(1), outputCoinDecimals), + output: this.formatUnits(_output + BigInt(1), outputCoinDecimals), timestamp: Date.now(), } - return { route, output: curve.formatUnits(_output + BigInt(1), outputCoinDecimals) } + return { route, output: this.formatUnits(_output + BigInt(1), outputCoinDecimals) } } -export const getArgs = (route: IRoute): { +export function getArgs(this: Curve, route: IRoute): { _route: string[], _swapParams: number[][], _pools?: string[], @@ -337,40 +325,43 @@ export const getArgs = (route: IRoute): { _baseTokens?: string[], _secondBasePools?: string[], _secondBaseTokens?: string[] -} => _getExchangeArgs(route) +} { + return _getExchangeArgs.call(this, route) +} -export const swapExpected = async (inputCoin: string, outputCoin: string, amount: number | string): Promise => - (await getBestRouteAndOutput(inputCoin, outputCoin, amount))['output'] +export async function swapExpected(this: Curve, inputCoin: string, outputCoin: string, amount: number | string): Promise { + return (await getBestRouteAndOutput.call(this, inputCoin, outputCoin, amount))['output'] +} -export const swapRequired = async (inputCoin: string, outputCoin: string, outAmount: number | string): Promise => { - const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin); - const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress); +export async function swapRequired(this: Curve, inputCoin: string, outputCoin: string, outAmount: number | string): Promise { + const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses.call(this, inputCoin, outputCoin); + const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals.call(this, inputCoinAddress, outputCoinAddress); const _outAmount = parseUnits(outAmount, outputCoinDecimals); - const p1 = (await _getUsdRate(inputCoinAddress)) || 1; - const p2 = (await _getUsdRate(outputCoinAddress)) || 1; + const p1 = (await _getUsdRate.call(this, inputCoinAddress)) || 1; + const p2 = (await _getUsdRate.call(this, outputCoinAddress)) || 1; const approximateRequiredAmount = Number(outAmount) * p2 / p1; - const route = await _getBestRoute(inputCoinAddress, outputCoinAddress, approximateRequiredAmount); + const route = await _getBestRoute.call(this, inputCoinAddress, outputCoinAddress, approximateRequiredAmount); - const contract = curve.contracts[curve.constants.ALIASES.router].contract; - const { _route, _swapParams, _pools, _basePools, _baseTokens, _secondBasePools, _secondBaseTokens } = _getExchangeArgs(route); + const contract = this.contracts[this.constants.ALIASES.router].contract; + const { _route, _swapParams, _pools, _basePools, _baseTokens, _secondBasePools, _secondBaseTokens } = _getExchangeArgs.call(this, route); let _required; if ("get_dx(address[11],uint256[5][5],uint256,address[5],address[5],address[5],address[5],address[5])" in contract) { - _required = await contract.get_dx(_route, _swapParams, _outAmount, _pools, _basePools, _baseTokens, _secondBasePools, _secondBaseTokens, curve.constantOptions); + _required = await contract.get_dx(_route, _swapParams, _outAmount, _pools, _basePools, _baseTokens, _secondBasePools, _secondBaseTokens, this.constantOptions); } else if (_pools) { - _required = await contract.get_dx(_route, _swapParams, _outAmount, _pools, _basePools, _baseTokens, curve.constantOptions); + _required = await contract.get_dx(_route, _swapParams, _outAmount, _pools, _basePools, _baseTokens, this.constantOptions); } else { - _required = await contract.get_dx(_route, _swapParams, _outAmount, curve.constantOptions); + _required = await contract.get_dx(_route, _swapParams, _outAmount, this.constantOptions); } - return curve.formatUnits(_required, inputCoinDecimals) + return this.formatUnits(_required, inputCoinDecimals) } -export const swapPriceImpact = async (inputCoin: string, outputCoin: string, amount: number | string): Promise => { - const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin); - const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress); - const { route, output } = _getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount); +export async function swapPriceImpact(this: Curve, inputCoin: string, outputCoin: string, amount: number | string): Promise { + const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses.call(this, inputCoin, outputCoin); + const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals.call(this, inputCoinAddress, outputCoinAddress); + const { route, output } = _getBestRouteAndOutput.call(this, inputCoinAddress, outputCoinAddress, amount); const _amount = parseUnits(amount, inputCoinDecimals); const _output = parseUnits(output, outputCoinDecimals); @@ -378,22 +369,22 @@ export const swapPriceImpact = async (inputCoin: string, outputCoin: string, amo const amountIntBN = toBN(_amount, 0); if (smallAmountIntBN.gte(amountIntBN)) return 0; - const contract = curve.contracts[curve.constants.ALIASES.router].contract; + const contract = this.contracts[this.constants.ALIASES.router].contract; let _smallAmount = fromBN(smallAmountIntBN.div(10 ** inputCoinDecimals), inputCoinDecimals); - const { _route, _swapParams, _pools } = _getExchangeArgs(route); + const { _route, _swapParams, _pools } = _getExchangeArgs.call(this, route); let _smallOutput: bigint; try { if (_pools) { - _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, _pools, curve.constantOptions); + _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, _pools, this.constantOptions); } else { - _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, curve.constantOptions); + _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, this.constantOptions); } - } catch (e) { - _smallAmount = curve.parseUnits("1", inputCoinDecimals); // Dirty hack + } catch { + _smallAmount = this.parseUnits("1", inputCoinDecimals); // Dirty hack if (_pools) { - _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, _pools, curve.constantOptions); + _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, _pools, this.constantOptions); } else { - _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, curve.constantOptions); + _smallOutput = await contract.get_dy(_route, _swapParams, _smallAmount, this.constantOptions); } } const priceImpactBN = _get_price_impact(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals); @@ -401,49 +392,49 @@ export const swapPriceImpact = async (inputCoin: string, outputCoin: string, amo return Number(_cutZeros(priceImpactBN.toFixed(4))) } -export const swapIsApproved = async (inputCoin: string, amount: number | string): Promise => { - return await hasAllowance([inputCoin], [amount], curve.signerAddress, curve.constants.ALIASES.router); +export async function swapIsApproved(this: Curve, inputCoin: string, amount: number | string): Promise { + return await hasAllowance.call(this, [inputCoin], [amount], this.signerAddress, this.constants.ALIASES.router); } -export const swapApproveEstimateGas = async (inputCoin: string, amount: number | string): Promise => { - return await ensureAllowanceEstimateGas([inputCoin], [amount], curve.constants.ALIASES.router); +export async function swapApproveEstimateGas(this: Curve, inputCoin: string, amount: number | string): Promise { + return await ensureAllowanceEstimateGas.call(this, [inputCoin], [amount], this.constants.ALIASES.router); } -export const swapApprove = async (inputCoin: string, amount: number | string): Promise => { - return await ensureAllowance([inputCoin], [amount], curve.constants.ALIASES.router); +export async function swapApprove(this: Curve, inputCoin: string, amount: number | string): Promise { + return await ensureAllowance.call(this, [inputCoin], [amount], this.constants.ALIASES.router); } -export const swapEstimateGas = async (inputCoin: string, outputCoin: string, amount: number | string): Promise => { - const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin); - const [inputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress); - const { route } = _getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount); +export async function swapEstimateGas(this: Curve, inputCoin: string, outputCoin: string, amount: number | string): Promise { + const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses.call(this, inputCoin, outputCoin); + const [inputCoinDecimals] = _getCoinDecimals.call(this, inputCoinAddress, outputCoinAddress); + const { route } = _getBestRouteAndOutput.call(this, inputCoinAddress, outputCoinAddress, amount); if (route.length === 0) return 0 const _amount = parseUnits(amount, inputCoinDecimals); - const [gas] = await _estimateGasForDifferentRoutes([route], inputCoinAddress, outputCoinAddress, _amount); + const [gas] = await _estimateGasForDifferentRoutes.call(this, [route], inputCoinAddress, outputCoinAddress, _amount); return gas } -export const swap = async (inputCoin: string, outputCoin: string, amount: number | string, slippage = 0.5): Promise => { - const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin); - const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress); +export async function swap(this: Curve, inputCoin: string, outputCoin: string, amount: number | string, slippage = 0.5): Promise { + const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses.call(this, inputCoin, outputCoin); + const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals.call(this, inputCoinAddress, outputCoinAddress); - await swapApprove(inputCoin, amount); - const { route, output } = _getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount); + await swapApprove.call(this, inputCoin, amount); + const { route, output } = _getBestRouteAndOutput.call(this, inputCoinAddress, outputCoinAddress, amount); if (route.length === 0) { throw new Error("This pair can't be exchanged"); } - const { _route, _swapParams, _pools } = _getExchangeArgs(route); + const { _route, _swapParams, _pools } = _getExchangeArgs.call(this, route); const _amount = parseUnits(amount, inputCoinDecimals); const minRecvAmountBN: BigNumber = BN(output).times(100 - slippage).div(100); const _minRecvAmount = fromBN(minRecvAmountBN, outputCoinDecimals); - const contract = curve.contracts[curve.constants.ALIASES.router].contract; - const value = isEth(inputCoinAddress) ? _amount : curve.parseUnits("0"); + const contract = this.contracts[this.constants.ALIASES.router].contract; + const value = isEth(inputCoinAddress) ? _amount : this.parseUnits("0"); - await curve.updateFeeData(); + await this.updateFeeData(); if (_pools) { const gasLimit = (DIGas(await contract.exchange.estimateGas( _route, @@ -451,24 +442,24 @@ export const swap = async (inputCoin: string, outputCoin: string, amount: number _amount, _minRecvAmount, _pools, - { ...curve.constantOptions, value } - ))) * (curve.chainId === 1 ? curve.parseUnits("130", 0) : curve.parseUnits("160", 0)) / curve.parseUnits("100", 0); - return await contract.exchange(_route, _swapParams, _amount, _minRecvAmount, _pools, { ...curve.options, value, gasLimit }); + { ...this.constantOptions, value } + ))) * (this.chainId === 1 ? this.parseUnits("130", 0) : this.parseUnits("160", 0)) / this.parseUnits("100", 0); + return await contract.exchange(_route, _swapParams, _amount, _minRecvAmount, _pools, { ...this.options, value, gasLimit }); } else { const gasLimit = (DIGas(await contract.exchange.estimateGas( _route, _swapParams, _amount, _minRecvAmount, - { ...curve.constantOptions, value } - ))) * curve.parseUnits("160", 0) / curve.parseUnits("100", 0); - return await contract.exchange(_route, _swapParams, _amount, _minRecvAmount, { ...curve.options, value, gasLimit }); + { ...this.constantOptions, value } + ))) * this.parseUnits("160", 0) / this.parseUnits("100", 0); + return await contract.exchange(_route, _swapParams, _amount, _minRecvAmount, { ...this.options, value, gasLimit }); } } -export const getSwappedAmount = async (tx: ethers.ContractTransactionResponse, outputCoin: string): Promise => { - const [outputCoinAddress] = _getCoinAddresses(outputCoin); - const [outputCoinDecimals] = _getCoinDecimals(outputCoinAddress); +export async function getSwappedAmount(this: Curve, tx: ethers.ContractTransactionResponse, outputCoin: string): Promise { + const [outputCoinAddress] = _getCoinAddresses.call(this, outputCoin); + const [outputCoinDecimals] = _getCoinDecimals.call(this, outputCoinAddress); const txInfo: ethers.ContractTransactionReceipt | null = await tx.wait(); if (txInfo === null) return '0.0' @@ -482,10 +473,10 @@ export const getSwappedAmount = async (tx: ethers.ContractTransactionResponse, o ethers.dataSlice(txInfo.logs[txInfo.logs.length - i].data, 0) ); break; - } catch (err) {} + } catch {} } if (res === undefined) return '0.0' - return curve.formatUnits(res[res.length - 1], outputCoinDecimals); + return this.formatUnits(res[res.length - 1], outputCoinDecimals); } diff --git a/src/utils.ts b/src/utils.ts index a41ef517..d29b545f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import {Contract} from 'ethers'; +import {Contract, ethers} from 'ethers'; import {Contract as MulticallContract} from "@curvefi/ethcall"; import BigNumber from 'bignumber.js'; import { @@ -13,7 +13,7 @@ import { IVolumeAndAPYs, REFERENCE_ASSET, } from './interfaces'; -import {curve} from "./curve.js"; +import {Curve} from "./curve.js"; import { _getCurveLiteNetworks, _getFactoryAPYs, @@ -22,11 +22,12 @@ import { _getVolumes, } from "./external-api.js"; import {_getAllPoolsFromApi, _getUsdPricesFromApi} from "./cached.js"; -import ERC20Abi from './constants/abis/ERC20.json' with { type: 'json' }; +import ERC20Abi from './constants/abis/ERC20.json' with {type: 'json'}; import {L2Networks} from './constants/L2Networks.js'; import {volumeNetworks} from "./constants/volumeNetworks.js"; import {getPool} from "./pools/index.js"; import {NETWORK_CONSTANTS} from "./constants/network_constants.js"; +import {formatUnits} from "./constants/utils"; export const ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; @@ -53,8 +54,8 @@ export const formatNumber = (n: number | string, decimals = 18): string => { return !fractional ? integer : integer + "." + fractional.slice(0, decimals); } -export const parseUnits = (n: number | string, decimals = 18): bigint => { - return curve.parseUnits(formatNumber(n, decimals), decimals); +export function parseUnits(n: number | string, decimals = 18): bigint { + return ethers.parseUnits(formatNumber(n, decimals), decimals); } // bignumber.js @@ -62,7 +63,7 @@ export const parseUnits = (n: number | string, decimals = 18): bigint => { export const BN = (val: number | string): BigNumber => new BigNumber(checkNumber(val)); export const toBN = (n: bigint, decimals = 18): BigNumber => { - return BN(curve.formatUnits(n, decimals)); + return BN(formatUnits(n, decimals)); } export const toStringFromBN = (bn: BigNumber, decimals = 18): string => { @@ -70,7 +71,7 @@ export const toStringFromBN = (bn: BigNumber, decimals = 18): string => { } export const fromBN = (bn: BigNumber, decimals = 18): bigint => { - return curve.parseUnits(toStringFromBN(bn, decimals), decimals) + return parseUnits(toStringFromBN(bn, decimals), decimals) } // ------------------- @@ -78,7 +79,7 @@ export const fromBN = (bn: BigNumber, decimals = 18): bigint => { export const isEth = (address: string): boolean => address.toLowerCase() === ETH_ADDRESS.toLowerCase(); export const getEthIndex = (addresses: string[]): number => addresses.map((address: string) => address.toLowerCase()).indexOf(ETH_ADDRESS.toLowerCase()); -export const mulBy1_3 = (n: bigint): bigint => n * curve.parseUnits("130", 0) / curve.parseUnits("100", 0); +export const mulBy1_3 = (n: bigint): bigint => n * parseUnits("130", 0) / parseUnits("100", 0); export const smartNumber = (abstractNumber: bigint | bigint[]): number | number[] => { if(Array.isArray(abstractNumber)) { @@ -115,15 +116,15 @@ export const gasSum = (gas: number[], currentGas: number | number[]): number[] = } // coins can be either addresses or symbols -export const _getCoinAddressesNoCheck = (...coins: string[] | string[][]): string[] => { +export function _getCoinAddressesNoCheck(this: Curve, ...coins: string[] | string[][]): string[] { if (coins.length == 1 && Array.isArray(coins[0])) coins = coins[0]; coins = coins as string[]; - return coins.map((c) => c.toLowerCase()).map((c) => curve.constants.COINS[c] || c); + return coins.map((c) => c.toLowerCase()).map((c) => this.constants.COINS[c] || c); } -export const _getCoinAddresses = (...coins: string[] | string[][]): string[] => { - const coinAddresses = _getCoinAddressesNoCheck(...coins); - const availableAddresses = [...Object.keys(curve.constants.DECIMALS), ...curve.constants.GAUGES]; +export function _getCoinAddresses(this: Curve, ...coins: string[] | string[][]): string[] { + const coinAddresses = _getCoinAddressesNoCheck.call(this, ...coins); + const availableAddresses = [...Object.keys(this.constants.DECIMALS), ...this.constants.GAUGES]; for (const coinAddr of coinAddresses) { if (!availableAddresses.includes(coinAddr)) throw Error(`Coin with address '${coinAddr}' is not available`); } @@ -131,16 +132,16 @@ export const _getCoinAddresses = (...coins: string[] | string[][]): string[] => return coinAddresses } -export const _getCoinDecimals = (...coinAddresses: string[] | string[][]): number[] => { +export function _getCoinDecimals(this: Curve, ...coinAddresses: string[] | string[][]): number[] { if (coinAddresses.length == 1 && Array.isArray(coinAddresses[0])) coinAddresses = coinAddresses[0]; coinAddresses = coinAddresses as string[]; - return coinAddresses.map((coinAddr) => curve.constants.DECIMALS[coinAddr.toLowerCase()] ?? 18); // 18 for gauges + return coinAddresses.map((coinAddr) => this.constants.DECIMALS[coinAddr.toLowerCase()] ?? 18); // 18 for gauges } -export const _getBalances = async (coins: string[], addresses: string[]): Promise> => { - const coinAddresses = _getCoinAddresses(coins); - const decimals = _getCoinDecimals(coinAddresses); +export async function _getBalances(this: Curve, coins: string[], addresses: string[]): Promise> { + const coinAddresses = _getCoinAddresses.call(this, coins); + const decimals = _getCoinDecimals.call(this, coinAddresses); const ethIndex = getEthIndex(coinAddresses); if (ethIndex !== -1) { @@ -149,14 +150,14 @@ export const _getBalances = async (coins: string[], addresses: string[]): Promis const contractCalls = []; for (const coinAddr of coinAddresses) { - contractCalls.push(...addresses.map((address: string) => curve.contracts[coinAddr].multicallContract.balanceOf(address))); + contractCalls.push(...addresses.map((address: string) => this.contracts[coinAddr].multicallContract.balanceOf(address))); } - const _response: bigint[] = await curve.multicallProvider.all(contractCalls); + const _response: bigint[] = await this.multicallProvider.all(contractCalls); if (ethIndex !== -1) { const ethBalances: bigint[] = []; for (const address of addresses) { - ethBalances.push(await curve.provider.getBalance(address)); + ethBalances.push(await this.provider.getBalance(address)); } _response.splice(ethIndex * addresses.length, 0, ...ethBalances); } @@ -168,36 +169,36 @@ export const _getBalances = async (coins: string[], addresses: string[]): Promis const balances: IDict = {}; for (const address of addresses) { - balances[address] = _balances[address].map((b, i: number ) => curve.formatUnits(b, decimals[i])); + balances[address] = _balances[address].map((b, i: number ) => this.formatUnits(b, decimals[i])); } return balances; } -export const _prepareAddresses = (addresses: string[] | string[][]): string[] => { +export function _prepareAddresses(this: Curve, addresses: string[] | string[][]): string[] { if (addresses.length == 1 && Array.isArray(addresses[0])) addresses = addresses[0]; - if (addresses.length === 0 && curve.signerAddress !== '') addresses = [curve.signerAddress]; + if (addresses.length === 0 && this.signerAddress !== '') addresses = [this.signerAddress]; addresses = addresses as string[]; return addresses.filter((val, idx, arr) => arr.indexOf(val) === idx) } -export const _getAddress = (address: string): string => { - address = address || curve.signerAddress; +export function _getAddress(this: Curve, address: string): string { + address = address || this.signerAddress; if (!address) throw Error("Need to connect wallet or pass address into args"); return address } -export const getBalances = async (coins: string[], ...addresses: string[] | string[][]): Promise | string[]> => { - addresses = _prepareAddresses(addresses); - const balances: IDict = await _getBalances(coins, addresses); +export async function getBalances(this: Curve, coins: string[], ...addresses: string[] | string[][]): Promise | string[]> { + addresses = _prepareAddresses.call(this, addresses); + const balances: IDict = await _getBalances.call(this, coins, addresses); return addresses.length === 1 ? balances[addresses[0]] : balances } -export const _getAllowance = async (coins: string[], address: string, spender: string): Promise => { +export async function _getAllowance(this: Curve, coins: string[], address: string, spender: string): Promise { const _coins = [...coins] const ethIndex = getEthIndex(_coins); if (ethIndex !== -1) { @@ -207,10 +208,10 @@ export const _getAllowance = async (coins: string[], address: string, spender: s let allowance: bigint[]; if (_coins.length === 1) { - allowance = [await curve.contracts[_coins[0]].contract.allowance(address, spender, curve.constantOptions)]; + allowance = [await this.contracts[_coins[0]].contract.allowance(address, spender, this.constantOptions)]; } else { - const contractCalls = _coins.map((coinAddr) => curve.contracts[coinAddr].multicallContract.allowance(address, spender)); - allowance = await curve.multicallProvider.all(contractCalls); + const contractCalls = _coins.map((coinAddr) => this.contracts[coinAddr].multicallContract.allowance(address, spender)); + allowance = await this.multicallProvider.all(contractCalls); } @@ -222,44 +223,44 @@ export const _getAllowance = async (coins: string[], address: string, spender: s } // coins can be either addresses or symbols -export const getAllowance = async (coins: string[], address: string, spender: string): Promise => { - const coinAddresses = _getCoinAddresses(coins); - const decimals = _getCoinDecimals(coinAddresses); - const _allowance = await _getAllowance(coinAddresses, address, spender); +export async function getAllowance(this: Curve, coins: string[], address: string, spender: string): Promise { + const coinAddresses = _getCoinAddresses.call(this, coins); + const decimals = _getCoinDecimals.call(this, coinAddresses); + const _allowance = await _getAllowance.call(this, coinAddresses, address, spender); - return _allowance.map((a, i) => curve.formatUnits(a, decimals[i])) + return _allowance.map((a, i) => this.formatUnits(a, decimals[i])) } // coins can be either addresses or symbols -export const hasAllowance = async (coins: string[], amounts: (number | string)[], address: string, spender: string): Promise => { - const coinAddresses = _getCoinAddresses(coins); - const decimals = _getCoinDecimals(coinAddresses); - const _allowance = await _getAllowance(coinAddresses, address, spender); +export async function hasAllowance(this: Curve, coins: string[], amounts: (number | string)[], address: string, spender: string): Promise { + const coinAddresses = _getCoinAddresses.call(this, coins); + const decimals = _getCoinDecimals.call(this, coinAddresses); + const _allowance = await _getAllowance.call(this, coinAddresses, address, spender); const _amounts = amounts.map((a, i) => parseUnits(a, decimals[i])); return _allowance.map((a, i) => a >= _amounts[i]).reduce((a, b) => a && b); } -export const _ensureAllowance = async (coins: string[], amounts: bigint[], spender: string, isMax = true): Promise => { - const address = curve.signerAddress; - const allowance: bigint[] = await _getAllowance(coins, address, spender); +export async function _ensureAllowance(this: Curve, coins: string[], amounts: bigint[], spender: string, isMax = true): Promise { + const address = this.signerAddress; + const allowance: bigint[] = await _getAllowance.call(this, coins, address, spender); const txHashes: string[] = [] for (let i = 0; i < allowance.length; i++) { if (allowance[i] < amounts[i]) { - const contract = curve.contracts[coins[i]].contract; + const contract = this.contracts[coins[i]].contract; const _approveAmount = isMax ? MAX_ALLOWANCE : amounts[i]; - await curve.updateFeeData(); + await this.updateFeeData(); - if (allowance[i] > curve.parseUnits("0")) { - const gasLimit = mulBy1_3(DIGas(await contract.approve.estimateGas(spender, curve.parseUnits("0"), curve.constantOptions))); - const resetTx = await contract.approve(spender, curve.parseUnits("0"), { ...curve.options, gasLimit }); + if (allowance[i] > parseUnits("0")) { + const gasLimit = mulBy1_3(DIGas(await contract.approve.estimateGas(spender, parseUnits("0"), this.constantOptions))); + const resetTx = await contract.approve(spender, parseUnits("0"), { ...this.options, gasLimit }); txHashes.push(resetTx.hash); await resetTx.wait(); } - const gasLimit = mulBy1_3(DIGas(await contract.approve.estimateGas(spender, _approveAmount, curve.constantOptions))); - const approveTx = await contract.approve(spender, _approveAmount, { ...curve.options, gasLimit }); + const gasLimit = mulBy1_3(DIGas(await contract.approve.estimateGas(spender, _approveAmount, this.constantOptions))); + const approveTx = await contract.approve(spender, _approveAmount, { ...this.options, gasLimit }); txHashes.push(approveTx.hash); await approveTx.wait(); } @@ -269,20 +270,20 @@ export const _ensureAllowance = async (coins: string[], amounts: bigint[], spend } // coins can be either addresses or symbols -export const ensureAllowanceEstimateGas = async (coins: string[], amounts: (number | string)[], spender: string, isMax = true): Promise => { - const coinAddresses = _getCoinAddresses(coins); - const decimals = _getCoinDecimals(coinAddresses); +export async function ensureAllowanceEstimateGas(this: Curve, coins: string[], amounts: (number | string)[], spender: string, isMax = true): Promise { + const coinAddresses = _getCoinAddresses.call(this, coins); + const decimals = _getCoinDecimals.call(this, coinAddresses); const _amounts = amounts.map((a, i) => parseUnits(a, decimals[i])); - const address = curve.signerAddress; - const _allowance: bigint[] = await _getAllowance(coinAddresses, address, spender); + const address = this.signerAddress; + const _allowance: bigint[] = await _getAllowance.call(this, coinAddresses, address, spender); let gas = [0,0]; for (let i = 0; i < _allowance.length; i++) { if (_allowance[i] < _amounts[i]) { - const contract = curve.contracts[coinAddresses[i]].contract; + const contract = this.contracts[coinAddresses[i]].contract; const _approveAmount = isMax ? MAX_ALLOWANCE : _amounts[i]; - if (_allowance[i] > curve.parseUnits("0")) { - let currentGas = smartNumber(await contract.approve.estimateGas(spender, curve.parseUnits("0"), curve.constantOptions)); + if (_allowance[i] > parseUnits("0")) { + let currentGas = smartNumber(await contract.approve.estimateGas(spender, parseUnits("0"), this.constantOptions)); // For some coins (crv for example ) we can't estimate the second tx gas (approve: 0 --> amount), so we assume it will cost the same amount of gas if (typeof currentGas === "number") { currentGas = currentGas * 2; @@ -291,7 +292,7 @@ export const ensureAllowanceEstimateGas = async (coins: string[], amounts: (numb } gas = gasSum(gas, currentGas); } else { - const currentGas = smartNumber(await contract.approve.estimateGas(spender, _approveAmount, curve.constantOptions)); + const currentGas = smartNumber(await contract.approve.estimateGas(spender, _approveAmount, this.constantOptions)); gas = gasSum(gas, currentGas); } } @@ -301,31 +302,31 @@ export const ensureAllowanceEstimateGas = async (coins: string[], amounts: (numb } // coins can be either addresses or symbols -export const ensureAllowance = async (coins: string[], amounts: (number | string)[], spender: string, isMax = true): Promise => { - const coinAddresses = _getCoinAddresses(coins); - const decimals = _getCoinDecimals(coinAddresses); +export async function ensureAllowance(this: Curve, coins: string[], amounts: (number | string)[], spender: string, isMax = true): Promise { + const coinAddresses = _getCoinAddresses.call(this, coins); + const decimals = _getCoinDecimals.call(this, coinAddresses); const _amounts = amounts.map((a, i) => parseUnits(a, decimals[i])); - return await _ensureAllowance(coinAddresses, _amounts, spender, isMax) + return await _ensureAllowance.call(this, coinAddresses, _amounts, spender, isMax) } -export const getPoolIdBySwapAddress = (swapAddress: string): string => { - const poolsData = curve.getPoolsData(); +export function getPoolIdBySwapAddress(this: Curve, swapAddress: string): string { + const poolsData = this.getPoolsData(); const poolIds = Object.entries(poolsData).filter(([, poolData]) => poolData.swap_address.toLowerCase() === swapAddress.toLowerCase()); if (poolIds.length === 0) return ""; return poolIds[0][0]; } -export const _getRewardsFromApi = async (): Promise> => { - const network = curve.constants.NETWORK_NAME; - const allTypesExtendedPoolData = await _getAllPoolsFromApi(network, curve.isLiteChain); +export async function _getRewardsFromApi(this: Curve): Promise> { + const network = this.constants.NETWORK_NAME; + const allTypesExtendedPoolData = await _getAllPoolsFromApi.call(this, network); const rewardsDict: IDict = {}; for (const extendedPoolData of allTypesExtendedPoolData) { for (const pool of extendedPoolData.poolData) { if (pool.gaugeAddress) { rewardsDict[pool.gaugeAddress.toLowerCase()] = (pool.gaugeRewards ?? pool.gaugeExtraRewards ?? []) - .filter((r) => curve.chainId === 1 || r.tokenAddress.toLowerCase() !== curve.constants.COINS.crv); + .filter((r) => this.chainId === 1 || r.tokenAddress.toLowerCase() !== this.constants.COINS.crv); } } } @@ -334,14 +335,14 @@ export const _getRewardsFromApi = async (): Promise> => } const _usdRatesCache: IDict<{ rate: number, time: number }> = {} -export const _getUsdRate = async (assetId: string): Promise => { - if (curve.chainId === 1 && assetId.toLowerCase() === '0x8762db106b2c2a0bccb3a80d1ed41273552616e8') return 0; // RSR - const pricesFromApi = await _getUsdPricesFromApi(); +export async function _getUsdRate(this: Curve, assetId: string): Promise { + if (this.chainId === 1 && assetId.toLowerCase() === '0x8762db106b2c2a0bccb3a80d1ed41273552616e8') return 0; // RSR + const pricesFromApi = await _getUsdPricesFromApi(this.constants.NETWORK_NAME); if (assetId.toLowerCase() in pricesFromApi) return pricesFromApi[assetId.toLowerCase()]; - if (assetId === 'USD' || (curve.chainId === 137 && (assetId.toLowerCase() === curve.constants.COINS.am3crv.toLowerCase()))) return 1 + if (assetId === 'USD' || (this.chainId === 137 && (assetId.toLowerCase() === this.constants.COINS.am3crv.toLowerCase()))) return 1 - let chainName = curve.isLiteChain? await curve.constants.NETWORK_NAME : { + let chainName = this.isLiteChain? await this.constants.NETWORK_NAME : { 1: 'ethereum', 10: 'optimistic-ethereum', 56: "binance-smart-chain", @@ -360,9 +361,9 @@ export const _getUsdRate = async (assetId: string): Promise => { 43114: 'avalanche', 42161: 'arbitrum-one', 1313161554: 'aurora', - }[curve.chainId]; + }[this.chainId]; - const nativeTokenName = curve.isLiteChain ? curve.constants?.API_CONSTANTS?.nativeTokenName:{ + const nativeTokenName = this.isLiteChain ? this.constants?.API_CONSTANTS?.nativeTokenName:{ 1: 'ethereum', 10: 'ethereum', 56: 'binancecoin', @@ -381,15 +382,15 @@ export const _getUsdRate = async (assetId: string): Promise => { 43114: 'avalanche-2', 42161: 'ethereum', 1313161554: 'ethereum', - }[curve.chainId] as string; + }[this.chainId] as string; if (chainName === undefined) { throw Error('curve object is not initialized') } if (nativeTokenName === undefined) { - if(curve.isLiteChain && curve.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase() && curve.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase() in pricesFromApi) { - return pricesFromApi[curve.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase()]; + if(this.isLiteChain && this.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase() && this.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase() in pricesFromApi) { + return pricesFromApi[this.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase()]; } else { throw Error('nativeTokenName not found') } @@ -406,17 +407,17 @@ export const _getUsdRate = async (assetId: string): Promise => { assetId = isEth(assetId) ? nativeTokenName : assetId.toLowerCase(); // No EURT on Coingecko Polygon - if (curve.chainId === 137 && assetId.toLowerCase() === curve.constants.COINS.eurt) { + if (this.chainId === 137 && assetId.toLowerCase() === this.constants.COINS.eurt) { chainName = 'ethereum'; assetId = '0xC581b735A1688071A1746c968e0798D642EDE491'.toLowerCase(); // EURT Ethereum } // CRV - if (assetId.toLowerCase() === curve.constants.ALIASES.crv) { + if (assetId.toLowerCase() === this.constants.ALIASES.crv) { assetId = 'curve-dao-token'; } - if(curve.isLiteChain && assetId.toLowerCase() === curve.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase()) { + if(this.isLiteChain && assetId.toLowerCase() === this.constants.API_CONSTANTS?.wrappedNativeTokenAddress.toLowerCase()) { assetId = nativeTokenName } @@ -435,7 +436,7 @@ export const _getUsdRate = async (assetId: string): Promise => { 'time': Date.now(), }; } else { - if (!curve.isLiteChain) { + if (!this.isLiteChain) { console.warn(`Non-200 response for ${assetId}:`, response.status, data); } _usdRatesCache[assetId] = { @@ -444,7 +445,7 @@ export const _getUsdRate = async (assetId: string): Promise => { }; } } catch (err: any) { - if (!curve.isLiteChain) { + if (!this.isLiteChain) { console.error(`Error fetching USD rate for ${assetId}:`, err.message); } _usdRatesCache[assetId] = { @@ -457,13 +458,13 @@ export const _getUsdRate = async (assetId: string): Promise => { return _usdRatesCache[assetId]['rate'] } -export const getUsdRate = async (coin: string): Promise => { - const [coinAddress] = _getCoinAddressesNoCheck(coin); - return await _getUsdRate(coinAddress); +export async function getUsdRate(this: Curve, coin: string): Promise { + const [coinAddress] = _getCoinAddressesNoCheck.call(this, coin); + return await _getUsdRate.call(this, coinAddress); } -export const getBaseFeeByLastBlock = async (): Promise => { - const provider = curve.provider; +export async function getBaseFeeByLastBlock(this: Curve): Promise { + const provider = this.provider; try { const block = await provider.getBlock('latest'); @@ -477,62 +478,62 @@ export const getBaseFeeByLastBlock = async (): Promise => { } } -export const getGasPrice = async () => { - const provider = curve.provider; +export async function getGasPrice(this: Curve) { + const provider = this.provider; return Number((Number((await provider.getFeeData()).gasPrice) / 1e9).toFixed(2)); } -export const getGasPriceFromL1 = async (): Promise => { - if(L2Networks.includes(curve.chainId) && curve.L1WeightedGasPrice) { - return curve.L1WeightedGasPrice + 1e9; // + 1 gwei +export async function getGasPriceFromL1(this: Curve): Promise { + if(L2Networks.includes(this.chainId) && this.L1WeightedGasPrice) { + return this.L1WeightedGasPrice + 1e9; // + 1 gwei } else { throw Error("This method exists only for L2 networks"); } } -export const getGasPriceFromL2 = async (): Promise => { - if(curve.chainId === 42161) { - return await getBaseFeeByLastBlock() +export async function getGasPriceFromL2(this: Curve): Promise { + if(this.chainId === 42161) { + return await getBaseFeeByLastBlock.call(this) } - if(curve.chainId === 196) { - return await getGasPrice() // gwei + if(this.chainId === 196) { + return await getGasPrice.call(this) // gwei } - if(curve.chainId === 324) { - return await getGasPrice() // gwei + if(this.chainId === 324) { + return await getGasPrice.call(this) // gwei } - if(curve.chainId === 5000) { - return await getGasPrice() // gwei + if(this.chainId === 5000) { + return await getGasPrice.call(this) // gwei } - if(L2Networks.includes(curve.chainId)) { - const gasPrice = await curve.contracts[curve.constants.ALIASES.gas_oracle_blob].contract.gasPrice({"gasPrice":"0x2000000"}); + if(L2Networks.includes(this.chainId)) { + const gasPrice = await this.contracts[this.constants.ALIASES.gas_oracle_blob].contract.gasPrice({"gasPrice":"0x2000000"}); return Number(gasPrice); } else { throw Error("This method exists only for L2 networks"); } } -export const getGasInfoForL2 = async (): Promise> => { - if(curve.chainId === 42161) { - const baseFee = await getBaseFeeByLastBlock() +export async function getGasInfoForL2(this: Curve ): Promise> { + if(this.chainId === 42161) { + const baseFee = await getBaseFeeByLastBlock.call(this) return { maxFeePerGas: Number(((baseFee * 1.1) + 0.01).toFixed(2)), maxPriorityFeePerGas: 0.01, } - } else if(curve.chainId === 196) { - const gasPrice = await getGasPrice() + } else if(this.chainId === 196) { + const gasPrice = await getGasPrice.call(this) return { gasPrice, } - } else if(curve.chainId === 324) { - const gasPrice = await getGasPrice() + } else if(this.chainId === 324) { + const gasPrice = await getGasPrice.call(this) return { gasPrice, } - } else if(curve.chainId === 5000) { - const baseFee = await getBaseFeeByLastBlock() + } else if(this.chainId === 5000) { + const baseFee = await getBaseFeeByLastBlock.call(this) return { maxFeePerGas: Number(((baseFee * 1.1) + 0.01).toFixed(2)), @@ -551,7 +552,7 @@ export const getTxCostsUsd = (ethUsdRate: number, gasPrice: number, gas: number } } -export const getCurveLiteNetworks = async (): Promise => { +export async function getCurveLiteNetworks(this: Curve): Promise { return await _getCurveLiteNetworks() } @@ -560,7 +561,7 @@ export const getNetworkNameByChainId = (chainId: number, networks: ICurveLiteNet return network ? network.id : "Unknown Network"; } -export const getNetworkConstants = async (chainId: IChainId | number): Promise> => { +export async function getNetworkConstants(this: Curve, chainId: IChainId | number): Promise> { if (chainId in NETWORK_CONSTANTS) { return { ...NETWORK_CONSTANTS[chainId], IS_LITE_CHAIN: false}; } else { @@ -570,48 +571,48 @@ export const getNetworkConstants = async (chainId: IChainId | number): Promise => { - const networkConstants = await getNetworkConstants(chainId); - const allTypesExtendedPoolData = await _getAllPoolsFromApi(networkConstants.NAME, networkConstants.IS_LITE_CHAIN); +export async function getTVL(this: Curve, chainId = this.chainId): Promise { + const networkConstants = await getNetworkConstants.call(this, chainId); + const allTypesExtendedPoolData = await _getAllPoolsFromApi.call(this, networkConstants.NAME); return allTypesExtendedPoolData.reduce((sum, data) => sum + (data.tvl ?? data.tvlAll ?? 0), 0) } -export const getVolumeApiController = async (network: INetworkName): Promise => { - if(curve.isLiteChain && curve.chainId !== 146) { +export async function getVolumeApiController(this: Curve, network: INetworkName): Promise { + if(this.isLiteChain && this.chainId !== 146) { throw Error('This method is not supported for the lite version') } - if(volumeNetworks.getVolumes.includes(curve.chainId)) { - return await _getVolumes(network); + if(volumeNetworks.getVolumes.includes(this.chainId)) { + return await _getVolumes(network); } - if(volumeNetworks.getFactoryAPYs.includes(curve.chainId)) { + if(volumeNetworks.getFactoryAPYs.includes(this.chainId)) { return await _getFactoryAPYs(network); } - if(volumeNetworks.getSubgraphData.includes(curve.chainId)) { + if(volumeNetworks.getSubgraphData.includes(this.chainId)) { return await _getSubgraphData(network); } throw Error(`Can't get volume for network: ${network}`); } -export const getVolume = async (chainId = curve.chainId): Promise<{ totalVolume: number, cryptoVolume: number, cryptoShare: number }> => { - if(curve.isLiteChain && curve.chainId !== 146) { +export async function getVolume(this: Curve, chainId = this.chainId): Promise<{ totalVolume: number, cryptoVolume: number, cryptoShare: number }> { + if(this.isLiteChain && this.chainId !== 146) { throw Error('This method is not supported for the lite version') } - const networkConstants = await getNetworkConstants(chainId); - const { totalVolume, cryptoVolume, cryptoShare } = await getVolumeApiController(networkConstants.NAME); + const networkConstants = await getNetworkConstants.call(this, chainId); + const { totalVolume, cryptoVolume, cryptoShare } = await getVolumeApiController.call(this, networkConstants.NAME); return { totalVolume, cryptoVolume, cryptoShare } } -export const _setContracts = (address: string, abi: any) => { +export function _setContracts(this: Curve, address: string, abi: any) { const contracts = { abi, - contract: new Contract(address, abi, curve.signer || curve.provider), + contract: new Contract(address, abi, this.signer || this.provider), multicallContract: new MulticallContract(address, abi), } - curve.contracts[address] = contracts; + this.contracts[address] = contracts; return contracts; } @@ -647,10 +648,10 @@ export const _get_price_impact = ( return BN(1).minus(rateBN.div(smallRateBN)).times(100); } -export const getCoinsData = async (...coins: string[] | string[][]): Promise<{name: string, symbol: string, decimals: number}[]> => { +export async function getCoinsData(this: Curve, ...coins: string[] | string[][]): Promise<{name: string, symbol: string, decimals: number}[]> { if (coins.length == 1 && Array.isArray(coins[0])) coins = coins[0]; coins = coins as string[]; - const coinAddresses = _getCoinAddressesNoCheck(coins); + const coinAddresses = _getCoinAddressesNoCheck.call(this, coins); console.log(coinAddresses); const ethIndex = getEthIndex(coinAddresses); @@ -663,7 +664,7 @@ export const getCoinsData = async (...coins: string[] | string[][]): Promise<{na const coinContract = new MulticallContract(coinAddr, ERC20Abi); contractCalls.push(coinContract.name(), coinContract.symbol(), coinContract.decimals()); } - const _response = await curve.multicallProvider.all(contractCalls); + const _response = await this.multicallProvider.all(contractCalls); if (ethIndex !== -1) { _response.splice(ethIndex * 2, 0, ...['Ethereum', 'ETH', 18]); @@ -674,16 +675,15 @@ export const getCoinsData = async (...coins: string[] | string[][]): Promise<{na res.push({ name: _response.shift() as string, symbol: _response.shift() as string, - decimals: Number(curve.formatUnits(_response.shift() as string, 0)), + decimals: Number(this.formatUnits(_response.shift() as string, 0)), }) }); return res; } - -export const hasDepositAndStake = (): boolean => "deposit_and_stake" in curve.constants.ALIASES; -export const hasRouter = (): boolean => "router" in curve.constants.ALIASES; +export function hasDepositAndStake(this: Curve): boolean { return "deposit_and_stake" in this.constants.ALIASES; } +export function hasRouter(this: Curve): boolean { return "router" in this.constants.ALIASES; } export const findAbiFunction = (abi: Abi, methodName: string) => abi.filter((item) => item.type == 'function' && item.name === methodName) as AbiFunction[] @@ -712,25 +712,25 @@ export const assetTypeNameHandler = (assetTypeName: string): REFERENCE_ASSET => } } -export const getBasePools = async (): Promise => { - const factoryContract = curve.contracts[curve.constants.ALIASES['stable_ng_factory']].contract; - const factoryMulticallContract = curve.contracts[curve.constants.ALIASES['stable_ng_factory']].multicallContract; +export async function getBasePools(this: Curve): Promise { + const factoryContract = this.contracts[this.constants.ALIASES['stable_ng_factory']].contract; + const factoryMulticallContract = this.contracts[this.constants.ALIASES['stable_ng_factory']].multicallContract; - const basePoolCount = Number(curve.formatUnits(await factoryContract.base_pool_count(), 0)); + const basePoolCount = Number(this.formatUnits(await factoryContract.base_pool_count(), 0)); const calls = []; for (let i = 0; i < basePoolCount; i++) { calls.push(factoryMulticallContract.base_pool_list(i)); } - const basePoolList = (await curve.multicallProvider.all(calls) as string[]).map((item: string) => item.toLowerCase()); + const basePoolList = (await this.multicallProvider.all(calls) as string[]).map((item: string) => item.toLowerCase()); - const pools = {...curve.constants.STABLE_NG_FACTORY_POOLS_DATA, ...curve.constants.FACTORY_POOLS_DATA, ...curve.constants.POOLS_DATA}; + const pools = {...this.constants.STABLE_NG_FACTORY_POOLS_DATA, ...this.constants.FACTORY_POOLS_DATA, ...this.constants.POOLS_DATA}; const basePoolIds = Object.keys(pools).filter((item: string) => basePoolList.includes(pools[item].swap_address)); return basePoolIds.map((poolId) => { - const pool = getPool(poolId); + const pool = getPool.call(this, poolId); return { id: poolId, name: pool.name, diff --git a/test/stats.test.ts b/test/stats.test.ts index facdc2d7..d4b471b7 100644 --- a/test/stats.test.ts +++ b/test/stats.test.ts @@ -68,7 +68,7 @@ const poolStatsTest = (name: string) => { let pool: PoolTemplate; before(async function () { - pool = getPool(name); + pool = getPool.call(_curve, name); });