Skip to content
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ dist-ssr/
*.tsbuildinfo
coverage/
.npm/
apps/api/src/version.json

# Compiled TypeScript files (if target is same as source)
*.js
*.js.map
*.d.ts
*.d.ts.map

# Keep scripts directory
!scripts/*.js

# Editor directories and files
.idea/
.vscode/
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import express from "express";

import { Quote, QuoteRequest, SwapperError, SwapQuoteData } from "@gemwallet/types";
import { StonfiProvider, Protocol, MayanProvider, CetusAggregatorProvider, RelayProvider, OrcaWhirlpoolProvider } from "@gemwallet/swapper";
import versionInfo from "./version.json";

if (process.env.NODE_ENV !== "production") {
const rootEnvPath = path.resolve(__dirname, "../../..", ".env");
Expand Down Expand Up @@ -36,7 +37,8 @@ const providers: Record<string, Protocol> = {
app.get("/", (_, res) => {
res.json({
providers: Object.keys(providers),
version: process.env.npm_package_version,
version: versionInfo.version,
commit: versionInfo.commit,
});
});

Expand Down
2 changes: 1 addition & 1 deletion apps/api/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"declarationMap": true,
"composite": true
},
"include": ["src/**/*"],
"include": ["src/**/*", "src/version.json"],
"exclude": ["node_modules", "dist"],
"references": [
{ "path": "../../packages/swapper" },
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"private": true,
"description": "core-ts package for gemwallet",
"scripts": {
"build": "pnpm --recursive --filter \"./packages/**\" run build && pnpm --filter \"./apps/**\" run build",
"generate-version": "node scripts/generate-version.js",
"build": "pnpm run generate-version && pnpm --recursive --filter \"./packages/**\" run build && pnpm --filter \"./apps/**\" run build",
"dev": "pnpm --parallel --filter \"./**\" run dev",
"start:api": "pnpm --filter @gemwallet/api start",
"dev:api": "pnpm --filter @gemwallet/api dev",
Expand Down
12 changes: 6 additions & 6 deletions packages/swapper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@
"@gemwallet/types": "workspace:*",
"@mayanfinance/swap-sdk": "12.0.0",
"@mysten/sui": "1.35.0",
"@orca-so/whirlpools": "5.0.0",
"@orca-so/whirlpools-client": "5.0.0",
"@orca-so/whirlpools": "6.0.0",
"@orca-so/whirlpools-client": "6.0.0",
"@orca-so/whirlpools-core": "3.0.0",
"@solana/kit": "5.0.0",
"@solana-program/token-2022": "0.6.1",
"@solana/instructions": "5.0.0",
"@solana/kit": "5.0.0",
"@solana/spl-token": "0.4.13",
"@solana/web3.js": "1.98.0",
"@ston-fi/api": "0.21.0",
"@ston-fi/api": "0.29.0",
"@ston-fi/sdk": "2.3.0",
"@ton/ton": "15.2.1",
"@ton/ton": "15.4.0",
"@types/bn.js": "5.1.6",
"bn.js": "5.2.1",
"js-sha3": "0.9.3"
},
"files": [
"dist"
]
}
}
115 changes: 115 additions & 0 deletions packages/swapper/src/stonfi/integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { Chain, QuoteRequest } from "@gemwallet/types";

import { StonfiProvider } from "./index";
import { createQuoteRequest, TON_ASSET, USDT_TON_ASSET } from "./testkit";

const runIntegration = process.env.STONFI_INTEGRATION_TEST === "1";
const describeIntegration = runIntegration ? describe : describe.skip;

const TON_RPC_ENDPOINT =
process.env.TON_URL || "https://toncenter.com";

// A valid TON wallet address for testing (TON Foundation address)
const WALLET_ADDRESS = "EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N";

const REQUEST_TEMPLATE: QuoteRequest = createQuoteRequest({
from_address: WALLET_ADDRESS,
to_address: WALLET_ADDRESS,
from_asset: TON_ASSET,
to_asset: USDT_TON_ASSET,
from_value: "1000000000", // 1 TON
referral_bps: 50,
slippage_bps: 100,
});

const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

