diff --git a/src/client.ts b/src/client.ts index f97272b..c9a0afd 100644 --- a/src/client.ts +++ b/src/client.ts @@ -26,7 +26,7 @@ import { StandardData, TokenParams, WalletBalance, -} from "./types"; +} from "./types/types"; const DEFAULT_BASE_URL = "https://api.enso.finance/api/v1"; /** @@ -62,7 +62,7 @@ export class EnsoClient { baseURL, headers: { Authorization: `Bearer ${apiKey}`, - } + }, }); } @@ -585,6 +585,15 @@ export class EnsoClient { url, }); } + + public async getAccountId(): Promise { + const url = `/account/accountId`; + + return this.request({ + method: "GET", + url, + }); + } } // Custom error classes diff --git a/src/index.ts b/src/index.ts index 16f52d4..627282d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,7 +27,7 @@ import { TokenData, TokenParams, WalletBalance -} from "./types"; +} from "./types/types"; export type { ActionData, Address, ApproveData, ApproveParams, BalanceParams, BundleAction, BundleData, BundleParams, ConnectedNetwork, IporShortcutData, IporShortcutInputData, MultiPriceParams, Network, NonTokenizedPositionData, PriceData, diff --git a/src/types/actions.ts b/src/types/actions.ts index c997f34..3e56bf2 100644 --- a/src/types/actions.ts +++ b/src/types/actions.ts @@ -1,6 +1,6 @@ // src/types/actions.ts - Updated to match OpenAPI specification -import { Address, BytesArg, Quantity } from "../types"; +import { Address, BytesArg, Quantity } from "./types"; /** * Route action using Enso's routing engine. @@ -129,6 +129,8 @@ export type RepayAction = { amountIn: ActionOutputReference; /** Address of the lending pool contract */ primaryAddress: Address; + /** The address of the user whose debt is being repaid" */ + onBehalfOf?: Address; }; }; diff --git a/src/types.ts b/src/types/types.ts similarity index 97% rename from src/types.ts rename to src/types/types.ts index 50e6c00..c623695 100644 --- a/src/types.ts +++ b/src/types/types.ts @@ -3,7 +3,7 @@ /** * @fileoverview Type definitions for the Enso Finance API SDK */ -import { BundleAction } from "./types/actions"; +import { BundleAction } from "./actions"; export type { BundleAction }; /** @@ -61,6 +61,8 @@ export type RouteParams = { spender?: Address; /** Chain ID of the network to execute the transaction on */ chainId: number; + /** Chain ID of the destination network for cross-chain bridging */ + destinationChainId?: number; /** Amount of tokenIn to swap in wei */ amountIn: Quantity[]; /** Slippage in basis points (1/10000). If specified, minAmountOut should not be specified */ @@ -428,6 +430,8 @@ export type BundleParams = { ignoreAggregators?: string[]; /** Referral code that will be included in an on-chain event */ referralCode?: string; + /** A list of standards to be ignored from consideration */ + ignoreStandards?: string[] | null; }; /** @@ -444,6 +448,7 @@ export type BundleData = { tx: Transaction; /** Amounts out for each action */ amountsOut: Record; + route?: Hop[]; }; /** @@ -562,6 +567,7 @@ export interface IporShortcutData { logs: string[]; /** Tenderly simulation URL */ simulationURL: string; + route?: Hop[]; } /** @@ -590,6 +596,8 @@ export interface NonTokenizedParams { protocolSlug?: string; /** Chain ID of the network of the nontokenized position */ chainId?: number; + /** Chain ID of the destination network for cross-chain bridging */ + destinationChainId?: number; /** Ethereum addresses of the nontokenized positions */ address?: Address[]; /** Ethereum addresses for contract interaction of nontokenized position */ diff --git a/tests/bigNumberIshHandling.test.ts b/tests/bigNumberIshHandling.test.ts index 74a2270..b3b7bd6 100644 --- a/tests/bigNumberIshHandling.test.ts +++ b/tests/bigNumberIshHandling.test.ts @@ -1,7 +1,7 @@ import axios from "axios"; import MockAdapter from "axios-mock-adapter"; import { EnsoClient } from "../src"; -import { Address, ApproveData, ApproveParams, Transaction } from "../src/types"; +import { Address, ApproveData, ApproveParams, Transaction } from "../src/types/types"; describe("BigNumberIsh Handling", () => { let client: EnsoClient; diff --git a/tests/client.test.ts b/tests/client.test.ts index 3d051e0..a9489ff 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -20,7 +20,7 @@ import { RouteParams, StandardData, TokenParams, -} from "../src/types"; +} from "../src/types/types"; // Mock data fixtures const mockRouteData = { diff --git a/tests/docs.test.ts b/tests/docs.actions.test.ts similarity index 96% rename from tests/docs.test.ts rename to tests/docs.actions.test.ts index 2910024..005db6a 100644 --- a/tests/docs.test.ts +++ b/tests/docs.actions.test.ts @@ -1,4 +1,4 @@ -import { EnsoClient } from "../src"; +import { Address, BundleAction, EnsoClient } from "../src"; describe("docs", () => { const client = new EnsoClient({ @@ -6,8 +6,6 @@ describe("docs", () => { }); beforeAll(() => {}); - // Generated Jest tests from MDX files - it("slippage", async () => { const bundle = await client.getBundleData( { @@ -313,6 +311,31 @@ describe("docs", () => { console.log(JSON.stringify(bundle, null, 2)); }); + it("repay on behalf of other", async () => { + const bundleData = await client.getBundleData( + { + chainId: 1, // Mainnet + fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" as Address, + routingStrategy: "delegate", + }, + [ + // 3. Repay the ETH debt + { + protocol: "compound-v2", + action: "repay", + args: { + tokenIn: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // ETH + amountIn: "300000000000000000", + primaryAddress: "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", // cETH contract + onBehalfOf: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + }, + ], + ); + + console.log(JSON.stringify(bundleData)); + }); + it("harvest", async () => { const bundle = await client.getBundleData( { @@ -436,7 +459,7 @@ describe("docs", () => { console.log(JSON.stringify(bundle, null, 2)); }); - it("bridge", async () => { + it.skip("bridge", async () => { const bundle = await client.getBundleData( { chainId: 1, diff --git a/tests/docs.route.test.ts b/tests/docs.route.test.ts new file mode 100644 index 0000000..2e7839f --- /dev/null +++ b/tests/docs.route.test.ts @@ -0,0 +1,127 @@ +import { Address, BundleAction, EnsoClient, RouteParams } from "../src"; + +describe("docs route tests", () => { + const client = new EnsoClient({ + apiKey: "56b3d1f4-5c59-4fc1-8998-16d001e277bc", + }); + beforeAll(() => {}); + + const ETHEREUM_MAINNET = 1; + const PLUME_MAINNET = 98866; + + // Token addresses + const USDC_MAINNET = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as Address; + const USDC_E_PLUME = "0x78adD880A697070c1e765Ac44D65323a0DcCE913" as Address; // USDC.e on Plume + const MYPUSD_PLUME = "0xAf5aEAb2248415716569Be5d24FbE10b16590D6c" as Address; // Mystic vault myPUSD + + const testWallet = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" as Address; + + it("routes tokens crosschain", async () => { + const route = await client.getRouteData({ + fromAddress: testWallet, + receiver: testWallet, + spender: testWallet, + chainId: ETHEREUM_MAINNET, + destinationChainId: PLUME_MAINNET, + amountIn: ["1000000000"], // 1,000 USDC (6 decimals) + tokenIn: [USDC_MAINNET], + tokenOut: [USDC_E_PLUME], + routingStrategy: "delegate", + slippage: "300", // 3% slippage for cross-chain + referralCode: "cross-chain-test", + }); + + expect(route).toBeDefined(); + + expect(route.gas).toBeDefined(); + expect(route.amountOut).toBeDefined(); + expect(route.tx).toBeDefined(); + expect(route.tx.data).toBeDefined(); + expect(route.tx.to).toBeDefined(); + expect(route.tx.from).toBe(testWallet); + + const amountOutNum = parseFloat(route.amountOut.toString()); + expect(amountOutNum).toBeGreaterThan(0); + + // Cross-chain should have some fee/slippage but not excessive + expect(amountOutNum).toBeGreaterThan(900000000); // At least 900 USDC out + + console.log(route); + }); + + it.skip("routes tokens crosschain and outputs the route", async () => { + const route = await client.getRouteData({ + fromAddress: testWallet, + receiver: testWallet, + spender: testWallet, + chainId: ETHEREUM_MAINNET, + destinationChainId: PLUME_MAINNET, + amountIn: ["1000000000"], // 1,000 USDC (6 decimals) + tokenIn: [USDC_MAINNET], + tokenOut: [USDC_E_PLUME], + routingStrategy: "delegate", + slippage: "300", // 3% slippage for cross-chain + referralCode: "cross-chain-test", + }); + + // Validate cross-chain specific properties + expect(route.route).toBeDefined(); + expect(route.route.length).toBeGreaterThan(0); + console.log(route); + }); + + it("should route USDC from Ethereum mainnet and zap into Plume Mystic vault (myPUSD)", async () => { + const routeParams: RouteParams = { + fromAddress: testWallet, + receiver: testWallet, + spender: testWallet, + chainId: ETHEREUM_MAINNET, + destinationChainId: PLUME_MAINNET, + amountIn: ["2000000000"], // 2,000 USDC (6 decimals) + tokenIn: [USDC_MAINNET], + tokenOut: [MYPUSD_PLUME], // Mystic vault myPUSD + routingStrategy: "delegate", + slippage: "500", // 5% slippage for complex cross-chain + vault operation + referralCode: "vault-zap-test", + }; + + const route = await client.getRouteData(routeParams); + + // Validate the response structure + expect(route).toBeDefined(); + expect(route.route).toBeDefined(); + expect(route.gas).toBeDefined(); + expect(route.amountOut).toBeDefined(); + expect(route.tx).toBeDefined(); + + // This should be a complex route with multiple steps + expect(route.route.length).toBeGreaterThan(0); + + console.log(route); + // Log detailed route information + console.log( + "Cross-chain vault zap route:", + JSON.stringify( + { + routeSteps: route.route.length, + firstAction: route.route[0]?.action, + lastAction: route.route[route.route.length - 1]?.action, + amountOut: route.amountOut, + gas: route.gas, + priceImpact: route.priceImpact, + feeAmount: route.feeAmount, + }, + null, + 2, + ), + ); + + // Validate gas estimates are reasonable for complex operation + const gasNum = parseFloat(route.gas.toString()); + expect(gasNum).toBeGreaterThan(300000); // Complex operation needs more gas + + // Validate we get some vault tokens back + const amountOutNum = parseFloat(route.amountOut.toString()); + expect(amountOutNum).toBeGreaterThan(0); + }, 45000); // 45 second timeout for complex route +}); diff --git a/tests/integration.test.ts b/tests/integration.test.ts index 7bfa684..9d24e15 100644 --- a/tests/integration.test.ts +++ b/tests/integration.test.ts @@ -1,7 +1,7 @@ import { EnsoClient } from "../src/index"; import { setupServer } from "msw/node"; import { http, HttpResponse } from "msw"; -import { Address, BundleAction } from "../src/types"; +import { Address, BundleAction } from "../src/types/types"; // Mock server for integration tests const server = setupServer(