From 6c4f7537723db89d714e64fbe65a74e9869570cf Mon Sep 17 00:00:00 2001 From: "Luren L." Date: Thu, 31 Oct 2024 23:40:04 -0400 Subject: [PATCH 1/7] add new Dexes --- src/config.ts | 20 +++++++++ src/lib/KriyaV2.ts | 22 ++++++++++ src/lib/aftermath.ts | 25 +++++++++++ src/lib/index.ts | 13 ++++++ src/lib/kriyaV3.ts | 99 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 src/lib/KriyaV2.ts create mode 100644 src/lib/aftermath.ts create mode 100644 src/lib/kriyaV3.ts diff --git a/src/config.ts b/src/config.ts index 3ec8920..0864541 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,6 +12,26 @@ export const config = { "0xdaa46292632c3c4d8f31f23ea0f9b36a28ff3677e9684980e4438403a67a3d8f", TURBOSPACKAGEID: "0x1a3c42ded7b75cdf4ebc7c7b7da9d1e1db49f16fcdca934fac003f35f39ecad9", + KRIYA_V3_VERSION: + "0xf5145a7ac345ca8736cf8c76047d00d6d378f30e81be6f6eb557184d9de93c78", + KRIYA_V3_PACKAGEID: + "0xbd8d4489782042c6fafad4de4bc6a5e0b84a43c6c00647ffd7062d1e2bb7549e", + KRIYA_V2_PACKAGEID: + "0xa0eba10b173538c8fecca1dff298e488402cc9ff374f8a12ca7758eebe830b66", + CLOCK_ADDRESS: + "0x6", + AFTERMATH_PACKAGEID: + "0xc4049b2d1cc0f6e017fda8260e4377cecd236bd7f56a54fee120816e72e2e0dd", + AFTERMATH_POOLREGISTRY: + "0xfcc774493db2c45c79f688f88d28023a3e7d98e4ee9f48bbf5c7990f651577ae", + AFTERMATH_FEEVAULT: + "0xf194d9b1bcad972e45a7dd67dd49b3ee1e3357a00a50850c52cd51bb450e13b4", + AFTERMATH_TREASURY: + "0x28e499dff5e864a2eafe476269a4f5035f1c16f338da7be18b103499abf271ce", + AFTERMATH_INSURANCE_FUND: + "0xf0c40d67b078000e18032334c3325c47b9ec9f3d9ae4128be820d54663d14e3b", + AFTERMATH_REFERRAL_VAULT: + "0x35d35b0e5b177593d8c3a801462485572fc30861e6ce96a55af6dc4730709278", }; export function updateConfig(newConfig: Partial) { diff --git a/src/lib/KriyaV2.ts b/src/lib/KriyaV2.ts new file mode 100644 index 0000000..7c5dcf4 --- /dev/null +++ b/src/lib/KriyaV2.ts @@ -0,0 +1,22 @@ +import { Transaction, TransactionObjectArgument } from "@mysten/sui/transactions"; +import { config } from "../config"; + +export async function makeKriyaV2PTB(txb: Transaction, poolId: string, byAmountIn: boolean, coinA: any, amount: any, a2b: boolean, typeArguments: any) { + + const func = a2b ? 'swap_token_x' : 'swap_token_y'; + + const args = [ + txb.object(poolId), + coinA, + typeof amount === 'number' ? txb.pure.u64(amount) : amount, + txb.pure.u64(0), + ] + + const [coinB] = txb.moveCall({ + target: `${config.KRIYA_V2_PACKAGEID}::spot_dex::${func}`, + typeArguments: typeArguments, + arguments: args, + }) + + return coinB +} \ No newline at end of file diff --git a/src/lib/aftermath.ts b/src/lib/aftermath.ts new file mode 100644 index 0000000..4223e89 --- /dev/null +++ b/src/lib/aftermath.ts @@ -0,0 +1,25 @@ +import { Transaction, TransactionObjectArgument } from "@mysten/sui/transactions"; +import { config } from "../config"; + +export async function makeAftermathPTB(txb: Transaction, poolId: string, coinA: any, amountOut: any, a2b: boolean, typeArguments: any) { + + const args = [ + txb.object(poolId), + txb.object(config.AFTERMATH_POOLREGISTRY), + txb.object(config.AFTERMATH_FEEVAULT), + txb.object(config.AFTERMATH_TREASURY), + txb.object(config.AFTERMATH_INSURANCE_FUND), + txb.object(config.AFTERMATH_REFERRAL_VAULT), + coinA, + txb.pure.u64(amountOut), + txb.pure.u64('800000000000000000'), // 80%, use https://suivision.xyz/txblock/AvASModFbU6Bmu6FNghqBsVqktnhB9QZKQjdYfnuxNvo?tab=Overview as an reference + ] + + const res = txb.moveCall({ + target: `${config.AFTERMATH_PACKAGEID}::swap::swap_exact_in`, + typeArguments: typeArguments, + arguments: args, + }) + + return res +} \ No newline at end of file diff --git a/src/lib/index.ts b/src/lib/index.ts index 75170db..7223168 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -3,6 +3,9 @@ import { makeCETUSPTB } from "./cetus"; import { makeTurbosPTB } from "./turbos"; import { config } from "../config"; import { Router } from "../types"; +import { makeKriyaV3PTB } from "./kriyaV3"; +import { makeAftermathPTB } from "./aftermath"; +import { makeKriyaV2PTB } from "./KriyaV2"; /** @@ -65,6 +68,7 @@ export async function swapRoutePTB(userAddress: string, minAmountOut: number, tx const tempTokenB = route.target; const a2b = route.a2b; const typeArguments = route.info_for_ptb.typeArguments; + const amountOut = route.amount_out; let amountInPTB; let tuborsVersion; @@ -127,6 +131,15 @@ export async function swapRoutePTB(userAddress: string, minAmountOut: number, tx txb.transferObjects([turbosCoinA], userAddress); pathTempCoin = turbosCoinB; } + else if (provider === "kriyaV3") { + pathTempCoin = await makeKriyaV3PTB(txb, poolId, true, pathTempCoin, amountInPTB, a2b, typeArguments) + } + else if (provider === "aftermath") { + pathTempCoin = await makeAftermathPTB(txb, poolId, pathTempCoin, amountOut, a2b, typeArguments) + } + else if (provider === "kriyaV2") { + pathTempCoin = await makeKriyaV2PTB(txb, poolId, true, pathTempCoin, amountInPTB, a2b, typeArguments) + } } txb.mergeCoins(finalCoinB, [pathTempCoin]); diff --git a/src/lib/kriyaV3.ts b/src/lib/kriyaV3.ts new file mode 100644 index 0000000..5362ae8 --- /dev/null +++ b/src/lib/kriyaV3.ts @@ -0,0 +1,99 @@ +import { Transaction, TransactionObjectArgument } from "@mysten/sui/transactions"; +import { config } from "../config"; + +export async function makeKriyaV3PTB(txb: Transaction, poolId: string, byAmountIn: boolean, coinA: any, amount: any, a2b: boolean, typeArguments: any) { + + const sqrtPriceLimit = BigInt(a2b ? '4295048016' : '79226673515401279992447579055') + const args = [ + txb.object(poolId), + txb.pure.bool(a2b), + txb.pure.bool(byAmountIn), + typeof amount === 'number' ? txb.pure.u64(amount) : amount, + txb.pure.u128(sqrtPriceLimit), + txb.object(config.CLOCK_ADDRESS), + txb.object(config.KRIYA_V3_VERSION), + ] + const [receive_balance_a, receive_balance_b, receipt] = txb.moveCall({ + target: `${config.KRIYA_V3_PACKAGEID}::trade::flash_swap`, + typeArguments: typeArguments, + arguments: args, + }) + + if (a2b) { + txb.moveCall({ + target: '0x2::balance::destroy_zero', + arguments: [receive_balance_a], + typeArguments: [typeArguments[0]] + }) + + let BalanceA = txb.moveCall({ + target: "0x2::coin::into_balance", + arguments: [coinA], + typeArguments: [typeArguments[0]], + }); + + const [BalanceB] = txb.moveCall({ + target: '0x2::balance::zero', + typeArguments: [typeArguments[1]] + }) + + txb.moveCall({ + target: `${config.KRIYA_V3_PACKAGEID}::trade::repay_flash_swap`, + arguments: [ + txb.object(poolId), + receipt, + + BalanceA, + BalanceB, + txb.object(config.KRIYA_V3_VERSION), + ], + typeArguments: typeArguments + }) + + const receiveCoin: any = txb.moveCall({ + target: `0x2::coin::from_balance`, + arguments: [receive_balance_b], + typeArguments: [typeArguments[1]] + }) + return receiveCoin + } + + txb.moveCall({ + target: '0x2::balance::destroy_zero', + arguments: [receive_balance_b], + typeArguments: [typeArguments[1]] + }) + + let BalanceB = txb.moveCall({ + target: "0x2::coin::into_balance", + arguments: [coinA], + typeArguments: [typeArguments[1]], + }); + + const [BalanceA] = txb.moveCall({ + target: '0x2::balance::zero', + typeArguments: [typeArguments[0]] + }) + + txb.moveCall({ + target: `${config.KRIYA_V3_PACKAGEID}::trade::repay_flash_swap`, + arguments: [ + txb.object(poolId), + receipt, + BalanceA, + BalanceB, + txb.object(config.KRIYA_V3_VERSION), + ], + typeArguments: typeArguments + }) + + const receiveCoin: any = txb.moveCall({ + target: `0x2::coin::from_balance`, + arguments: [receive_balance_a], + typeArguments: [typeArguments[0]] + }) + return receiveCoin +} + + + From 18ba0de9af107112bf340e5d0e36ddea84feaa35 Mon Sep 17 00:00:00 2001 From: "Luren L." Date: Thu, 31 Oct 2024 23:42:03 -0400 Subject: [PATCH 2/7] reorder Dex --- src/lib/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/index.ts b/src/lib/index.ts index 7223168..be7669c 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -131,15 +131,16 @@ export async function swapRoutePTB(userAddress: string, minAmountOut: number, tx txb.transferObjects([turbosCoinA], userAddress); pathTempCoin = turbosCoinB; } + else if (provider === "kriyaV2") { + pathTempCoin = await makeKriyaV2PTB(txb, poolId, true, pathTempCoin, amountInPTB, a2b, typeArguments) + } else if (provider === "kriyaV3") { pathTempCoin = await makeKriyaV3PTB(txb, poolId, true, pathTempCoin, amountInPTB, a2b, typeArguments) } else if (provider === "aftermath") { pathTempCoin = await makeAftermathPTB(txb, poolId, pathTempCoin, amountOut, a2b, typeArguments) } - else if (provider === "kriyaV2") { - pathTempCoin = await makeKriyaV2PTB(txb, poolId, true, pathTempCoin, amountInPTB, a2b, typeArguments) - } + } txb.mergeCoins(finalCoinB, [pathTempCoin]); From 20e12c2cde144823af246f78caf5d674f36515a3 Mon Sep 17 00:00:00 2001 From: "Luren L." Date: Fri, 1 Nov 2024 01:18:59 -0400 Subject: [PATCH 3/7] update interface --- src/lib/index.ts | 4 ++-- src/lib/retrieveAPI.ts | 18 +++++++++++------- src/types.ts | 3 ++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/lib/index.ts b/src/lib/index.ts index be7669c..422a39e 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -68,7 +68,6 @@ export async function swapRoutePTB(userAddress: string, minAmountOut: number, tx const tempTokenB = route.target; const a2b = route.a2b; const typeArguments = route.info_for_ptb.typeArguments; - const amountOut = route.amount_out; let amountInPTB; let tuborsVersion; @@ -138,7 +137,8 @@ export async function swapRoutePTB(userAddress: string, minAmountOut: number, tx pathTempCoin = await makeKriyaV3PTB(txb, poolId, true, pathTempCoin, amountInPTB, a2b, typeArguments) } else if (provider === "aftermath") { - pathTempCoin = await makeAftermathPTB(txb, poolId, pathTempCoin, amountOut, a2b, typeArguments) + const amountLimit = route.info_for_ptb.amountLimit; + pathTempCoin = await makeAftermathPTB(txb, poolId, pathTempCoin, amountLimit, a2b, typeArguments) } } diff --git a/src/lib/retrieveAPI.ts b/src/lib/retrieveAPI.ts index f44b79e..b38f383 100644 --- a/src/lib/retrieveAPI.ts +++ b/src/lib/retrieveAPI.ts @@ -25,17 +25,21 @@ export async function getRoute( if (!config.BASE_URL) { throw new Error("API base URL is not set"); } - const params = { + const params = new URLSearchParams({ from: fromCoin, target: toCoin, amount: (typeof amountIn === 'bigint' ? Number(amountIn) : amountIn).toString(), - by_amount_in: swapOptions?.byAmountIn !== undefined ? swapOptions.byAmountIn : true, - depth: swapOptions?.depth !== undefined ? swapOptions.depth : 3, - providers: swapOptions?.dexList && swapOptions.dexList.length > 0 ? swapOptions.dexList.join(',') : undefined - }; - + by_amount_in: swapOptions?.byAmountIn !== undefined ? swapOptions.byAmountIn.toString() : 'true', + depth: swapOptions?.depth !== undefined ? swapOptions.depth.toString() : '3', + }).toString(); + let dexString = ''; + if (swapOptions?.dexList && swapOptions.dexList.length > 0) { + dexString = swapOptions.dexList.map(dex => `providers=${dex}`).join('&'); + } + + const fullParams = dexString ? `${params}&${dexString}` : params; try { - const { data } = await axios.get(config.BASE_URL, { params }); + const { data } = await axios.get(`${config.BASE_URL}?${fullParams}`); if (!data) { throw new Error('No data returned from the API.'); diff --git a/src/types.ts b/src/types.ts index b2781bb..e6827f5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,8 @@ export enum Dex { Cetus = 'cetus', Turbos = 'turbos', - Kriya = 'kriya', + KriyaV2 = 'kriyaV2', + KriyaV3 = 'kriyaV3', Aftermath = 'aftermath' } From 28e2a0c26c359cbab52fe4ec403cf29759d8d875 Mon Sep 17 00:00:00 2001 From: "Luren L." Date: Mon, 4 Nov 2024 23:44:04 -0800 Subject: [PATCH 4/7] update --- src/lib/index.ts | 3 +-- src/lib/retrieveAPI.ts | 2 +- src/main.ts | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/index.ts b/src/lib/index.ts index 422a39e..d33febb 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -19,13 +19,12 @@ import { makeKriyaV2PTB } from "./KriyaV2"; * @returns {Promise} - The final output coin transaction result. * @throws {Error} - Throws an error if no routes are found or if the outer amount_in does not match the sum of route amount_in values. */ -export async function swapRoutePTB(userAddress: string, minAmountOut: number, txb: Transaction, coinIn: TransactionResult, router: Router): Promise { +export async function swapRoutePTB(userAddress: string, minAmountOut: number, txb: Transaction, coinIn: TransactionResult, router: Router, referral: number = 0): Promise { if (!router.routes || router.routes.length === 0) { throw new Error("No routes found in data"); } const tokenA = router.from; const tokenB = router.target; - const referral = 0; const allPaths = JSON.parse(JSON.stringify(router.routes)); console.log(`tokenA: ${tokenA}, tokenB: ${tokenB}`); if ( diff --git a/src/lib/retrieveAPI.ts b/src/lib/retrieveAPI.ts index b38f383..10cfcc1 100644 --- a/src/lib/retrieveAPI.ts +++ b/src/lib/retrieveAPI.ts @@ -20,7 +20,7 @@ export async function getRoute( fromCoin: string, toCoin: string, amountIn: number | string | bigint, - swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number } = { dexList: [Dex.Cetus], byAmountIn: true, depth: 3 } + swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number } = { dexList: [], byAmountIn: true, depth: 3 } ): Promise { if (!config.BASE_URL) { throw new Error("API base URL is not set"); diff --git a/src/main.ts b/src/main.ts index 13cbf8a..8a9f01d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -33,7 +33,7 @@ export async function swapPTB( coin: TransactionResult, amountIn: number | string | bigint, minAmountOut: number, - swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number } = { dexList: [Dex.Cetus], byAmountIn: true, depth: 3 } + swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number } = { dexList: [], byAmountIn: true, depth: 3 } ): Promise { // Get the output coin from the swap route and transfer it to the user @@ -70,7 +70,7 @@ export async function swap( toCoin: string, amountIn: number | string | bigint, minAmountOut: number, - swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number, isDryRun?: boolean, keypair?: Ed25519Keypair } = { dexList: [Dex.Cetus], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } + swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number, isDryRun?: boolean, keypair?: Ed25519Keypair } = { dexList: [], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } ) { const txb = new Transaction(); txb.setSender(address); From eeed57cc08d05ac95b793688d219b304f8d9485f Mon Sep 17 00:00:00 2001 From: "Luren L." Date: Wed, 6 Nov 2024 22:16:29 -0800 Subject: [PATCH 5/7] add type of SwapOptions --- src/lib/retrieveAPI.ts | 30 ++++++++++++++++++------------ src/main.ts | 40 +++++++++++++++++----------------------- src/types.ts | 10 ++++++++++ 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/lib/retrieveAPI.ts b/src/lib/retrieveAPI.ts index 10cfcc1..50f17b6 100644 --- a/src/lib/retrieveAPI.ts +++ b/src/lib/retrieveAPI.ts @@ -1,30 +1,29 @@ import axios from 'axios'; import { config } from '../config'; -import { Router } from '../types'; -import { Dex } from '../types'; +import { Router, SwapOptions } from '../types'; + /** - * Fetches the swap route from the API based on the provided parameters. + * Fetches the optimal swap route between two coins using the provided parameters. * * @param {string} fromCoin - The coin type to swap from. * @param {string} toCoin - The coin type to swap to. - * @param {number | string | bigint} amountIn - The amount of the input coin. - * @param {Object} [swapOptions] - Optional swap options. - * @param {string[]} [swapOptions.dexList] - List of DEX providers to use. - * @param {boolean} [swapOptions.byAmountIn=true] - Whether to swap by amount in. - * @param {number} [swapOptions.depth=3] - The depth of the swap route. - * @returns {Promise} - The swap route information. - * @throws {Error} - Throws an error if the API base URL is not set or if the API call fails. + * @param {number | string | bigint} amountIn - The amount of the input coin to swap. + * @param {SwapOptions} [swapOptions] - Optional parameters for the swap operation. + * @returns {Promise} - Returns a promise that resolves to the router object containing swap routes. + * @throws {Error} - Throws an error if the API base URL is not set or if no data is returned from the API. */ export async function getRoute( fromCoin: string, toCoin: string, amountIn: number | string | bigint, - swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number } = { dexList: [], byAmountIn: true, depth: 3 } + swapOptions: SwapOptions = { dexList: [], byAmountIn: true, depth: 3 } ): Promise { if (!config.BASE_URL) { throw new Error("API base URL is not set"); } + + // Construct query parameters for the API request const params = new URLSearchParams({ from: fromCoin, target: toCoin, @@ -32,18 +31,25 @@ export async function getRoute( by_amount_in: swapOptions?.byAmountIn !== undefined ? swapOptions.byAmountIn.toString() : 'true', depth: swapOptions?.depth !== undefined ? swapOptions.depth.toString() : '3', }).toString(); + + // Construct dex provider string if dexList is provided let dexString = ''; if (swapOptions?.dexList && swapOptions.dexList.length > 0) { dexString = swapOptions.dexList.map(dex => `providers=${dex}`).join('&'); } - + + // Combine parameters and dexString for the full API request const fullParams = dexString ? `${params}&${dexString}` : params; + try { + // Make the API request to fetch the swap route const { data } = await axios.get(`${config.BASE_URL}?${fullParams}`); if (!data) { throw new Error('No data returned from the API.'); } + + // Set the from and target properties in the returned data data.data.from = fromCoin; data.data.target = toCoin; diff --git a/src/main.ts b/src/main.ts index 8a9f01d..379da1d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,11 +3,12 @@ import { Transaction, TransactionResult } from '@mysten/sui/transactions'; import { SuiClient } from '@mysten/sui/dist/cjs/client'; import { Ed25519Keypair } from '@mysten/sui/dist/cjs/keypairs/ed25519'; import { getCoinPTB, parseSwapTransactionResult } from './utils'; -import { Dex } from './types'; +import { Dex, SwapOptions } from './types'; export { swapRoutePTB } from './lib'; export { getRoute } from './lib/retrieveAPI'; -export { Dex, Router } from './types'; +export { Dex, Router, SwapOptions } from './types'; + /** * Executes a swap transaction using the provided parameters. @@ -19,10 +20,7 @@ export { Dex, Router } from './types'; * @param {TransactionResult} coin - The transaction result object. * @param {number | string | bigint} amountIn - The amount of the input coin. * @param {number} minAmountOut - The minimum amount of the output coin. - * @param {Object} [swapOptions] - Optional swap options. - * @param {Dex[]} [swapOptions.dexList] - List of DEXs to use. - * @param {boolean} [swapOptions.byAmountIn] - Whether to swap by amount in. - * @param {number} [swapOptions.depth] - The depth of the swap. + * @param {SwapOptions} [swapOptions] - Optional swap options. * @returns {Promise} - The final transaction object. */ export async function swapPTB( @@ -33,7 +31,7 @@ export async function swapPTB( coin: TransactionResult, amountIn: number | string | bigint, minAmountOut: number, - swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number } = { dexList: [], byAmountIn: true, depth: 3 } + swapOptions: SwapOptions = { dexList: [], byAmountIn: true, depth: 3 } ): Promise { // Get the output coin from the swap route and transfer it to the user @@ -45,23 +43,19 @@ export async function swapPTB( } + /** - * Executes a swap transaction using the provided parameters. + * Executes a swap operation between two coins. * - * @param {string} address - The user's address. - * @param {SuiClient} client - The Sui client instance. - * @param {string} fromCoin - The coin to swap from. - * @param {string} toCoin - The coin to swap to. - * @param {number | string | bigint} amountIn - The amount of the input coin. - * @param {number} minAmountOut - The minimum amount of the output coin. - * @param {Object} [swapOptions] - Optional swap options. - * @param {Dex[]} [swapOptions.dexList] - List of DEXs to use. - * @param {boolean} [swapOptions.byAmountIn] - Whether to swap by amount in. - * @param {number} [swapOptions.depth] - The depth of the swap. - * @param {boolean} [swapOptions.isDryRun] - Whether to perform a dry run of the transaction. - * @param {Ed25519Keypair} [swapOptions.keypair] - The keypair for signing the transaction. - * @returns {Promise} - The transaction result or dry run result. - * @throws {Error} - Throws an error if the keypair is not provided for signing and submitting the transaction. + * @param {string} address - The user's address initiating the swap. + * @param {SuiClient} client - The Sui client instance for blockchain interaction. + * @param {string} fromCoin - The coin type to swap from. + * @param {string} toCoin - The coin type to swap to. + * @param {number | string | bigint} amountIn - The amount of the input coin to swap. + * @param {number} minAmountOut - The minimum acceptable amount of the output coin. + * @param {SwapOptions} [swapOptions] - Optional parameters for the swap operation. + * @returns {Promise} - Returns a promise that resolves to the transaction result or dry run result. + * @throws {Error} - Throws an error if keypair is not provided for non-dry run transactions. */ export async function swap( address: string, @@ -70,7 +64,7 @@ export async function swap( toCoin: string, amountIn: number | string | bigint, minAmountOut: number, - swapOptions: { dexList?: Dex[], byAmountIn?: boolean, depth?: number, isDryRun?: boolean, keypair?: Ed25519Keypair } = { dexList: [], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } + swapOptions: SwapOptions = { dexList: [], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } ) { const txb = new Transaction(); txb.setSender(address); diff --git a/src/types.ts b/src/types.ts index e6827f5..d03f305 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +import { Ed25519Keypair } from '@mysten/sui/dist/cjs/keypairs/ed25519'; + export enum Dex { Cetus = 'cetus', Turbos = 'turbos', @@ -14,3 +16,11 @@ export type Router = { target: string; dexList: Dex[]; } + +export type SwapOptions = { + dexList?: Dex[]; + byAmountIn?: boolean; + depth?: number; + isDryRun?: boolean; + keypair?: Ed25519Keypair; +}; From 123e9eaf9ce2186af899937de76b531122dbdcdc Mon Sep 17 00:00:00 2001 From: ComeOnOliver <43215937+ComeOnOliver@users.noreply.github.com> Date: Sat, 9 Nov 2024 17:06:14 -0500 Subject: [PATCH 6/7] add referer to swapOptions --- .env.sample | 6 ++- README.md | 85 ++++++++++++++++++++++++------------------ sample/demo.ts | 9 ++++- src/lib/retrieveAPI.ts | 8 +++- src/main.ts | 14 +++---- src/types.ts | 1 + 6 files changed, 73 insertions(+), 50 deletions(-) diff --git a/.env.sample b/.env.sample index f8d121a..38f6554 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1,5 @@ -MNEMONIC = '' +NAVI_DEX_AGGREGATOR_API_BASE_URL = '' # Required, default: https://aggregator-api.naviprotocol.io/find_routes + +# Optional in Sample/Demo.ts RPC = '' -NAVI_DEX_AGGREGATOR_API_BASE_URL = '' \ No newline at end of file +MNEMONIC = '' \ No newline at end of file diff --git a/README.md b/README.md index 0a454ef..5227d55 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # navi-aggregator-sdk -*NAVI Aggregator for Sui Defi Ecosystem* +## [NAVI Aggregator for Sui Defi Ecosystem](https://navi.ag) -This project provides a TypeScript SDK for interacting with the Sui Defi projects, allowing developers to integrate token swap functionalities, manage transactions, and interact with the blockchain using NAVI's aggregator. +This TypeScript SDK simplifies integration with decentralized exchanges (DEXs) on the Sui blockchain, allowing developers to execute token swaps in Move-based PTB applications or directly leverage the SDK for optimized token swaps across multiple sources for the best prices. + +For full details, please see the [Documentation](https://naviprotocol.gitbook.io/navi-protocol-docs/getting-started/navi-dex-aggregator). ## Supported DEX -* CETUS +* Cetus * Turbos -* DeepBook v2/v3 - -To be added: +* DeepBook v3 * Aftermath * Kriya v2/v3 @@ -17,43 +17,54 @@ To be added: npm i navi-aggregator-sdk ``` -## Environment Setup -Ensure you have a .env file set up with the following variables: +## Usage +* Get Quote + +Pass in the fromCoin, toCoin, and amountIn. The output will be the quote for the swap. +```typescript +import { getRoute } from 'navi-aggregator-sdk'; -```bash -MNEMONIC= -RPC= -apiBaseURL = +const quote = await getRoute(fromCoin: string, toCoin: string, amountIn: number | string | bigint); +console.log(`Amount In: ${quote.amount_in}, Amount Out: ${quote.amount_out}`); +console.log(`Routes: ${quote.routes}`); ``` +* Coin-In-Coin-Out PTB function -## Usage -Explanation of Parameters: - * Executes a swap transaction using the provided parameters. - * - * @param {string} address - The user's address. - * @param {SuiClient} client - The Sui client instance. - * @param {string} fromCoin - The coin to swap from. - * @param {string} toCoin - The coin to swap to. - * @param {number | string | bigint} amountIn - The amount of the input coin. - * @param {number} minAmountOut - The minimum amount of the output coin. - * @param {boolean} [isDryRun=true] - Whether to perform a dry run of the transaction. - * @param {Ed25519Keypair} [keypair] - The keypair for signing the transaction. - * @param {Object} [swapOptions] - Optional swap options. - * @param {string[]} [swapOptions.dexList] - List of DEXs to use. - * @param {boolean} [swapOptions.byAmountIn] - Whether to swap by amount in. - * @param {number} [swapOptions.depth] - The depth of the swap. - * @throws {Error} - Throws an error if keypair is not provided for non-dry run transactions. - -```Typescript -export async function swap( +Pass in a coinObject as the coin parameter. The output will be the final coin object after the swap. +```typescript +import { swapPTB } from 'navi-aggregator-sdk'; + +const coinB = await swapPTB( address: string, - client: SuiClient, + txb: Transaction, fromCoin: string, toCoin: string, + coin: TransactionResult, amountIn: number | string | bigint, minAmountOut: number, - isDryRun: boolean = true, - keypair?: Ed25519Keypair, - swapOptions: { dexList?: string[], byAmountIn?: boolean, depth?: number } = { dexList: ['cetus'], byAmountIn: true, depth: 3 } + swapOptions: SwapOptions = { referer: 'https://www.navi.ag/', dexList: [], byAmountIn: true, depth: 3 } ) -``` \ No newline at end of file +``` +* Swap function + +The swap function is a wrapper for the getRoute and swapPTB functions. Set `isDryRun` from `swapOptions` to true to get a dry run result and balance changes. It will submit the transaction and return the result if `isDryRun` is set to false and a `keypair` is provided. +```typescript +import { swap } from 'navi-aggregator-sdk'; + +const result = await swap( + address: string, + client: SuiClient, + fromCoin: string, + toCoin: string, + amountIn: number | string | bigint, + minAmountOut: number, + swapOptions: SwapOptions = { referer: 'https://www.navi.ag/', dexList: [], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } +); +``` + +## Demo +See the [demo](sample/demo.ts) for examples of how to use the SDK with NAVI-SDK. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/sample/demo.ts b/sample/demo.ts index bb88cc2..cd060ad 100644 --- a/sample/demo.ts +++ b/sample/demo.ts @@ -1,6 +1,6 @@ import { NAVISDKClient } from "navi-sdk"; import * as dotenv from "dotenv"; -import { swap } from '../src/main'; +import { swap, getRoute } from '../src/main'; dotenv.config(); @@ -22,7 +22,12 @@ const amount = 1e6; // 1e9 = 1 SUI const slippage = 10; // 5% slippage const minAmountOut = 1e5; // Minimum amount of tokenB to receive is 1 wUSDC -swap(account.address, account.client, tokenA, tokenB, amount, minAmountOut, { isDryRun: true }).then(async res => { +swap(account.address, account.client, tokenA, tokenB, amount, minAmountOut).then(async res => { console.log(await res.status); console.log(await res.balanceChanges); }); + +getRoute(tokenA, tokenB, amount).then(async res => { + console.log(res.amount_in); + console.log(res.amount_out); +}); diff --git a/src/lib/retrieveAPI.ts b/src/lib/retrieveAPI.ts index 50f17b6..ff22d85 100644 --- a/src/lib/retrieveAPI.ts +++ b/src/lib/retrieveAPI.ts @@ -17,7 +17,7 @@ export async function getRoute( fromCoin: string, toCoin: string, amountIn: number | string | bigint, - swapOptions: SwapOptions = { dexList: [], byAmountIn: true, depth: 3 } + swapOptions: SwapOptions = { referer: 'https://www.navi.ag/', dexList: [], byAmountIn: true, depth: 3 }, ): Promise { if (!config.BASE_URL) { throw new Error("API base URL is not set"); @@ -43,7 +43,11 @@ export async function getRoute( try { // Make the API request to fetch the swap route - const { data } = await axios.get(`${config.BASE_URL}?${fullParams}`); + const { data } = await axios.get(`${config.BASE_URL}?${fullParams}`, { + headers: { + 'referer': swapOptions.referer + } + }); if (!data) { throw new Error('No data returned from the API.'); diff --git a/src/main.ts b/src/main.ts index 379da1d..8922d7f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,7 +21,7 @@ export { Dex, Router, SwapOptions } from './types'; * @param {number | string | bigint} amountIn - The amount of the input coin. * @param {number} minAmountOut - The minimum amount of the output coin. * @param {SwapOptions} [swapOptions] - Optional swap options. - * @returns {Promise} - The final transaction object. + * @returns {Promise} - The final transaction object. */ export async function swapPTB( address: string, @@ -31,15 +31,14 @@ export async function swapPTB( coin: TransactionResult, amountIn: number | string | bigint, minAmountOut: number, - swapOptions: SwapOptions = { dexList: [], byAmountIn: true, depth: 3 } -): Promise { + swapOptions: SwapOptions = { referer: 'https://www.navi.ag/', dexList: [], byAmountIn: true, depth: 3 } +): Promise { // Get the output coin from the swap route and transfer it to the user const router = await import('./lib/retrieveAPI').then(module => module.getRoute(fromCoin, toCoin, amountIn, swapOptions)); const finalCoinB = await import('./lib').then(module => module.swapRoutePTB(address, minAmountOut, txb, coin, router)); - txb.transferObjects([finalCoinB], address); - return txb; + return finalCoinB; } @@ -64,14 +63,15 @@ export async function swap( toCoin: string, amountIn: number | string | bigint, minAmountOut: number, - swapOptions: SwapOptions = { dexList: [], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } + swapOptions: SwapOptions = { referer: 'https://www.navi.ag/', dexList: [], byAmountIn: true, depth: 3, isDryRun: true, keypair: undefined } ) { const txb = new Transaction(); txb.setSender(address); const coinA = await getCoinPTB(address, fromCoin, amountIn, txb, client); - await swapPTB(address, txb, fromCoin, toCoin, coinA, amountIn, minAmountOut, swapOptions); + const finalCoinB = await swapPTB(address, txb, fromCoin, toCoin, coinA, amountIn, minAmountOut, swapOptions); + txb.transferObjects([finalCoinB], address); if (swapOptions.isDryRun) { const dryRunTxBytes: Uint8Array = await txb.build({ diff --git a/src/types.ts b/src/types.ts index d03f305..cd82158 100644 --- a/src/types.ts +++ b/src/types.ts @@ -18,6 +18,7 @@ export type Router = { } export type SwapOptions = { + referer: string; dexList?: Dex[]; byAmountIn?: boolean; depth?: number; From 0228a35c3fdc808a2260debcf08d13a6534e0cb4 Mon Sep 17 00:00:00 2001 From: ComeOnOliver <43215937+ComeOnOliver@users.noreply.github.com> Date: Sat, 9 Nov 2024 17:07:41 -0500 Subject: [PATCH 7/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5227d55..0340150 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ const coinB = await swapPTB( ``` * Swap function -The swap function is a wrapper for the getRoute and swapPTB functions. Set `isDryRun` from `swapOptions` to true to get a dry run result and balance changes. It will submit the transaction and return the result if `isDryRun` is set to false and a `keypair` is provided. +The swap function is a wrapper for the getRoute and swapPTB functions. Set `isDryRun` from `swapOptions` to true to get a dry run result and balance changes. It will submit the transaction and return the result if a `keypair` is provided. ```typescript import { swap } from 'navi-aggregator-sdk';