@sun-protocol/sun-sdk-protocols 0.1.0-beta.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 +30 -0
- package/dist/chunk-5XDX5563.js +99 -0
- package/dist/chunk-5XDX5563.js.map +1 -0
- package/dist/chunk-C2YCVBPI.js +212 -0
- package/dist/chunk-C2YCVBPI.js.map +1 -0
- package/dist/chunk-ECCGOXNA.js +1317 -0
- package/dist/chunk-ECCGOXNA.js.map +1 -0
- package/dist/chunk-HD2S3Q7L.js +746 -0
- package/dist/chunk-HD2S3Q7L.js.map +1 -0
- package/dist/chunk-L5TZCDPH.js +561 -0
- package/dist/chunk-L5TZCDPH.js.map +1 -0
- package/dist/chunk-OM4OW4KB.js +224 -0
- package/dist/chunk-OM4OW4KB.js.map +1 -0
- package/dist/chunk-PEGREDLT.js +935 -0
- package/dist/chunk-PEGREDLT.js.map +1 -0
- package/dist/chunk-TSHXXRH2.js +103 -0
- package/dist/chunk-TSHXXRH2.js.map +1 -0
- package/dist/chunk-VFVKMC4H.js +521 -0
- package/dist/chunk-VFVKMC4H.js.map +1 -0
- package/dist/chunk-YMGZDXI4.js +1209 -0
- package/dist/chunk-YMGZDXI4.js.map +1 -0
- package/dist/common-8VQQ0FSU.d.cts +146 -0
- package/dist/common-8VQQ0FSU.d.ts +146 -0
- package/dist/execute-BNKh6dT6.d.cts +187 -0
- package/dist/execute-CVhcKZxF.d.ts +187 -0
- package/dist/index.cjs +5619 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +139 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +200 -0
- package/dist/index.js.map +1 -0
- package/dist/intents-BSXq1HvW.d.cts +200 -0
- package/dist/intents-CwOttD75.d.ts +200 -0
- package/dist/liquidity/index.cjs +2441 -0
- package/dist/liquidity/index.cjs.map +1 -0
- package/dist/liquidity/index.d.cts +83 -0
- package/dist/liquidity/index.d.ts +83 -0
- package/dist/liquidity/index.js +32 -0
- package/dist/liquidity/index.js.map +1 -0
- package/dist/positions/index.cjs +1544 -0
- package/dist/positions/index.cjs.map +1 -0
- package/dist/positions/index.d.cts +159 -0
- package/dist/positions/index.d.ts +159 -0
- package/dist/positions/index.js +25 -0
- package/dist/positions/index.js.map +1 -0
- package/dist/pump/index.cjs +1178 -0
- package/dist/pump/index.cjs.map +1 -0
- package/dist/pump/index.d.cts +16 -0
- package/dist/pump/index.d.ts +16 -0
- package/dist/pump/index.js +29 -0
- package/dist/pump/index.js.map +1 -0
- package/dist/swap/index.cjs +2259 -0
- package/dist/swap/index.cjs.map +1 -0
- package/dist/swap/index.d.cts +33 -0
- package/dist/swap/index.d.ts +33 -0
- package/dist/swap/index.js +61 -0
- package/dist/swap/index.js.map +1 -0
- package/dist/types-BTPdCC7k.d.cts +160 -0
- package/dist/types-BfrouFmO.d.ts +160 -0
- package/package.json +94 -0
|
@@ -0,0 +1,2259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/swap/index.ts
|
|
21
|
+
var swap_exports = {};
|
|
22
|
+
__export(swap_exports, {
|
|
23
|
+
PSM_PROTOCOL_ID: () => PSM_PROTOCOL_ID,
|
|
24
|
+
PsmSwapClient: () => PsmSwapClient,
|
|
25
|
+
SwapRouterClient: () => SwapRouterClient,
|
|
26
|
+
UNIVERSAL_ROUTER_PROTOCOL_ID: () => UNIVERSAL_ROUTER_PROTOCOL_ID,
|
|
27
|
+
V2SwapClient: () => V2SwapClient,
|
|
28
|
+
WTRX_PROTOCOL_ID: () => WTRX_PROTOCOL_ID,
|
|
29
|
+
createPsmClient: () => createPsmClient,
|
|
30
|
+
createPsmSwapClient: () => createPsmSwapClient,
|
|
31
|
+
createRouterSwapExecutor: () => createRouterSwapExecutor,
|
|
32
|
+
createSwapRouterClient: () => createSwapRouterClient,
|
|
33
|
+
createV2Client: () => createV2Client,
|
|
34
|
+
createV2SwapClient: () => createV2SwapClient,
|
|
35
|
+
createV2SwapExecutor: () => createV2SwapExecutor,
|
|
36
|
+
detectWtrxSwap: () => detectWtrxSwap,
|
|
37
|
+
isNativeTrxToken: () => isNativeTrxToken,
|
|
38
|
+
isWrappedTrxToken: () => isWrappedTrxToken,
|
|
39
|
+
materializeUniversalRouterAction: () => materializeUniversalRouterAction,
|
|
40
|
+
normalizeRouterToken: () => normalizeRouterToken,
|
|
41
|
+
normalizeV2TrxPairPath: () => normalizeV2TrxPairPath,
|
|
42
|
+
planPsmSwap: () => planPsmSwap,
|
|
43
|
+
planRouterSwap: () => planRouterSwap,
|
|
44
|
+
quotePsmSwap: () => quotePsmSwap,
|
|
45
|
+
quoteRouterSwap: () => quoteRouterSwap,
|
|
46
|
+
quoteSwap: () => quoteSwap,
|
|
47
|
+
readPsm: () => readPsm
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(swap_exports);
|
|
50
|
+
|
|
51
|
+
// src/context.ts
|
|
52
|
+
var import_sun_sdk_api2 = require("@sun-protocol/sun-sdk-api");
|
|
53
|
+
var import_sun_sdk_chains = require("@sun-protocol/sun-sdk-chains");
|
|
54
|
+
var import_sun_sdk_core2 = require("@sun-protocol/sun-sdk-core");
|
|
55
|
+
var import_sun_sdk_runtime = require("@sun-protocol/sun-sdk-runtime");
|
|
56
|
+
|
|
57
|
+
// src/execute-http-action.ts
|
|
58
|
+
var import_sun_sdk_api = require("@sun-protocol/sun-sdk-api");
|
|
59
|
+
var import_sun_sdk_core = require("@sun-protocol/sun-sdk-core");
|
|
60
|
+
async function executeHttpAction(action, fetchImpl, jsonParser = import_sun_sdk_api.defaultJsonParser) {
|
|
61
|
+
if (action.type !== "http-request" || action.execute !== "api") {
|
|
62
|
+
throw new import_sun_sdk_core.SDKError("SDK_INVALID_ARGUMENT", `Action ${action.id} is not an HTTP action`, {
|
|
63
|
+
actionId: action.id,
|
|
64
|
+
actionType: action.type
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const request = action.request;
|
|
68
|
+
const headers = {
|
|
69
|
+
Accept: "application/json",
|
|
70
|
+
...request.headers
|
|
71
|
+
};
|
|
72
|
+
let body;
|
|
73
|
+
if (request.body !== void 0) {
|
|
74
|
+
if (typeof request.body === "string") {
|
|
75
|
+
body = request.body;
|
|
76
|
+
} else {
|
|
77
|
+
body = JSON.stringify(request.body);
|
|
78
|
+
if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return (0, import_sun_sdk_api.requestJson)(request.url, {
|
|
82
|
+
service: "Protocols HTTP action",
|
|
83
|
+
fetchImpl,
|
|
84
|
+
jsonParser,
|
|
85
|
+
init: {
|
|
86
|
+
method: request.method,
|
|
87
|
+
headers,
|
|
88
|
+
...body !== void 0 ? { body } : {}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/context.ts
|
|
94
|
+
function createDefaultIdFactory() {
|
|
95
|
+
let nextPlanId2 = 0;
|
|
96
|
+
return () => {
|
|
97
|
+
nextPlanId2 += 1;
|
|
98
|
+
return `sun-plan-${nextPlanId2}`;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function createProtocolsContext(options) {
|
|
102
|
+
if (options.runtime && (options.tronClient || options.wallet || options.getWallet || options.onSubmitted)) {
|
|
103
|
+
throw new import_sun_sdk_core2.SDKError(
|
|
104
|
+
"SDK_INVALID_ARGUMENT",
|
|
105
|
+
"Use either runtime or tronClient/wallet/onSubmitted when creating a protocol client"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
if (options.wallet && !options.tronClient) {
|
|
109
|
+
throw new import_sun_sdk_core2.SDKError("SDK_INVALID_ARGUMENT", "wallet requires a tronClient");
|
|
110
|
+
}
|
|
111
|
+
if (options.getWallet && !options.tronClient) {
|
|
112
|
+
throw new import_sun_sdk_core2.SDKError("SDK_INVALID_ARGUMENT", "getWallet requires a tronClient");
|
|
113
|
+
}
|
|
114
|
+
if (options.wallet && options.getWallet) {
|
|
115
|
+
throw new import_sun_sdk_core2.SDKError("SDK_INVALID_ARGUMENT", "Use either wallet or getWallet when creating a protocol client");
|
|
116
|
+
}
|
|
117
|
+
const runtime = options.runtime ?? (options.tronClient ? (0, import_sun_sdk_runtime.createRuntime)({
|
|
118
|
+
network: options.network,
|
|
119
|
+
tronClient: options.tronClient,
|
|
120
|
+
...options.wallet ? { wallet: options.wallet } : {},
|
|
121
|
+
...options.getWallet ? { getWallet: options.getWallet } : {},
|
|
122
|
+
...options.onSubmitted ? { onSubmitted: options.onSubmitted } : {}
|
|
123
|
+
}) : void 0);
|
|
124
|
+
if (runtime && runtime.network !== options.network) {
|
|
125
|
+
throw new import_sun_sdk_core2.SDKError("SDK_INVALID_ARGUMENT", "Protocols runtime network mismatch", {
|
|
126
|
+
sdkNetwork: options.network,
|
|
127
|
+
runtimeNetwork: runtime.network
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const chain = (0, import_sun_sdk_chains.getChainConfig)(options.network);
|
|
131
|
+
const endpoints = { ...(0, import_sun_sdk_chains.getNetworkEndpoints)(options.network), ...options.endpoints };
|
|
132
|
+
const fetchImpl = options.fetchImpl ?? import_sun_sdk_api2.defaultFetch;
|
|
133
|
+
const jsonParser = options.jsonParser ?? import_sun_sdk_api2.defaultJsonParser;
|
|
134
|
+
const now = options.now ?? Date.now;
|
|
135
|
+
const getTransactionTime = options.getTransactionTime ?? (() => (0, import_sun_sdk_api2.getServerTime)(endpoints.time, fetchImpl, jsonParser));
|
|
136
|
+
const sunPumpApi = options.clients?.sunPumpApi ?? (endpoints.sunPump ? new import_sun_sdk_api2.SunPumpApiClient({ baseUrl: endpoints.sunPump, fetchImpl, jsonParser }) : void 0);
|
|
137
|
+
return {
|
|
138
|
+
network: options.network,
|
|
139
|
+
chain,
|
|
140
|
+
endpoints,
|
|
141
|
+
...runtime ? { runtime } : {},
|
|
142
|
+
fetchImpl,
|
|
143
|
+
jsonParser,
|
|
144
|
+
routerApi: options.clients?.routerApi ?? new import_sun_sdk_api2.RouterApiClient({ fetchImpl, jsonParser }),
|
|
145
|
+
...sunPumpApi ? { sunPumpApi } : {},
|
|
146
|
+
adapters: options.adapters ?? {},
|
|
147
|
+
now,
|
|
148
|
+
getTransactionTime: async () => {
|
|
149
|
+
try {
|
|
150
|
+
const timestamp = await getTransactionTime();
|
|
151
|
+
if (Number.isSafeInteger(timestamp) && timestamp > 0) return timestamp;
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
return now();
|
|
155
|
+
},
|
|
156
|
+
idFactory: options.idFactory ?? createDefaultIdFactory()
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function requireRuntime(context, operation) {
|
|
160
|
+
if (!context.runtime) {
|
|
161
|
+
throw new import_sun_sdk_core2.SDKError("SDK_RUNTIME_ERROR", `${operation} requires a runtime`, {
|
|
162
|
+
operation,
|
|
163
|
+
network: context.network
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return context.runtime;
|
|
167
|
+
}
|
|
168
|
+
function resolveProtocolContract(context, overrides, name) {
|
|
169
|
+
const configured = context.chain.contracts;
|
|
170
|
+
const address = overrides?.[name] ?? configured[name];
|
|
171
|
+
if (!address) {
|
|
172
|
+
throw new import_sun_sdk_core2.SDKError("SDK_INVALID_ARGUMENT", `No configured address for ${name}`, { name });
|
|
173
|
+
}
|
|
174
|
+
return (0, import_sun_sdk_core2.assertTronAddress)(address, name);
|
|
175
|
+
}
|
|
176
|
+
async function requireWalletAddress(context, operation) {
|
|
177
|
+
return (await requireWalletSnapshot(context, operation)).address;
|
|
178
|
+
}
|
|
179
|
+
async function requireWalletSnapshot(context, operation) {
|
|
180
|
+
const runtime = requireRuntime(context, operation);
|
|
181
|
+
const wallet = await runtime.requireWallet(operation);
|
|
182
|
+
return {
|
|
183
|
+
wallet,
|
|
184
|
+
address: (0, import_sun_sdk_core2.assertTronAddress)(await wallet.getAddress(), "wallet address")
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function createContextExecutor(context) {
|
|
188
|
+
const runtime = context.runtime;
|
|
189
|
+
let walletPromise;
|
|
190
|
+
const requireExecutionWallet = () => {
|
|
191
|
+
walletPromise ??= runtime?.requireWallet("transaction plan execution");
|
|
192
|
+
if (!walletPromise) {
|
|
193
|
+
return Promise.reject(new import_sun_sdk_core2.SDKError("SDK_RUNTIME_ERROR", "Transaction plan execution requires a runtime"));
|
|
194
|
+
}
|
|
195
|
+
return walletPromise;
|
|
196
|
+
};
|
|
197
|
+
return {
|
|
198
|
+
network: context.network,
|
|
199
|
+
...runtime ? {
|
|
200
|
+
getAddress: async () => {
|
|
201
|
+
const wallet = await requireExecutionWallet();
|
|
202
|
+
return (0, import_sun_sdk_core2.assertTronAddress)(await wallet.getAddress(), "wallet address");
|
|
203
|
+
},
|
|
204
|
+
sendAction: async (action) => {
|
|
205
|
+
const wallet = await requireExecutionWallet();
|
|
206
|
+
return runtime.sendAction(action, { wallet });
|
|
207
|
+
},
|
|
208
|
+
...runtime.waitForTransactionReceipt ? { waitForTransactionReceipt: runtime.waitForTransactionReceipt.bind(runtime) } : {},
|
|
209
|
+
signTypedData: async (payload) => {
|
|
210
|
+
const wallet = await requireExecutionWallet();
|
|
211
|
+
return runtime.signTypedData(payload, { wallet });
|
|
212
|
+
}
|
|
213
|
+
} : {},
|
|
214
|
+
executeHttpAction: (action) => executeHttpAction(action, context.fetchImpl, context.jsonParser)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/execute-plan.ts
|
|
219
|
+
var import_sun_sdk_core4 = require("@sun-protocol/sun-sdk-core");
|
|
220
|
+
|
|
221
|
+
// src/errors.ts
|
|
222
|
+
var import_sun_sdk_core3 = require("@sun-protocol/sun-sdk-core");
|
|
223
|
+
function isWalletRejection(error) {
|
|
224
|
+
if (!error || typeof error !== "object") return false;
|
|
225
|
+
const candidate = error;
|
|
226
|
+
return candidate.code === 4001 || typeof candidate.message === "string" && /reject|denied|cancel/i.test(candidate.message);
|
|
227
|
+
}
|
|
228
|
+
function normalizeProtocolError(error, fallbackCode, message, context = {}) {
|
|
229
|
+
if (error instanceof import_sun_sdk_core3.SDKError) return error;
|
|
230
|
+
const code = isWalletRejection(error) ? "SDK_WALLET_REJECTED" : fallbackCode;
|
|
231
|
+
return new import_sun_sdk_core3.SDKError(code, message, { ...context, cause: error });
|
|
232
|
+
}
|
|
233
|
+
function withExecutionContext(error, context) {
|
|
234
|
+
return new import_sun_sdk_core3.SDKError(error.code, error.message, {
|
|
235
|
+
...error.context,
|
|
236
|
+
actionId: context.actionId,
|
|
237
|
+
completedActionIds: context.completedActionIds,
|
|
238
|
+
cause: error
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/execute-plan.ts
|
|
243
|
+
async function executePlanAction(action, executor, completedActions = []) {
|
|
244
|
+
try {
|
|
245
|
+
if (action.waitForReceipt && !executor.waitForTransactionReceipt) {
|
|
246
|
+
throw new import_sun_sdk_core4.SDKError(
|
|
247
|
+
"SDK_RUNTIME_ERROR",
|
|
248
|
+
`Action ${action.id} requires transaction receipt waiting capability`,
|
|
249
|
+
{ actionId: action.id, finality: action.waitForReceipt }
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (action.execute === "runtime") {
|
|
253
|
+
let actionToSend;
|
|
254
|
+
let materializedAction;
|
|
255
|
+
if (action.type === "deferred-contract-call") {
|
|
256
|
+
if (!executor.materializeAction) {
|
|
257
|
+
throw new import_sun_sdk_core4.SDKError("SDK_RUNTIME_ERROR", `Action ${action.id} requires a deferred action materializer`);
|
|
258
|
+
}
|
|
259
|
+
const resolvedAction = await executor.materializeAction(action, completedActions);
|
|
260
|
+
materializedAction = {
|
|
261
|
+
...resolvedAction,
|
|
262
|
+
id: action.id,
|
|
263
|
+
...action.intent === void 0 ? {} : { intent: action.intent }
|
|
264
|
+
};
|
|
265
|
+
actionToSend = materializedAction;
|
|
266
|
+
} else if (action.type === "contract-call" || action.type === "approve") {
|
|
267
|
+
actionToSend = action;
|
|
268
|
+
} else {
|
|
269
|
+
throw new import_sun_sdk_core4.SDKError(
|
|
270
|
+
"SDK_RUNTIME_ERROR",
|
|
271
|
+
`Runtime action ${action.id} materialized to unsupported type: ${action.type}`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (!executor.sendAction) {
|
|
275
|
+
throw new import_sun_sdk_core4.SDKError("SDK_RUNTIME_ERROR", `Action ${action.id} requires a runtime executor`);
|
|
276
|
+
}
|
|
277
|
+
const result = await executor.sendAction(actionToSend);
|
|
278
|
+
const receipt = action.waitForReceipt && executor.waitForTransactionReceipt ? await executor.waitForTransactionReceipt(result.txid, { finality: action.waitForReceipt }) : void 0;
|
|
279
|
+
if (receipt && !receipt.success) {
|
|
280
|
+
throw new import_sun_sdk_core4.SDKError("SDK_CONTRACT_ERROR", `Transaction ${result.txid} failed`, {
|
|
281
|
+
actionId: action.id,
|
|
282
|
+
txid: result.txid,
|
|
283
|
+
receipt
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
action,
|
|
288
|
+
result,
|
|
289
|
+
txid: result.txid,
|
|
290
|
+
...receipt ? { receipt } : {},
|
|
291
|
+
...materializedAction ? { materializedAction } : {}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
if (action.execute === "wallet-signature") {
|
|
295
|
+
if (!action.typedData) {
|
|
296
|
+
throw new import_sun_sdk_core4.SDKError("SDK_INVALID_ARGUMENT", `Action ${action.id} is missing typedData`);
|
|
297
|
+
}
|
|
298
|
+
if (!executor.signTypedData) {
|
|
299
|
+
throw new import_sun_sdk_core4.SDKError("SDK_WALLET_CAPABILITY_ERROR", `Action ${action.id} requires typed-data signing`);
|
|
300
|
+
}
|
|
301
|
+
const signature = await executor.signTypedData(action.typedData);
|
|
302
|
+
return { action, result: signature };
|
|
303
|
+
}
|
|
304
|
+
if (action.execute === "api") {
|
|
305
|
+
if (!executor.executeHttpAction) {
|
|
306
|
+
throw new import_sun_sdk_core4.SDKError("SDK_RUNTIME_ERROR", `Action ${action.id} requires an API executor`);
|
|
307
|
+
}
|
|
308
|
+
return { action, result: await executor.executeHttpAction(action) };
|
|
309
|
+
}
|
|
310
|
+
throw new import_sun_sdk_core4.SDKError("SDK_RUNTIME_ERROR", "Unsupported action executor");
|
|
311
|
+
} catch (error) {
|
|
312
|
+
const normalized = normalizeProtocolError(
|
|
313
|
+
error,
|
|
314
|
+
action.execute === "api" ? "SDK_API_ERROR" : "SDK_RUNTIME_ERROR",
|
|
315
|
+
`Failed to execute action ${action.id}`
|
|
316
|
+
);
|
|
317
|
+
throw withExecutionContext(normalized, {
|
|
318
|
+
actionId: action.id,
|
|
319
|
+
completedActionIds: completedActions.map((result) => result.action.id)
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function executeTransactionPlan(plan, executor) {
|
|
324
|
+
if (executor.network && executor.network !== plan.network) {
|
|
325
|
+
throw new import_sun_sdk_core4.SDKError("SDK_INVALID_ARGUMENT", "Plan and executor network mismatch", {
|
|
326
|
+
planNetwork: plan.network,
|
|
327
|
+
executorNetwork: executor.network
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (plan.owner) {
|
|
331
|
+
if (!executor.getAddress) {
|
|
332
|
+
throw new import_sun_sdk_core4.SDKError("SDK_RUNTIME_ERROR", `Plan ${plan.id} requires a wallet address`, {
|
|
333
|
+
planId: plan.id,
|
|
334
|
+
owner: plan.owner
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
const actualAddress = await executor.getAddress();
|
|
338
|
+
if (actualAddress !== plan.owner) {
|
|
339
|
+
throw new import_sun_sdk_core4.SDKError(
|
|
340
|
+
"SDK_WALLET_ACCOUNT_MISMATCH",
|
|
341
|
+
"Transaction plan was created for a different wallet",
|
|
342
|
+
{
|
|
343
|
+
planId: plan.id,
|
|
344
|
+
expectedAddress: plan.owner,
|
|
345
|
+
actualAddress
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const orderedActions = [...plan.approvals, ...plan.transactions];
|
|
351
|
+
const receiptAction = orderedActions.find((action) => action.waitForReceipt !== void 0);
|
|
352
|
+
if (receiptAction && !executor.waitForTransactionReceipt) {
|
|
353
|
+
throw new import_sun_sdk_core4.SDKError(
|
|
354
|
+
"SDK_RUNTIME_ERROR",
|
|
355
|
+
`Action ${receiptAction.id} requires transaction receipt waiting capability`,
|
|
356
|
+
{ planId: plan.id, actionId: receiptAction.id, finality: receiptAction.waitForReceipt }
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
const actionResults = [];
|
|
360
|
+
const txids = [];
|
|
361
|
+
let finalResult;
|
|
362
|
+
for (const action of orderedActions) {
|
|
363
|
+
const actionResult = await executePlanAction(action, executor, actionResults);
|
|
364
|
+
actionResults.push(actionResult);
|
|
365
|
+
if (action.execute === "runtime") {
|
|
366
|
+
if (!actionResult.txid) {
|
|
367
|
+
throw new import_sun_sdk_core4.SDKError("SDK_RUNTIME_ERROR", `Runtime action ${action.id} did not return a transaction id`);
|
|
368
|
+
}
|
|
369
|
+
txids.push(actionResult.txid);
|
|
370
|
+
const raw = typeof actionResult.result === "object" && actionResult.result !== null ? actionResult.result.raw : void 0;
|
|
371
|
+
finalResult = { type: "transaction", txid: actionResult.txid, raw };
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
if (action.execute === "wallet-signature") {
|
|
375
|
+
finalResult = { type: "signature", signature: actionResult.result };
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
finalResult = { type: "api", data: actionResult.result };
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
plan,
|
|
382
|
+
actions: actionResults,
|
|
383
|
+
txids,
|
|
384
|
+
finalResult
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function isTransactionPlan(input) {
|
|
388
|
+
if (typeof input !== "object" || input === null) return false;
|
|
389
|
+
const candidate = input;
|
|
390
|
+
return Array.isArray(candidate.approvals) && Array.isArray(candidate.transactions);
|
|
391
|
+
}
|
|
392
|
+
async function executePlanTransactions(plan, executor) {
|
|
393
|
+
const result = await executeTransactionPlan(
|
|
394
|
+
{ ...plan, approvals: [] },
|
|
395
|
+
executor
|
|
396
|
+
);
|
|
397
|
+
return { ...result, plan };
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/swap/router-execute.ts
|
|
401
|
+
var import_sun_sdk_core10 = require("@sun-protocol/sun-sdk-core");
|
|
402
|
+
|
|
403
|
+
// src/internal/router-action.ts
|
|
404
|
+
var import_sun_sdk_core5 = require("@sun-protocol/sun-sdk-core");
|
|
405
|
+
var UNIVERSAL_ROUTER_MATERIALIZATION_KIND = "universal-router-swap";
|
|
406
|
+
function toJsonValue(value) {
|
|
407
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
if (Array.isArray(value)) {
|
|
411
|
+
return value.map(toJsonValue);
|
|
412
|
+
}
|
|
413
|
+
if (typeof value === "object") {
|
|
414
|
+
const objectValue = value;
|
|
415
|
+
const result = {};
|
|
416
|
+
for (const [key, entry] of Object.entries(objectValue)) {
|
|
417
|
+
if (entry !== void 0) {
|
|
418
|
+
result[key] = toJsonValue(entry);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
throw new TypeError(`Value is not JSON-serializable: ${typeof value}`);
|
|
424
|
+
}
|
|
425
|
+
function toJsonObject(value) {
|
|
426
|
+
const normalized = toJsonValue(value);
|
|
427
|
+
if (normalized === null || Array.isArray(normalized) || typeof normalized !== "object") {
|
|
428
|
+
throw new TypeError("Value is not a JSON object");
|
|
429
|
+
}
|
|
430
|
+
return normalized;
|
|
431
|
+
}
|
|
432
|
+
function createUniversalRouterDeferredAction(input) {
|
|
433
|
+
return (0, import_sun_sdk_core5.createDeferredContractCallAction)({
|
|
434
|
+
id: input.id,
|
|
435
|
+
materialization: {
|
|
436
|
+
kind: UNIVERSAL_ROUTER_MATERIALIZATION_KIND,
|
|
437
|
+
data: toJsonObject(input.data)
|
|
438
|
+
},
|
|
439
|
+
...input.intent !== void 0 ? { intent: input.intent } : {}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/internal/universal-router-adapter.ts
|
|
444
|
+
var import_sun_sdk_core8 = require("@sun-protocol/sun-sdk-core");
|
|
445
|
+
var import_universal_router_sdk = require("@sun-protocol/universal-router-sdk");
|
|
446
|
+
var import_sun_sdk_sunswap_v3 = require("@sun-protocol/sun-sdk-sunswap-v3");
|
|
447
|
+
|
|
448
|
+
// src/internal/tokens.ts
|
|
449
|
+
var import_sun_sdk_chains2 = require("@sun-protocol/sun-sdk-chains");
|
|
450
|
+
var import_sun_sdk_core6 = require("@sun-protocol/sun-sdk-core");
|
|
451
|
+
var import_sun_sdk_sunswap_v2 = require("@sun-protocol/sun-sdk-sunswap-v2");
|
|
452
|
+
function evmHexToTronAddress(address, label = "address") {
|
|
453
|
+
const normalized = address.startsWith("0x") ? address.toLowerCase() : `0x${address.toLowerCase()}`;
|
|
454
|
+
return (0, import_sun_sdk_sunswap_v2.evmHexToTronAddress)(normalized, label);
|
|
455
|
+
}
|
|
456
|
+
function tronAddressToEvmAddress(address, label = "address") {
|
|
457
|
+
return `0x${(0, import_sun_sdk_sunswap_v2.tronAddressToEvmHex)((0, import_sun_sdk_core6.assertTronAddress)(address, label))}`;
|
|
458
|
+
}
|
|
459
|
+
function normalizeTronAddress(address, label = "address") {
|
|
460
|
+
if (/^41[0-9a-fA-F]{40}$/.test(address)) return evmHexToTronAddress(`0x${address.slice(2)}`, label);
|
|
461
|
+
if (/^0x[0-9a-fA-F]{40}$/.test(address)) return evmHexToTronAddress(address, label);
|
|
462
|
+
return evmHexToTronAddress(tronAddressToEvmAddress(address, label), label);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/common.ts
|
|
466
|
+
var import_sun_sdk_core7 = require("@sun-protocol/sun-sdk-core");
|
|
467
|
+
var PERCENT_PATTERN = /^(\d+)(?:\.(\d+))?%$/;
|
|
468
|
+
var BASE_UNIT_PATTERN = /^\d+$/;
|
|
469
|
+
function parseSlippage(value) {
|
|
470
|
+
if (value instanceof import_sun_sdk_core7.Percent) {
|
|
471
|
+
validateSlippage(value);
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
const match = PERCENT_PATTERN.exec(value);
|
|
475
|
+
if (!match) {
|
|
476
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", "Slippage must be a percentage string", {
|
|
477
|
+
slippage: value
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
const whole = match[1] ?? "0";
|
|
481
|
+
const fraction = match[2] ?? "";
|
|
482
|
+
const scale = 10n ** BigInt(fraction.length);
|
|
483
|
+
const percentageUnits = BigInt(whole) * scale + BigInt(fraction || "0");
|
|
484
|
+
const percent = new import_sun_sdk_core7.Percent(percentageUnits.toString(), (100n * scale).toString());
|
|
485
|
+
validateSlippage(percent);
|
|
486
|
+
return percent;
|
|
487
|
+
}
|
|
488
|
+
function validateSlippage(value) {
|
|
489
|
+
if (value.lessThan(0) || value.greaterThan(1)) {
|
|
490
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", "Slippage must be between 0% and 100%", {
|
|
491
|
+
slippage: value.toSignificant()
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function slippageToBips(value) {
|
|
496
|
+
const percent = parseSlippage(value);
|
|
497
|
+
const numerator = BigInt(percent.numerator.toString()) * 10000n;
|
|
498
|
+
const denominator = BigInt(percent.denominator.toString());
|
|
499
|
+
if (numerator % denominator !== 0n) {
|
|
500
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", "Slippage must resolve to a whole basis point", {
|
|
501
|
+
slippage: typeof value === "string" ? value : value.toSignificant()
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
return Number(numerator / denominator);
|
|
505
|
+
}
|
|
506
|
+
function applySlippageMin(expected, slippageBips) {
|
|
507
|
+
return expected * BigInt(1e4 - slippageBips) / 10000n;
|
|
508
|
+
}
|
|
509
|
+
function applySlippageMax(expected, slippageBips) {
|
|
510
|
+
const numerator = expected * BigInt(1e4 + slippageBips);
|
|
511
|
+
return (numerator + 9999n) / 10000n;
|
|
512
|
+
}
|
|
513
|
+
function normalizeBaseUnitAmount(value, label = "amount", options = {}) {
|
|
514
|
+
if (typeof value === "number" && !Number.isSafeInteger(value)) {
|
|
515
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", `${label} must be a safe integer`, {
|
|
516
|
+
label,
|
|
517
|
+
value
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
const text = value.toString();
|
|
521
|
+
if (!BASE_UNIT_PATTERN.test(text)) {
|
|
522
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", `${label} must be an unsigned base-unit integer`, {
|
|
523
|
+
label,
|
|
524
|
+
value: text
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
const amount = BigInt(text);
|
|
528
|
+
if (options.allowZero ? amount < 0n : amount <= 0n) {
|
|
529
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", `${label} must be ${options.allowZero ? "non-negative" : "positive"}`, {
|
|
530
|
+
label,
|
|
531
|
+
value: text
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
return amount.toString();
|
|
535
|
+
}
|
|
536
|
+
function normalizeDeadline(context, options = {}) {
|
|
537
|
+
if (options.deadline !== void 0) {
|
|
538
|
+
return normalizeBaseUnitAmount(options.deadline, "deadline");
|
|
539
|
+
}
|
|
540
|
+
const ttlSeconds = options.ttlSeconds ?? 1200;
|
|
541
|
+
if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds <= 0) {
|
|
542
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", "ttlSeconds must be a positive safe integer", {
|
|
543
|
+
ttlSeconds
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
return (BigInt(Math.floor(context.now() / 1e3)) + BigInt(ttlSeconds)).toString();
|
|
547
|
+
}
|
|
548
|
+
function normalizeTransactionValidForSeconds(value) {
|
|
549
|
+
const transactionValidForSeconds = value ?? 1200;
|
|
550
|
+
if (!Number.isSafeInteger(transactionValidForSeconds) || transactionValidForSeconds <= 0) {
|
|
551
|
+
throw new import_sun_sdk_core7.SDKError(
|
|
552
|
+
"SDK_INVALID_ARGUMENT",
|
|
553
|
+
"transactionValidForSeconds must be a positive safe integer",
|
|
554
|
+
{ transactionValidForSeconds }
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
return transactionValidForSeconds;
|
|
558
|
+
}
|
|
559
|
+
function normalizeFeeLimit(value, defaultValue) {
|
|
560
|
+
const feeLimit = value ?? defaultValue;
|
|
561
|
+
if (!Number.isSafeInteger(feeLimit) || feeLimit <= 0) {
|
|
562
|
+
throw new import_sun_sdk_core7.SDKError("SDK_INVALID_ARGUMENT", "feeLimit must be a positive safe integer in sun", {
|
|
563
|
+
feeLimit
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
return feeLimit;
|
|
567
|
+
}
|
|
568
|
+
async function resolveTransactionDeadline(context, transactionValidForSeconds) {
|
|
569
|
+
const nowSeconds = BigInt(Math.ceil(await context.getTransactionTime() / 1e3));
|
|
570
|
+
return (nowSeconds + BigInt(transactionValidForSeconds)).toString();
|
|
571
|
+
}
|
|
572
|
+
async function normalizeRecipient(context, recipient, operation, walletAddress) {
|
|
573
|
+
if (recipient !== void 0) return (0, import_sun_sdk_core7.assertTronAddress)(recipient, "recipient");
|
|
574
|
+
if (walletAddress !== void 0) return walletAddress;
|
|
575
|
+
return requireWalletAddress(context, operation);
|
|
576
|
+
}
|
|
577
|
+
function nextPlanId(context, prefix) {
|
|
578
|
+
return `${prefix}-${context.idFactory()}`;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// src/swap/fee-limit.ts
|
|
582
|
+
var DEFAULT_WTRX_SWAP_FEE_LIMIT = 1e9;
|
|
583
|
+
var DEFAULT_UNIVERSAL_ROUTER_SWAP_FEE_LIMIT = 5e8;
|
|
584
|
+
var DEFAULT_PSM_SWAP_FEE_LIMIT = 25e7;
|
|
585
|
+
var DEFAULT_PSM_APPROVAL_FEE_LIMIT = 1e9;
|
|
586
|
+
|
|
587
|
+
// src/internal/universal-router-adapter.ts
|
|
588
|
+
function requireString(route, key) {
|
|
589
|
+
const value = route[key];
|
|
590
|
+
if (typeof value !== "string") {
|
|
591
|
+
throw new import_sun_sdk_core8.SDKError("SDK_INVALID_ARGUMENT", `Router route is missing ${String(key)}`, { key, route });
|
|
592
|
+
}
|
|
593
|
+
return value;
|
|
594
|
+
}
|
|
595
|
+
function requireStringArray(route, key) {
|
|
596
|
+
const value = route[key];
|
|
597
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
598
|
+
throw new import_sun_sdk_core8.SDKError("SDK_INVALID_ARGUMENT", `Router route is missing ${String(key)}`, { key, route });
|
|
599
|
+
}
|
|
600
|
+
return value;
|
|
601
|
+
}
|
|
602
|
+
function normalizePoolKey(poolKey) {
|
|
603
|
+
if (poolKey === null || poolKey === void 0) {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
if (typeof poolKey !== "object") {
|
|
607
|
+
throw new import_sun_sdk_core8.SDKError("SDK_INVALID_ARGUMENT", "Router route poolKey must be an object or null", { poolKey });
|
|
608
|
+
}
|
|
609
|
+
const value = poolKey;
|
|
610
|
+
const token0 = value.token0 ?? value.currency0;
|
|
611
|
+
const token1 = value.token1 ?? value.currency1;
|
|
612
|
+
if (typeof token0 !== "string" || typeof token1 !== "string" || typeof value.hooks !== "string" || typeof value.fee !== "number" || typeof value.parameters !== "string") {
|
|
613
|
+
throw new import_sun_sdk_core8.SDKError("SDK_INVALID_ARGUMENT", "Router route poolKey has invalid fields", { poolKey });
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
token0,
|
|
617
|
+
token1,
|
|
618
|
+
hooks: value.hooks,
|
|
619
|
+
fee: value.fee,
|
|
620
|
+
parameters: value.parameters
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function normalizeRouteData(route) {
|
|
624
|
+
const poolKeysRaw = route.poolKeys;
|
|
625
|
+
if (!Array.isArray(poolKeysRaw)) {
|
|
626
|
+
throw new import_sun_sdk_core8.SDKError("SDK_INVALID_ARGUMENT", "Router route is missing poolKeys", { route });
|
|
627
|
+
}
|
|
628
|
+
return {
|
|
629
|
+
amountIn: requireString(route, "amountIn"),
|
|
630
|
+
amountInRaw: requireString(route, "amountInRaw"),
|
|
631
|
+
amountOut: requireString(route, "amountOut"),
|
|
632
|
+
amountOutRaw: requireString(route, "amountOutRaw"),
|
|
633
|
+
amountOutMinimum: typeof route.amountOutMinimum === "string" ? route.amountOutMinimum : "0",
|
|
634
|
+
amountOutMinimumRaw: typeof route.amountOutMinimumRaw === "string" ? route.amountOutMinimumRaw : "0",
|
|
635
|
+
inUsd: typeof route.inUsd === "string" ? route.inUsd : "0",
|
|
636
|
+
outUsd: typeof route.outUsd === "string" ? route.outUsd : "0",
|
|
637
|
+
impact: typeof route.impact === "string" ? route.impact : "0",
|
|
638
|
+
fee: typeof route.fee === "string" ? route.fee : "0",
|
|
639
|
+
containsUnverifiedHook: route.containsUnverifiedHook === true,
|
|
640
|
+
tokens: requireStringArray(route, "tokens"),
|
|
641
|
+
symbols: requireStringArray(route, "symbols"),
|
|
642
|
+
poolFees: requireStringArray(route, "poolFees"),
|
|
643
|
+
poolVersions: requireStringArray(route, "poolVersions"),
|
|
644
|
+
poolKeys: poolKeysRaw.map(normalizePoolKey),
|
|
645
|
+
stepAmountsOut: requireStringArray(route, "stepAmountsOut"),
|
|
646
|
+
...typeof route.amountInReferralBips === "number" ? { amountInReferralBips: route.amountInReferralBips } : {},
|
|
647
|
+
...typeof route.amountOutReferralBips === "number" ? { amountOutReferralBips: route.amountOutReferralBips } : {}
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function routeStartsWithNativeTrx(chain, route) {
|
|
651
|
+
return route.tokens[0] === chain.contracts.trx;
|
|
652
|
+
}
|
|
653
|
+
function buildUniversalRouterSwapAction(input) {
|
|
654
|
+
const routeData = normalizeRouteData(input.route);
|
|
655
|
+
const hops = routeData.poolVersions.length;
|
|
656
|
+
if (hops === 0 || routeData.tokens.length !== hops + 1 || routeData.poolFees.length < hops || routeData.poolVersions.some((version) => !Object.values(import_universal_router_sdk.PoolVersion).includes(version))) {
|
|
657
|
+
throw new import_sun_sdk_core8.SDKError("SDK_INVALID_ARGUMENT", "Router route has inconsistent hop data");
|
|
658
|
+
}
|
|
659
|
+
routeData.tokens = routeData.tokens.map((token) => normalizeTronAddress(token));
|
|
660
|
+
const swapTradeRoute = (0, import_universal_router_sdk.parseRouteAPIResponse)(routeData, input.network === "nile", {
|
|
661
|
+
slippageBips: input.slippageBips
|
|
662
|
+
});
|
|
663
|
+
if (input.recipient) {
|
|
664
|
+
swapTradeRoute.recipient = new import_universal_router_sdk.Address(input.recipient);
|
|
665
|
+
}
|
|
666
|
+
const tradePlanner = new import_universal_router_sdk.TradePlanner([swapTradeRoute], false, {
|
|
667
|
+
permitOptions: input.permit ? { permitEnabled: true, permit: input.permit } : { permitEnabled: false }
|
|
668
|
+
});
|
|
669
|
+
tradePlanner.encode();
|
|
670
|
+
const usdtAddress = input.chain.contracts.usdt;
|
|
671
|
+
const sources = /* @__PURE__ */ new Map();
|
|
672
|
+
swapTradeRoute.pools.forEach((pool, index) => {
|
|
673
|
+
if (pool.type !== import_universal_router_sdk.PoolType.V3 || routeData.tokens[index + 1] !== usdtAddress) return;
|
|
674
|
+
const address = (0, import_sun_sdk_sunswap_v3.computeV3PoolAddress)({
|
|
675
|
+
network: input.network,
|
|
676
|
+
tokenA: routeData.tokens[index],
|
|
677
|
+
tokenB: usdtAddress,
|
|
678
|
+
fee: pool.fee,
|
|
679
|
+
factory: input.chain.contracts.sunswapV3Factory,
|
|
680
|
+
wrappedNative: input.chain.contracts.wtrx
|
|
681
|
+
});
|
|
682
|
+
sources.set(address, { address, role: "v3-pool" });
|
|
683
|
+
});
|
|
684
|
+
const usdtTransfer = {
|
|
685
|
+
network: input.network,
|
|
686
|
+
transfersUsdt: sources.size > 0,
|
|
687
|
+
sources: [...sources.values()]
|
|
688
|
+
};
|
|
689
|
+
return (0, import_sun_sdk_core8.createContractCallAction)({
|
|
690
|
+
id: "universal-router-swap",
|
|
691
|
+
target: input.chain.contracts.universalRouter,
|
|
692
|
+
functionSelector: "execute(bytes,bytes[],uint256)",
|
|
693
|
+
parameters: [
|
|
694
|
+
{ type: "bytes", value: tradePlanner.commands },
|
|
695
|
+
{ type: "bytes[]", value: tradePlanner.inputs },
|
|
696
|
+
{ type: "uint256", value: input.deadline }
|
|
697
|
+
],
|
|
698
|
+
...routeStartsWithNativeTrx(input.chain, routeData) ? { callValue: BigInt(routeData.amountInRaw) } : {},
|
|
699
|
+
feeLimit: normalizeFeeLimit(input.feeLimit, DEFAULT_UNIVERSAL_ROUTER_SWAP_FEE_LIMIT),
|
|
700
|
+
metadata: { usdtTransfer }
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// src/usdt-transfer.ts
|
|
705
|
+
var import_sun_sdk_core9 = require("@sun-protocol/sun-sdk-core");
|
|
706
|
+
async function usdtValidateTransfer(input) {
|
|
707
|
+
if (input.transfersUsdt === false) return { status: "allowed" };
|
|
708
|
+
if (input.transfersUsdt !== true) return { status: "unknown", reason: "CHECK_FAILED" };
|
|
709
|
+
if (input.sources.length === 0) return { status: "unknown", reason: "MISSING_TRANSFER_SOURCE" };
|
|
710
|
+
try {
|
|
711
|
+
const paused = await input.reader.paused();
|
|
712
|
+
if (typeof paused !== "boolean") throw new Error("Invalid paused result");
|
|
713
|
+
if (paused) return { status: "blocked", reason: "USDT_PAUSED" };
|
|
714
|
+
const sources = /* @__PURE__ */ new Map();
|
|
715
|
+
for (const source of input.sources) {
|
|
716
|
+
const address = normalizeTronAddress(source.address);
|
|
717
|
+
sources.set(address, { ...source, address });
|
|
718
|
+
}
|
|
719
|
+
const checks = await Promise.all([...sources.values()].map(async (source) => {
|
|
720
|
+
const blacklisted = await input.reader.isBlackListed(source.address);
|
|
721
|
+
if (typeof blacklisted !== "boolean") throw new Error("Invalid blacklist result");
|
|
722
|
+
return { source, blacklisted };
|
|
723
|
+
}));
|
|
724
|
+
const blocked = checks.filter((check) => check.blacklisted).map((check) => check.source);
|
|
725
|
+
return blocked.length > 0 ? { status: "blocked", reason: "USDT_SOURCE_BLACKLISTED", sources: blocked } : { status: "allowed" };
|
|
726
|
+
} catch {
|
|
727
|
+
return { status: "unknown", reason: "CHECK_FAILED" };
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function parseTransferContext(context, action) {
|
|
731
|
+
const data = action.metadata?.usdtTransfer;
|
|
732
|
+
if (!data) throw new Error("Missing USDT transfer context");
|
|
733
|
+
if (data.network !== context.network || typeof data.transfersUsdt !== "boolean" || !Array.isArray(data.sources)) {
|
|
734
|
+
throw new Error("Invalid USDT transfer context; rebuild the plan");
|
|
735
|
+
}
|
|
736
|
+
const sources = data.sources.map((source) => {
|
|
737
|
+
if (!source || typeof source.address !== "string" || source.role !== "v3-pool" && source.role !== "position-manager") {
|
|
738
|
+
throw new Error("Invalid USDT transfer source");
|
|
739
|
+
}
|
|
740
|
+
const address = normalizeTronAddress(source.address);
|
|
741
|
+
if (source.role === "position-manager" && address !== normalizeTronAddress(action.target)) {
|
|
742
|
+
throw new Error("USDT sweep source does not match the position manager");
|
|
743
|
+
}
|
|
744
|
+
return { address, role: source.role };
|
|
745
|
+
});
|
|
746
|
+
if (!data.transfersUsdt && sources.length > 0) throw new Error("Unexpected USDT sources");
|
|
747
|
+
return { network: context.network, transfersUsdt: data.transfersUsdt, sources };
|
|
748
|
+
}
|
|
749
|
+
function boolRead(target, name, address) {
|
|
750
|
+
return {
|
|
751
|
+
target,
|
|
752
|
+
functionSelector: name === "paused" ? "paused()" : "isBlackListed(address)",
|
|
753
|
+
parameters: address === void 0 ? [] : [{ type: "address", value: address }],
|
|
754
|
+
abiFunction: {
|
|
755
|
+
type: "function",
|
|
756
|
+
name,
|
|
757
|
+
stateMutability: "view",
|
|
758
|
+
inputs: name === "paused" ? [] : [{ name: "_user", type: "address" }],
|
|
759
|
+
outputs: [{ name: "", type: "bool" }]
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
async function assertUsdtTransfer(context, action) {
|
|
764
|
+
let result;
|
|
765
|
+
if (!action.metadata?.usdtTransfer) {
|
|
766
|
+
result = { status: "unknown", reason: "MISSING_TRANSFER_SOURCE" };
|
|
767
|
+
} else {
|
|
768
|
+
try {
|
|
769
|
+
const data = parseTransferContext(context, action);
|
|
770
|
+
if (data.transfersUsdt && !data.sources.some((source) => source.role === "v3-pool")) {
|
|
771
|
+
result = { status: "unknown", reason: "MISSING_TRANSFER_SOURCE" };
|
|
772
|
+
} else {
|
|
773
|
+
const read = (name, address) => {
|
|
774
|
+
if (!context.runtime) throw new Error("USDT transfer validation requires a runtime");
|
|
775
|
+
return context.runtime.readContract(boolRead(context.chain.contracts.usdt, name, address));
|
|
776
|
+
};
|
|
777
|
+
result = await usdtValidateTransfer({
|
|
778
|
+
...data,
|
|
779
|
+
reader: { paused: () => read("paused"), isBlackListed: (address) => read("isBlackListed", address) }
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
} catch {
|
|
783
|
+
result = { status: "unknown", reason: "CHECK_FAILED" };
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (result.status === "allowed") return;
|
|
787
|
+
throw new import_sun_sdk_core9.SDKError(
|
|
788
|
+
result.status === "blocked" ? "SDK_USDT_TRANSFER_BLOCKED" : "SDK_USDT_TRANSFER_UNKNOWN",
|
|
789
|
+
result.status === "blocked" ? "USDT transfer is currently restricted" : "Unable to verify USDT transfer status",
|
|
790
|
+
{ ...result, usdtAddress: context.chain.contracts.usdt, actionId: action.id }
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// src/swap/router-execute.ts
|
|
795
|
+
function signatureFromResults(actionId, completed) {
|
|
796
|
+
if (!actionId) return void 0;
|
|
797
|
+
const result = completed.find((item) => item.action.id === actionId)?.result;
|
|
798
|
+
return typeof result === "string" ? result.startsWith("0x") ? result : `0x${result}` : void 0;
|
|
799
|
+
}
|
|
800
|
+
async function materializeUniversalRouterActionWithSignature(context, action, permitSignature) {
|
|
801
|
+
if (action.materialization.kind !== UNIVERSAL_ROUTER_MATERIALIZATION_KIND) {
|
|
802
|
+
throw new import_sun_sdk_core10.SDKError("SDK_RUNTIME_ERROR", `Unsupported deferred action kind: ${action.materialization.kind}`);
|
|
803
|
+
}
|
|
804
|
+
const data = action.materialization.data;
|
|
805
|
+
if (data.network !== context.network) {
|
|
806
|
+
throw new import_sun_sdk_core10.SDKError("SDK_USDT_TRANSFER_UNKNOWN", "Network changed; rebuild the swap plan", { reason: "CHECK_FAILED" });
|
|
807
|
+
}
|
|
808
|
+
if (data.signatureActionId && !permitSignature) {
|
|
809
|
+
throw new import_sun_sdk_core10.SDKError("SDK_INVALID_ARGUMENT", "Router swap requires the planned Permit2 signature", {
|
|
810
|
+
actionId: action.id,
|
|
811
|
+
signatureActionId: data.signatureActionId
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
if (data.signatureActionId && !data.permitSingle) {
|
|
815
|
+
throw new import_sun_sdk_core10.SDKError("SDK_RUNTIME_ERROR", "Router swap plan is missing Permit2 permit data", {
|
|
816
|
+
actionId: action.id,
|
|
817
|
+
signatureActionId: data.signatureActionId
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
const normalizedSignature = permitSignature ? permitSignature.startsWith("0x") ? permitSignature : `0x${permitSignature}` : void 0;
|
|
821
|
+
const permit = normalizedSignature && data.permitSingle ? { ...data.permitSingle, signature: normalizedSignature } : void 0;
|
|
822
|
+
return buildUniversalRouterSwapAction({
|
|
823
|
+
network: context.network,
|
|
824
|
+
chain: context.chain,
|
|
825
|
+
route: data.route,
|
|
826
|
+
slippageBips: BigInt(data.slippageBips),
|
|
827
|
+
deadline: await resolveTransactionDeadline(context, data.transactionValidForSeconds),
|
|
828
|
+
...data.recipient ? { recipient: data.recipient } : {},
|
|
829
|
+
...permit ? { permit } : {},
|
|
830
|
+
...data.feeLimit !== void 0 ? { feeLimit: data.feeLimit } : {}
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
async function materializeUniversalRouterAction(context, action, completedActions) {
|
|
834
|
+
const data = action.materialization.data;
|
|
835
|
+
const signature = signatureFromResults(data.signatureActionId, completedActions);
|
|
836
|
+
return materializeUniversalRouterActionWithSignature(context, action, signature);
|
|
837
|
+
}
|
|
838
|
+
function createRouterSwapExecutor(context, options) {
|
|
839
|
+
const executor = createContextExecutor(context);
|
|
840
|
+
return {
|
|
841
|
+
...executor,
|
|
842
|
+
sendAction: async (action) => {
|
|
843
|
+
if (action.target === context.chain.contracts.universalRouter || action.intent?.scope.protocol === "universal-router" && action.intent.kind === "swap") {
|
|
844
|
+
await assertUsdtTransfer(context, action);
|
|
845
|
+
}
|
|
846
|
+
if (!executor.sendAction) throw new import_sun_sdk_core10.SDKError("SDK_RUNTIME_ERROR", "Swap execution requires a runtime");
|
|
847
|
+
return executor.sendAction(action);
|
|
848
|
+
},
|
|
849
|
+
materializeAction: (action, completed) => options ? materializeUniversalRouterActionWithSignature(context, action, options.permitSignature) : materializeUniversalRouterAction(context, action, completed)
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// src/swap/plan.ts
|
|
854
|
+
var import_sun_sdk_core17 = require("@sun-protocol/sun-sdk-core");
|
|
855
|
+
|
|
856
|
+
// src/approval/permit2.ts
|
|
857
|
+
var import_sun_sdk_core14 = require("@sun-protocol/sun-sdk-core");
|
|
858
|
+
|
|
859
|
+
// src/internal/permit2-adapter.ts
|
|
860
|
+
var import_sun_sdk_core11 = require("@sun-protocol/sun-sdk-core");
|
|
861
|
+
var import_permit2_sdk = require("@sun-protocol/permit2-sdk");
|
|
862
|
+
var PERMIT2_TYPED_DATA_CHAIN_IDS = {
|
|
863
|
+
mainnet: 728126428,
|
|
864
|
+
nile: 3448148188
|
|
865
|
+
};
|
|
866
|
+
function buildPermit2HelperRead(input) {
|
|
867
|
+
return {
|
|
868
|
+
target: input.helper,
|
|
869
|
+
functionSelector: "checkPermit2Allowance(address,address,address,address,uint256)",
|
|
870
|
+
parameters: [
|
|
871
|
+
{ type: "address", value: input.permit2 },
|
|
872
|
+
{ type: "address", value: input.token },
|
|
873
|
+
{ type: "address", value: input.owner },
|
|
874
|
+
{ type: "address", value: input.spender },
|
|
875
|
+
{ type: "uint256", value: input.amount }
|
|
876
|
+
],
|
|
877
|
+
outputs: [{ type: "bool", name: "approved" }]
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function normalizePermit2HelperResult(result) {
|
|
881
|
+
if (typeof result === "boolean") return result;
|
|
882
|
+
if (Array.isArray(result) && result.length === 1 && typeof result[0] === "boolean") return result[0];
|
|
883
|
+
throw new import_sun_sdk_core11.SDKError("SDK_CONTRACT_ERROR", "Invalid Permit2Helper approval result", { result });
|
|
884
|
+
}
|
|
885
|
+
function buildPermit2AllowanceRead(input) {
|
|
886
|
+
return {
|
|
887
|
+
target: input.permit2,
|
|
888
|
+
functionSelector: "allowance(address,address,address)",
|
|
889
|
+
parameters: [
|
|
890
|
+
{ type: "address", value: input.owner },
|
|
891
|
+
{ type: "address", value: input.token },
|
|
892
|
+
{ type: "address", value: input.spender }
|
|
893
|
+
],
|
|
894
|
+
outputs: [
|
|
895
|
+
{ type: "uint160", name: "amount" },
|
|
896
|
+
{ type: "uint48", name: "expiration" },
|
|
897
|
+
{ type: "uint48", name: "nonce" }
|
|
898
|
+
]
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
function bigintFrom(value, label) {
|
|
902
|
+
if (typeof value === "bigint") return value;
|
|
903
|
+
if (typeof value === "number" && Number.isSafeInteger(value)) return BigInt(value);
|
|
904
|
+
if (typeof value === "string" && /^[0-9]+$/.test(value)) return BigInt(value);
|
|
905
|
+
throw new import_sun_sdk_core11.SDKError("SDK_CONTRACT_ERROR", `Invalid Permit2 allowance ${label}`, { value });
|
|
906
|
+
}
|
|
907
|
+
function normalizePermit2Allowance(result) {
|
|
908
|
+
if (Array.isArray(result)) {
|
|
909
|
+
return {
|
|
910
|
+
amount: bigintFrom(result[0], "amount"),
|
|
911
|
+
expiration: bigintFrom(result[1], "expiration"),
|
|
912
|
+
nonce: bigintFrom(result[2], "nonce")
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
if (typeof result === "object" && result !== null) {
|
|
916
|
+
const value = result;
|
|
917
|
+
return {
|
|
918
|
+
amount: bigintFrom(value.amount ?? value[0], "amount"),
|
|
919
|
+
expiration: bigintFrom(value.expiration ?? value[1], "expiration"),
|
|
920
|
+
nonce: bigintFrom(value.nonce ?? value[2], "nonce")
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
throw new import_sun_sdk_core11.SDKError("SDK_CONTRACT_ERROR", "Invalid Permit2 allowance result", { result });
|
|
924
|
+
}
|
|
925
|
+
function buildPermit2TypedData(input) {
|
|
926
|
+
return {
|
|
927
|
+
primaryType: "PermitSingle",
|
|
928
|
+
domain: {
|
|
929
|
+
name: "Permit2",
|
|
930
|
+
chainId: PERMIT2_TYPED_DATA_CHAIN_IDS[input.network],
|
|
931
|
+
verifyingContract: (0, import_permit2_sdk.toEvmHex)(input.permit2)
|
|
932
|
+
},
|
|
933
|
+
types: import_permit2_sdk.PERMIT_TYPES,
|
|
934
|
+
message: {
|
|
935
|
+
details: {
|
|
936
|
+
token: (0, import_permit2_sdk.toEvmHex)(input.token),
|
|
937
|
+
amount: input.amount,
|
|
938
|
+
expiration: input.expiration,
|
|
939
|
+
nonce: input.nonce
|
|
940
|
+
},
|
|
941
|
+
spender: (0, import_permit2_sdk.toEvmHex)(input.spender),
|
|
942
|
+
sigDeadline: input.sigDeadline
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
function buildPermit2ApproveAction(input) {
|
|
947
|
+
return (0, import_sun_sdk_core11.createContractCallAction)({
|
|
948
|
+
id: input.id,
|
|
949
|
+
target: input.permit2,
|
|
950
|
+
functionSelector: "approve(address,address,uint160,uint48)",
|
|
951
|
+
waitForReceipt: "included",
|
|
952
|
+
parameters: [
|
|
953
|
+
{ type: "address", value: input.token },
|
|
954
|
+
{ type: "address", value: input.spender },
|
|
955
|
+
{ type: "uint160", value: input.amount },
|
|
956
|
+
{ type: "uint48", value: input.expiration }
|
|
957
|
+
]
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// src/approval/plan.ts
|
|
962
|
+
var import_sun_sdk_core13 = require("@sun-protocol/sun-sdk-core");
|
|
963
|
+
|
|
964
|
+
// src/approval/check.ts
|
|
965
|
+
async function readClassicAllowance(runtime, requirement) {
|
|
966
|
+
if (requirement.asset.type === "native") return "0";
|
|
967
|
+
const result = await runtime.readContract({
|
|
968
|
+
target: requirement.asset.token,
|
|
969
|
+
functionSelector: "allowance(address,address)",
|
|
970
|
+
parameters: [
|
|
971
|
+
{ type: "address", value: requirement.owner },
|
|
972
|
+
{ type: "address", value: requirement.spender }
|
|
973
|
+
],
|
|
974
|
+
outputs: [{ type: "uint256", name: "allowance" }]
|
|
975
|
+
});
|
|
976
|
+
return BigInt(result).toString();
|
|
977
|
+
}
|
|
978
|
+
async function checkClassicAllowance(runtime, requirement) {
|
|
979
|
+
if (requirement.asset.type === "native") {
|
|
980
|
+
return { allowance: requirement.amount, sufficient: true };
|
|
981
|
+
}
|
|
982
|
+
const allowance = await readClassicAllowance(runtime, requirement);
|
|
983
|
+
return {
|
|
984
|
+
allowance,
|
|
985
|
+
sufficient: BigInt(allowance) >= BigInt(requirement.amount)
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// src/approval/classic.ts
|
|
990
|
+
var import_sun_sdk_core12 = require("@sun-protocol/sun-sdk-core");
|
|
991
|
+
function buildClassicApproveAction(requirement, options = {}) {
|
|
992
|
+
if (requirement.asset.type === "native") return void 0;
|
|
993
|
+
return (0, import_sun_sdk_core12.createApproveAction)({
|
|
994
|
+
id: `approve-${requirement.asset.token}-${requirement.spender}`,
|
|
995
|
+
target: requirement.asset.token,
|
|
996
|
+
spender: requirement.spender,
|
|
997
|
+
amount: options.amount === "exact" ? requirement.amount : import_sun_sdk_core12.MaxUint256.toString(),
|
|
998
|
+
...options.feeLimit !== void 0 ? { feeLimit: options.feeLimit } : {}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/approval/plan.ts
|
|
1003
|
+
async function planApproval(context, requirement, options = {}) {
|
|
1004
|
+
const mode = options.mode ?? "auto";
|
|
1005
|
+
normalizeBaseUnitAmount(requirement.amount, "approval amount");
|
|
1006
|
+
if (requirement.asset.type === "native") {
|
|
1007
|
+
return {
|
|
1008
|
+
mode,
|
|
1009
|
+
requirement,
|
|
1010
|
+
allowance: requirement.amount,
|
|
1011
|
+
sufficient: true,
|
|
1012
|
+
actions: []
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (mode === "none") {
|
|
1016
|
+
return { mode, requirement, actions: [] };
|
|
1017
|
+
}
|
|
1018
|
+
if (mode === "permit2") {
|
|
1019
|
+
throw new import_sun_sdk_core13.SDKError(
|
|
1020
|
+
"SDK_WALLET_CAPABILITY_ERROR",
|
|
1021
|
+
"Permit2 approval is unavailable until a Permit2 adapter is configured",
|
|
1022
|
+
{ mode, token: requirement.asset.token }
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
const runtime = requireRuntime(context, "Token allowance check");
|
|
1026
|
+
const check = await checkClassicAllowance(runtime, requirement);
|
|
1027
|
+
if (check.sufficient) {
|
|
1028
|
+
return {
|
|
1029
|
+
mode,
|
|
1030
|
+
requirement,
|
|
1031
|
+
allowance: check.allowance,
|
|
1032
|
+
sufficient: true,
|
|
1033
|
+
actions: []
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
const action = buildClassicApproveAction(requirement, options);
|
|
1037
|
+
return {
|
|
1038
|
+
mode,
|
|
1039
|
+
requirement,
|
|
1040
|
+
allowance: check.allowance,
|
|
1041
|
+
sufficient: false,
|
|
1042
|
+
actions: action ? [action] : []
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// src/approval/permit2.ts
|
|
1047
|
+
async function hasTypedDataCapability(context, capabilities) {
|
|
1048
|
+
if (capabilities) return capabilities.signTypedData;
|
|
1049
|
+
return (await context.runtime?.getWallet())?.capabilities.signTypedData === true;
|
|
1050
|
+
}
|
|
1051
|
+
function normalizePlanDeadlineValue(value) {
|
|
1052
|
+
return typeof value === "bigint" ? value.toString() : value;
|
|
1053
|
+
}
|
|
1054
|
+
var MAX_UINT160 = "1461501637330902918203684832716283019655932542975";
|
|
1055
|
+
async function planRouterPermit2Authorization(context, input) {
|
|
1056
|
+
if (input.approval === "none") {
|
|
1057
|
+
return { actions: [], mode: "none" };
|
|
1058
|
+
}
|
|
1059
|
+
const helper = context.chain.contracts.permit2Helper;
|
|
1060
|
+
if (!helper) {
|
|
1061
|
+
throw new import_sun_sdk_core14.SDKError("SDK_INVALID_ARGUMENT", `Permit2Helper is not configured for ${context.network}`, {
|
|
1062
|
+
network: context.network,
|
|
1063
|
+
contract: "permit2Helper"
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
const runtime = requireRuntime(context, "Router Permit2 authorization");
|
|
1067
|
+
const actions = [];
|
|
1068
|
+
const token = (0, import_sun_sdk_core14.assertTronAddress)(input.token, "token");
|
|
1069
|
+
const spender = input.spender ? (0, import_sun_sdk_core14.assertTronAddress)(input.spender, "spender") : context.chain.contracts.universalRouter;
|
|
1070
|
+
const tokenApproval = await planApproval(context, {
|
|
1071
|
+
asset: { type: "token", token },
|
|
1072
|
+
owner: input.owner,
|
|
1073
|
+
spender: context.chain.contracts.permit2,
|
|
1074
|
+
amount: input.amount
|
|
1075
|
+
}, {
|
|
1076
|
+
mode: "auto",
|
|
1077
|
+
amount: input.approveAmountType ?? "exact"
|
|
1078
|
+
});
|
|
1079
|
+
actions.push(...tokenApproval.actions);
|
|
1080
|
+
const approved = normalizePermit2HelperResult(await runtime.readContract(buildPermit2HelperRead({
|
|
1081
|
+
helper,
|
|
1082
|
+
permit2: context.chain.contracts.permit2,
|
|
1083
|
+
owner: input.owner,
|
|
1084
|
+
token,
|
|
1085
|
+
spender,
|
|
1086
|
+
amount: input.amount
|
|
1087
|
+
})));
|
|
1088
|
+
const permit2Amount = input.approveAmountType === "max" ? MAX_UINT160 : input.amount;
|
|
1089
|
+
if (approved) {
|
|
1090
|
+
return { actions, mode: "already-approved" };
|
|
1091
|
+
}
|
|
1092
|
+
const expiration = normalizeDeadline(context, {
|
|
1093
|
+
ttlSeconds: input.ttlSeconds ?? 30 * 24 * 60 * 60,
|
|
1094
|
+
...input.deadline !== void 0 ? { deadline: normalizePlanDeadlineValue(input.deadline) } : {}
|
|
1095
|
+
}).toString();
|
|
1096
|
+
const sigDeadline = normalizeDeadline(context, { ttlSeconds: 3600 }).toString();
|
|
1097
|
+
if ((input.approval === "auto" || input.approval === "permit2") && await hasTypedDataCapability(context, input.walletCapabilities)) {
|
|
1098
|
+
const allowance = normalizePermit2Allowance(await runtime.readContract(buildPermit2AllowanceRead({
|
|
1099
|
+
permit2: context.chain.contracts.permit2,
|
|
1100
|
+
owner: input.owner,
|
|
1101
|
+
token,
|
|
1102
|
+
spender
|
|
1103
|
+
})));
|
|
1104
|
+
const typedData = buildPermit2TypedData({
|
|
1105
|
+
network: context.network,
|
|
1106
|
+
permit2: context.chain.contracts.permit2,
|
|
1107
|
+
owner: input.owner,
|
|
1108
|
+
token,
|
|
1109
|
+
spender,
|
|
1110
|
+
amount: permit2Amount,
|
|
1111
|
+
expiration,
|
|
1112
|
+
sigDeadline,
|
|
1113
|
+
nonce: allowance.nonce.toString()
|
|
1114
|
+
});
|
|
1115
|
+
const signatureActionId = `${nextPlanId(context, "permit2")}-signature`;
|
|
1116
|
+
actions.push((0, import_sun_sdk_core14.createTypedDataSignatureAction)({
|
|
1117
|
+
id: signatureActionId,
|
|
1118
|
+
typedData
|
|
1119
|
+
}));
|
|
1120
|
+
return {
|
|
1121
|
+
actions,
|
|
1122
|
+
signatureActionId,
|
|
1123
|
+
permitSingle: typedData.message,
|
|
1124
|
+
mode: "typed-data"
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
if (input.approval === "permit2" || input.approval === "auto" || input.approval === "approve") {
|
|
1128
|
+
actions.push(buildPermit2ApproveAction({
|
|
1129
|
+
id: `${nextPlanId(context, "permit2")}-approve`,
|
|
1130
|
+
permit2: context.chain.contracts.permit2,
|
|
1131
|
+
token,
|
|
1132
|
+
spender,
|
|
1133
|
+
amount: permit2Amount,
|
|
1134
|
+
expiration
|
|
1135
|
+
}));
|
|
1136
|
+
return { actions, mode: "on-chain" };
|
|
1137
|
+
}
|
|
1138
|
+
throw new import_sun_sdk_core14.SDKError(
|
|
1139
|
+
"SDK_INVALID_ARGUMENT",
|
|
1140
|
+
"Unsupported approval mode for Router Permit2 authorization",
|
|
1141
|
+
{ approval: input.approval }
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// src/swap/tokens.ts
|
|
1146
|
+
var import_sun_sdk_core15 = require("@sun-protocol/sun-sdk-core");
|
|
1147
|
+
function isNativeTrxToken(context, token) {
|
|
1148
|
+
return token.toUpperCase() === "TRX" || token === context.chain.contracts.trx;
|
|
1149
|
+
}
|
|
1150
|
+
function normalizeRouterToken(context, token) {
|
|
1151
|
+
return isNativeTrxToken(context, token) ? context.chain.contracts.trx : (0, import_sun_sdk_core15.assertTronAddress)(token, "token");
|
|
1152
|
+
}
|
|
1153
|
+
function normalizeV2TrxPairPath(context, input) {
|
|
1154
|
+
const tokenInIsTrx = isNativeTrxToken(context, input.tokenIn);
|
|
1155
|
+
const tokenOutIsTrx = isNativeTrxToken(context, input.tokenOut);
|
|
1156
|
+
if (tokenInIsTrx === tokenOutIsTrx) {
|
|
1157
|
+
throw new import_sun_sdk_core15.SDKError("SDK_INVALID_ARGUMENT", "V2 swap currently supports exactly one TRX side", {
|
|
1158
|
+
tokenIn: input.tokenIn,
|
|
1159
|
+
tokenOut: input.tokenOut
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
const token = (0, import_sun_sdk_core15.assertTronAddress)(tokenInIsTrx ? input.tokenOut : input.tokenIn, "token");
|
|
1163
|
+
return tokenInIsTrx ? { direction: "trx-to-token", token, path: [context.chain.contracts.wtrx, token] } : { direction: "token-to-trx", token, path: [token, context.chain.contracts.wtrx] };
|
|
1164
|
+
}
|
|
1165
|
+
function normalizeV2PathToken(context, token, label) {
|
|
1166
|
+
if (isNativeTrxToken(context, token) || token === context.chain.contracts.wtrx) {
|
|
1167
|
+
return context.chain.contracts.wtrx;
|
|
1168
|
+
}
|
|
1169
|
+
return (0, import_sun_sdk_core15.assertTronAddress)(token, label);
|
|
1170
|
+
}
|
|
1171
|
+
function isWrappedTrxToken(context, token) {
|
|
1172
|
+
return token === context.chain.contracts.wtrx;
|
|
1173
|
+
}
|
|
1174
|
+
function detectWtrxSwap(context, input) {
|
|
1175
|
+
const amountIn = normalizeBaseUnitAmount(input.amountIn, "amountIn");
|
|
1176
|
+
const tokenInIsTrx = isNativeTrxToken(context, input.tokenIn);
|
|
1177
|
+
const tokenOutIsTrx = isNativeTrxToken(context, input.tokenOut);
|
|
1178
|
+
const tokenInIsWtrx = isWrappedTrxToken(context, input.tokenIn);
|
|
1179
|
+
const tokenOutIsWtrx = isWrappedTrxToken(context, input.tokenOut);
|
|
1180
|
+
let action;
|
|
1181
|
+
if (tokenInIsTrx && tokenOutIsWtrx) action = "wrap";
|
|
1182
|
+
if (tokenInIsWtrx && tokenOutIsTrx) action = "unwrap";
|
|
1183
|
+
if (!action) return void 0;
|
|
1184
|
+
return {
|
|
1185
|
+
kind: "wtrx",
|
|
1186
|
+
source: "wtrx",
|
|
1187
|
+
action,
|
|
1188
|
+
tokenIn: input.tokenIn,
|
|
1189
|
+
tokenOut: input.tokenOut,
|
|
1190
|
+
amountIn,
|
|
1191
|
+
amountOut: amountIn,
|
|
1192
|
+
route: {
|
|
1193
|
+
type: action === "wrap" ? "WTRX_WRAP" : "WTRX_UNWRAP",
|
|
1194
|
+
amountIn,
|
|
1195
|
+
amountOut: amountIn
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
function normalizeV2SwapPath(context, input) {
|
|
1200
|
+
const tokenInIsTrx = isNativeTrxToken(context, input.tokenIn);
|
|
1201
|
+
const tokenOutIsTrx = isNativeTrxToken(context, input.tokenOut);
|
|
1202
|
+
const tokenInIsWtrx = isWrappedTrxToken(context, input.tokenIn);
|
|
1203
|
+
const tokenOutIsWtrx = isWrappedTrxToken(context, input.tokenOut);
|
|
1204
|
+
if (tokenInIsTrx && (tokenOutIsTrx || tokenOutIsWtrx) || tokenInIsWtrx && tokenOutIsTrx) {
|
|
1205
|
+
throw new import_sun_sdk_core15.SDKError("SDK_INVALID_ARGUMENT", "V2 swap does not handle TRX wrap or unwrap", {
|
|
1206
|
+
tokenIn: input.tokenIn,
|
|
1207
|
+
tokenOut: input.tokenOut
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
const inputToken = normalizeV2PathToken(context, input.tokenIn, "tokenIn");
|
|
1211
|
+
const outputToken = normalizeV2PathToken(context, input.tokenOut, "tokenOut");
|
|
1212
|
+
const path = (input.path ?? [input.tokenIn, input.tokenOut]).map(
|
|
1213
|
+
(token, index) => normalizeV2PathToken(context, token, `path[${index}]`)
|
|
1214
|
+
);
|
|
1215
|
+
const originalPath = input.path ?? [input.tokenIn, input.tokenOut];
|
|
1216
|
+
if (inputToken === outputToken) {
|
|
1217
|
+
throw new import_sun_sdk_core15.SDKError("SDK_INVALID_ARGUMENT", "V2 swap tokenIn and tokenOut must differ", {
|
|
1218
|
+
tokenIn: input.tokenIn,
|
|
1219
|
+
tokenOut: input.tokenOut
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
if (path.length < 2 || path[0] !== inputToken || path[path.length - 1] !== outputToken) {
|
|
1223
|
+
throw new import_sun_sdk_core15.SDKError("SDK_INVALID_ARGUMENT", "V2 swap path must start with tokenIn and end with tokenOut", {
|
|
1224
|
+
tokenIn: input.tokenIn,
|
|
1225
|
+
tokenOut: input.tokenOut,
|
|
1226
|
+
path: originalPath
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
if (path.some((token, index) => index > 0 && token === path[index - 1])) {
|
|
1230
|
+
throw new import_sun_sdk_core15.SDKError("SDK_INVALID_ARGUMENT", "V2 swap path must not contain duplicate adjacent tokens", {
|
|
1231
|
+
tokenIn: input.tokenIn,
|
|
1232
|
+
tokenOut: input.tokenOut,
|
|
1233
|
+
path: originalPath
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
const direction = tokenInIsTrx ? "trx-to-token" : tokenOutIsTrx ? "token-to-trx" : "token-to-token";
|
|
1237
|
+
return { direction, token: tokenInIsTrx ? outputToken : inputToken, path };
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
// src/swap/intents.ts
|
|
1241
|
+
var import_sun_sdk_core16 = require("@sun-protocol/sun-sdk-core");
|
|
1242
|
+
|
|
1243
|
+
// src/internal/intents.ts
|
|
1244
|
+
function attachApprovalIntent(actions, scope, tokenSymbol) {
|
|
1245
|
+
const intent = { kind: "approve", scope, tokenSymbol };
|
|
1246
|
+
return actions.map((action) => action.execute === "runtime" ? { ...action, intent } : action);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// src/swap/intents.ts
|
|
1250
|
+
var UNIVERSAL_ROUTER_PROTOCOL_ID = "universal-router";
|
|
1251
|
+
var PSM_PROTOCOL_ID = "psm";
|
|
1252
|
+
var WTRX_PROTOCOL_ID = "wtrx";
|
|
1253
|
+
function swapIntentScope(protocol, operation) {
|
|
1254
|
+
return {
|
|
1255
|
+
domain: "swap",
|
|
1256
|
+
protocol,
|
|
1257
|
+
...operation === void 0 ? {} : { operation }
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
function routerRouteSymbols(route) {
|
|
1261
|
+
const symbols = route.symbols;
|
|
1262
|
+
if (!Array.isArray(symbols) || symbols.length < 2 || symbols.some((symbol) => typeof symbol !== "string" || symbol.length === 0)) {
|
|
1263
|
+
throw new import_sun_sdk_core16.SDKError("SDK_API_ERROR", "Selected Router route is missing token symbols");
|
|
1264
|
+
}
|
|
1265
|
+
return {
|
|
1266
|
+
from: symbols[0],
|
|
1267
|
+
to: symbols[symbols.length - 1]
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// src/swap/plan.ts
|
|
1272
|
+
function stringifyRoute(route) {
|
|
1273
|
+
try {
|
|
1274
|
+
return JSON.stringify(route);
|
|
1275
|
+
} catch {
|
|
1276
|
+
return void 0;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
function findSelectedRouteIndex(quote, route) {
|
|
1280
|
+
const serializedRoute = stringifyRoute(route);
|
|
1281
|
+
return quote.routes.findIndex((candidate) => {
|
|
1282
|
+
if (candidate === route) return true;
|
|
1283
|
+
if (serializedRoute === void 0) return false;
|
|
1284
|
+
return stringifyRoute(candidate) === serializedRoute;
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
function isWtrxRoute(route) {
|
|
1288
|
+
return typeof route === "object" && route !== null && (route.type === "WTRX_WRAP" || route.type === "WTRX_UNWRAP");
|
|
1289
|
+
}
|
|
1290
|
+
function buildWtrxSwapPlan(context, quote, route, owner, feeLimit) {
|
|
1291
|
+
if (stringifyRoute(route) !== stringifyRoute(quote.route)) {
|
|
1292
|
+
throw new import_sun_sdk_core17.SDKError("SDK_INVALID_ARGUMENT", "Selected WTRX route must come from the quote", {
|
|
1293
|
+
quoteRoute: quote.route,
|
|
1294
|
+
route
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
const resolvedFeeLimit = normalizeFeeLimit(feeLimit, DEFAULT_WTRX_SWAP_FEE_LIMIT);
|
|
1298
|
+
const intent = {
|
|
1299
|
+
kind: quote.action,
|
|
1300
|
+
scope: swapIntentScope(WTRX_PROTOCOL_ID, quote.action),
|
|
1301
|
+
amount: (0, import_sun_sdk_core17.formatUnits)(BigInt(quote.amountIn), context.chain.nativeCurrency.decimals)
|
|
1302
|
+
};
|
|
1303
|
+
const transaction = quote.action === "wrap" ? (0, import_sun_sdk_core17.createContractCallAction)({
|
|
1304
|
+
id: `${nextPlanId(context, "swap-wtrx")}-wrap`,
|
|
1305
|
+
target: context.chain.contracts.wtrx,
|
|
1306
|
+
functionSelector: "deposit()",
|
|
1307
|
+
parameters: [],
|
|
1308
|
+
callValue: BigInt(quote.amountIn),
|
|
1309
|
+
feeLimit: resolvedFeeLimit,
|
|
1310
|
+
intent
|
|
1311
|
+
}) : (0, import_sun_sdk_core17.createContractCallAction)({
|
|
1312
|
+
id: `${nextPlanId(context, "swap-wtrx")}-unwrap`,
|
|
1313
|
+
target: context.chain.contracts.wtrx,
|
|
1314
|
+
functionSelector: "withdraw(uint256)",
|
|
1315
|
+
parameters: [{ type: "uint256", value: quote.amountIn }],
|
|
1316
|
+
feeLimit: resolvedFeeLimit,
|
|
1317
|
+
intent
|
|
1318
|
+
});
|
|
1319
|
+
return {
|
|
1320
|
+
id: nextPlanId(context, "swap-wtrx"),
|
|
1321
|
+
kind: "swap",
|
|
1322
|
+
network: context.network,
|
|
1323
|
+
owner,
|
|
1324
|
+
summary: {
|
|
1325
|
+
title: quote.action === "wrap" ? "Wrap TRX" : "Unwrap WTRX",
|
|
1326
|
+
lines: [`Amount ${quote.amountIn}`]
|
|
1327
|
+
},
|
|
1328
|
+
approvals: [],
|
|
1329
|
+
transactions: [transaction],
|
|
1330
|
+
metadata: {
|
|
1331
|
+
protocol: "wtrx",
|
|
1332
|
+
action: quote.action,
|
|
1333
|
+
amountIn: quote.amountIn,
|
|
1334
|
+
amountOut: quote.amountOut,
|
|
1335
|
+
tokenIn: quote.tokenIn,
|
|
1336
|
+
tokenOut: quote.tokenOut,
|
|
1337
|
+
feeLimit: resolvedFeeLimit
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
async function planRouterSwap(context, input) {
|
|
1342
|
+
const { wallet, address: owner } = await requireWalletSnapshot(context, "Router swap plan");
|
|
1343
|
+
if (input.quote.kind === "wtrx") {
|
|
1344
|
+
if (!isWtrxRoute(input.route)) {
|
|
1345
|
+
throw new import_sun_sdk_core17.SDKError("SDK_INVALID_ARGUMENT", "WTRX swap planning requires a WTRX route");
|
|
1346
|
+
}
|
|
1347
|
+
return buildWtrxSwapPlan(context, input.quote, input.route, owner, input.feeLimit);
|
|
1348
|
+
}
|
|
1349
|
+
const selectedRouteIndex = findSelectedRouteIndex(input.quote, input.route);
|
|
1350
|
+
if (selectedRouteIndex < 0) {
|
|
1351
|
+
throw new import_sun_sdk_core17.SDKError("SDK_INVALID_ARGUMENT", "Selected route must come from quote.routes", {
|
|
1352
|
+
routeCount: input.quote.routes.length,
|
|
1353
|
+
tokenIn: input.quote.tokenIn,
|
|
1354
|
+
tokenOut: input.quote.tokenOut,
|
|
1355
|
+
amountIn: input.quote.amountIn
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
const selectedRoute = input.quote.routes[selectedRouteIndex];
|
|
1359
|
+
if (!selectedRoute) {
|
|
1360
|
+
throw new import_sun_sdk_core17.SDKError("SDK_RUNTIME_ERROR", "Selected router route could not be resolved after validation", {
|
|
1361
|
+
selectedRouteIndex,
|
|
1362
|
+
routeCount: input.quote.routes.length
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
const symbols = routerRouteSymbols(selectedRoute);
|
|
1366
|
+
const intentScope = swapIntentScope(UNIVERSAL_ROUTER_PROTOCOL_ID);
|
|
1367
|
+
const recipient = await normalizeRecipient(context, input.recipient, "Router swap recipient", owner);
|
|
1368
|
+
const transactionValidForSeconds = normalizeTransactionValidForSeconds(input.transactionValidForSeconds);
|
|
1369
|
+
const slippageBips = slippageToBips(input.slippage ?? "0.5%");
|
|
1370
|
+
const feeLimit = normalizeFeeLimit(input.feeLimit, DEFAULT_UNIVERSAL_ROUTER_SWAP_FEE_LIMIT);
|
|
1371
|
+
const tokenIn = input.quote.tokenIn;
|
|
1372
|
+
const approvals = [];
|
|
1373
|
+
let signatureActionId;
|
|
1374
|
+
let permitSingle;
|
|
1375
|
+
if (!isNativeTrxToken(context, tokenIn)) {
|
|
1376
|
+
const authorization = await planRouterPermit2Authorization(context, {
|
|
1377
|
+
owner,
|
|
1378
|
+
token: (0, import_sun_sdk_core17.assertTronAddress)(tokenIn, "tokenIn"),
|
|
1379
|
+
amount: input.quote.amountIn,
|
|
1380
|
+
approval: input.approval ?? "auto",
|
|
1381
|
+
approveAmountType: "max",
|
|
1382
|
+
walletCapabilities: wallet.capabilities
|
|
1383
|
+
});
|
|
1384
|
+
approvals.push(...attachApprovalIntent(authorization.actions, intentScope, symbols.from));
|
|
1385
|
+
signatureActionId = authorization.signatureActionId;
|
|
1386
|
+
permitSingle = authorization.permitSingle;
|
|
1387
|
+
}
|
|
1388
|
+
const transaction = createUniversalRouterDeferredAction({
|
|
1389
|
+
id: `${nextPlanId(context, "swap-router")}-execute`,
|
|
1390
|
+
data: {
|
|
1391
|
+
network: context.network,
|
|
1392
|
+
route: selectedRoute,
|
|
1393
|
+
slippageBips: slippageBips.toString(),
|
|
1394
|
+
transactionValidForSeconds,
|
|
1395
|
+
recipient,
|
|
1396
|
+
feeLimit,
|
|
1397
|
+
...signatureActionId ? { signatureActionId } : {},
|
|
1398
|
+
...permitSingle ? { permitSingle } : {}
|
|
1399
|
+
},
|
|
1400
|
+
intent: {
|
|
1401
|
+
kind: "swap",
|
|
1402
|
+
scope: intentScope,
|
|
1403
|
+
from: { value: selectedRoute.amountIn, symbol: symbols.from },
|
|
1404
|
+
to: { value: selectedRoute.amountOut, symbol: symbols.to },
|
|
1405
|
+
...input.recipient === void 0 ? {} : { recipient }
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
return {
|
|
1409
|
+
id: nextPlanId(context, "swap-router"),
|
|
1410
|
+
kind: "swap",
|
|
1411
|
+
network: context.network,
|
|
1412
|
+
owner,
|
|
1413
|
+
summary: {
|
|
1414
|
+
title: "Swap with Universal Router",
|
|
1415
|
+
lines: [`Spend ${selectedRoute.amountIn}`, `Expected output ${selectedRoute.amountOut}`]
|
|
1416
|
+
},
|
|
1417
|
+
approvals,
|
|
1418
|
+
transactions: [transaction],
|
|
1419
|
+
metadata: {
|
|
1420
|
+
protocol: "universal-router",
|
|
1421
|
+
selectedRouteIndex,
|
|
1422
|
+
tokenIn: input.quote.tokenIn,
|
|
1423
|
+
tokenOut: input.quote.tokenOut,
|
|
1424
|
+
amountIn: selectedRoute.amountInRaw,
|
|
1425
|
+
amountOut: selectedRoute.amountOutRaw,
|
|
1426
|
+
amountInFormatted: selectedRoute.amountIn,
|
|
1427
|
+
amountOutFormatted: selectedRoute.amountOut,
|
|
1428
|
+
slippageBips,
|
|
1429
|
+
recipient,
|
|
1430
|
+
transactionValidForSeconds,
|
|
1431
|
+
feeLimit
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// src/swap/quote.ts
|
|
1437
|
+
var import_sun_sdk_core18 = require("@sun-protocol/sun-sdk-core");
|
|
1438
|
+
function requireRoutes(response) {
|
|
1439
|
+
if (response.code !== 0) {
|
|
1440
|
+
throw new import_sun_sdk_core18.SDKError("SDK_NO_ROUTE", response.message ?? "Router API returned no route", {
|
|
1441
|
+
code: response.code,
|
|
1442
|
+
message: response.message
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
if (!Array.isArray(response.data) || response.data.length === 0) {
|
|
1446
|
+
throw new import_sun_sdk_core18.SDKError("SDK_NO_ROUTE", "Router API returned no route", {
|
|
1447
|
+
code: response.code
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
return response.data;
|
|
1451
|
+
}
|
|
1452
|
+
function normalizeRouteTypeList(input) {
|
|
1453
|
+
if (input.routerRouteTypes !== void 0 && input.typeList !== void 0) {
|
|
1454
|
+
throw new import_sun_sdk_core18.SDKError("SDK_INVALID_ARGUMENT", "Use routerRouteTypes or typeList, not both", {
|
|
1455
|
+
routerRouteTypes: input.routerRouteTypes,
|
|
1456
|
+
typeList: input.typeList
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
return input.routerRouteTypes !== void 0 ? input.routerRouteTypes.join(",") : input.typeList;
|
|
1460
|
+
}
|
|
1461
|
+
function requireRouterAmountString(route, field, routeIndex) {
|
|
1462
|
+
const value = route[field];
|
|
1463
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1464
|
+
throw new import_sun_sdk_core18.SDKError("SDK_API_ERROR", `Router route has invalid ${field}`, {
|
|
1465
|
+
routeIndex,
|
|
1466
|
+
field,
|
|
1467
|
+
value
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
return value;
|
|
1471
|
+
}
|
|
1472
|
+
function normalizeRouterRawAmount(value, field, routeIndex) {
|
|
1473
|
+
try {
|
|
1474
|
+
return normalizeBaseUnitAmount(value, `Router route ${field}`);
|
|
1475
|
+
} catch {
|
|
1476
|
+
throw new import_sun_sdk_core18.SDKError("SDK_API_ERROR", `Router route has invalid ${field}`, {
|
|
1477
|
+
routeIndex,
|
|
1478
|
+
field,
|
|
1479
|
+
value
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
function validateRouterRoute(route, routeIndex, requestedAmountIn) {
|
|
1484
|
+
if (typeof route !== "object" || route === null || Array.isArray(route)) {
|
|
1485
|
+
throw new import_sun_sdk_core18.SDKError("SDK_API_ERROR", "Router route must be an object", {
|
|
1486
|
+
routeIndex,
|
|
1487
|
+
route
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
const routeRecord = route;
|
|
1491
|
+
const amountIn = requireRouterAmountString(routeRecord, "amountIn", routeIndex);
|
|
1492
|
+
const amountOut = requireRouterAmountString(routeRecord, "amountOut", routeIndex);
|
|
1493
|
+
const amountInRaw = normalizeRouterRawAmount(
|
|
1494
|
+
requireRouterAmountString(routeRecord, "amountInRaw", routeIndex),
|
|
1495
|
+
"amountInRaw",
|
|
1496
|
+
routeIndex
|
|
1497
|
+
);
|
|
1498
|
+
const amountOutRaw = normalizeRouterRawAmount(
|
|
1499
|
+
requireRouterAmountString(routeRecord, "amountOutRaw", routeIndex),
|
|
1500
|
+
"amountOutRaw",
|
|
1501
|
+
routeIndex
|
|
1502
|
+
);
|
|
1503
|
+
if (amountInRaw !== requestedAmountIn) {
|
|
1504
|
+
throw new import_sun_sdk_core18.SDKError("SDK_API_ERROR", "Router route input amount does not match the request", {
|
|
1505
|
+
routeIndex,
|
|
1506
|
+
requestedAmountIn,
|
|
1507
|
+
routeAmountInRaw: amountInRaw
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
return {
|
|
1511
|
+
...routeRecord,
|
|
1512
|
+
amountIn,
|
|
1513
|
+
amountInRaw,
|
|
1514
|
+
amountOut,
|
|
1515
|
+
amountOutRaw
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
async function quoteRouterSwap(context, input) {
|
|
1519
|
+
const wtrxQuote = detectWtrxSwap(context, input);
|
|
1520
|
+
if (wtrxQuote) return wtrxQuote;
|
|
1521
|
+
const amountIn = normalizeBaseUnitAmount(input.amountIn, "amountIn");
|
|
1522
|
+
const typeList = normalizeRouteTypeList(input);
|
|
1523
|
+
const routerEndpoint = context.endpoints.router;
|
|
1524
|
+
if (!routerEndpoint) {
|
|
1525
|
+
throw new import_sun_sdk_core18.SDKError("SDK_UNSUPPORTED_NETWORK", "Router API endpoint is not configured for this network", {
|
|
1526
|
+
network: context.network
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
const routesResponse = await context.routerApi.getRoutes(routerEndpoint, {
|
|
1530
|
+
fromToken: normalizeRouterToken(context, input.tokenIn),
|
|
1531
|
+
toToken: normalizeRouterToken(context, input.tokenOut),
|
|
1532
|
+
amountIn,
|
|
1533
|
+
...typeList !== void 0 ? { typeList } : {},
|
|
1534
|
+
...input.includeUnverifiedV4Hook !== void 0 ? { includeUnverifiedV4Hook: input.includeUnverifiedV4Hook } : {}
|
|
1535
|
+
});
|
|
1536
|
+
const routes = requireRoutes(routesResponse).map((route, routeIndex) => validateRouterRoute(route, routeIndex, amountIn));
|
|
1537
|
+
const bestRoute = routes[0];
|
|
1538
|
+
if (!bestRoute) {
|
|
1539
|
+
throw new import_sun_sdk_core18.SDKError("SDK_NO_ROUTE", "Router API returned no route");
|
|
1540
|
+
}
|
|
1541
|
+
return {
|
|
1542
|
+
kind: "router",
|
|
1543
|
+
source: "router",
|
|
1544
|
+
tokenIn: input.tokenIn,
|
|
1545
|
+
tokenOut: input.tokenOut,
|
|
1546
|
+
amountIn: bestRoute.amountInRaw,
|
|
1547
|
+
amountOut: bestRoute.amountOutRaw,
|
|
1548
|
+
amountInFormatted: bestRoute.amountIn,
|
|
1549
|
+
amountOutFormatted: bestRoute.amountOut,
|
|
1550
|
+
routes,
|
|
1551
|
+
bestRoute
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
var quoteSwap = quoteRouterSwap;
|
|
1555
|
+
|
|
1556
|
+
// src/swap/workflow.ts
|
|
1557
|
+
var import_sun_sdk_core19 = require("@sun-protocol/sun-sdk-core");
|
|
1558
|
+
function assertSwapPlan(plan, protocols, clientName) {
|
|
1559
|
+
const protocol = plan.metadata.protocol;
|
|
1560
|
+
if (plan.kind !== "swap" || typeof protocol !== "string" || !protocols.includes(protocol) || plan.transactions.length === 0) {
|
|
1561
|
+
throw new import_sun_sdk_core19.SDKError("SDK_INVALID_ARGUMENT", `Expected a ${clientName} swap plan`, {
|
|
1562
|
+
planId: plan.id,
|
|
1563
|
+
kind: plan.kind,
|
|
1564
|
+
protocol,
|
|
1565
|
+
transactionCount: plan.transactions.length
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// src/swap/router.ts
|
|
1571
|
+
var SwapRouterClient = class {
|
|
1572
|
+
constructor(context) {
|
|
1573
|
+
this.context = context;
|
|
1574
|
+
}
|
|
1575
|
+
context;
|
|
1576
|
+
quote(input) {
|
|
1577
|
+
return quoteRouterSwap(this.context, input);
|
|
1578
|
+
}
|
|
1579
|
+
plan(input) {
|
|
1580
|
+
return planRouterSwap(this.context, input);
|
|
1581
|
+
}
|
|
1582
|
+
executeAction(action) {
|
|
1583
|
+
return executePlanAction(action, createRouterSwapExecutor(this.context));
|
|
1584
|
+
}
|
|
1585
|
+
async submit(plan, options = {}) {
|
|
1586
|
+
assertSwapPlan(plan, ["universal-router", "wtrx"], "Router");
|
|
1587
|
+
return executePlanTransactions(
|
|
1588
|
+
plan,
|
|
1589
|
+
createRouterSwapExecutor(this.context, options)
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
async execute(input) {
|
|
1593
|
+
const plan = isTransactionPlan(input) ? input : await planRouterSwap(this.context, input);
|
|
1594
|
+
assertSwapPlan(plan, ["universal-router", "wtrx"], "Router");
|
|
1595
|
+
return executeTransactionPlan(plan, createRouterSwapExecutor(this.context));
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
function createSwapRouterClient(options) {
|
|
1599
|
+
return new SwapRouterClient(createProtocolsContext(options));
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
// src/internal/v2-swap-action.ts
|
|
1603
|
+
var import_sun_sdk_sunswap_v22 = require("@sun-protocol/sun-sdk-sunswap-v2");
|
|
1604
|
+
var import_sun_sdk_core20 = require("@sun-protocol/sun-sdk-core");
|
|
1605
|
+
var V2_SWAP_MATERIALIZATION_KIND = "sunswap-v2-swap";
|
|
1606
|
+
function requireAmount(data, key) {
|
|
1607
|
+
const value = data[key];
|
|
1608
|
+
if (value === void 0) {
|
|
1609
|
+
throw new import_sun_sdk_core20.SDKError("SDK_RUNTIME_ERROR", `Deferred V2 swap is missing ${key}`, {
|
|
1610
|
+
operation: data.operation,
|
|
1611
|
+
key
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
return value;
|
|
1615
|
+
}
|
|
1616
|
+
function createDeferredV2SwapAction(input) {
|
|
1617
|
+
return (0, import_sun_sdk_core20.createDeferredContractCallAction)({
|
|
1618
|
+
id: `sunswap-v2-${input.data.operation}`,
|
|
1619
|
+
materialization: {
|
|
1620
|
+
kind: V2_SWAP_MATERIALIZATION_KIND,
|
|
1621
|
+
data: input.data
|
|
1622
|
+
}
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
async function materializeV2SwapAction(context, action) {
|
|
1626
|
+
if (action.materialization.kind !== V2_SWAP_MATERIALIZATION_KIND) {
|
|
1627
|
+
throw new import_sun_sdk_core20.SDKError("SDK_RUNTIME_ERROR", `Unsupported deferred action kind: ${action.materialization.kind}`);
|
|
1628
|
+
}
|
|
1629
|
+
const data = action.materialization.data;
|
|
1630
|
+
const options = {
|
|
1631
|
+
network: context.network,
|
|
1632
|
+
id: action.id,
|
|
1633
|
+
path: data.path,
|
|
1634
|
+
recipient: data.recipient,
|
|
1635
|
+
deadline: await resolveTransactionDeadline(context, data.transactionValidForSeconds)
|
|
1636
|
+
};
|
|
1637
|
+
switch (data.operation) {
|
|
1638
|
+
case "swap-exact-eth-for-tokens":
|
|
1639
|
+
return (0, import_sun_sdk_sunswap_v22.buildV2SwapExactEthForTokensAction)({
|
|
1640
|
+
...options,
|
|
1641
|
+
amountIn: requireAmount(data, "amountIn"),
|
|
1642
|
+
amountOutMin: requireAmount(data, "amountOutMin")
|
|
1643
|
+
});
|
|
1644
|
+
case "swap-eth-for-exact-tokens":
|
|
1645
|
+
return (0, import_sun_sdk_sunswap_v22.buildV2SwapEthForExactTokensAction)({
|
|
1646
|
+
...options,
|
|
1647
|
+
amountOut: requireAmount(data, "amountOut"),
|
|
1648
|
+
amountInMax: requireAmount(data, "amountInMax")
|
|
1649
|
+
});
|
|
1650
|
+
case "swap-exact-tokens-for-eth":
|
|
1651
|
+
return (0, import_sun_sdk_sunswap_v22.buildV2SwapExactTokensForEthAction)({
|
|
1652
|
+
...options,
|
|
1653
|
+
amountIn: requireAmount(data, "amountIn"),
|
|
1654
|
+
amountOutMin: requireAmount(data, "amountOutMin")
|
|
1655
|
+
});
|
|
1656
|
+
case "swap-exact-tokens-for-tokens":
|
|
1657
|
+
return (0, import_sun_sdk_sunswap_v22.buildV2SwapExactTokensForTokensAction)({
|
|
1658
|
+
...options,
|
|
1659
|
+
amountIn: requireAmount(data, "amountIn"),
|
|
1660
|
+
amountOutMin: requireAmount(data, "amountOutMin")
|
|
1661
|
+
});
|
|
1662
|
+
case "swap-tokens-for-exact-eth":
|
|
1663
|
+
return (0, import_sun_sdk_sunswap_v22.buildV2SwapTokensForExactEthAction)({
|
|
1664
|
+
...options,
|
|
1665
|
+
amountOut: requireAmount(data, "amountOut"),
|
|
1666
|
+
amountInMax: requireAmount(data, "amountInMax")
|
|
1667
|
+
});
|
|
1668
|
+
case "swap-tokens-for-exact-tokens":
|
|
1669
|
+
return (0, import_sun_sdk_sunswap_v22.buildV2SwapTokensForExactTokensAction)({
|
|
1670
|
+
...options,
|
|
1671
|
+
amountOut: requireAmount(data, "amountOut"),
|
|
1672
|
+
amountInMax: requireAmount(data, "amountInMax")
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
// src/swap/v2-execute.ts
|
|
1678
|
+
function createV2SwapExecutor(context) {
|
|
1679
|
+
return {
|
|
1680
|
+
...createContextExecutor(context),
|
|
1681
|
+
materializeAction: (action) => materializeV2SwapAction(context, action)
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
// src/swap/psm.ts
|
|
1686
|
+
var import_sun_sdk_psm = require("@sun-protocol/sun-sdk-psm");
|
|
1687
|
+
var import_sun_sdk_core22 = require("@sun-protocol/sun-sdk-core");
|
|
1688
|
+
|
|
1689
|
+
// src/internal/reads.ts
|
|
1690
|
+
var import_sun_sdk_core21 = require("@sun-protocol/sun-sdk-core");
|
|
1691
|
+
async function readRequiredContract(context, call, operation) {
|
|
1692
|
+
const runtime = requireRuntime(context, operation);
|
|
1693
|
+
const value = await runtime.readContract(call);
|
|
1694
|
+
if (value === void 0 || value === null) {
|
|
1695
|
+
throw new import_sun_sdk_core21.SDKError("SDK_CONTRACT_ERROR", `${operation} returned an empty result`, { call });
|
|
1696
|
+
}
|
|
1697
|
+
return value;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
// src/swap/psm.ts
|
|
1701
|
+
function normalizePsmApprovalMode(value) {
|
|
1702
|
+
if (value === void 0) return "auto";
|
|
1703
|
+
if (value === "auto" || value === "approve" || value === "none") return value;
|
|
1704
|
+
throw new import_sun_sdk_core22.SDKError("SDK_INVALID_ARGUMENT", "unsupported PSM approval mode", {
|
|
1705
|
+
approval: value
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
function resolvePsmContracts(context, overrides) {
|
|
1709
|
+
return {
|
|
1710
|
+
psmUsdt: resolveProtocolContract(context, overrides, "psmUsdt"),
|
|
1711
|
+
psmUsdd: resolveProtocolContract(context, overrides, "psmUsdd"),
|
|
1712
|
+
psm: resolveProtocolContract(context, overrides, "psm"),
|
|
1713
|
+
psmGemJoin: resolveProtocolContract(context, overrides, "psmGemJoin"),
|
|
1714
|
+
psmInfoReader: resolveProtocolContract(context, overrides, "psmInfoReader")
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
function invalidAmountShape(mode) {
|
|
1718
|
+
throw new import_sun_sdk_core22.SDKError(
|
|
1719
|
+
"SDK_INVALID_ARGUMENT",
|
|
1720
|
+
mode === "exact-in" ? "exact-in PSM swap requires only amountIn" : "exact-out PSM swap requires only amountOut",
|
|
1721
|
+
{ mode }
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
function normalizeSpecifiedAmount(value, label) {
|
|
1725
|
+
if (typeof value !== "string") {
|
|
1726
|
+
throw new import_sun_sdk_core22.SDKError("SDK_INVALID_ARGUMENT", `${label} must be a string`, {
|
|
1727
|
+
[label]: value
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
return normalizeBaseUnitAmount(value, label);
|
|
1731
|
+
}
|
|
1732
|
+
function normalizeQuoteInput(context, input) {
|
|
1733
|
+
const mode = input.mode ?? "exact-in";
|
|
1734
|
+
let specifiedAmount;
|
|
1735
|
+
if (mode === "exact-in") {
|
|
1736
|
+
if (input.amountIn === void 0 || input.amountOut !== void 0) return invalidAmountShape(mode);
|
|
1737
|
+
specifiedAmount = normalizeSpecifiedAmount(input.amountIn, "amountIn");
|
|
1738
|
+
} else if (mode === "exact-out") {
|
|
1739
|
+
if (input.amountOut === void 0 || input.amountIn !== void 0) return invalidAmountShape(mode);
|
|
1740
|
+
specifiedAmount = normalizeSpecifiedAmount(input.amountOut, "amountOut");
|
|
1741
|
+
} else {
|
|
1742
|
+
throw new import_sun_sdk_core22.SDKError("SDK_INVALID_ARGUMENT", "unsupported PSM quote mode", { mode });
|
|
1743
|
+
}
|
|
1744
|
+
const tokenIn = (0, import_sun_sdk_core22.assertTronAddress)(input.tokenIn, "tokenIn");
|
|
1745
|
+
const tokenOut = (0, import_sun_sdk_core22.assertTronAddress)(input.tokenOut, "tokenOut");
|
|
1746
|
+
const { psmUsdt, psmUsdd } = resolvePsmContracts(context, input.contracts);
|
|
1747
|
+
let direction;
|
|
1748
|
+
if (tokenIn === psmUsdt && tokenOut === psmUsdd) {
|
|
1749
|
+
direction = "usdt-to-usdd";
|
|
1750
|
+
} else if (tokenIn === psmUsdd && tokenOut === psmUsdt) {
|
|
1751
|
+
direction = "usdd-to-usdt";
|
|
1752
|
+
} else {
|
|
1753
|
+
throw new import_sun_sdk_core22.SDKError("SDK_INVALID_ARGUMENT", "PSM swap only supports its configured USDT/USDD pair", {
|
|
1754
|
+
tokenIn,
|
|
1755
|
+
tokenOut,
|
|
1756
|
+
psmUsdt,
|
|
1757
|
+
psmUsdd
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
return { mode, direction, specifiedAmount, tokenIn, tokenOut };
|
|
1761
|
+
}
|
|
1762
|
+
async function readPsm(context, input = {}) {
|
|
1763
|
+
const contracts = resolvePsmContracts(context, input.contracts);
|
|
1764
|
+
const result = await readRequiredContract(
|
|
1765
|
+
context,
|
|
1766
|
+
(0, import_sun_sdk_psm.buildPsmInfoRead)({
|
|
1767
|
+
network: context.network,
|
|
1768
|
+
psm: contracts.psm,
|
|
1769
|
+
infoReader: contracts.psmInfoReader
|
|
1770
|
+
}),
|
|
1771
|
+
"PSM info read"
|
|
1772
|
+
);
|
|
1773
|
+
return (0, import_sun_sdk_psm.createPsmSnapshot)((0, import_sun_sdk_psm.normalizePsmInfoResult)(result));
|
|
1774
|
+
}
|
|
1775
|
+
async function quotePsmSwap(context, input) {
|
|
1776
|
+
const normalized = normalizeQuoteInput(context, input);
|
|
1777
|
+
const snapshot = await readPsm(context, input);
|
|
1778
|
+
return {
|
|
1779
|
+
...(0, import_sun_sdk_psm.quotePsm)({
|
|
1780
|
+
mode: normalized.mode,
|
|
1781
|
+
direction: normalized.direction,
|
|
1782
|
+
specifiedAmount: normalized.specifiedAmount,
|
|
1783
|
+
snapshot
|
|
1784
|
+
}),
|
|
1785
|
+
kind: "psm",
|
|
1786
|
+
source: "psm",
|
|
1787
|
+
tokenIn: normalized.tokenIn,
|
|
1788
|
+
tokenOut: normalized.tokenOut
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
async function planPsmSwap(context, input) {
|
|
1792
|
+
const { address: owner } = await requireWalletSnapshot(context, "PSM swap plan");
|
|
1793
|
+
const feeLimit = normalizeFeeLimit(input.feeLimit, DEFAULT_PSM_SWAP_FEE_LIMIT);
|
|
1794
|
+
const quote = await quotePsmSwap(context, input);
|
|
1795
|
+
const recipient = input.recipient !== void 0 ? (0, import_sun_sdk_core22.assertTronAddress)(input.recipient, "PSM recipient") : owner;
|
|
1796
|
+
const contracts = resolvePsmContracts(context, input.contracts);
|
|
1797
|
+
const tokenIn = quote.direction === "usdt-to-usdd" ? contracts.psmUsdt : contracts.psmUsdd;
|
|
1798
|
+
const spender = quote.direction === "usdt-to-usdd" ? contracts.psmGemJoin : contracts.psm;
|
|
1799
|
+
const approvalMode = normalizePsmApprovalMode(input.approval);
|
|
1800
|
+
const approval = await planApproval(context, {
|
|
1801
|
+
asset: { type: "token", token: tokenIn },
|
|
1802
|
+
owner,
|
|
1803
|
+
spender,
|
|
1804
|
+
amount: quote.amountIn
|
|
1805
|
+
}, {
|
|
1806
|
+
mode: approvalMode,
|
|
1807
|
+
amount: "max",
|
|
1808
|
+
feeLimit: DEFAULT_PSM_APPROVAL_FEE_LIMIT
|
|
1809
|
+
});
|
|
1810
|
+
const inputSymbol = quote.direction === "usdt-to-usdd" ? "USDT" : "USDD";
|
|
1811
|
+
const outputSymbol = quote.direction === "usdt-to-usdd" ? "USDD" : "USDT";
|
|
1812
|
+
const inputDecimals = quote.direction === "usdt-to-usdd" ? 6 : 18;
|
|
1813
|
+
const outputDecimals = quote.direction === "usdt-to-usdd" ? 18 : 6;
|
|
1814
|
+
const intentScope = swapIntentScope(PSM_PROTOCOL_ID, quote.direction);
|
|
1815
|
+
const planId = nextPlanId(context, "swap-psm");
|
|
1816
|
+
const actionOptions = {
|
|
1817
|
+
network: context.network,
|
|
1818
|
+
psm: contracts.psm,
|
|
1819
|
+
recipient,
|
|
1820
|
+
gemAmount: quote.gemAmount,
|
|
1821
|
+
feeLimit,
|
|
1822
|
+
id: `${planId}-swap`
|
|
1823
|
+
};
|
|
1824
|
+
const transactionAction = quote.direction === "usdt-to-usdd" ? (0, import_sun_sdk_psm.buildPsmSellGemAction)(actionOptions) : (0, import_sun_sdk_psm.buildPsmBuyGemAction)(actionOptions);
|
|
1825
|
+
const transaction = {
|
|
1826
|
+
...transactionAction,
|
|
1827
|
+
intent: {
|
|
1828
|
+
kind: "swap",
|
|
1829
|
+
scope: intentScope,
|
|
1830
|
+
from: { value: (0, import_sun_sdk_core22.formatUnits)(BigInt(quote.amountIn), inputDecimals), symbol: inputSymbol },
|
|
1831
|
+
to: { value: (0, import_sun_sdk_core22.formatUnits)(BigInt(quote.amountOut), outputDecimals), symbol: outputSymbol },
|
|
1832
|
+
...input.recipient === void 0 ? {} : { recipient }
|
|
1833
|
+
}
|
|
1834
|
+
};
|
|
1835
|
+
return {
|
|
1836
|
+
id: planId,
|
|
1837
|
+
kind: "swap",
|
|
1838
|
+
network: context.network,
|
|
1839
|
+
owner,
|
|
1840
|
+
summary: {
|
|
1841
|
+
title: "Swap with PSM",
|
|
1842
|
+
lines: [
|
|
1843
|
+
`Spend ${quote.amountIn} token units`,
|
|
1844
|
+
`Receive ${quote.amountOut} token units`
|
|
1845
|
+
]
|
|
1846
|
+
},
|
|
1847
|
+
approvals: attachApprovalIntent(approval.actions, intentScope, inputSymbol),
|
|
1848
|
+
transactions: [transaction],
|
|
1849
|
+
metadata: {
|
|
1850
|
+
protocol: "psm",
|
|
1851
|
+
mode: quote.mode,
|
|
1852
|
+
direction: quote.direction,
|
|
1853
|
+
amountIn: quote.amountIn,
|
|
1854
|
+
amountOut: quote.amountOut,
|
|
1855
|
+
specifiedAmount: quote.specifiedAmount,
|
|
1856
|
+
gemAmount: quote.gemAmount,
|
|
1857
|
+
feeAmount: quote.feeAmount,
|
|
1858
|
+
feeRate: quote.feeRate,
|
|
1859
|
+
availableAmountOut: quote.availableAmountOut,
|
|
1860
|
+
owner,
|
|
1861
|
+
recipient,
|
|
1862
|
+
spender,
|
|
1863
|
+
approvalMode
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1867
|
+
var PsmSwapClient = class {
|
|
1868
|
+
constructor(context) {
|
|
1869
|
+
this.context = context;
|
|
1870
|
+
}
|
|
1871
|
+
context;
|
|
1872
|
+
read(input = {}) {
|
|
1873
|
+
return readPsm(this.context, input);
|
|
1874
|
+
}
|
|
1875
|
+
quote(input) {
|
|
1876
|
+
return quotePsmSwap(this.context, input);
|
|
1877
|
+
}
|
|
1878
|
+
plan(input) {
|
|
1879
|
+
return planPsmSwap(this.context, input);
|
|
1880
|
+
}
|
|
1881
|
+
executeAction(action) {
|
|
1882
|
+
return executePlanAction(action, createContextExecutor(this.context));
|
|
1883
|
+
}
|
|
1884
|
+
submit(plan) {
|
|
1885
|
+
assertSwapPlan(plan, ["psm"], "PSM");
|
|
1886
|
+
return executePlanTransactions(plan, createContextExecutor(this.context));
|
|
1887
|
+
}
|
|
1888
|
+
async execute(input) {
|
|
1889
|
+
const plan = isTransactionPlan(input) ? input : await planPsmSwap(this.context, input);
|
|
1890
|
+
assertSwapPlan(plan, ["psm"], "PSM");
|
|
1891
|
+
return executeTransactionPlan(plan, createContextExecutor(this.context));
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
function createPsmSwapClient(context) {
|
|
1895
|
+
return new PsmSwapClient(context);
|
|
1896
|
+
}
|
|
1897
|
+
function createPsmClient(options) {
|
|
1898
|
+
return createPsmSwapClient(createProtocolsContext(options));
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// src/swap/v2.ts
|
|
1902
|
+
var import_sun_sdk_sunswap_v23 = require("@sun-protocol/sun-sdk-sunswap-v2");
|
|
1903
|
+
var import_sun_sdk_core23 = require("@sun-protocol/sun-sdk-core");
|
|
1904
|
+
function normalizeV2Mode(input) {
|
|
1905
|
+
const mode = input.mode ?? "exact-in";
|
|
1906
|
+
if (mode === "exact-in") {
|
|
1907
|
+
normalizeBaseUnitAmount(input.amountIn ?? "", "amountIn");
|
|
1908
|
+
if (input.amountOut !== void 0) {
|
|
1909
|
+
throw new import_sun_sdk_core23.SDKError("SDK_INVALID_ARGUMENT", "exact-in V2 swap does not accept amountOut");
|
|
1910
|
+
}
|
|
1911
|
+
return mode;
|
|
1912
|
+
}
|
|
1913
|
+
normalizeBaseUnitAmount(input.amountOut ?? "", "amountOut");
|
|
1914
|
+
if (input.amountIn !== void 0) {
|
|
1915
|
+
throw new import_sun_sdk_core23.SDKError("SDK_INVALID_ARGUMENT", "exact-out V2 swap does not accept amountIn");
|
|
1916
|
+
}
|
|
1917
|
+
return mode;
|
|
1918
|
+
}
|
|
1919
|
+
function requireAmount2(amounts, index, operation) {
|
|
1920
|
+
const amount = amounts[index];
|
|
1921
|
+
if (amount === void 0) {
|
|
1922
|
+
throw new import_sun_sdk_core23.SDKError("SDK_CONTRACT_ERROR", "V2 router returned an incomplete amount path", {
|
|
1923
|
+
operation,
|
|
1924
|
+
amounts
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
return amount;
|
|
1928
|
+
}
|
|
1929
|
+
function requireAmountPath(amounts, path, operation) {
|
|
1930
|
+
if (amounts.length !== path.length) {
|
|
1931
|
+
throw new import_sun_sdk_core23.SDKError("SDK_CONTRACT_ERROR", "V2 router returned an incomplete amount path", {
|
|
1932
|
+
operation,
|
|
1933
|
+
amounts,
|
|
1934
|
+
path
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
function normalizeAllowedTradingPairResult(result) {
|
|
1939
|
+
if (typeof result === "boolean") return result;
|
|
1940
|
+
if (Array.isArray(result) && typeof result[0] === "boolean") return result[0];
|
|
1941
|
+
return Boolean(result);
|
|
1942
|
+
}
|
|
1943
|
+
async function assertV2PathAllowed(context, path) {
|
|
1944
|
+
const runtime = requireRuntime(context, "V2 allowed trading pair check");
|
|
1945
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
1946
|
+
const tokenA = (0, import_sun_sdk_core23.assertTronAddress)(path[index] ?? "", `path[${index}]`);
|
|
1947
|
+
const tokenB = (0, import_sun_sdk_core23.assertTronAddress)(path[index + 1] ?? "", `path[${index + 1}]`);
|
|
1948
|
+
const allowed = normalizeAllowedTradingPairResult(await runtime.readContract((0, import_sun_sdk_sunswap_v23.buildV2RouterAllowedTradingPairRead)({
|
|
1949
|
+
network: context.network,
|
|
1950
|
+
tokenA,
|
|
1951
|
+
tokenB
|
|
1952
|
+
})));
|
|
1953
|
+
if (!allowed) {
|
|
1954
|
+
throw new import_sun_sdk_core23.SDKError("SDK_NO_ROUTE", "SunSwap V2 router does not allow this trading pair", {
|
|
1955
|
+
operation: "v2-allowed-trading-pair-check",
|
|
1956
|
+
blockedPair: [tokenA, tokenB],
|
|
1957
|
+
path
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
async function quoteV2Swap(context, input) {
|
|
1963
|
+
const runtime = requireRuntime(context, "V2 swap quote");
|
|
1964
|
+
const mode = normalizeV2Mode(input);
|
|
1965
|
+
const pathInfo = normalizeV2SwapPath(context, input);
|
|
1966
|
+
await assertV2PathAllowed(context, pathInfo.path);
|
|
1967
|
+
if (mode === "exact-in") {
|
|
1968
|
+
const amountIn = normalizeBaseUnitAmount(input.amountIn ?? "", "amountIn");
|
|
1969
|
+
const amounts2 = (0, import_sun_sdk_sunswap_v23.normalizeV2AmountsResult)(await runtime.readContract((0, import_sun_sdk_sunswap_v23.buildV2RouterAmountsOutRead)({
|
|
1970
|
+
network: context.network,
|
|
1971
|
+
amountIn,
|
|
1972
|
+
path: pathInfo.path
|
|
1973
|
+
})));
|
|
1974
|
+
requireAmountPath(amounts2, pathInfo.path, "v2-exact-in-quote");
|
|
1975
|
+
return {
|
|
1976
|
+
kind: "v2",
|
|
1977
|
+
source: "v2",
|
|
1978
|
+
mode,
|
|
1979
|
+
direction: pathInfo.direction,
|
|
1980
|
+
tokenIn: input.tokenIn,
|
|
1981
|
+
tokenOut: input.tokenOut,
|
|
1982
|
+
amountIn,
|
|
1983
|
+
amountOut: requireAmount2(amounts2, amounts2.length - 1, "v2-exact-in-quote"),
|
|
1984
|
+
path: pathInfo.path
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
const amountOut = normalizeBaseUnitAmount(input.amountOut ?? "", "amountOut");
|
|
1988
|
+
const amounts = (0, import_sun_sdk_sunswap_v23.normalizeV2AmountsResult)(await runtime.readContract((0, import_sun_sdk_sunswap_v23.buildV2RouterAmountsInRead)({
|
|
1989
|
+
network: context.network,
|
|
1990
|
+
amountOut,
|
|
1991
|
+
path: pathInfo.path
|
|
1992
|
+
})));
|
|
1993
|
+
requireAmountPath(amounts, pathInfo.path, "v2-exact-out-quote");
|
|
1994
|
+
return {
|
|
1995
|
+
kind: "v2",
|
|
1996
|
+
source: "v2",
|
|
1997
|
+
mode,
|
|
1998
|
+
direction: pathInfo.direction,
|
|
1999
|
+
tokenIn: input.tokenIn,
|
|
2000
|
+
tokenOut: input.tokenOut,
|
|
2001
|
+
amountIn: requireAmount2(amounts, 0, "v2-exact-out-quote"),
|
|
2002
|
+
amountOut,
|
|
2003
|
+
path: pathInfo.path
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
async function planV2Swap(context, input) {
|
|
2007
|
+
const { address: owner } = await requireWalletSnapshot(context, "V2 swap plan");
|
|
2008
|
+
const quote = await quoteV2Swap(context, input);
|
|
2009
|
+
const recipient = await normalizeRecipient(context, input.recipient, "V2 swap recipient", owner);
|
|
2010
|
+
const transactionValidForSeconds = normalizeTransactionValidForSeconds(input.transactionValidForSeconds);
|
|
2011
|
+
const slippageBips = slippageToBips(input.slippage ?? "0.5%");
|
|
2012
|
+
const approvals = [];
|
|
2013
|
+
if (quote.mode === "exact-in" && quote.direction === "trx-to-token") {
|
|
2014
|
+
const minAmountOut = applySlippageMin(BigInt(quote.amountOut), slippageBips).toString();
|
|
2015
|
+
const transaction2 = createDeferredV2SwapAction({
|
|
2016
|
+
data: {
|
|
2017
|
+
operation: "swap-exact-eth-for-tokens",
|
|
2018
|
+
amountIn: quote.amountIn,
|
|
2019
|
+
amountOutMin: minAmountOut,
|
|
2020
|
+
path: quote.path,
|
|
2021
|
+
recipient,
|
|
2022
|
+
transactionValidForSeconds
|
|
2023
|
+
}
|
|
2024
|
+
});
|
|
2025
|
+
return {
|
|
2026
|
+
id: nextPlanId(context, "swap-v2"),
|
|
2027
|
+
kind: "swap",
|
|
2028
|
+
network: context.network,
|
|
2029
|
+
owner,
|
|
2030
|
+
summary: {
|
|
2031
|
+
title: "Swap with SunSwap V2",
|
|
2032
|
+
lines: [`Spend ${quote.amountIn} sun`, `Receive at least ${minAmountOut} token units`]
|
|
2033
|
+
},
|
|
2034
|
+
approvals,
|
|
2035
|
+
transactions: [transaction2],
|
|
2036
|
+
metadata: {
|
|
2037
|
+
protocol: "sunswap-v2",
|
|
2038
|
+
mode: quote.mode,
|
|
2039
|
+
direction: quote.direction,
|
|
2040
|
+
amountIn: quote.amountIn,
|
|
2041
|
+
quotedAmountOut: quote.amountOut,
|
|
2042
|
+
minAmountOut,
|
|
2043
|
+
slippageBips,
|
|
2044
|
+
path: quote.path,
|
|
2045
|
+
recipient,
|
|
2046
|
+
transactionValidForSeconds
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
if (quote.mode === "exact-out" && quote.direction === "trx-to-token") {
|
|
2051
|
+
const maxAmountIn2 = applySlippageMax(BigInt(quote.amountIn), slippageBips).toString();
|
|
2052
|
+
const transaction2 = createDeferredV2SwapAction({
|
|
2053
|
+
data: {
|
|
2054
|
+
operation: "swap-eth-for-exact-tokens",
|
|
2055
|
+
amountOut: quote.amountOut,
|
|
2056
|
+
amountInMax: maxAmountIn2,
|
|
2057
|
+
path: quote.path,
|
|
2058
|
+
recipient,
|
|
2059
|
+
transactionValidForSeconds
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
return {
|
|
2063
|
+
id: nextPlanId(context, "swap-v2"),
|
|
2064
|
+
kind: "swap",
|
|
2065
|
+
network: context.network,
|
|
2066
|
+
owner,
|
|
2067
|
+
summary: {
|
|
2068
|
+
title: "Swap with SunSwap V2",
|
|
2069
|
+
lines: [`Spend at most ${maxAmountIn2} sun`, `Receive ${quote.amountOut} token units`]
|
|
2070
|
+
},
|
|
2071
|
+
approvals,
|
|
2072
|
+
transactions: [transaction2],
|
|
2073
|
+
metadata: {
|
|
2074
|
+
protocol: "sunswap-v2",
|
|
2075
|
+
mode: quote.mode,
|
|
2076
|
+
direction: quote.direction,
|
|
2077
|
+
amountOut: quote.amountOut,
|
|
2078
|
+
quotedAmountIn: quote.amountIn,
|
|
2079
|
+
maxAmountIn: maxAmountIn2,
|
|
2080
|
+
slippageBips,
|
|
2081
|
+
path: quote.path,
|
|
2082
|
+
recipient,
|
|
2083
|
+
transactionValidForSeconds
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
const tokenInputAmount = quote.mode === "exact-in" ? quote.amountIn : applySlippageMax(BigInt(quote.amountIn), slippageBips).toString();
|
|
2088
|
+
const approval = await planApproval(context, {
|
|
2089
|
+
asset: { type: "token", token: (0, import_sun_sdk_core23.assertTronAddress)(input.tokenIn, "tokenIn") },
|
|
2090
|
+
owner,
|
|
2091
|
+
spender: context.chain.contracts.sunswapV2Router,
|
|
2092
|
+
amount: tokenInputAmount
|
|
2093
|
+
}, {
|
|
2094
|
+
mode: input.approval ?? "auto",
|
|
2095
|
+
amount: "exact"
|
|
2096
|
+
});
|
|
2097
|
+
approvals.push(...approval.actions);
|
|
2098
|
+
if (quote.mode === "exact-in") {
|
|
2099
|
+
const minAmountOut = applySlippageMin(BigInt(quote.amountOut), slippageBips).toString();
|
|
2100
|
+
const transaction2 = quote.direction === "token-to-trx" ? createDeferredV2SwapAction({
|
|
2101
|
+
data: {
|
|
2102
|
+
operation: "swap-exact-tokens-for-eth",
|
|
2103
|
+
amountIn: quote.amountIn,
|
|
2104
|
+
amountOutMin: minAmountOut,
|
|
2105
|
+
path: quote.path,
|
|
2106
|
+
recipient,
|
|
2107
|
+
transactionValidForSeconds
|
|
2108
|
+
}
|
|
2109
|
+
}) : createDeferredV2SwapAction({
|
|
2110
|
+
data: {
|
|
2111
|
+
operation: "swap-exact-tokens-for-tokens",
|
|
2112
|
+
amountIn: quote.amountIn,
|
|
2113
|
+
amountOutMin: minAmountOut,
|
|
2114
|
+
path: quote.path,
|
|
2115
|
+
recipient,
|
|
2116
|
+
transactionValidForSeconds
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
2119
|
+
return {
|
|
2120
|
+
id: nextPlanId(context, "swap-v2"),
|
|
2121
|
+
kind: "swap",
|
|
2122
|
+
network: context.network,
|
|
2123
|
+
owner,
|
|
2124
|
+
summary: {
|
|
2125
|
+
title: "Swap with SunSwap V2",
|
|
2126
|
+
lines: [
|
|
2127
|
+
`Sell ${quote.amountIn} token units`,
|
|
2128
|
+
`Receive at least ${minAmountOut} ${quote.direction === "token-to-trx" ? "sun" : "token units"}`
|
|
2129
|
+
]
|
|
2130
|
+
},
|
|
2131
|
+
approvals,
|
|
2132
|
+
transactions: [transaction2],
|
|
2133
|
+
metadata: {
|
|
2134
|
+
protocol: "sunswap-v2",
|
|
2135
|
+
mode: quote.mode,
|
|
2136
|
+
direction: quote.direction,
|
|
2137
|
+
amountIn: quote.amountIn,
|
|
2138
|
+
quotedAmountOut: quote.amountOut,
|
|
2139
|
+
minAmountOut,
|
|
2140
|
+
slippageBips,
|
|
2141
|
+
approvalMode: input.approval ?? "auto",
|
|
2142
|
+
path: quote.path,
|
|
2143
|
+
recipient,
|
|
2144
|
+
transactionValidForSeconds,
|
|
2145
|
+
owner,
|
|
2146
|
+
spender: context.chain.contracts.sunswapV2Router
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
}
|
|
2150
|
+
const maxAmountIn = tokenInputAmount;
|
|
2151
|
+
const transaction = quote.direction === "token-to-trx" ? createDeferredV2SwapAction({
|
|
2152
|
+
data: {
|
|
2153
|
+
operation: "swap-tokens-for-exact-eth",
|
|
2154
|
+
amountOut: quote.amountOut,
|
|
2155
|
+
amountInMax: maxAmountIn,
|
|
2156
|
+
path: quote.path,
|
|
2157
|
+
recipient,
|
|
2158
|
+
transactionValidForSeconds
|
|
2159
|
+
}
|
|
2160
|
+
}) : createDeferredV2SwapAction({
|
|
2161
|
+
data: {
|
|
2162
|
+
operation: "swap-tokens-for-exact-tokens",
|
|
2163
|
+
amountOut: quote.amountOut,
|
|
2164
|
+
amountInMax: maxAmountIn,
|
|
2165
|
+
path: quote.path,
|
|
2166
|
+
recipient,
|
|
2167
|
+
transactionValidForSeconds
|
|
2168
|
+
}
|
|
2169
|
+
});
|
|
2170
|
+
return {
|
|
2171
|
+
id: nextPlanId(context, "swap-v2"),
|
|
2172
|
+
kind: "swap",
|
|
2173
|
+
network: context.network,
|
|
2174
|
+
owner,
|
|
2175
|
+
summary: {
|
|
2176
|
+
title: "Swap with SunSwap V2",
|
|
2177
|
+
lines: [
|
|
2178
|
+
`Spend at most ${maxAmountIn} token units`,
|
|
2179
|
+
`Receive ${quote.amountOut} ${quote.direction === "token-to-trx" ? "sun" : "token units"}`
|
|
2180
|
+
]
|
|
2181
|
+
},
|
|
2182
|
+
approvals,
|
|
2183
|
+
transactions: [transaction],
|
|
2184
|
+
metadata: {
|
|
2185
|
+
protocol: "sunswap-v2",
|
|
2186
|
+
mode: quote.mode,
|
|
2187
|
+
direction: quote.direction,
|
|
2188
|
+
amountOut: quote.amountOut,
|
|
2189
|
+
quotedAmountIn: quote.amountIn,
|
|
2190
|
+
maxAmountIn,
|
|
2191
|
+
slippageBips,
|
|
2192
|
+
approvalMode: input.approval ?? "auto",
|
|
2193
|
+
path: quote.path,
|
|
2194
|
+
recipient,
|
|
2195
|
+
transactionValidForSeconds,
|
|
2196
|
+
owner,
|
|
2197
|
+
spender: context.chain.contracts.sunswapV2Router
|
|
2198
|
+
}
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
var V2SwapClient = class {
|
|
2202
|
+
constructor(context) {
|
|
2203
|
+
this.context = context;
|
|
2204
|
+
}
|
|
2205
|
+
context;
|
|
2206
|
+
quote(_input) {
|
|
2207
|
+
return quoteV2Swap(this.context, _input);
|
|
2208
|
+
}
|
|
2209
|
+
plan(input) {
|
|
2210
|
+
return planV2Swap(this.context, input);
|
|
2211
|
+
}
|
|
2212
|
+
executeAction(action) {
|
|
2213
|
+
return executePlanAction(action, createV2SwapExecutor(this.context));
|
|
2214
|
+
}
|
|
2215
|
+
submit(plan) {
|
|
2216
|
+
assertSwapPlan(plan, ["sunswap-v2"], "SunSwap V2");
|
|
2217
|
+
return executePlanTransactions(plan, createV2SwapExecutor(this.context));
|
|
2218
|
+
}
|
|
2219
|
+
async execute(input) {
|
|
2220
|
+
const plan = isTransactionPlan(input) ? input : await planV2Swap(this.context, input);
|
|
2221
|
+
assertSwapPlan(plan, ["sunswap-v2"], "SunSwap V2");
|
|
2222
|
+
return executeTransactionPlan(plan, createV2SwapExecutor(this.context));
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
function createV2SwapClient(context) {
|
|
2226
|
+
return new V2SwapClient(context);
|
|
2227
|
+
}
|
|
2228
|
+
function createV2Client(options) {
|
|
2229
|
+
return createV2SwapClient(createProtocolsContext(options));
|
|
2230
|
+
}
|
|
2231
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2232
|
+
0 && (module.exports = {
|
|
2233
|
+
PSM_PROTOCOL_ID,
|
|
2234
|
+
PsmSwapClient,
|
|
2235
|
+
SwapRouterClient,
|
|
2236
|
+
UNIVERSAL_ROUTER_PROTOCOL_ID,
|
|
2237
|
+
V2SwapClient,
|
|
2238
|
+
WTRX_PROTOCOL_ID,
|
|
2239
|
+
createPsmClient,
|
|
2240
|
+
createPsmSwapClient,
|
|
2241
|
+
createRouterSwapExecutor,
|
|
2242
|
+
createSwapRouterClient,
|
|
2243
|
+
createV2Client,
|
|
2244
|
+
createV2SwapClient,
|
|
2245
|
+
createV2SwapExecutor,
|
|
2246
|
+
detectWtrxSwap,
|
|
2247
|
+
isNativeTrxToken,
|
|
2248
|
+
isWrappedTrxToken,
|
|
2249
|
+
materializeUniversalRouterAction,
|
|
2250
|
+
normalizeRouterToken,
|
|
2251
|
+
normalizeV2TrxPairPath,
|
|
2252
|
+
planPsmSwap,
|
|
2253
|
+
planRouterSwap,
|
|
2254
|
+
quotePsmSwap,
|
|
2255
|
+
quoteRouterSwap,
|
|
2256
|
+
quoteSwap,
|
|
2257
|
+
readPsm
|
|
2258
|
+
});
|
|
2259
|
+
//# sourceMappingURL=index.cjs.map
|