Skip to content
This repository has been archived by the owner on Nov 22, 2024. It is now read-only.

Commit

Permalink
Merge pull request #7 from naviprotocol/Add-new-Dexes
Browse files Browse the repository at this point in the history
add new Dexes
  • Loading branch information
ComeOnOliver authored Nov 10, 2024
2 parents eafd26c + 0228a35 commit 3558e39
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 89 deletions.
6 changes: 4 additions & 2 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -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 = ''
MNEMONIC = ''
85 changes: 48 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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=<your_wallet_mnemonic>
RPC=<your_sui_rpc_url>
apiBaseURL = <api_url>
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 }
)
```
```
* 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 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.
9 changes: 7 additions & 2 deletions sample/demo.ts
Original file line number Diff line number Diff line change
@@ -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();

Expand All @@ -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);
});
20 changes: 20 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof config>) {
Expand Down
22 changes: 22 additions & 0 deletions src/lib/KriyaV2.ts
Original file line number Diff line number Diff line change
@@ -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
}
25 changes: 25 additions & 0 deletions src/lib/aftermath.ts
Original file line number Diff line number Diff line change
@@ -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
}
17 changes: 15 additions & 2 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";


/**
Expand All @@ -16,13 +19,12 @@ import { Router } from "../types";
* @returns {Promise<TransactionResult>} - 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<TransactionResult> {
export async function swapRoutePTB(userAddress: string, minAmountOut: number, txb: Transaction, coinIn: TransactionResult, router: Router, referral: number = 0): Promise<TransactionResult> {
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 (
Expand Down Expand Up @@ -127,6 +129,17 @@ 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") {
const amountLimit = route.info_for_ptb.amountLimit;
pathTempCoin = await makeAftermathPTB(txb, poolId, pathTempCoin, amountLimit, a2b, typeArguments)
}

}

txb.mergeCoins(finalCoinB, [pathTempCoin]);
Expand Down
99 changes: 99 additions & 0 deletions src/lib/kriyaV3.ts
Original file line number Diff line number Diff line change
@@ -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
}



Loading

0 comments on commit 3558e39

Please sign in to comment.