Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
StandardData,
TokenParams,
WalletBalance,
} from "./types";
} from "./types/types";

const DEFAULT_BASE_URL = "https://api.enso.finance/api/v1";
/**
Expand Down Expand Up @@ -62,7 +62,7 @@ export class EnsoClient {
baseURL,
headers: {
Authorization: `Bearer ${apiKey}`,
}
},
});
}

Expand Down Expand Up @@ -585,6 +585,15 @@ export class EnsoClient {
url,
});
}

public async getAccountId(): Promise<string> {
const url = `/account/accountId`;

return this.request<string>({
method: "GET",
url,
});
}
}

// Custom error classes
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion src/types/actions.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -129,6 +129,8 @@ export type RepayAction = {
amountIn: ActionOutputReference<Quantity>;
/** Address of the lending pool contract */
primaryAddress: Address;
/** The address of the user whose debt is being repaid" */
onBehalfOf?: Address;
};
};

Expand Down
10 changes: 9 additions & 1 deletion src/types.ts → src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

/**
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
};

/**
Expand All @@ -444,6 +448,7 @@ export type BundleData = {
tx: Transaction;
/** Amounts out for each action */
amountsOut: Record<Address, Quantity>;
route?: Hop[];
};

/**
Expand Down Expand Up @@ -562,6 +567,7 @@ export interface IporShortcutData {
logs: string[];
/** Tenderly simulation URL */
simulationURL: string;
route?: Hop[];
}

/**
Expand Down Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion tests/bigNumberIshHandling.test.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
RouteParams,
StandardData,
TokenParams,
} from "../src/types";
} from "../src/types/types";

// Mock data fixtures
const mockRouteData = {
Expand Down
31 changes: 27 additions & 4 deletions tests/docs.test.ts → tests/docs.actions.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { EnsoClient } from "../src";
import { Address, BundleAction, EnsoClient } from "../src";

describe("docs", () => {
const client = new EnsoClient({
apiKey: "56b3d1f4-5c59-4fc1-8998-16d001e277bc",
});
beforeAll(() => {});

// Generated Jest tests from MDX files

it("slippage", async () => {
const bundle = await client.getBundleData(
{
Expand Down Expand Up @@ -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(
{
Expand Down Expand Up @@ -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,
Expand Down
127 changes: 127 additions & 0 deletions tests/docs.route.test.ts
Original file line number Diff line number Diff line change
@@ -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
});
2 changes: 1 addition & 1 deletion tests/integration.test.ts
Original file line number Diff line number Diff line change
@@ -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(
Expand Down