describeIntegration("Stonfi live integration", () => {
jest.setTimeout(60_000);
const provider = new StonfiProvider(TON_RPC_ENDPOINT);

// Add delay between tests to avoid rate limiting from public RPC
afterEach(async () => {
await delay(2000);
});

it("fetches a live quote for TON -> USDT", async () => {
const quote = await provider.get_quote(REQUEST_TEMPLATE);

expect(BigInt(quote.output_value) > 0).toBe(true);
expect(quote.output_min_value).toBeDefined();

console.log("TON -> USDT quote", quote);
});

it("fetches a live quote and builds quote data for TON -> USDT", async () => {
const quote = await provider.get_quote(REQUEST_TEMPLATE);

expect(BigInt(quote.output_value) > 0).toBe(true);

const quoteData = await provider.get_quote_data(quote);

expect(typeof quoteData.data).toBe("string");
expect(quoteData.data.length).toBeGreaterThan(0);
expect(quoteData.to).toBeDefined();
expect(quoteData.value).toBeDefined();

console.log("TON -> USDT quoteData", quoteData);
});

it("fetches a live quote and builds quote data for USDT -> TON", async () => {
const reverseRequest = createQuoteRequest({
from_address: WALLET_ADDRESS,
to_address: WALLET_ADDRESS,
from_asset: USDT_TON_ASSET,
to_asset: TON_ASSET,
from_value: "1000000", // 1 USDT
referral_bps: 50,
slippage_bps: 100,
});

const quote = await provider.get_quote(reverseRequest);

expect(BigInt(quote.output_value) > 0).toBe(true);

console.log("USDT -> TON quote", quote);

const quoteData = await provider.get_quote_data(quote);

expect(typeof quoteData.data).toBe("string");
expect(quoteData.data.length).toBeGreaterThan(0);

console.log("USDT -> TON quoteData", quoteData);
});

it("fetches a live quote for jetton to jetton swap", async () => {
const NOT_COIN = {
id: `${Chain.Ton}_EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT`,
symbol: "NOT",
decimals: 9,
};

const jettonToJettonRequest = createQuoteRequest({
from_address: WALLET_ADDRESS,
to_address: WALLET_ADDRESS,
from_asset: USDT_TON_ASSET,
to_asset: NOT_COIN,
from_value: "1000000", // 1 USDT
referral_bps: 50,
slippage_bps: 100,
});

const quote = await provider.get_quote(jettonToJettonRequest);

expect(BigInt(quote.output_value) > 0).toBe(true);

console.log("USDT -> NOT quote", quote);

const quoteData = await provider.get_quote_data(quote);

expect(typeof quoteData.data).toBe("string");
expect(quoteData.data.length).toBeGreaterThan(0);

console.log("USDT -> NOT quoteData", quoteData);
});
});
54 changes: 54 additions & 0 deletions packages/swapper/src/stonfi/testkit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Chain, Quote, QuoteRequest } from "@gemwallet/types";

export const TON_ASSET = {
id: Chain.Ton,
symbol: "TON",
decimals: 9,
};

export const USDT_TON_ASSET = {
id: `${Chain.Ton}_EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs`,
symbol: "USDT",
decimals: 6,
};

export function createQuoteRequest(overrides: Partial<QuoteRequest> = {}): QuoteRequest {
const base: QuoteRequest = {
from_address: "UQDummyFromAddress1111111111111111111111111111",
to_address: "UQDummyToAddress11111111111111111111111111111",
from_asset: TON_ASSET,
to_asset: USDT_TON_ASSET,
from_value: "1000000000", // 1 TON
referral_bps: 0,
slippage_bps: 100,
};

const { from_asset, to_asset, ...restOverrides } = overrides;

return {
...base,
...restOverrides,
from_asset: {
...base.from_asset,
...(from_asset ?? {}),
},
to_asset: {
...base.to_asset,
...(to_asset ?? {}),
},
};
}

export function buildQuoteFixture(
requestOverrides: Partial<QuoteRequest> = {},
quoteOverrides: Partial<Omit<Quote, "quote">> = {},
): Quote {
return {
quote: createQuoteRequest(requestOverrides),
output_value: "0",
output_min_value: "0",
eta_in_seconds: 3,
route_data: {},
...quoteOverrides,
};
}
Loading
Loading