diff --git a/src/constants/index.ts b/src/constants/index.ts index 2b11031..ae1f8ba 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -25,4 +25,5 @@ export const TOKENS_MAPPING: Record = { BTC: '0xae478ff7d83ed072dbc5e264250e67ef58f57c99d89b447efd8a0a2e8b2be76e::coin::T', // wormhole wrapped BTC WETH: '0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::WETH', // LayerZero WETH USDC: '0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC', // layerzero USDC + amAPT: '0x111ae3e5bc816a5e63c2da97d0aa3886519e0cd5e4b046659fa35796bd11542a::amapt_token::AmnisApt' // Amnis APT }; diff --git a/src/modules/LiquidityModule.ts b/src/modules/LiquidityModule.ts index 0f0e98b..e381faa 100644 --- a/src/modules/LiquidityModule.ts +++ b/src/modules/LiquidityModule.ts @@ -24,6 +24,8 @@ import { } from '../utils'; import { CreateTXPayloadParams } from './SwapModule'; +import {VERSION_0, VERSION_0_5} from "../constants"; +import {getCurve, getScriptsFor} from "../utils/contracts"; interface ICreateBurnLiquidityPayload { fromToken: AptosResourceType; @@ -31,6 +33,7 @@ interface ICreateBurnLiquidityPayload { burnAmount: Decimal | number; slippage: number; curveType: CurveType; + version?: typeof VERSION_0 | typeof VERSION_0_5; } interface ICalculateRatesParams { @@ -40,10 +43,11 @@ interface ICalculateRatesParams { interactiveToken: 'from' | 'to'; curveType: CurveType; slippage: number; + version?: typeof VERSION_0 | typeof VERSION_0_5; } interface ICalculateSupplyParams - extends Pick { + extends Pick { toAmount: Decimal | number; fromAmount: Decimal | number; toReserve: Decimal | number; @@ -58,6 +62,7 @@ interface ICalculateBurnLiquidityParams { slippage: number; burnAmount: Decimal | number; curveType: CurveType; + version?: typeof VERSION_0 | typeof VERSION_0_5; } type TGetResourcesPayload = Omit< @@ -79,15 +84,21 @@ export class LiquidityModule implements IModule { } async checkPoolExistence(params: TGetResourcesPayload): Promise { - const { moduleAccount, resourceAccount } = this.sdk.networkOptions; + const { moduleAccount, resourceAccount, moduleAccountV05, resourceAccountV05 } = this.sdk.networkOptions; const curves = this.sdk.curves; + const { version = VERSION_0 } = params; + + const moduleAcc = version === VERSION_0_5 ? moduleAccountV05 : moduleAccount; + const resourceAcc = version === VERSION_0_5 ? resourceAccountV05 : resourceAccount; + const modulesLiquidityPool = composeType( - moduleAccount, + moduleAcc, 'liquidity_pool', 'LiquidityPool', ); - const curve = curves[params.curveType]; + const curve = getCurve(params.curveType, curves, version); + const liquidityPoolType = getPoolStr( params.fromToken, params.toToken, @@ -98,7 +109,7 @@ export class LiquidityModule implements IModule { try { const liquidityPoolResource = await this.sdk.Resources.fetchAccountResource( - resourceAccount, + resourceAcc, liquidityPoolType, ); return Boolean(liquidityPoolResource?.type); @@ -108,14 +119,19 @@ export class LiquidityModule implements IModule { } async getLiquidityPoolResource(params: TGetResourcesPayload) { - const { moduleAccount, resourceAccount } = this.sdk.networkOptions; + const { moduleAccount, resourceAccount, moduleAccountV05, resourceAccountV05 } = this.sdk.networkOptions; const curves = this.sdk.curves; + const { version = VERSION_0 } = params; + + const moduleAcc = version === VERSION_0_5 ? moduleAccountV05 : moduleAccount; + const resourceAcc = version === VERSION_0_5 ? resourceAccountV05 : resourceAccount; + const curve = getCurve(params.curveType, curves, version); + const modulesLiquidityPool = composeType( - moduleAccount, + moduleAcc, 'liquidity_pool', 'LiquidityPool', ); - const curve = curves[params.curveType]; const liquidityPoolType = getPoolStr( params.fromToken, @@ -129,7 +145,7 @@ export class LiquidityModule implements IModule { try { liquidityPoolResource = await this.sdk.Resources.fetchAccountResource( - resourceAccount, + resourceAcc, liquidityPoolType, ); } catch (e) { @@ -140,9 +156,11 @@ export class LiquidityModule implements IModule { async getLiquiditySupplyResource(params: TGetResourcesPayload) { const curves = this.sdk.curves; - const { modules, resourceAccount } = this.sdk.networkOptions; + const { modules, resourceAccount, resourceAccountV05 } = this.sdk.networkOptions; + const { version = VERSION_0 } = params; - const curve = curves[params.curveType]; + const curve = getCurve(params.curveType, curves, version); + const resourceAcc = version === VERSION_0_5 ? resourceAccountV05 : resourceAccount; function getPoolLpStr( coinX: string, @@ -153,8 +171,7 @@ export class LiquidityModule implements IModule { ? [coinX, coinY] : [coinY, coinX]; return composeType( - // - resourceAccount, + resourceAcc, 'lp_coin', 'LP', [sortedX, sortedY, curve], @@ -168,7 +185,7 @@ export class LiquidityModule implements IModule { try { liquidityPoolResource = await this.sdk.Resources.fetchAccountResource( - resourceAccount, + resourceAcc, composeType(modules.CoinInfo, [lpString]), ); } catch (e) { @@ -307,17 +324,21 @@ export class LiquidityModule implements IModule { } const isPoolExisted = await this.checkPoolExistence(params); + const { version = VERSION_0 } = params; + + const { moduleAccountV05, moduleAccount } = this.sdk.networkOptions; + const moduleAcc = version === VERSION_0_5 ? moduleAccountV05 : moduleAccount; - const { modules } = this.sdk.networkOptions; const curves = this.sdk.curves; + const scriptsVersion = getScriptsFor(version); const functionName = composeType( - modules.Scripts, + moduleAcc, + scriptsVersion, isPoolExisted ? 'add_liquidity' : 'register_pool_and_add_liquidity', ); - - const curve = curves[params.curveType]; + const curve = getCurve(params.curveType, curves, version); const isSorted = is_sorted(params.fromToken, params.toToken); const typeArguments = isSorted @@ -366,10 +387,13 @@ export class LiquidityModule implements IModule { ); } + const { version = VERSION_0 } = params; + const curves = this.sdk.curves; - const curve = curves[params.curveType]; + const curve = getCurve(params.curveType, curves, version); - const { modules } = this.sdk.networkOptions; + const { moduleAccountV05, moduleAccount } = this.sdk.networkOptions; + const moduleAcc = version === VERSION_0_5 ? moduleAccountV05 : moduleAccount; const output = await this.calculateOutputBurn(params); @@ -382,7 +406,9 @@ export class LiquidityModule implements IModule { ? [params.burnAmount.toString(), xOutput, yOutput] : [params.burnAmount.toString(), yOutput, xOutput]; - const functionName = composeType(modules.Scripts, 'remove_liquidity'); + const scriptsVersion = getScriptsFor(version); + + const functionName = composeType(moduleAcc, scriptsVersion, 'remove_liquidity'); const typeArguments = isSorted ? [params.fromToken, params.toToken, curve] diff --git a/src/tests/pool.test.ts b/src/tests/pool.test.ts index 778c770..77855f7 100644 --- a/src/tests/pool.test.ts +++ b/src/tests/pool.test.ts @@ -1,4 +1,12 @@ -import { MODULES_ACCOUNT, RESOURCES_ACCOUNT, TOKENS_MAPPING } from '../constants'; +import { + MODULES_ACCOUNT, + MODULES_V05_ACCOUNT, + RESOURCES_ACCOUNT, + RESOURCES_V05_ACCOUNT, + TOKENS_MAPPING, + VERSION_0, + VERSION_0_5, +} from '../constants'; import SDK from '../main'; @@ -7,13 +15,15 @@ describe('Liquidity Module', () => { nodeUrl: 'https://fullnode.mainnet.aptoslabs.com/v1', networkOptions: { resourceAccount: RESOURCES_ACCOUNT, - moduleAccount: MODULES_ACCOUNT + moduleAccount: MODULES_ACCOUNT, + resourceAccountV05: RESOURCES_V05_ACCOUNT, + moduleAccountV05: MODULES_V05_ACCOUNT } }); const curves = sdk.curves; - test('calculateLiquidityRates (from mode), uncorrelated', async () => { + test('calculateLiquidityRates (from mode), uncorrelated, v0', async () => { const output = await sdk.Liquidity.calculateRateAndMinReceivedLP({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, @@ -21,6 +31,7 @@ describe('Liquidity Module', () => { curveType: 'uncorrelated', interactiveToken: 'from', slippage: 0.005, + version: VERSION_0 }); console.log( @@ -31,7 +42,7 @@ describe('Liquidity Module', () => { expect(output.rate.length).toBeGreaterThan(0); }); - test('calculateLiquidityRates (to mode), uncorrelated', async () => { + test('calculateLiquidityRates (to mode), uncorrelated, v0', async () => { const output = await sdk.Liquidity.calculateRateAndMinReceivedLP({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, @@ -39,6 +50,7 @@ describe('Liquidity Module', () => { curveType: 'uncorrelated', interactiveToken: 'to', slippage: 0.005, + version: VERSION_0 }); console.log( @@ -49,7 +61,7 @@ describe('Liquidity Module', () => { expect(output.rate.length).toBeGreaterThan(0); }); - test('calculateLiquidityRates (from mode), stable', async () => { + test('calculateLiquidityRates (from mode), stable, v0', async () => { const output = await sdk.Liquidity.calculateRateAndMinReceivedLP({ fromToken: TOKENS_MAPPING.USDC, toToken: TOKENS_MAPPING.USDT, @@ -57,6 +69,7 @@ describe('Liquidity Module', () => { curveType: 'stable', interactiveToken: 'from', slippage: 0.005, + version: VERSION_0 }); console.log( @@ -67,7 +80,7 @@ describe('Liquidity Module', () => { expect(output.rate.length).toBeGreaterThan(0); }); - test('calculateLiquidityRates (to mode), stable', async () => { + test('calculateLiquidityRates (to mode), stable, v0', async () => { const output = await sdk.Liquidity.calculateRateAndMinReceivedLP({ fromToken: TOKENS_MAPPING.USDC, toToken: TOKENS_MAPPING.USDT, @@ -75,6 +88,7 @@ describe('Liquidity Module', () => { curveType: 'stable', interactiveToken: 'to', slippage: 0.005, + version: VERSION_0 }); console.log( @@ -85,7 +99,83 @@ describe('Liquidity Module', () => { expect(output.rate.length).toBeGreaterThan(0); }); - test('createAddLiquidityPayload (uncorrelated from mode)', async () => { + test('calculateLiquidityRates (from mode), uncorrelated, v0.5', async () => { + + try { + await sdk.Liquidity.calculateRateAndMinReceivedLP({ + fromToken: TOKENS_MAPPING.APTOS, + toToken: TOKENS_MAPPING.USDC, + amount: 100000000, // 1 APTOS + curveType: 'uncorrelated', + interactiveToken: 'from', + slippage: 0.005, + version: VERSION_0_5 + }); + } catch (e) { + expect(e).toMatchObject( + new Error('LiquidityPool not existed'), + ); + } + }); + + test('calculateLiquidityRates (to mode), uncorrelated, v0.5', async () => { + + try { + await sdk.Liquidity.calculateRateAndMinReceivedLP({ + fromToken: TOKENS_MAPPING.APTOS, + toToken: TOKENS_MAPPING.USDC, + amount: 1000000, // 1 USDC + curveType: 'uncorrelated', + interactiveToken: 'to', + slippage: 0.005, + version: VERSION_0_5 + }); + } catch(e) { + expect(e).toMatchObject( + new Error('LiquidityPool not existed'), + ); + } + }); + + test('calculateLiquidityRates (from mode), stable, v0.5', async () => { + const output = await sdk.Liquidity.calculateRateAndMinReceivedLP({ + fromToken: TOKENS_MAPPING.USDC, + toToken: TOKENS_MAPPING.USDT, + amount: 2000000, // 2 USDC + curveType: 'stable', + interactiveToken: 'from', + slippage: 0.005, + version: VERSION_0_5 + }); + + console.log( + `2000000 USDC → ${output.rate} USDT && receiveLp ${output.receiveLp}`, + ); + + expect(typeof output).toBe('object'); + expect(output.rate.length).toBeGreaterThan(0); + }); + + test('calculateLiquidityRates (to mode), stable, v0.5', async () => { + const output = await sdk.Liquidity.calculateRateAndMinReceivedLP({ + fromToken: TOKENS_MAPPING.USDC, + toToken: TOKENS_MAPPING.USDT, + amount: 2000000, // 2 USDT + curveType: 'stable', + interactiveToken: 'to', + slippage: 0.005, + version: VERSION_0_5 + }); + + console.log( + `2000000 USDT → ${output.rate} USDC && receiveLp ${output.receiveLp}`, + ); + + expect(typeof output).toBe('object'); + expect(output.rate.length).toBeGreaterThan(0); + }); + + test('createAddLiquidityPayload (uncorrelated from mode), v0', async () => { const output = await sdk.Liquidity.createAddLiquidityPayload({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, @@ -94,6 +184,7 @@ describe('Liquidity Module', () => { interactiveToken: 'from', slippage: 0.005, curveType: 'uncorrelated', + version: VERSION_0 }); expect(output).toStrictEqual({ @@ -109,7 +200,7 @@ describe('Liquidity Module', () => { }); }); - test('createAddLiquidityPayload (uncorrelated to mode)', async () => { + test('createAddLiquidityPayload (uncorrelated to mode), v0', async () => { const output = await sdk.Liquidity.createAddLiquidityPayload({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, @@ -118,6 +209,7 @@ describe('Liquidity Module', () => { interactiveToken: 'to', slippage: 0.005, curveType: 'uncorrelated', + version: VERSION_0 }); expect(output).toStrictEqual({ @@ -133,7 +225,7 @@ describe('Liquidity Module', () => { }); }); - test('createAddLiquidityPayload (uncorrelated from mode)', async () => { + test('createAddLiquidityPayload (uncorrelated from mode), v0', async () => { const output = await sdk.Liquidity.createAddLiquidityPayload({ fromToken: '0x8d87a65ba30e09357fa2edea2c80dbac296e5dec2b18287113500b902942929d::celer_coin_manager::UsdcCoin', @@ -144,6 +236,7 @@ describe('Liquidity Module', () => { interactiveToken: 'from', slippage: 0.005, curveType: 'uncorrelated', + version: VERSION_0 }); expect(output).toStrictEqual({ @@ -159,13 +252,14 @@ describe('Liquidity Module', () => { }); }); - test('createBurnLiquidityPayload (uncorrelated)', async () => { + test('createBurnLiquidityPayload (uncorrelated), v0', async () => { const output = await sdk.Liquidity.createBurnLiquidityPayload({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, slippage: 0.005, curveType: 'uncorrelated', burnAmount: 100000, + version: VERSION_0 }); console.log('createBurnLiquidityPayload', output); @@ -183,13 +277,64 @@ describe('Liquidity Module', () => { }); }); - test('calculateOutputBurn', async () => { + test('createAddLiquidityPayload (stable from mode), v0.5', async () => { + const output = await sdk.Liquidity.createAddLiquidityPayload({ + fromToken: TOKENS_MAPPING.amAPT, + toToken: TOKENS_MAPPING.APTOS, + fromAmount: 100000, // 0.001 amAPT + toAmount: 89158, // 0.00089158 APTOS + interactiveToken: 'from', + slippage: 0.005, + curveType: 'stable', + version: VERSION_0_5 + }); + + expect(output).toStrictEqual({ + type: 'entry_function_payload', + function: + '0x163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::scripts::add_liquidity', + type_arguments: [ + TOKENS_MAPPING.amAPT, + TOKENS_MAPPING.APTOS, + curves.stableV05, + ], + arguments: ["100000", "99500", "89158", "88712"] + }); + }); + + test('createBurnLiquidityPayload (stable), v0.5', async () => { + const output = await sdk.Liquidity.createBurnLiquidityPayload({ + fromToken: TOKENS_MAPPING.amAPT, + toToken: TOKENS_MAPPING.APTOS, + slippage: 0.005, + curveType: 'stable', + burnAmount: 389490, + version: VERSION_0_5 + }); + + console.log('createBurnLiquidityPayload', output); + + expect(output).toEqual({ + type: 'entry_function_payload', + function: + '0x163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::scripts::remove_liquidity', + type_arguments: [ + TOKENS_MAPPING.amAPT, + TOKENS_MAPPING.APTOS, + curves.stableV05, + ], + arguments: ['389490', expect.any(String), expect.any(String)], + }); + }); + + test('calculateOutputBurn, v0', async () => { const output = await sdk.Liquidity.calculateOutputBurn({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, slippage: 0.005, curveType: 'uncorrelated', burnAmount: 100000, + version: VERSION_0 }); expect(output).toEqual({ @@ -202,34 +347,37 @@ describe('Liquidity Module', () => { }); }); - test('Check Pool Existence ', async () => { + test('Check Pool Existence, v0', async () => { const output = await sdk.Liquidity.checkPoolExistence({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, curveType: 'uncorrelated', + version: VERSION_0, }); expect(output).toEqual(true); }); - test('Check Pool Existence ', async () => { + test('Check Pool Existence, v0 ', async () => { const output = await sdk.Liquidity.checkPoolExistence({ fromToken: '0x8d87a65ba30e09357fa2edea2c80dbac296e5dec2b18287113500b902942929d::celer_coin_manager::UsdcCoin', toToken: '0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO', curveType: 'uncorrelated', + version: VERSION_0, }); expect(output).toEqual(false); }); - test('getAmountIn', async () => { + test('getAmountIn, v0', async () => { const output = await sdk.Liquidity.getAmountIn({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, amount: 100000000, // 1 APTOS curveType: 'uncorrelated', slippage: 0.005, + version: VERSION_0, }); console.log( @@ -240,13 +388,14 @@ describe('Liquidity Module', () => { expect(output.length).toBeGreaterThan(0); }); - test('getAmountOut', async () => { + test('getAmountOut, v0', async () => { const output = await sdk.Liquidity.getAmountOut({ fromToken: TOKENS_MAPPING.APTOS, toToken: TOKENS_MAPPING.USDC, amount: 1000000, // 1 USDC curveType: 'uncorrelated', slippage: 0.005, + version: VERSION_0, }); console.log(