@vulcx/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/dist/client.d.ts +13 -0
- package/dist/errors.d.ts +20 -0
- package/dist/index.cjs.js +155 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.esm.js +147 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.umd.js +161 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# @vulcx/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the Vulcx DEX aggregator API. Works in Node.js, browsers, and any JavaScript runtime with `fetch`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @vulcx/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or via CDN:
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<script src="https://unpkg.com/@vulcx/sdk"></script>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { VulcxSDK } from "@vulcx/sdk";
|
|
21
|
+
|
|
22
|
+
const vulcx = new VulcxSDK({
|
|
23
|
+
apiKey: "vulcx_your_api_key_here",
|
|
24
|
+
chain: "solana", // or "fogo"
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Get a quote
|
|
28
|
+
const quote = await vulcx.quote({
|
|
29
|
+
inputMint: "So11111111111111111111111111111111111111112",
|
|
30
|
+
outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
31
|
+
amount: "1000000000", // 1 SOL in lamports
|
|
32
|
+
swapMode: "ExactIn",
|
|
33
|
+
slippageBps: 50,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log(`Output: ${quote.amountOut}, Impact: ${quote.priceImpactPercent}`);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
### `new VulcxSDK(config)`
|
|
42
|
+
|
|
43
|
+
| Parameter | Type | Default | Description |
|
|
44
|
+
| ----------- | -------- | ----------------------------- | -------------------------- |
|
|
45
|
+
| `apiKey` | `string` | **required** | Your API key |
|
|
46
|
+
| `chain` | `string` | `"solana"` | `"solana"` or `"fogo"` |
|
|
47
|
+
| `baseUrl` | `string` | `"https://api.vulcx.xyz"` | API base URL |
|
|
48
|
+
| `timeout` | `number` | `30000` | Request timeout in ms |
|
|
49
|
+
| `retries` | `number` | `2` | Retry count for 429/5xx |
|
|
50
|
+
|
|
51
|
+
### `sdk.quote(params): Promise<QuoteResponse>`
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const quote = await vulcx.quote({
|
|
55
|
+
inputMint: "So111...",
|
|
56
|
+
outputMint: "EPjFW...",
|
|
57
|
+
amount: "1000000000",
|
|
58
|
+
swapMode: "ExactIn", // or "ExactOut"
|
|
59
|
+
slippageBps: 50, // optional, default 50
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `sdk.swap(params): Promise<SwapResponse>`
|
|
64
|
+
|
|
65
|
+
Returns a base64-encoded unsigned transaction.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const swap = await vulcx.swap({
|
|
69
|
+
userWallet: "9WzDX...",
|
|
70
|
+
inputMint: "So111...",
|
|
71
|
+
outputMint: "EPjFW...",
|
|
72
|
+
amount: "1000000000",
|
|
73
|
+
swapMode: "ExactIn",
|
|
74
|
+
slippageBps: 50,
|
|
75
|
+
skipSimulation: false,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Sign and send swap.transaction with your wallet adapter
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `sdk.instructions(params): Promise<InstructionsResponse>`
|
|
82
|
+
|
|
83
|
+
Returns raw instructions for composability.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const ixs = await vulcx.instructions({
|
|
87
|
+
userWallet: "9WzDX...",
|
|
88
|
+
inputMint: "So111...",
|
|
89
|
+
outputMint: "EPjFW...",
|
|
90
|
+
amount: "1000000000",
|
|
91
|
+
swapMode: "ExactIn",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Build your own transaction with ixs.instructions
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Error Handling
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { VulcxSDK, NoRouteError, RateLimitError, AuthError } from "@vulcx/sdk";
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const quote = await vulcx.quote({ ... });
|
|
104
|
+
} catch (err) {
|
|
105
|
+
if (err instanceof NoRouteError) {
|
|
106
|
+
console.log("No route found between tokens");
|
|
107
|
+
} else if (err instanceof RateLimitError) {
|
|
108
|
+
console.log("Rate limited, try again later");
|
|
109
|
+
} else if (err instanceof AuthError) {
|
|
110
|
+
console.log("Invalid API key");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Framework Examples
|
|
116
|
+
|
|
117
|
+
### React
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { VulcxSDK } from "@vulcx/sdk";
|
|
121
|
+
import { useEffect, useState } from "react";
|
|
122
|
+
|
|
123
|
+
const sdk = new VulcxSDK({ apiKey: "vulcx_..." });
|
|
124
|
+
|
|
125
|
+
function SwapPage() {
|
|
126
|
+
const [quote, setQuote] = useState(null);
|
|
127
|
+
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
sdk.quote({
|
|
130
|
+
inputMint: "So111...",
|
|
131
|
+
outputMint: "EPjFW...",
|
|
132
|
+
amount: "1000000000",
|
|
133
|
+
swapMode: "ExactIn",
|
|
134
|
+
}).then(setQuote);
|
|
135
|
+
}, []);
|
|
136
|
+
|
|
137
|
+
return <div>{quote && <p>Output: {quote.amountOut}</p>}</div>;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Node.js
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
const { VulcxSDK } = require("@vulcx/sdk");
|
|
145
|
+
|
|
146
|
+
const sdk = new VulcxSDK({ apiKey: process.env.VULCX_KEY });
|
|
147
|
+
const quote = await sdk.quote({ ... });
|
|
148
|
+
```
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SDKConfig, QuoteRequest, QuoteResponse, SwapRequest, SwapResponse, InstructionsRequest, InstructionsResponse } from "./types";
|
|
2
|
+
export declare class VulcxSDK {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly chain;
|
|
5
|
+
private readonly baseUrl;
|
|
6
|
+
private readonly timeout;
|
|
7
|
+
private readonly retries;
|
|
8
|
+
constructor(config: SDKConfig);
|
|
9
|
+
quote(params: QuoteRequest): Promise<QuoteResponse>;
|
|
10
|
+
swap(params: SwapRequest): Promise<SwapResponse>;
|
|
11
|
+
instructions(params: InstructionsRequest): Promise<InstructionsResponse>;
|
|
12
|
+
private request;
|
|
13
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare class VulcxError extends Error {
|
|
2
|
+
readonly statusCode: number;
|
|
3
|
+
readonly body?: unknown | undefined;
|
|
4
|
+
constructor(message: string, statusCode: number, body?: unknown | undefined);
|
|
5
|
+
}
|
|
6
|
+
export declare class RateLimitError extends VulcxError {
|
|
7
|
+
constructor(body?: unknown);
|
|
8
|
+
}
|
|
9
|
+
export declare class NoRouteError extends VulcxError {
|
|
10
|
+
constructor(body?: unknown);
|
|
11
|
+
}
|
|
12
|
+
export declare class BadRequestError extends VulcxError {
|
|
13
|
+
constructor(message: string, body?: unknown);
|
|
14
|
+
}
|
|
15
|
+
export declare class AuthError extends VulcxError {
|
|
16
|
+
constructor(body?: unknown);
|
|
17
|
+
}
|
|
18
|
+
export declare class ServerError extends VulcxError {
|
|
19
|
+
constructor(message: string, body?: unknown);
|
|
20
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class VulcxError extends Error {
|
|
4
|
+
constructor(message, statusCode, body) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.statusCode = statusCode;
|
|
7
|
+
this.body = body;
|
|
8
|
+
this.name = "VulcxError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
class RateLimitError extends VulcxError {
|
|
12
|
+
constructor(body) {
|
|
13
|
+
super("Rate limit exceeded", 429, body);
|
|
14
|
+
this.name = "RateLimitError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
class NoRouteError extends VulcxError {
|
|
18
|
+
constructor(body) {
|
|
19
|
+
super("No route found", 404, body);
|
|
20
|
+
this.name = "NoRouteError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class BadRequestError extends VulcxError {
|
|
24
|
+
constructor(message, body) {
|
|
25
|
+
super(message, 400, body);
|
|
26
|
+
this.name = "BadRequestError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
class AuthError extends VulcxError {
|
|
30
|
+
constructor(body) {
|
|
31
|
+
super("Invalid or missing API key", 401, body);
|
|
32
|
+
this.name = "AuthError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class ServerError extends VulcxError {
|
|
36
|
+
constructor(message, body) {
|
|
37
|
+
super(message, 500, body);
|
|
38
|
+
this.name = "ServerError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const DEFAULT_BASE_URL = "https://api.vulcx.xyz";
|
|
43
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
44
|
+
const DEFAULT_RETRIES = 2;
|
|
45
|
+
class VulcxSDK {
|
|
46
|
+
constructor(config) {
|
|
47
|
+
if (!config.apiKey)
|
|
48
|
+
throw new Error("apiKey is required");
|
|
49
|
+
this.apiKey = config.apiKey;
|
|
50
|
+
this.chain = config.chain ?? "solana";
|
|
51
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
52
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
53
|
+
this.retries = config.retries ?? DEFAULT_RETRIES;
|
|
54
|
+
}
|
|
55
|
+
async quote(params) {
|
|
56
|
+
const qs = new URLSearchParams({
|
|
57
|
+
inputMint: params.inputMint,
|
|
58
|
+
outputMint: params.outputMint,
|
|
59
|
+
amount: params.amount,
|
|
60
|
+
swapMode: params.swapMode,
|
|
61
|
+
});
|
|
62
|
+
if (params.slippageBps !== undefined) {
|
|
63
|
+
qs.set("slippageBps", String(params.slippageBps));
|
|
64
|
+
}
|
|
65
|
+
return this.request("GET", `/api/v1/quote?${qs}`);
|
|
66
|
+
}
|
|
67
|
+
async swap(params) {
|
|
68
|
+
return this.request("POST", "/api/v1/swap", params);
|
|
69
|
+
}
|
|
70
|
+
async instructions(params) {
|
|
71
|
+
return this.request("POST", "/api/v1/instructions", params);
|
|
72
|
+
}
|
|
73
|
+
async request(method, path, body) {
|
|
74
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
75
|
+
const url = `${this.baseUrl}${path}${separator}chain=${this.chain}`;
|
|
76
|
+
const headers = {
|
|
77
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
78
|
+
Accept: "application/json",
|
|
79
|
+
};
|
|
80
|
+
if (body) {
|
|
81
|
+
headers["Content-Type"] = "application/json";
|
|
82
|
+
}
|
|
83
|
+
let lastError;
|
|
84
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
85
|
+
if (attempt > 0) {
|
|
86
|
+
await sleep(Math.min(1000 * 2 ** (attempt - 1), 8000));
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
91
|
+
const res = await fetch(url, {
|
|
92
|
+
method,
|
|
93
|
+
headers,
|
|
94
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
});
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
if (res.ok) {
|
|
99
|
+
const parsed = (await res.json());
|
|
100
|
+
// API responses wrap the payload in {success, data}; hand back the
|
|
101
|
+
// payload the way the method signatures promise.
|
|
102
|
+
if (parsed && typeof parsed === "object" && "success" in parsed) {
|
|
103
|
+
if (!parsed.success) {
|
|
104
|
+
throw new VulcxError(parsed.error ?? "request failed", res.status, parsed);
|
|
105
|
+
}
|
|
106
|
+
return parsed.data;
|
|
107
|
+
}
|
|
108
|
+
return parsed;
|
|
109
|
+
}
|
|
110
|
+
const errBody = await res.json().catch(() => ({}));
|
|
111
|
+
const errMsg = errBody?.error ?? res.statusText;
|
|
112
|
+
switch (res.status) {
|
|
113
|
+
case 401:
|
|
114
|
+
case 403:
|
|
115
|
+
throw new AuthError(errBody);
|
|
116
|
+
case 400:
|
|
117
|
+
throw new BadRequestError(errMsg, errBody);
|
|
118
|
+
case 404:
|
|
119
|
+
throw new NoRouteError(errBody);
|
|
120
|
+
case 429:
|
|
121
|
+
lastError = new RateLimitError(errBody);
|
|
122
|
+
continue;
|
|
123
|
+
default:
|
|
124
|
+
if (res.status >= 500) {
|
|
125
|
+
lastError = new ServerError(errMsg, errBody);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
throw new VulcxError(errMsg, res.status, errBody);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (err instanceof AuthError ||
|
|
133
|
+
err instanceof BadRequestError ||
|
|
134
|
+
err instanceof NoRouteError ||
|
|
135
|
+
err instanceof VulcxError) {
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
lastError = err;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
throw lastError ?? new Error("request failed");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function sleep(ms) {
|
|
145
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
exports.AuthError = AuthError;
|
|
149
|
+
exports.BadRequestError = BadRequestError;
|
|
150
|
+
exports.NoRouteError = NoRouteError;
|
|
151
|
+
exports.RateLimitError = RateLimitError;
|
|
152
|
+
exports.ServerError = ServerError;
|
|
153
|
+
exports.VulcxError = VulcxError;
|
|
154
|
+
exports.VulcxSDK = VulcxSDK;
|
|
155
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":[null,null],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
type SwapMode = "ExactIn" | "ExactOut";
|
|
2
|
+
type Chain = "solana" | "fogo";
|
|
3
|
+
type PriceImpactSeverity = "none" | "low" | "moderate" | "high" | "extreme";
|
|
4
|
+
interface SDKConfig {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
chain?: Chain;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
retries?: number;
|
|
10
|
+
}
|
|
11
|
+
interface QuoteRequest {
|
|
12
|
+
inputMint: string;
|
|
13
|
+
outputMint: string;
|
|
14
|
+
amount: string;
|
|
15
|
+
swapMode: SwapMode;
|
|
16
|
+
slippageBps?: number;
|
|
17
|
+
}
|
|
18
|
+
interface RouteInfo {
|
|
19
|
+
poolAddress: string;
|
|
20
|
+
poolType: string;
|
|
21
|
+
percent: number;
|
|
22
|
+
inputMint: string;
|
|
23
|
+
outputMint: string;
|
|
24
|
+
}
|
|
25
|
+
interface QuoteResponse {
|
|
26
|
+
inputMint: string;
|
|
27
|
+
outputMint: string;
|
|
28
|
+
amountIn: string;
|
|
29
|
+
amountOut: string;
|
|
30
|
+
priceImpactBps: number;
|
|
31
|
+
priceImpactPercent: string;
|
|
32
|
+
priceImpactSeverity: PriceImpactSeverity;
|
|
33
|
+
priceImpactWarning: string;
|
|
34
|
+
feeBps: number;
|
|
35
|
+
routes: RouteInfo[];
|
|
36
|
+
routePath: string[];
|
|
37
|
+
hopCount: number;
|
|
38
|
+
otherAmountThreshold: string;
|
|
39
|
+
}
|
|
40
|
+
interface SwapRequest {
|
|
41
|
+
userWallet: string;
|
|
42
|
+
inputMint: string;
|
|
43
|
+
outputMint: string;
|
|
44
|
+
amount: string;
|
|
45
|
+
swapMode: SwapMode;
|
|
46
|
+
slippageBps?: number;
|
|
47
|
+
skipSimulation?: boolean;
|
|
48
|
+
}
|
|
49
|
+
interface SimulationResult {
|
|
50
|
+
success: boolean;
|
|
51
|
+
computeUnitsConsumed: number;
|
|
52
|
+
computeUnitsTotal: number;
|
|
53
|
+
logs: string[];
|
|
54
|
+
error: string;
|
|
55
|
+
slippageExceeded: boolean;
|
|
56
|
+
insufficientFunds: boolean;
|
|
57
|
+
accountsNeeded: string[];
|
|
58
|
+
}
|
|
59
|
+
interface SwapResponse {
|
|
60
|
+
transaction: string;
|
|
61
|
+
lastValidBlockHeight: number;
|
|
62
|
+
amountIn: string;
|
|
63
|
+
amountOut: string;
|
|
64
|
+
minAmountOut?: string;
|
|
65
|
+
maxAmountIn?: string;
|
|
66
|
+
feeAmount: string;
|
|
67
|
+
simulation?: SimulationResult;
|
|
68
|
+
computeUnitsEstimate: number;
|
|
69
|
+
route: string[];
|
|
70
|
+
hopCount: number;
|
|
71
|
+
pools: string[];
|
|
72
|
+
isSplitRoute: boolean;
|
|
73
|
+
splitPercents?: number[];
|
|
74
|
+
}
|
|
75
|
+
interface InstructionsRequest {
|
|
76
|
+
userWallet: string;
|
|
77
|
+
inputMint: string;
|
|
78
|
+
outputMint: string;
|
|
79
|
+
amount: string;
|
|
80
|
+
swapMode: SwapMode;
|
|
81
|
+
slippageBps?: number;
|
|
82
|
+
}
|
|
83
|
+
interface RawAccountMeta {
|
|
84
|
+
publicKey: string;
|
|
85
|
+
isSigner: boolean;
|
|
86
|
+
isWritable: boolean;
|
|
87
|
+
}
|
|
88
|
+
interface RawInstruction {
|
|
89
|
+
programId: string;
|
|
90
|
+
accounts: RawAccountMeta[];
|
|
91
|
+
data: string;
|
|
92
|
+
}
|
|
93
|
+
interface InstructionsResponse {
|
|
94
|
+
instructions: RawInstruction[];
|
|
95
|
+
addressLookupTableAddresses: string[];
|
|
96
|
+
amountIn: string;
|
|
97
|
+
amountOut: string;
|
|
98
|
+
otherAmountThreshold: string;
|
|
99
|
+
feeAmount: string;
|
|
100
|
+
hopCount: number;
|
|
101
|
+
route: string[];
|
|
102
|
+
pools: string[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
declare class VulcxSDK {
|
|
106
|
+
private readonly apiKey;
|
|
107
|
+
private readonly chain;
|
|
108
|
+
private readonly baseUrl;
|
|
109
|
+
private readonly timeout;
|
|
110
|
+
private readonly retries;
|
|
111
|
+
constructor(config: SDKConfig);
|
|
112
|
+
quote(params: QuoteRequest): Promise<QuoteResponse>;
|
|
113
|
+
swap(params: SwapRequest): Promise<SwapResponse>;
|
|
114
|
+
instructions(params: InstructionsRequest): Promise<InstructionsResponse>;
|
|
115
|
+
private request;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
declare class VulcxError extends Error {
|
|
119
|
+
readonly statusCode: number;
|
|
120
|
+
readonly body?: unknown | undefined;
|
|
121
|
+
constructor(message: string, statusCode: number, body?: unknown | undefined);
|
|
122
|
+
}
|
|
123
|
+
declare class RateLimitError extends VulcxError {
|
|
124
|
+
constructor(body?: unknown);
|
|
125
|
+
}
|
|
126
|
+
declare class NoRouteError extends VulcxError {
|
|
127
|
+
constructor(body?: unknown);
|
|
128
|
+
}
|
|
129
|
+
declare class BadRequestError extends VulcxError {
|
|
130
|
+
constructor(message: string, body?: unknown);
|
|
131
|
+
}
|
|
132
|
+
declare class AuthError extends VulcxError {
|
|
133
|
+
constructor(body?: unknown);
|
|
134
|
+
}
|
|
135
|
+
declare class ServerError extends VulcxError {
|
|
136
|
+
constructor(message: string, body?: unknown);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { AuthError, BadRequestError, NoRouteError, RateLimitError, ServerError, VulcxError, VulcxSDK };
|
|
140
|
+
export type { Chain, InstructionsRequest, InstructionsResponse, PriceImpactSeverity, QuoteRequest, QuoteResponse, RawAccountMeta, RawInstruction, RouteInfo, SDKConfig, SimulationResult, SwapMode, SwapRequest, SwapResponse };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
class VulcxError extends Error {
|
|
2
|
+
constructor(message, statusCode, body) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.statusCode = statusCode;
|
|
5
|
+
this.body = body;
|
|
6
|
+
this.name = "VulcxError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
class RateLimitError extends VulcxError {
|
|
10
|
+
constructor(body) {
|
|
11
|
+
super("Rate limit exceeded", 429, body);
|
|
12
|
+
this.name = "RateLimitError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class NoRouteError extends VulcxError {
|
|
16
|
+
constructor(body) {
|
|
17
|
+
super("No route found", 404, body);
|
|
18
|
+
this.name = "NoRouteError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class BadRequestError extends VulcxError {
|
|
22
|
+
constructor(message, body) {
|
|
23
|
+
super(message, 400, body);
|
|
24
|
+
this.name = "BadRequestError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
class AuthError extends VulcxError {
|
|
28
|
+
constructor(body) {
|
|
29
|
+
super("Invalid or missing API key", 401, body);
|
|
30
|
+
this.name = "AuthError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class ServerError extends VulcxError {
|
|
34
|
+
constructor(message, body) {
|
|
35
|
+
super(message, 500, body);
|
|
36
|
+
this.name = "ServerError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DEFAULT_BASE_URL = "https://api.vulcx.xyz";
|
|
41
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
42
|
+
const DEFAULT_RETRIES = 2;
|
|
43
|
+
class VulcxSDK {
|
|
44
|
+
constructor(config) {
|
|
45
|
+
if (!config.apiKey)
|
|
46
|
+
throw new Error("apiKey is required");
|
|
47
|
+
this.apiKey = config.apiKey;
|
|
48
|
+
this.chain = config.chain ?? "solana";
|
|
49
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
50
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
51
|
+
this.retries = config.retries ?? DEFAULT_RETRIES;
|
|
52
|
+
}
|
|
53
|
+
async quote(params) {
|
|
54
|
+
const qs = new URLSearchParams({
|
|
55
|
+
inputMint: params.inputMint,
|
|
56
|
+
outputMint: params.outputMint,
|
|
57
|
+
amount: params.amount,
|
|
58
|
+
swapMode: params.swapMode,
|
|
59
|
+
});
|
|
60
|
+
if (params.slippageBps !== undefined) {
|
|
61
|
+
qs.set("slippageBps", String(params.slippageBps));
|
|
62
|
+
}
|
|
63
|
+
return this.request("GET", `/api/v1/quote?${qs}`);
|
|
64
|
+
}
|
|
65
|
+
async swap(params) {
|
|
66
|
+
return this.request("POST", "/api/v1/swap", params);
|
|
67
|
+
}
|
|
68
|
+
async instructions(params) {
|
|
69
|
+
return this.request("POST", "/api/v1/instructions", params);
|
|
70
|
+
}
|
|
71
|
+
async request(method, path, body) {
|
|
72
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
73
|
+
const url = `${this.baseUrl}${path}${separator}chain=${this.chain}`;
|
|
74
|
+
const headers = {
|
|
75
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
76
|
+
Accept: "application/json",
|
|
77
|
+
};
|
|
78
|
+
if (body) {
|
|
79
|
+
headers["Content-Type"] = "application/json";
|
|
80
|
+
}
|
|
81
|
+
let lastError;
|
|
82
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
83
|
+
if (attempt > 0) {
|
|
84
|
+
await sleep(Math.min(1000 * 2 ** (attempt - 1), 8000));
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
89
|
+
const res = await fetch(url, {
|
|
90
|
+
method,
|
|
91
|
+
headers,
|
|
92
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
93
|
+
signal: controller.signal,
|
|
94
|
+
});
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
if (res.ok) {
|
|
97
|
+
const parsed = (await res.json());
|
|
98
|
+
// API responses wrap the payload in {success, data}; hand back the
|
|
99
|
+
// payload the way the method signatures promise.
|
|
100
|
+
if (parsed && typeof parsed === "object" && "success" in parsed) {
|
|
101
|
+
if (!parsed.success) {
|
|
102
|
+
throw new VulcxError(parsed.error ?? "request failed", res.status, parsed);
|
|
103
|
+
}
|
|
104
|
+
return parsed.data;
|
|
105
|
+
}
|
|
106
|
+
return parsed;
|
|
107
|
+
}
|
|
108
|
+
const errBody = await res.json().catch(() => ({}));
|
|
109
|
+
const errMsg = errBody?.error ?? res.statusText;
|
|
110
|
+
switch (res.status) {
|
|
111
|
+
case 401:
|
|
112
|
+
case 403:
|
|
113
|
+
throw new AuthError(errBody);
|
|
114
|
+
case 400:
|
|
115
|
+
throw new BadRequestError(errMsg, errBody);
|
|
116
|
+
case 404:
|
|
117
|
+
throw new NoRouteError(errBody);
|
|
118
|
+
case 429:
|
|
119
|
+
lastError = new RateLimitError(errBody);
|
|
120
|
+
continue;
|
|
121
|
+
default:
|
|
122
|
+
if (res.status >= 500) {
|
|
123
|
+
lastError = new ServerError(errMsg, errBody);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
throw new VulcxError(errMsg, res.status, errBody);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
if (err instanceof AuthError ||
|
|
131
|
+
err instanceof BadRequestError ||
|
|
132
|
+
err instanceof NoRouteError ||
|
|
133
|
+
err instanceof VulcxError) {
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
lastError = err;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
throw lastError ?? new Error("request failed");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function sleep(ms) {
|
|
143
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { AuthError, BadRequestError, NoRouteError, RateLimitError, ServerError, VulcxError, VulcxSDK };
|
|
147
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":[null,null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.VulcxSDK = {}));
|
|
5
|
+
})(this, (function (exports) { 'use strict';
|
|
6
|
+
|
|
7
|
+
class VulcxError extends Error {
|
|
8
|
+
constructor(message, statusCode, body) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.statusCode = statusCode;
|
|
11
|
+
this.body = body;
|
|
12
|
+
this.name = "VulcxError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class RateLimitError extends VulcxError {
|
|
16
|
+
constructor(body) {
|
|
17
|
+
super("Rate limit exceeded", 429, body);
|
|
18
|
+
this.name = "RateLimitError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class NoRouteError extends VulcxError {
|
|
22
|
+
constructor(body) {
|
|
23
|
+
super("No route found", 404, body);
|
|
24
|
+
this.name = "NoRouteError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
class BadRequestError extends VulcxError {
|
|
28
|
+
constructor(message, body) {
|
|
29
|
+
super(message, 400, body);
|
|
30
|
+
this.name = "BadRequestError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class AuthError extends VulcxError {
|
|
34
|
+
constructor(body) {
|
|
35
|
+
super("Invalid or missing API key", 401, body);
|
|
36
|
+
this.name = "AuthError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
class ServerError extends VulcxError {
|
|
40
|
+
constructor(message, body) {
|
|
41
|
+
super(message, 500, body);
|
|
42
|
+
this.name = "ServerError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const DEFAULT_BASE_URL = "https://api.vulcx.xyz";
|
|
47
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
48
|
+
const DEFAULT_RETRIES = 2;
|
|
49
|
+
class VulcxSDK {
|
|
50
|
+
constructor(config) {
|
|
51
|
+
if (!config.apiKey)
|
|
52
|
+
throw new Error("apiKey is required");
|
|
53
|
+
this.apiKey = config.apiKey;
|
|
54
|
+
this.chain = config.chain ?? "solana";
|
|
55
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
56
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
57
|
+
this.retries = config.retries ?? DEFAULT_RETRIES;
|
|
58
|
+
}
|
|
59
|
+
async quote(params) {
|
|
60
|
+
const qs = new URLSearchParams({
|
|
61
|
+
inputMint: params.inputMint,
|
|
62
|
+
outputMint: params.outputMint,
|
|
63
|
+
amount: params.amount,
|
|
64
|
+
swapMode: params.swapMode,
|
|
65
|
+
});
|
|
66
|
+
if (params.slippageBps !== undefined) {
|
|
67
|
+
qs.set("slippageBps", String(params.slippageBps));
|
|
68
|
+
}
|
|
69
|
+
return this.request("GET", `/api/v1/quote?${qs}`);
|
|
70
|
+
}
|
|
71
|
+
async swap(params) {
|
|
72
|
+
return this.request("POST", "/api/v1/swap", params);
|
|
73
|
+
}
|
|
74
|
+
async instructions(params) {
|
|
75
|
+
return this.request("POST", "/api/v1/instructions", params);
|
|
76
|
+
}
|
|
77
|
+
async request(method, path, body) {
|
|
78
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
79
|
+
const url = `${this.baseUrl}${path}${separator}chain=${this.chain}`;
|
|
80
|
+
const headers = {
|
|
81
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
82
|
+
Accept: "application/json",
|
|
83
|
+
};
|
|
84
|
+
if (body) {
|
|
85
|
+
headers["Content-Type"] = "application/json";
|
|
86
|
+
}
|
|
87
|
+
let lastError;
|
|
88
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
89
|
+
if (attempt > 0) {
|
|
90
|
+
await sleep(Math.min(1000 * 2 ** (attempt - 1), 8000));
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const controller = new AbortController();
|
|
94
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
95
|
+
const res = await fetch(url, {
|
|
96
|
+
method,
|
|
97
|
+
headers,
|
|
98
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
99
|
+
signal: controller.signal,
|
|
100
|
+
});
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
if (res.ok) {
|
|
103
|
+
const parsed = (await res.json());
|
|
104
|
+
// API responses wrap the payload in {success, data}; hand back the
|
|
105
|
+
// payload the way the method signatures promise.
|
|
106
|
+
if (parsed && typeof parsed === "object" && "success" in parsed) {
|
|
107
|
+
if (!parsed.success) {
|
|
108
|
+
throw new VulcxError(parsed.error ?? "request failed", res.status, parsed);
|
|
109
|
+
}
|
|
110
|
+
return parsed.data;
|
|
111
|
+
}
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
const errBody = await res.json().catch(() => ({}));
|
|
115
|
+
const errMsg = errBody?.error ?? res.statusText;
|
|
116
|
+
switch (res.status) {
|
|
117
|
+
case 401:
|
|
118
|
+
case 403:
|
|
119
|
+
throw new AuthError(errBody);
|
|
120
|
+
case 400:
|
|
121
|
+
throw new BadRequestError(errMsg, errBody);
|
|
122
|
+
case 404:
|
|
123
|
+
throw new NoRouteError(errBody);
|
|
124
|
+
case 429:
|
|
125
|
+
lastError = new RateLimitError(errBody);
|
|
126
|
+
continue;
|
|
127
|
+
default:
|
|
128
|
+
if (res.status >= 500) {
|
|
129
|
+
lastError = new ServerError(errMsg, errBody);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
throw new VulcxError(errMsg, res.status, errBody);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
if (err instanceof AuthError ||
|
|
137
|
+
err instanceof BadRequestError ||
|
|
138
|
+
err instanceof NoRouteError ||
|
|
139
|
+
err instanceof VulcxError) {
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
lastError = err;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
throw lastError ?? new Error("request failed");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function sleep(ms) {
|
|
149
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
exports.AuthError = AuthError;
|
|
153
|
+
exports.BadRequestError = BadRequestError;
|
|
154
|
+
exports.NoRouteError = NoRouteError;
|
|
155
|
+
exports.RateLimitError = RateLimitError;
|
|
156
|
+
exports.ServerError = ServerError;
|
|
157
|
+
exports.VulcxError = VulcxError;
|
|
158
|
+
exports.VulcxSDK = VulcxSDK;
|
|
159
|
+
|
|
160
|
+
}));
|
|
161
|
+
//# sourceMappingURL=index.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":[null,null],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export type SwapMode = "ExactIn" | "ExactOut";
|
|
2
|
+
export type Chain = "solana" | "fogo";
|
|
3
|
+
export type PriceImpactSeverity = "none" | "low" | "moderate" | "high" | "extreme";
|
|
4
|
+
export interface SDKConfig {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
chain?: Chain;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
retries?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface QuoteRequest {
|
|
12
|
+
inputMint: string;
|
|
13
|
+
outputMint: string;
|
|
14
|
+
amount: string;
|
|
15
|
+
swapMode: SwapMode;
|
|
16
|
+
slippageBps?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface RouteInfo {
|
|
19
|
+
poolAddress: string;
|
|
20
|
+
poolType: string;
|
|
21
|
+
percent: number;
|
|
22
|
+
inputMint: string;
|
|
23
|
+
outputMint: string;
|
|
24
|
+
}
|
|
25
|
+
export interface QuoteResponse {
|
|
26
|
+
inputMint: string;
|
|
27
|
+
outputMint: string;
|
|
28
|
+
amountIn: string;
|
|
29
|
+
amountOut: string;
|
|
30
|
+
priceImpactBps: number;
|
|
31
|
+
priceImpactPercent: string;
|
|
32
|
+
priceImpactSeverity: PriceImpactSeverity;
|
|
33
|
+
priceImpactWarning: string;
|
|
34
|
+
feeBps: number;
|
|
35
|
+
routes: RouteInfo[];
|
|
36
|
+
routePath: string[];
|
|
37
|
+
hopCount: number;
|
|
38
|
+
otherAmountThreshold: string;
|
|
39
|
+
}
|
|
40
|
+
export interface SwapRequest {
|
|
41
|
+
userWallet: string;
|
|
42
|
+
inputMint: string;
|
|
43
|
+
outputMint: string;
|
|
44
|
+
amount: string;
|
|
45
|
+
swapMode: SwapMode;
|
|
46
|
+
slippageBps?: number;
|
|
47
|
+
skipSimulation?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface SimulationResult {
|
|
50
|
+
success: boolean;
|
|
51
|
+
computeUnitsConsumed: number;
|
|
52
|
+
computeUnitsTotal: number;
|
|
53
|
+
logs: string[];
|
|
54
|
+
error: string;
|
|
55
|
+
slippageExceeded: boolean;
|
|
56
|
+
insufficientFunds: boolean;
|
|
57
|
+
accountsNeeded: string[];
|
|
58
|
+
}
|
|
59
|
+
export interface SwapResponse {
|
|
60
|
+
transaction: string;
|
|
61
|
+
lastValidBlockHeight: number;
|
|
62
|
+
amountIn: string;
|
|
63
|
+
amountOut: string;
|
|
64
|
+
minAmountOut?: string;
|
|
65
|
+
maxAmountIn?: string;
|
|
66
|
+
feeAmount: string;
|
|
67
|
+
simulation?: SimulationResult;
|
|
68
|
+
computeUnitsEstimate: number;
|
|
69
|
+
route: string[];
|
|
70
|
+
hopCount: number;
|
|
71
|
+
pools: string[];
|
|
72
|
+
isSplitRoute: boolean;
|
|
73
|
+
splitPercents?: number[];
|
|
74
|
+
}
|
|
75
|
+
export interface InstructionsRequest {
|
|
76
|
+
userWallet: string;
|
|
77
|
+
inputMint: string;
|
|
78
|
+
outputMint: string;
|
|
79
|
+
amount: string;
|
|
80
|
+
swapMode: SwapMode;
|
|
81
|
+
slippageBps?: number;
|
|
82
|
+
}
|
|
83
|
+
export interface RawAccountMeta {
|
|
84
|
+
publicKey: string;
|
|
85
|
+
isSigner: boolean;
|
|
86
|
+
isWritable: boolean;
|
|
87
|
+
}
|
|
88
|
+
export interface RawInstruction {
|
|
89
|
+
programId: string;
|
|
90
|
+
accounts: RawAccountMeta[];
|
|
91
|
+
data: string;
|
|
92
|
+
}
|
|
93
|
+
export interface InstructionsResponse {
|
|
94
|
+
instructions: RawInstruction[];
|
|
95
|
+
addressLookupTableAddresses: string[];
|
|
96
|
+
amountIn: string;
|
|
97
|
+
amountOut: string;
|
|
98
|
+
otherAmountThreshold: string;
|
|
99
|
+
feeAmount: string;
|
|
100
|
+
hopCount: number;
|
|
101
|
+
route: string[];
|
|
102
|
+
pools: string[];
|
|
103
|
+
}
|
|
104
|
+
export interface APIErrorBody {
|
|
105
|
+
error: string;
|
|
106
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vulcx/sdk",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "TypeScript SDK for the Vulcx DEX aggregator API",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"browser": "dist/index.umd.js",
|
|
8
|
+
"unpkg": "dist/index.umd.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.esm.js",
|
|
13
|
+
"require": "./dist/index.cjs.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "rollup -c",
|
|
23
|
+
"dev": "rollup -c -w",
|
|
24
|
+
"typecheck": "tsc --noEmit"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@rollup/plugin-typescript": "^12.1.2",
|
|
28
|
+
"rollup": "^4.34.8",
|
|
29
|
+
"rollup-plugin-dts": "^6.1.1",
|
|
30
|
+
"tslib": "^2.8.1",
|
|
31
|
+
"typescript": "^5.7.3"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/argyros-ag/sdk"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"solana",
|
|
40
|
+
"dex",
|
|
41
|
+
"aggregator",
|
|
42
|
+
"swap",
|
|
43
|
+
"fogo",
|
|
44
|
+
"vulcx"
|
|
45
|
+
]
|
|
46
|
+
}
|