@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.
Files changed (60) hide show
  1. package/README.md +30 -0
  2. package/dist/chunk-5XDX5563.js +99 -0
  3. package/dist/chunk-5XDX5563.js.map +1 -0
  4. package/dist/chunk-C2YCVBPI.js +212 -0
  5. package/dist/chunk-C2YCVBPI.js.map +1 -0
  6. package/dist/chunk-ECCGOXNA.js +1317 -0
  7. package/dist/chunk-ECCGOXNA.js.map +1 -0
  8. package/dist/chunk-HD2S3Q7L.js +746 -0
  9. package/dist/chunk-HD2S3Q7L.js.map +1 -0
  10. package/dist/chunk-L5TZCDPH.js +561 -0
  11. package/dist/chunk-L5TZCDPH.js.map +1 -0
  12. package/dist/chunk-OM4OW4KB.js +224 -0
  13. package/dist/chunk-OM4OW4KB.js.map +1 -0
  14. package/dist/chunk-PEGREDLT.js +935 -0
  15. package/dist/chunk-PEGREDLT.js.map +1 -0
  16. package/dist/chunk-TSHXXRH2.js +103 -0
  17. package/dist/chunk-TSHXXRH2.js.map +1 -0
  18. package/dist/chunk-VFVKMC4H.js +521 -0
  19. package/dist/chunk-VFVKMC4H.js.map +1 -0
  20. package/dist/chunk-YMGZDXI4.js +1209 -0
  21. package/dist/chunk-YMGZDXI4.js.map +1 -0
  22. package/dist/common-8VQQ0FSU.d.cts +146 -0
  23. package/dist/common-8VQQ0FSU.d.ts +146 -0
  24. package/dist/execute-BNKh6dT6.d.cts +187 -0
  25. package/dist/execute-CVhcKZxF.d.ts +187 -0
  26. package/dist/index.cjs +5619 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.cts +139 -0
  29. package/dist/index.d.ts +139 -0
  30. package/dist/index.js +200 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/intents-BSXq1HvW.d.cts +200 -0
  33. package/dist/intents-CwOttD75.d.ts +200 -0
  34. package/dist/liquidity/index.cjs +2441 -0
  35. package/dist/liquidity/index.cjs.map +1 -0
  36. package/dist/liquidity/index.d.cts +83 -0
  37. package/dist/liquidity/index.d.ts +83 -0
  38. package/dist/liquidity/index.js +32 -0
  39. package/dist/liquidity/index.js.map +1 -0
  40. package/dist/positions/index.cjs +1544 -0
  41. package/dist/positions/index.cjs.map +1 -0
  42. package/dist/positions/index.d.cts +159 -0
  43. package/dist/positions/index.d.ts +159 -0
  44. package/dist/positions/index.js +25 -0
  45. package/dist/positions/index.js.map +1 -0
  46. package/dist/pump/index.cjs +1178 -0
  47. package/dist/pump/index.cjs.map +1 -0
  48. package/dist/pump/index.d.cts +16 -0
  49. package/dist/pump/index.d.ts +16 -0
  50. package/dist/pump/index.js +29 -0
  51. package/dist/pump/index.js.map +1 -0
  52. package/dist/swap/index.cjs +2259 -0
  53. package/dist/swap/index.cjs.map +1 -0
  54. package/dist/swap/index.d.cts +33 -0
  55. package/dist/swap/index.d.ts +33 -0
  56. package/dist/swap/index.js +61 -0
  57. package/dist/swap/index.js.map +1 -0
  58. package/dist/types-BTPdCC7k.d.cts +160 -0
  59. package/dist/types-BfrouFmO.d.ts +160 -0
  60. package/package.json +94 -0
@@ -0,0 +1,1544 @@
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/positions/index.ts
21
+ var positions_exports = {};
22
+ __export(positions_exports, {
23
+ PositionsClient: () => PositionsClient,
24
+ SUNSWAP_V3_POSITION_PROTOCOL_ID: () => SUNSWAP_V3_POSITION_PROTOCOL_ID,
25
+ SUNSWAP_V4_POSITION_PROTOCOL_ID: () => SUNSWAP_V4_POSITION_PROTOCOL_ID,
26
+ V3PositionsClient: () => V3PositionsClient,
27
+ V4PositionsClient: () => V4PositionsClient,
28
+ assertV3PositionUsdtTransfer: () => assertV3PositionUsdtTransfer,
29
+ createPositionsClient: () => createPositionsClient,
30
+ createV3PositionsExecutor: () => createV3PositionsExecutor
31
+ });
32
+ module.exports = __toCommonJS(positions_exports);
33
+
34
+ // src/positions/v3.ts
35
+ var import_sun_sdk_core13 = require("@sun-protocol/sun-sdk-core");
36
+ var import_sun_sdk_sunswap_v32 = require("@sun-protocol/sun-sdk-sunswap-v3");
37
+
38
+ // src/common.ts
39
+ var import_sun_sdk_core3 = require("@sun-protocol/sun-sdk-core");
40
+
41
+ // src/context.ts
42
+ var import_sun_sdk_api2 = require("@sun-protocol/sun-sdk-api");
43
+ var import_sun_sdk_chains = require("@sun-protocol/sun-sdk-chains");
44
+ var import_sun_sdk_core2 = require("@sun-protocol/sun-sdk-core");
45
+ var import_sun_sdk_runtime = require("@sun-protocol/sun-sdk-runtime");
46
+
47
+ // src/execute-http-action.ts
48
+ var import_sun_sdk_api = require("@sun-protocol/sun-sdk-api");
49
+ var import_sun_sdk_core = require("@sun-protocol/sun-sdk-core");
50
+ async function executeHttpAction(action, fetchImpl, jsonParser = import_sun_sdk_api.defaultJsonParser) {
51
+ if (action.type !== "http-request" || action.execute !== "api") {
52
+ throw new import_sun_sdk_core.SDKError("SDK_INVALID_ARGUMENT", `Action ${action.id} is not an HTTP action`, {
53
+ actionId: action.id,
54
+ actionType: action.type
55
+ });
56
+ }
57
+ const request = action.request;
58
+ const headers = {
59
+ Accept: "application/json",
60
+ ...request.headers
61
+ };
62
+ let body;
63
+ if (request.body !== void 0) {
64
+ if (typeof request.body === "string") {
65
+ body = request.body;
66
+ } else {
67
+ body = JSON.stringify(request.body);
68
+ if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
69
+ }
70
+ }
71
+ return (0, import_sun_sdk_api.requestJson)(request.url, {
72
+ service: "Protocols HTTP action",
73
+ fetchImpl,
74
+ jsonParser,
75
+ init: {
76
+ method: request.method,
77
+ headers,
78
+ ...body !== void 0 ? { body } : {}
79
+ }
80
+ });
81
+ }
82
+
83
+ // src/context.ts
84
+ function requireRuntime(context, operation) {
85
+ if (!context.runtime) {
86
+ throw new import_sun_sdk_core2.SDKError("SDK_RUNTIME_ERROR", `${operation} requires a runtime`, {
87
+ operation,
88
+ network: context.network
89
+ });
90
+ }
91
+ return context.runtime;
92
+ }
93
+ function resolveProtocolContract(context, overrides, name) {
94
+ const configured = context.chain.contracts;
95
+ const address = overrides?.[name] ?? configured[name];
96
+ if (!address) {
97
+ throw new import_sun_sdk_core2.SDKError("SDK_INVALID_ARGUMENT", `No configured address for ${name}`, { name });
98
+ }
99
+ return (0, import_sun_sdk_core2.assertTronAddress)(address, name);
100
+ }
101
+ async function requireWalletAddress(context, operation) {
102
+ return (await requireWalletSnapshot(context, operation)).address;
103
+ }
104
+ async function requireWalletSnapshot(context, operation) {
105
+ const runtime = requireRuntime(context, operation);
106
+ const wallet = await runtime.requireWallet(operation);
107
+ return {
108
+ wallet,
109
+ address: (0, import_sun_sdk_core2.assertTronAddress)(await wallet.getAddress(), "wallet address")
110
+ };
111
+ }
112
+ function createContextExecutor(context) {
113
+ const runtime = context.runtime;
114
+ let walletPromise;
115
+ const requireExecutionWallet = () => {
116
+ walletPromise ??= runtime?.requireWallet("transaction plan execution");
117
+ if (!walletPromise) {
118
+ return Promise.reject(new import_sun_sdk_core2.SDKError("SDK_RUNTIME_ERROR", "Transaction plan execution requires a runtime"));
119
+ }
120
+ return walletPromise;
121
+ };
122
+ return {
123
+ network: context.network,
124
+ ...runtime ? {
125
+ getAddress: async () => {
126
+ const wallet = await requireExecutionWallet();
127
+ return (0, import_sun_sdk_core2.assertTronAddress)(await wallet.getAddress(), "wallet address");
128
+ },
129
+ sendAction: async (action) => {
130
+ const wallet = await requireExecutionWallet();
131
+ return runtime.sendAction(action, { wallet });
132
+ },
133
+ ...runtime.waitForTransactionReceipt ? { waitForTransactionReceipt: runtime.waitForTransactionReceipt.bind(runtime) } : {},
134
+ signTypedData: async (payload) => {
135
+ const wallet = await requireExecutionWallet();
136
+ return runtime.signTypedData(payload, { wallet });
137
+ }
138
+ } : {},
139
+ executeHttpAction: (action) => executeHttpAction(action, context.fetchImpl, context.jsonParser)
140
+ };
141
+ }
142
+
143
+ // src/common.ts
144
+ var PERCENT_PATTERN = /^(\d+)(?:\.(\d+))?%$/;
145
+ var BASE_UNIT_PATTERN = /^\d+$/;
146
+ function parseSlippage(value) {
147
+ if (value instanceof import_sun_sdk_core3.Percent) {
148
+ validateSlippage(value);
149
+ return value;
150
+ }
151
+ const match = PERCENT_PATTERN.exec(value);
152
+ if (!match) {
153
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", "Slippage must be a percentage string", {
154
+ slippage: value
155
+ });
156
+ }
157
+ const whole = match[1] ?? "0";
158
+ const fraction = match[2] ?? "";
159
+ const scale = 10n ** BigInt(fraction.length);
160
+ const percentageUnits = BigInt(whole) * scale + BigInt(fraction || "0");
161
+ const percent = new import_sun_sdk_core3.Percent(percentageUnits.toString(), (100n * scale).toString());
162
+ validateSlippage(percent);
163
+ return percent;
164
+ }
165
+ function validateSlippage(value) {
166
+ if (value.lessThan(0) || value.greaterThan(1)) {
167
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", "Slippage must be between 0% and 100%", {
168
+ slippage: value.toSignificant()
169
+ });
170
+ }
171
+ }
172
+ function slippageToBips(value) {
173
+ const percent = parseSlippage(value);
174
+ const numerator = BigInt(percent.numerator.toString()) * 10000n;
175
+ const denominator = BigInt(percent.denominator.toString());
176
+ if (numerator % denominator !== 0n) {
177
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", "Slippage must resolve to a whole basis point", {
178
+ slippage: typeof value === "string" ? value : value.toSignificant()
179
+ });
180
+ }
181
+ return Number(numerator / denominator);
182
+ }
183
+ function applySlippageMin(expected, slippageBips) {
184
+ return expected * BigInt(1e4 - slippageBips) / 10000n;
185
+ }
186
+ function normalizeBaseUnitAmount(value, label = "amount", options = {}) {
187
+ if (typeof value === "number" && !Number.isSafeInteger(value)) {
188
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", `${label} must be a safe integer`, {
189
+ label,
190
+ value
191
+ });
192
+ }
193
+ const text = value.toString();
194
+ if (!BASE_UNIT_PATTERN.test(text)) {
195
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", `${label} must be an unsigned base-unit integer`, {
196
+ label,
197
+ value: text
198
+ });
199
+ }
200
+ const amount = BigInt(text);
201
+ if (options.allowZero ? amount < 0n : amount <= 0n) {
202
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", `${label} must be ${options.allowZero ? "non-negative" : "positive"}`, {
203
+ label,
204
+ value: text
205
+ });
206
+ }
207
+ return amount.toString();
208
+ }
209
+ function normalizeDeadline(context, options = {}) {
210
+ if (options.deadline !== void 0) {
211
+ return normalizeBaseUnitAmount(options.deadline, "deadline");
212
+ }
213
+ const ttlSeconds = options.ttlSeconds ?? 1200;
214
+ if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds <= 0) {
215
+ throw new import_sun_sdk_core3.SDKError("SDK_INVALID_ARGUMENT", "ttlSeconds must be a positive safe integer", {
216
+ ttlSeconds
217
+ });
218
+ }
219
+ return (BigInt(Math.floor(context.now() / 1e3)) + BigInt(ttlSeconds)).toString();
220
+ }
221
+ async function normalizeRecipient(context, recipient, operation, walletAddress) {
222
+ if (recipient !== void 0) return (0, import_sun_sdk_core3.assertTronAddress)(recipient, "recipient");
223
+ if (walletAddress !== void 0) return walletAddress;
224
+ return requireWalletAddress(context, operation);
225
+ }
226
+ function nextPlanId(context, prefix) {
227
+ return `${prefix}-${context.idFactory()}`;
228
+ }
229
+
230
+ // src/execute-plan.ts
231
+ var import_sun_sdk_core5 = require("@sun-protocol/sun-sdk-core");
232
+
233
+ // src/errors.ts
234
+ var import_sun_sdk_core4 = require("@sun-protocol/sun-sdk-core");
235
+ function isWalletRejection(error) {
236
+ if (!error || typeof error !== "object") return false;
237
+ const candidate = error;
238
+ return candidate.code === 4001 || typeof candidate.message === "string" && /reject|denied|cancel/i.test(candidate.message);
239
+ }
240
+ function normalizeProtocolError(error, fallbackCode, message, context = {}) {
241
+ if (error instanceof import_sun_sdk_core4.SDKError) return error;
242
+ const code = isWalletRejection(error) ? "SDK_WALLET_REJECTED" : fallbackCode;
243
+ return new import_sun_sdk_core4.SDKError(code, message, { ...context, cause: error });
244
+ }
245
+ function withExecutionContext(error, context) {
246
+ return new import_sun_sdk_core4.SDKError(error.code, error.message, {
247
+ ...error.context,
248
+ actionId: context.actionId,
249
+ completedActionIds: context.completedActionIds,
250
+ cause: error
251
+ });
252
+ }
253
+
254
+ // src/execute-plan.ts
255
+ async function executePlanAction(action, executor, completedActions = []) {
256
+ try {
257
+ if (action.waitForReceipt && !executor.waitForTransactionReceipt) {
258
+ throw new import_sun_sdk_core5.SDKError(
259
+ "SDK_RUNTIME_ERROR",
260
+ `Action ${action.id} requires transaction receipt waiting capability`,
261
+ { actionId: action.id, finality: action.waitForReceipt }
262
+ );
263
+ }
264
+ if (action.execute === "runtime") {
265
+ let actionToSend;
266
+ let materializedAction;
267
+ if (action.type === "deferred-contract-call") {
268
+ if (!executor.materializeAction) {
269
+ throw new import_sun_sdk_core5.SDKError("SDK_RUNTIME_ERROR", `Action ${action.id} requires a deferred action materializer`);
270
+ }
271
+ const resolvedAction = await executor.materializeAction(action, completedActions);
272
+ materializedAction = {
273
+ ...resolvedAction,
274
+ id: action.id,
275
+ ...action.intent === void 0 ? {} : { intent: action.intent }
276
+ };
277
+ actionToSend = materializedAction;
278
+ } else if (action.type === "contract-call" || action.type === "approve") {
279
+ actionToSend = action;
280
+ } else {
281
+ throw new import_sun_sdk_core5.SDKError(
282
+ "SDK_RUNTIME_ERROR",
283
+ `Runtime action ${action.id} materialized to unsupported type: ${action.type}`
284
+ );
285
+ }
286
+ if (!executor.sendAction) {
287
+ throw new import_sun_sdk_core5.SDKError("SDK_RUNTIME_ERROR", `Action ${action.id} requires a runtime executor`);
288
+ }
289
+ const result = await executor.sendAction(actionToSend);
290
+ const receipt = action.waitForReceipt && executor.waitForTransactionReceipt ? await executor.waitForTransactionReceipt(result.txid, { finality: action.waitForReceipt }) : void 0;
291
+ if (receipt && !receipt.success) {
292
+ throw new import_sun_sdk_core5.SDKError("SDK_CONTRACT_ERROR", `Transaction ${result.txid} failed`, {
293
+ actionId: action.id,
294
+ txid: result.txid,
295
+ receipt
296
+ });
297
+ }
298
+ return {
299
+ action,
300
+ result,
301
+ txid: result.txid,
302
+ ...receipt ? { receipt } : {},
303
+ ...materializedAction ? { materializedAction } : {}
304
+ };
305
+ }
306
+ if (action.execute === "wallet-signature") {
307
+ if (!action.typedData) {
308
+ throw new import_sun_sdk_core5.SDKError("SDK_INVALID_ARGUMENT", `Action ${action.id} is missing typedData`);
309
+ }
310
+ if (!executor.signTypedData) {
311
+ throw new import_sun_sdk_core5.SDKError("SDK_WALLET_CAPABILITY_ERROR", `Action ${action.id} requires typed-data signing`);
312
+ }
313
+ const signature = await executor.signTypedData(action.typedData);
314
+ return { action, result: signature };
315
+ }
316
+ if (action.execute === "api") {
317
+ if (!executor.executeHttpAction) {
318
+ throw new import_sun_sdk_core5.SDKError("SDK_RUNTIME_ERROR", `Action ${action.id} requires an API executor`);
319
+ }
320
+ return { action, result: await executor.executeHttpAction(action) };
321
+ }
322
+ throw new import_sun_sdk_core5.SDKError("SDK_RUNTIME_ERROR", "Unsupported action executor");
323
+ } catch (error) {
324
+ const normalized = normalizeProtocolError(
325
+ error,
326
+ action.execute === "api" ? "SDK_API_ERROR" : "SDK_RUNTIME_ERROR",
327
+ `Failed to execute action ${action.id}`
328
+ );
329
+ throw withExecutionContext(normalized, {
330
+ actionId: action.id,
331
+ completedActionIds: completedActions.map((result) => result.action.id)
332
+ });
333
+ }
334
+ }
335
+ async function executeTransactionPlan(plan, executor) {
336
+ if (executor.network && executor.network !== plan.network) {
337
+ throw new import_sun_sdk_core5.SDKError("SDK_INVALID_ARGUMENT", "Plan and executor network mismatch", {
338
+ planNetwork: plan.network,
339
+ executorNetwork: executor.network
340
+ });
341
+ }
342
+ if (plan.owner) {
343
+ if (!executor.getAddress) {
344
+ throw new import_sun_sdk_core5.SDKError("SDK_RUNTIME_ERROR", `Plan ${plan.id} requires a wallet address`, {
345
+ planId: plan.id,
346
+ owner: plan.owner
347
+ });
348
+ }
349
+ const actualAddress = await executor.getAddress();
350
+ if (actualAddress !== plan.owner) {
351
+ throw new import_sun_sdk_core5.SDKError(
352
+ "SDK_WALLET_ACCOUNT_MISMATCH",
353
+ "Transaction plan was created for a different wallet",
354
+ {
355
+ planId: plan.id,
356
+ expectedAddress: plan.owner,
357
+ actualAddress
358
+ }
359
+ );
360
+ }
361
+ }
362
+ const orderedActions = [...plan.approvals, ...plan.transactions];
363
+ const receiptAction = orderedActions.find((action) => action.waitForReceipt !== void 0);
364
+ if (receiptAction && !executor.waitForTransactionReceipt) {
365
+ throw new import_sun_sdk_core5.SDKError(
366
+ "SDK_RUNTIME_ERROR",
367
+ `Action ${receiptAction.id} requires transaction receipt waiting capability`,
368
+ { planId: plan.id, actionId: receiptAction.id, finality: receiptAction.waitForReceipt }
369
+ );
370
+ }
371
+ const actionResults = [];
372
+ const txids = [];
373
+ let finalResult;
374
+ for (const action of orderedActions) {
375
+ const actionResult = await executePlanAction(action, executor, actionResults);
376
+ actionResults.push(actionResult);
377
+ if (action.execute === "runtime") {
378
+ if (!actionResult.txid) {
379
+ throw new import_sun_sdk_core5.SDKError("SDK_RUNTIME_ERROR", `Runtime action ${action.id} did not return a transaction id`);
380
+ }
381
+ txids.push(actionResult.txid);
382
+ const raw = typeof actionResult.result === "object" && actionResult.result !== null ? actionResult.result.raw : void 0;
383
+ finalResult = { type: "transaction", txid: actionResult.txid, raw };
384
+ continue;
385
+ }
386
+ if (action.execute === "wallet-signature") {
387
+ finalResult = { type: "signature", signature: actionResult.result };
388
+ continue;
389
+ }
390
+ finalResult = { type: "api", data: actionResult.result };
391
+ }
392
+ return {
393
+ plan,
394
+ actions: actionResults,
395
+ txids,
396
+ finalResult
397
+ };
398
+ }
399
+
400
+ // src/positions/execute.ts
401
+ var import_sun_sdk_core8 = require("@sun-protocol/sun-sdk-core");
402
+
403
+ // src/usdt-transfer.ts
404
+ var import_sun_sdk_core7 = require("@sun-protocol/sun-sdk-core");
405
+
406
+ // src/internal/tokens.ts
407
+ var import_sun_sdk_chains2 = require("@sun-protocol/sun-sdk-chains");
408
+ var import_sun_sdk_core6 = require("@sun-protocol/sun-sdk-core");
409
+ var import_sun_sdk_sunswap_v2 = require("@sun-protocol/sun-sdk-sunswap-v2");
410
+ var PERCENT_PATTERN2 = /^(\d+)(?:\.(\d+))?%$/;
411
+ function isNativeTrxInput(context, token) {
412
+ return token.toUpperCase() === "TRX" || token === context.chain.contracts.trx;
413
+ }
414
+ function evmHexToTronAddress(address, label = "address") {
415
+ const normalized = address.startsWith("0x") ? address.toLowerCase() : `0x${address.toLowerCase()}`;
416
+ return (0, import_sun_sdk_sunswap_v2.evmHexToTronAddress)(normalized, label);
417
+ }
418
+ function tronAddressToEvmAddress(address, label = "address") {
419
+ return `0x${(0, import_sun_sdk_sunswap_v2.tronAddressToEvmHex)((0, import_sun_sdk_core6.assertTronAddress)(address, label))}`;
420
+ }
421
+ function normalizeTronAddress(address, label = "address") {
422
+ if (/^41[0-9a-fA-F]{40}$/.test(address)) return evmHexToTronAddress(`0x${address.slice(2)}`, label);
423
+ if (/^0x[0-9a-fA-F]{40}$/.test(address)) return evmHexToTronAddress(address, label);
424
+ return evmHexToTronAddress(tronAddressToEvmAddress(address, label), label);
425
+ }
426
+ function normalizeProtocolToken(context, token, label, metadata2 = {}) {
427
+ const wrappedContractAddress = (0, import_sun_sdk_chains2.getWrappedNativeAddress)(context.network);
428
+ const kind = isNativeTrxInput(context, token) ? "native" : "token";
429
+ const contractAddress = kind === "native" ? import_sun_sdk_core6.TRON_ZERO_ADDRESS : (0, import_sun_sdk_core6.assertTronAddress)(token, label);
430
+ const mathAddress = kind === "native" ? wrappedContractAddress : contractAddress;
431
+ const evmAddress = `0x${(0, import_sun_sdk_sunswap_v2.tronAddressToEvmHex)(mathAddress)}`.toLowerCase();
432
+ return {
433
+ kind,
434
+ input: token,
435
+ contractAddress,
436
+ wrappedContractAddress,
437
+ token: new import_sun_sdk_core6.Token(
438
+ context.chain.uniswapChainId,
439
+ evmAddress,
440
+ metadata2.decimals ?? 6,
441
+ metadata2.symbol,
442
+ metadata2.name,
443
+ true
444
+ )
445
+ };
446
+ }
447
+ function parseLiquidityPercentageInput(value, label) {
448
+ if (value instanceof import_sun_sdk_core6.Percent) return value;
449
+ const match = PERCENT_PATTERN2.exec(value);
450
+ if (!match) {
451
+ throw new import_sun_sdk_core6.SDKError("SDK_INVALID_ARGUMENT", `${label} must be a percentage string`, {
452
+ label,
453
+ percentage: value
454
+ });
455
+ }
456
+ const whole = match[1] ?? "0";
457
+ const fraction = match[2] ?? "";
458
+ const scale = 10n ** BigInt(fraction.length);
459
+ const percentageUnits = BigInt(whole) * scale + BigInt(fraction || "0");
460
+ return new import_sun_sdk_core6.Percent(percentageUnits.toString(), (100n * scale).toString());
461
+ }
462
+ function normalizeLiquidityPercentage(value, label) {
463
+ const percent = parseLiquidityPercentageInput(value, label);
464
+ if (percent.equalTo(0)) {
465
+ throw new import_sun_sdk_core6.SDKError("SDK_INVALID_ARGUMENT", `${label} must be greater than 0%`, {
466
+ label,
467
+ percentage: percent.toSignificant()
468
+ });
469
+ }
470
+ if (percent.greaterThan(1)) {
471
+ throw new import_sun_sdk_core6.SDKError("SDK_INVALID_ARGUMENT", `${label} must be at most 100%`, {
472
+ label,
473
+ percentage: percent.toSignificant()
474
+ });
475
+ }
476
+ return percent;
477
+ }
478
+
479
+ // src/usdt-transfer.ts
480
+ async function usdtValidateTransfer(input) {
481
+ if (input.transfersUsdt === false) return { status: "allowed" };
482
+ if (input.transfersUsdt !== true) return { status: "unknown", reason: "CHECK_FAILED" };
483
+ if (input.sources.length === 0) return { status: "unknown", reason: "MISSING_TRANSFER_SOURCE" };
484
+ try {
485
+ const paused = await input.reader.paused();
486
+ if (typeof paused !== "boolean") throw new Error("Invalid paused result");
487
+ if (paused) return { status: "blocked", reason: "USDT_PAUSED" };
488
+ const sources = /* @__PURE__ */ new Map();
489
+ for (const source of input.sources) {
490
+ const address = normalizeTronAddress(source.address);
491
+ sources.set(address, { ...source, address });
492
+ }
493
+ const checks = await Promise.all([...sources.values()].map(async (source) => {
494
+ const blacklisted = await input.reader.isBlackListed(source.address);
495
+ if (typeof blacklisted !== "boolean") throw new Error("Invalid blacklist result");
496
+ return { source, blacklisted };
497
+ }));
498
+ const blocked = checks.filter((check) => check.blacklisted).map((check) => check.source);
499
+ return blocked.length > 0 ? { status: "blocked", reason: "USDT_SOURCE_BLACKLISTED", sources: blocked } : { status: "allowed" };
500
+ } catch {
501
+ return { status: "unknown", reason: "CHECK_FAILED" };
502
+ }
503
+ }
504
+ function parseTransferContext(context, action) {
505
+ const data = action.metadata?.usdtTransfer;
506
+ if (!data) throw new Error("Missing USDT transfer context");
507
+ if (data.network !== context.network || typeof data.transfersUsdt !== "boolean" || !Array.isArray(data.sources)) {
508
+ throw new Error("Invalid USDT transfer context; rebuild the plan");
509
+ }
510
+ const sources = data.sources.map((source) => {
511
+ if (!source || typeof source.address !== "string" || source.role !== "v3-pool" && source.role !== "position-manager") {
512
+ throw new Error("Invalid USDT transfer source");
513
+ }
514
+ const address = normalizeTronAddress(source.address);
515
+ if (source.role === "position-manager" && address !== normalizeTronAddress(action.target)) {
516
+ throw new Error("USDT sweep source does not match the position manager");
517
+ }
518
+ return { address, role: source.role };
519
+ });
520
+ if (!data.transfersUsdt && sources.length > 0) throw new Error("Unexpected USDT sources");
521
+ return { network: context.network, transfersUsdt: data.transfersUsdt, sources };
522
+ }
523
+ function boolRead(target, name, address) {
524
+ return {
525
+ target,
526
+ functionSelector: name === "paused" ? "paused()" : "isBlackListed(address)",
527
+ parameters: address === void 0 ? [] : [{ type: "address", value: address }],
528
+ abiFunction: {
529
+ type: "function",
530
+ name,
531
+ stateMutability: "view",
532
+ inputs: name === "paused" ? [] : [{ name: "_user", type: "address" }],
533
+ outputs: [{ name: "", type: "bool" }]
534
+ }
535
+ };
536
+ }
537
+ async function assertUsdtTransfer(context, action) {
538
+ let result;
539
+ if (!action.metadata?.usdtTransfer) {
540
+ result = { status: "unknown", reason: "MISSING_TRANSFER_SOURCE" };
541
+ } else {
542
+ try {
543
+ const data = parseTransferContext(context, action);
544
+ if (data.transfersUsdt && !data.sources.some((source) => source.role === "v3-pool")) {
545
+ result = { status: "unknown", reason: "MISSING_TRANSFER_SOURCE" };
546
+ } else {
547
+ const read = (name, address) => {
548
+ if (!context.runtime) throw new Error("USDT transfer validation requires a runtime");
549
+ return context.runtime.readContract(boolRead(context.chain.contracts.usdt, name, address));
550
+ };
551
+ result = await usdtValidateTransfer({
552
+ ...data,
553
+ reader: { paused: () => read("paused"), isBlackListed: (address) => read("isBlackListed", address) }
554
+ });
555
+ }
556
+ } catch {
557
+ result = { status: "unknown", reason: "CHECK_FAILED" };
558
+ }
559
+ }
560
+ if (result.status === "allowed") return;
561
+ throw new import_sun_sdk_core7.SDKError(
562
+ result.status === "blocked" ? "SDK_USDT_TRANSFER_BLOCKED" : "SDK_USDT_TRANSFER_UNKNOWN",
563
+ result.status === "blocked" ? "USDT transfer is currently restricted" : "Unable to verify USDT transfer status",
564
+ { ...result, usdtAddress: context.chain.contracts.usdt, actionId: action.id }
565
+ );
566
+ }
567
+
568
+ // src/positions/execute.ts
569
+ async function assertV3PositionUsdtTransfer(context, action) {
570
+ await assertUsdtTransfer(context, action);
571
+ }
572
+ function createV3PositionsExecutor(context) {
573
+ const executor = createContextExecutor(context);
574
+ return {
575
+ ...executor,
576
+ sendAction: async (action) => {
577
+ await assertV3PositionUsdtTransfer(context, action);
578
+ if (!executor.sendAction) throw new import_sun_sdk_core8.SDKError("SDK_RUNTIME_ERROR", "V3 position execution requires a runtime");
579
+ return executor.sendAction(action);
580
+ }
581
+ };
582
+ }
583
+
584
+ // src/internal/method-parameters.ts
585
+ var import_sun_sdk_core9 = require("@sun-protocol/sun-sdk-core");
586
+ function methodParametersToAction(input) {
587
+ return (0, import_sun_sdk_core9.createContractCallAction)({
588
+ id: input.id,
589
+ target: input.target,
590
+ functionSelector: input.methodParameters.function_selector,
591
+ parameters: input.methodParameters.parameter,
592
+ callValue: BigInt(input.methodParameters.value),
593
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
594
+ ...input.waitForReceipt !== void 0 ? { waitForReceipt: input.waitForReceipt } : {},
595
+ ...input.metadata !== void 0 ? { metadata: input.metadata } : {},
596
+ ...input.intent !== void 0 ? { intent: input.intent } : {}
597
+ });
598
+ }
599
+
600
+ // src/internal/positions.ts
601
+ var import_sun_sdk_core10 = require("@sun-protocol/sun-sdk-core");
602
+ function assertPositionAuthorized(input) {
603
+ const wallet = (0, import_sun_sdk_core10.assertTronAddress)(input.wallet, "wallet");
604
+ const owner = (0, import_sun_sdk_core10.assertTronAddress)(input.owner, "owner");
605
+ const approved = input.approved ? (0, import_sun_sdk_core10.assertTronAddress)(input.approved, "approved") : void 0;
606
+ if (wallet === owner || wallet === approved || input.operatorApproved === true) return;
607
+ throw new import_sun_sdk_core10.SDKError("SDK_WALLET_CAPABILITY_ERROR", "Wallet is not authorized for this position", {
608
+ tokenId: input.tokenId,
609
+ owner,
610
+ wallet,
611
+ operator: wallet
612
+ });
613
+ }
614
+
615
+ // src/internal/reads.ts
616
+ var import_sun_sdk_core11 = require("@sun-protocol/sun-sdk-core");
617
+ async function readRequiredContract(context, call, operation) {
618
+ const runtime = requireRuntime(context, operation);
619
+ const value = await runtime.readContract(call);
620
+ if (value === void 0 || value === null) {
621
+ throw new import_sun_sdk_core11.SDKError("SDK_CONTRACT_ERROR", `${operation} returned an empty result`, { call });
622
+ }
623
+ return value;
624
+ }
625
+ async function readMulticallRequired(context, calls, operation) {
626
+ const runtime = requireRuntime(context, operation);
627
+ const results = await runtime.multicall(calls);
628
+ return results.map((result, index) => {
629
+ if (!result.success || result.value === void 0) {
630
+ throw new import_sun_sdk_core11.SDKError("SDK_CONTRACT_ERROR", `${operation} multicall item failed`, {
631
+ index,
632
+ call: calls[index],
633
+ error: result.error
634
+ });
635
+ }
636
+ return result.value;
637
+ });
638
+ }
639
+
640
+ // src/liquidity/v3.ts
641
+ var import_sun_sdk_core12 = require("@sun-protocol/sun-sdk-core");
642
+ var import_sun_sdk_sunswap_v3 = require("@sun-protocol/sun-sdk-sunswap-v3");
643
+ function integerString(value, label) {
644
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint") {
645
+ return BigInt(value.toString()).toString();
646
+ }
647
+ throw new import_sun_sdk_core12.SDKError("SDK_CONTRACT_ERROR", `${label} must be an integer-like contract result`, { value });
648
+ }
649
+ function integerNumber(value, label) {
650
+ const parsed = Number(integerString(value, label));
651
+ if (!Number.isSafeInteger(parsed)) {
652
+ throw new import_sun_sdk_core12.SDKError("SDK_CONTRACT_ERROR", `${label} must be a safe integer`, { value });
653
+ }
654
+ return parsed;
655
+ }
656
+ function parseV3Slot0(result) {
657
+ if (Array.isArray(result)) {
658
+ return {
659
+ sqrtRatioX96: integerString(result[0], "sqrtRatioX96"),
660
+ tickCurrent: integerNumber(result[1], "tickCurrent")
661
+ };
662
+ }
663
+ if (typeof result === "object" && result !== null) {
664
+ const slot0 = result;
665
+ return {
666
+ sqrtRatioX96: integerString(slot0.sqrtPriceX96 ?? slot0.sqrtRatioX96, "sqrtRatioX96"),
667
+ tickCurrent: integerNumber(slot0.tick, "tickCurrent")
668
+ };
669
+ }
670
+ throw new import_sun_sdk_core12.SDKError("SDK_CONTRACT_ERROR", "V3 slot0 result is malformed", { result });
671
+ }
672
+ async function resolveV3PoolState(context, input) {
673
+ const tokenA = normalizeProtocolToken(context, input.tokenA, "tokenA");
674
+ const tokenB = normalizeProtocolToken(context, input.tokenB, "tokenB");
675
+ const poolAddress = (0, import_sun_sdk_sunswap_v3.computeV3PoolAddress)({
676
+ network: context.network,
677
+ tokenA: tokenA.contractAddress,
678
+ tokenB: tokenB.contractAddress,
679
+ fee: input.fee,
680
+ factory: resolveProtocolContract(context, input.contracts, "sunswapV3Factory")
681
+ });
682
+ const [slot0Result, liquidityResult, feeResult, tickSpacingResult] = await readMulticallRequired(
683
+ context,
684
+ (0, import_sun_sdk_sunswap_v3.buildV3PoolStateReads)({ pool: poolAddress }),
685
+ "V3 pool state read"
686
+ );
687
+ const fee = integerNumber(feeResult, "fee");
688
+ if (fee !== input.fee) {
689
+ throw new import_sun_sdk_core12.SDKError("SDK_CONTRACT_ERROR", "V3 pool fee does not match requested fee", {
690
+ pool: poolAddress,
691
+ requestedFee: input.fee,
692
+ poolFee: fee
693
+ });
694
+ }
695
+ const slot0 = parseV3Slot0(slot0Result);
696
+ return {
697
+ sqrtRatioX96: slot0.sqrtRatioX96,
698
+ liquidity: integerString(liquidityResult, "liquidity"),
699
+ tickCurrent: slot0.tickCurrent,
700
+ tickSpacing: integerNumber(tickSpacingResult, "tickSpacing")
701
+ };
702
+ }
703
+
704
+ // src/positions/intents.ts
705
+ var SUNSWAP_V3_POSITION_PROTOCOL_ID = "sunswap-v3";
706
+ var SUNSWAP_V4_POSITION_PROTOCOL_ID = "sunswap-v4";
707
+ function positionIntentScope(protocol, operation) {
708
+ return { domain: "position", protocol, operation };
709
+ }
710
+
711
+ // src/positions/v3.ts
712
+ function integerString2(value, label) {
713
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint") {
714
+ return BigInt(value.toString()).toString();
715
+ }
716
+ throw new import_sun_sdk_core13.SDKError("SDK_CONTRACT_ERROR", `${label} must be an integer-like contract result`, { value });
717
+ }
718
+ function integerNumber2(value, label) {
719
+ const parsed = Number(integerString2(value, label));
720
+ if (!Number.isSafeInteger(parsed)) {
721
+ throw new import_sun_sdk_core13.SDKError("SDK_CONTRACT_ERROR", `${label} must be a safe integer`, { value });
722
+ }
723
+ return parsed;
724
+ }
725
+ function unwrapSingle(value) {
726
+ return Array.isArray(value) && value.length === 1 ? value[0] : value;
727
+ }
728
+ function parsePositionAddress(value, label) {
729
+ const raw = String(unwrapSingle(value));
730
+ try {
731
+ return (0, import_sun_sdk_core13.assertTronAddress)(raw, label);
732
+ } catch {
733
+ const evmHex = /^41[0-9a-fA-F]{40}$/.test(raw) ? `0x${raw.slice(2)}` : raw;
734
+ return evmHexToTronAddress(evmHex, label);
735
+ }
736
+ }
737
+ function normalizePositionToken(context, value, label) {
738
+ if (typeof value !== "string") {
739
+ throw new import_sun_sdk_core13.SDKError("SDK_CONTRACT_ERROR", `${label} must be an address string`, { value });
740
+ }
741
+ const publicAddress = parsePositionAddress(value, label);
742
+ const evmAddress = tronAddressToEvmAddress(publicAddress, label);
743
+ return {
744
+ publicAddress,
745
+ token: new import_sun_sdk_core13.Token(context.chain.uniswapChainId, evmAddress, 6, void 0, void 0, true)
746
+ };
747
+ }
748
+ function parsePositionResult(context, tokenId, result, owner, approved, operatorApproved) {
749
+ let token0;
750
+ let token1;
751
+ let fee;
752
+ let tickLower;
753
+ let tickUpper;
754
+ let liquidity;
755
+ let tokensOwed0;
756
+ let tokensOwed1;
757
+ if (Array.isArray(result)) {
758
+ token0 = result[2];
759
+ token1 = result[3];
760
+ fee = result[4];
761
+ tickLower = result[5];
762
+ tickUpper = result[6];
763
+ liquidity = result[7];
764
+ tokensOwed0 = result[10];
765
+ tokensOwed1 = result[11];
766
+ } else if (typeof result === "object" && result !== null) {
767
+ const position = result;
768
+ token0 = position.token0;
769
+ token1 = position.token1;
770
+ fee = position.fee;
771
+ tickLower = position.tickLower;
772
+ tickUpper = position.tickUpper;
773
+ liquidity = position.liquidity;
774
+ tokensOwed0 = position.tokensOwed0;
775
+ tokensOwed1 = position.tokensOwed1;
776
+ } else {
777
+ throw new import_sun_sdk_core13.SDKError("SDK_CONTRACT_ERROR", "V3 position result is malformed", { result });
778
+ }
779
+ const token0Info = normalizePositionToken(context, token0, "token0");
780
+ const token1Info = normalizePositionToken(context, token1, "token1");
781
+ return {
782
+ protocol: "sunswap-v3",
783
+ tokenId,
784
+ owner,
785
+ ...approved !== void 0 ? { approved } : {},
786
+ ...operatorApproved !== void 0 ? { operatorApproved } : {},
787
+ token0: token0Info.publicAddress,
788
+ token1: token1Info.publicAddress,
789
+ fee: integerNumber2(fee, "fee"),
790
+ tickLower: integerNumber2(tickLower, "tickLower"),
791
+ tickUpper: integerNumber2(tickUpper, "tickUpper"),
792
+ liquidity: integerString2(liquidity, "liquidity"),
793
+ tokensOwed0: integerString2(tokensOwed0, "tokensOwed0"),
794
+ tokensOwed1: integerString2(tokensOwed1, "tokensOwed1"),
795
+ token0Entity: token0Info.token,
796
+ token1Entity: token1Info.token
797
+ };
798
+ }
799
+ function removePercentage(input, snapshot) {
800
+ if (input.percentage !== void 0) return normalizeLiquidityPercentage(input.percentage, "percentage");
801
+ const liquidity = BigInt(normalizeBaseUnitAmount(input.liquidity, "liquidity"));
802
+ const total = BigInt(snapshot.liquidity);
803
+ if (liquidity > total) {
804
+ throw new import_sun_sdk_core13.SDKError("SDK_INVALID_ARGUMENT", "liquidity cannot exceed position liquidity", {
805
+ liquidity: liquidity.toString(),
806
+ totalLiquidity: total.toString()
807
+ });
808
+ }
809
+ return new import_sun_sdk_core13.Percent(liquidity.toString(), total.toString());
810
+ }
811
+ function currencyForCollect(context, token, publicAddress, receiveNative) {
812
+ return receiveNative && publicAddress === context.chain.contracts.wtrx ? context.chain.nativeCurrency : token;
813
+ }
814
+ var V3PositionsClient = class {
815
+ constructor(context) {
816
+ this.context = context;
817
+ }
818
+ context;
819
+ async read(input) {
820
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
821
+ const [positionResult, ownerResult, approvedResult] = await readMulticallRequired(
822
+ this.context,
823
+ (0, import_sun_sdk_sunswap_v32.buildV3PositionReads)({
824
+ network: this.context.network,
825
+ tokenId,
826
+ positionManager: resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager")
827
+ }),
828
+ "V3 position read"
829
+ );
830
+ const owner = parsePositionAddress(ownerResult, "owner");
831
+ const approved = approvedResult ? parsePositionAddress(approvedResult, "approved") : void 0;
832
+ const operator = input.operator ? (0, import_sun_sdk_core13.assertTronAddress)(input.operator, "operator") : void 0;
833
+ const operatorApproved = operator ? Boolean(await readRequiredContract(
834
+ this.context,
835
+ (0, import_sun_sdk_sunswap_v32.buildV3PositionApprovalForAllRead)({
836
+ network: this.context.network,
837
+ owner,
838
+ operator,
839
+ positionManager: resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager")
840
+ }),
841
+ "V3 position operator approval read"
842
+ )) : void 0;
843
+ const snapshot = parsePositionResult(
844
+ this.context,
845
+ tokenId,
846
+ positionResult,
847
+ owner,
848
+ approved,
849
+ operatorApproved
850
+ );
851
+ return {
852
+ protocol: snapshot.protocol,
853
+ tokenId: snapshot.tokenId,
854
+ owner: snapshot.owner,
855
+ ...snapshot.approved !== void 0 ? { approved: snapshot.approved } : {},
856
+ ...snapshot.operatorApproved !== void 0 ? { operatorApproved: snapshot.operatorApproved } : {},
857
+ token0: snapshot.token0,
858
+ token1: snapshot.token1,
859
+ fee: snapshot.fee,
860
+ tickLower: snapshot.tickLower,
861
+ tickUpper: snapshot.tickUpper,
862
+ liquidity: snapshot.liquidity,
863
+ tokensOwed0: snapshot.tokensOwed0,
864
+ tokensOwed1: snapshot.tokensOwed1
865
+ };
866
+ }
867
+ remove = {
868
+ plan: async (input) => this.planRemove(input),
869
+ execute: async (input) => executeTransactionPlan(await this.planRemove(input), createV3PositionsExecutor(this.context))
870
+ };
871
+ collect = {
872
+ plan: async (input) => this.planCollect(input),
873
+ execute: async (input) => executeTransactionPlan(await this.planCollect(input), createV3PositionsExecutor(this.context))
874
+ };
875
+ usdtTransferContext(snapshot, positionManager, input) {
876
+ const { network, chain } = this.context;
877
+ const usdtAddress = chain.contracts.usdt;
878
+ const transfersUsdt = snapshot.token0 === usdtAddress || snapshot.token1 === usdtAddress;
879
+ const sources = [];
880
+ const factory = resolveProtocolContract(this.context, input.contracts, "sunswapV3Factory");
881
+ if (transfersUsdt && positionManager === chain.contracts.sunswapV3PositionManager && factory === chain.contracts.sunswapV3Factory) {
882
+ sources.push({
883
+ address: (0, import_sun_sdk_sunswap_v32.computeV3PoolAddress)({ network, tokenA: snapshot.token0, tokenB: snapshot.token1, fee: snapshot.fee, factory }),
884
+ role: "v3-pool"
885
+ });
886
+ sources.push({ address: positionManager, role: "position-manager" });
887
+ }
888
+ return { network, transfersUsdt, sources };
889
+ }
890
+ async readAuthorizedPosition(tokenId, operation, positionManager, validationMode) {
891
+ const wallet = await requireWalletAddress(this.context, operation);
892
+ const [positionResult, ownerResult, approvedResult] = await readMulticallRequired(
893
+ this.context,
894
+ (0, import_sun_sdk_sunswap_v32.buildV3PositionReads)({ network: this.context.network, tokenId, positionManager }),
895
+ operation
896
+ );
897
+ const owner = parsePositionAddress(ownerResult, "owner");
898
+ const approved = approvedResult ? parsePositionAddress(approvedResult, "approved") : void 0;
899
+ const operatorApproved = validationMode === "legacy" ? void 0 : Boolean(await readRequiredContract(
900
+ this.context,
901
+ (0, import_sun_sdk_sunswap_v32.buildV3PositionApprovalForAllRead)({ network: this.context.network, owner, operator: wallet, positionManager }),
902
+ `${operation} operator approval read`
903
+ ));
904
+ if (validationMode !== "legacy") {
905
+ assertPositionAuthorized({
906
+ tokenId,
907
+ wallet,
908
+ owner,
909
+ ...approved !== void 0 ? { approved } : {},
910
+ ...operatorApproved !== void 0 ? { operatorApproved } : {}
911
+ });
912
+ }
913
+ return {
914
+ wallet,
915
+ snapshot: parsePositionResult(this.context, tokenId, positionResult, owner, approved, operatorApproved)
916
+ };
917
+ }
918
+ async planRemove(input) {
919
+ const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager");
920
+ const planId = nextPlanId(this.context, "position-v3-remove");
921
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
922
+ const { wallet, snapshot } = await this.readAuthorizedPosition(
923
+ tokenId,
924
+ "V3 remove position",
925
+ positionManager,
926
+ input.validationMode
927
+ );
928
+ const recipient = await normalizeRecipient(this.context, input.recipient, "V3 remove position", wallet);
929
+ const deadline = normalizeDeadline(this.context, input);
930
+ const slippage = parseSlippage(input.slippage ?? "0.5%");
931
+ const poolDerived = input.pool === void 0;
932
+ const poolState = input.pool ?? await resolveV3PoolState(this.context, {
933
+ tokenA: snapshot.token0,
934
+ tokenB: snapshot.token1,
935
+ fee: snapshot.fee,
936
+ contracts: input.contracts
937
+ });
938
+ const pool = new import_sun_sdk_sunswap_v32.Pool({
939
+ tokenA: snapshot.token0Entity,
940
+ tokenB: snapshot.token1Entity,
941
+ fee: snapshot.fee,
942
+ sqrtRatioX96: normalizeBaseUnitAmount(poolState.sqrtRatioX96, "sqrtRatioX96"),
943
+ liquidity: normalizeBaseUnitAmount(poolState.liquidity, "pool liquidity", { allowZero: true }),
944
+ tickCurrent: poolState.tickCurrent,
945
+ ...poolState.tickSpacing !== void 0 ? { tickSpacing: poolState.tickSpacing } : {}
946
+ });
947
+ const position = new import_sun_sdk_sunswap_v32.Position({
948
+ pool,
949
+ tickLower: snapshot.tickLower,
950
+ tickUpper: snapshot.tickUpper,
951
+ liquidity: snapshot.liquidity
952
+ });
953
+ const token0 = (0, import_sun_sdk_core13.assertTronAddress)(snapshot.token0, "token0");
954
+ const token1 = (0, import_sun_sdk_core13.assertTronAddress)(snapshot.token1, "token1");
955
+ const expectedCurrencyOwed0 = import_sun_sdk_core13.CurrencyAmount.fromRawAmount(
956
+ currencyForCollect(this.context, snapshot.token0Entity, token0, input.receiveNative),
957
+ input.expectedCurrencyOwed0 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed0, "expectedCurrencyOwed0", { allowZero: true }) : snapshot.tokensOwed0
958
+ );
959
+ const expectedCurrencyOwed1 = import_sun_sdk_core13.CurrencyAmount.fromRawAmount(
960
+ currencyForCollect(this.context, snapshot.token1Entity, token1, input.receiveNative),
961
+ input.expectedCurrencyOwed1 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed1, "expectedCurrencyOwed1", { allowZero: true }) : snapshot.tokensOwed1
962
+ );
963
+ const methodParameters = import_sun_sdk_sunswap_v32.NonfungiblePositionManager.removeCallParameters(position, {
964
+ tokenId,
965
+ liquidityPercentage: removePercentage(input, snapshot),
966
+ slippageTolerance: slippage,
967
+ deadline,
968
+ ...input.burnToken !== void 0 ? { burnToken: input.burnToken } : {},
969
+ collectOptions: {
970
+ recipient: tronAddressToEvmAddress(recipient, "recipient"),
971
+ expectedCurrencyOwed0,
972
+ expectedCurrencyOwed1
973
+ }
974
+ });
975
+ const action = methodParametersToAction({
976
+ id: `${planId}-tx`,
977
+ target: positionManager,
978
+ methodParameters,
979
+ metadata: { usdtTransfer: this.usdtTransferContext(snapshot, positionManager, input) },
980
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
981
+ intent: {
982
+ kind: "remove-liquidity",
983
+ scope: positionIntentScope(SUNSWAP_V3_POSITION_PROTOCOL_ID, "remove-position"),
984
+ positionId: tokenId
985
+ }
986
+ });
987
+ return {
988
+ id: planId,
989
+ kind: "position",
990
+ network: this.context.network,
991
+ owner: wallet,
992
+ summary: { title: "Remove SunSwap V3 position liquidity", lines: [`Position ${tokenId}`, `Recipient ${recipient}`] },
993
+ approvals: [],
994
+ transactions: [action],
995
+ metadata: {
996
+ protocol: "sunswap-v3",
997
+ operation: "remove-position",
998
+ tokenId,
999
+ owner: snapshot.owner,
1000
+ recipient,
1001
+ deadline,
1002
+ slippageBips: slippageToBips(input.slippage ?? "0.5%"),
1003
+ positionDerived: true,
1004
+ poolDerived
1005
+ }
1006
+ };
1007
+ }
1008
+ async planCollect(input) {
1009
+ const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager");
1010
+ const planId = nextPlanId(this.context, "position-v3-collect");
1011
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
1012
+ const { wallet, snapshot } = await this.readAuthorizedPosition(
1013
+ tokenId,
1014
+ "V3 collect position",
1015
+ positionManager,
1016
+ input.validationMode
1017
+ );
1018
+ const recipient = await normalizeRecipient(this.context, input.recipient, "V3 collect position", wallet);
1019
+ const token0 = (0, import_sun_sdk_core13.assertTronAddress)(snapshot.token0, "token0");
1020
+ const token1 = (0, import_sun_sdk_core13.assertTronAddress)(snapshot.token1, "token1");
1021
+ const methodParameters = import_sun_sdk_sunswap_v32.NonfungiblePositionManager.collectCallParameters({
1022
+ tokenId,
1023
+ recipient: tronAddressToEvmAddress(recipient, "recipient"),
1024
+ expectedCurrencyOwed0: import_sun_sdk_core13.CurrencyAmount.fromRawAmount(
1025
+ currencyForCollect(this.context, snapshot.token0Entity, token0, input.receiveNative),
1026
+ input.expectedCurrencyOwed0 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed0, "expectedCurrencyOwed0", { allowZero: true }) : snapshot.tokensOwed0
1027
+ ),
1028
+ expectedCurrencyOwed1: import_sun_sdk_core13.CurrencyAmount.fromRawAmount(
1029
+ currencyForCollect(this.context, snapshot.token1Entity, token1, input.receiveNative),
1030
+ input.expectedCurrencyOwed1 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed1, "expectedCurrencyOwed1", { allowZero: true }) : snapshot.tokensOwed1
1031
+ )
1032
+ });
1033
+ const action = methodParametersToAction({
1034
+ id: `${planId}-tx`,
1035
+ target: positionManager,
1036
+ methodParameters,
1037
+ metadata: { usdtTransfer: this.usdtTransferContext(snapshot, positionManager, input) },
1038
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
1039
+ intent: {
1040
+ kind: "collect-fees",
1041
+ scope: positionIntentScope(SUNSWAP_V3_POSITION_PROTOCOL_ID, "collect-position"),
1042
+ positionId: tokenId
1043
+ }
1044
+ });
1045
+ return {
1046
+ id: planId,
1047
+ kind: "position",
1048
+ network: this.context.network,
1049
+ owner: wallet,
1050
+ summary: { title: "Collect SunSwap V3 position fees", lines: [`Position ${tokenId}`, `Recipient ${recipient}`] },
1051
+ approvals: [],
1052
+ transactions: [action],
1053
+ metadata: {
1054
+ protocol: "sunswap-v3",
1055
+ operation: "collect-position",
1056
+ tokenId,
1057
+ owner: snapshot.owner,
1058
+ recipient
1059
+ }
1060
+ };
1061
+ }
1062
+ };
1063
+
1064
+ // src/positions/v4.ts
1065
+ var import_sun_sdk_core14 = require("@sun-protocol/sun-sdk-core");
1066
+ var import_sun_sdk_sunswap_v33 = require("@sun-protocol/sun-sdk-sunswap-v3");
1067
+ var import_sun_sdk_sunswap_v4 = require("@sun-protocol/sun-sdk-sunswap-v4");
1068
+ var Q96 = 1n << 96n;
1069
+ function parseString(value, label) {
1070
+ if (typeof value === "bigint" || typeof value === "number" || typeof value === "string") {
1071
+ return BigInt(value.toString()).toString();
1072
+ }
1073
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", `${label} must be an integer-like contract result`, { value });
1074
+ }
1075
+ function parseNumber(value, label) {
1076
+ const parsed = Number(parseString(value, label));
1077
+ if (!Number.isSafeInteger(parsed)) {
1078
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", `${label} must be a safe integer`, { value });
1079
+ }
1080
+ return parsed;
1081
+ }
1082
+ function unwrapSingle2(value) {
1083
+ return Array.isArray(value) && value.length === 1 ? value[0] : value;
1084
+ }
1085
+ function parseAddress(value, label) {
1086
+ const raw = String(unwrapSingle2(value));
1087
+ try {
1088
+ return (0, import_sun_sdk_core14.assertTronAddress)(raw, label);
1089
+ } catch {
1090
+ const evmHex = /^41[0-9a-fA-F]{40}$/.test(raw) ? `0x${raw.slice(2)}` : raw;
1091
+ return evmHexToTronAddress(evmHex, label);
1092
+ }
1093
+ }
1094
+ function parsePoolKey(value, network) {
1095
+ if (Array.isArray(value) && value.length >= 5) {
1096
+ return (0, import_sun_sdk_sunswap_v4.createV4PoolKey)({
1097
+ network,
1098
+ currencyA: parseAddress(value[0], "poolKey.currency0"),
1099
+ currencyB: parseAddress(value[1], "poolKey.currency1"),
1100
+ hooks: parseAddress(value[2], "poolKey.hooks"),
1101
+ fee: parseNumber(value[3], "poolKey.fee"),
1102
+ parameters: String(value[4])
1103
+ });
1104
+ }
1105
+ if (typeof value === "object" && value !== null) {
1106
+ const key = value;
1107
+ if (key.currency0 !== void 0 && key.currency1 !== void 0 && key.hooks !== void 0 && key.fee !== void 0 && key.parameters !== void 0) {
1108
+ return (0, import_sun_sdk_sunswap_v4.createV4PoolKey)({
1109
+ network,
1110
+ currencyA: parseAddress(key.currency0, "poolKey.currency0"),
1111
+ currencyB: parseAddress(key.currency1, "poolKey.currency1"),
1112
+ hooks: parseAddress(key.hooks, "poolKey.hooks"),
1113
+ fee: parseNumber(key.fee, "poolKey.fee"),
1114
+ parameters: String(key.parameters)
1115
+ });
1116
+ }
1117
+ }
1118
+ return void 0;
1119
+ }
1120
+ function signed24(value) {
1121
+ const masked = value & 0xffffffn;
1122
+ return Number((masked & 0x800000n) === 0n ? masked : masked - 0x1000000n);
1123
+ }
1124
+ function parsePackedPositionInfo(value) {
1125
+ const info = BigInt(String(unwrapSingle2(value)));
1126
+ return {
1127
+ tickLower: signed24(info >> 8n),
1128
+ tickUpper: signed24(info >> 32n)
1129
+ };
1130
+ }
1131
+ function parseOptionalPoolInfo(result, network) {
1132
+ if (Array.isArray(result)) {
1133
+ const poolKey = parsePoolKey(result[0], network);
1134
+ const ticks = result[2] !== void 0 ? {
1135
+ tickLower: parseNumber(result[1], "tickLower"),
1136
+ tickUpper: parseNumber(result[2], "tickUpper")
1137
+ } : result[1] !== void 0 ? parsePackedPositionInfo(result[1]) : {};
1138
+ return {
1139
+ ...poolKey !== void 0 ? { poolKey } : {},
1140
+ ...ticks
1141
+ };
1142
+ }
1143
+ if (typeof result === "object" && result !== null) {
1144
+ const info = result;
1145
+ const poolKey = parsePoolKey(info.poolKey, network);
1146
+ return {
1147
+ ...poolKey !== void 0 ? { poolKey } : {},
1148
+ ...info.tickLower !== void 0 ? { tickLower: parseNumber(info.tickLower, "tickLower") } : {},
1149
+ ...info.tickUpper !== void 0 ? { tickUpper: parseNumber(info.tickUpper, "tickUpper") } : {}
1150
+ };
1151
+ }
1152
+ return {};
1153
+ }
1154
+ function parseFeesResult(result) {
1155
+ const value = unwrapSingle2(result);
1156
+ if (Array.isArray(value) && value.length >= 2) {
1157
+ return {
1158
+ feesOwed0: parseString(value[0], "feesOwed0"),
1159
+ feesOwed1: parseString(value[1], "feesOwed1")
1160
+ };
1161
+ }
1162
+ if (typeof value === "object" && value !== null) {
1163
+ const fees = value;
1164
+ if (fees.feesOwed0 !== void 0 && fees.feesOwed1 !== void 0) {
1165
+ return {
1166
+ feesOwed0: parseString(fees.feesOwed0, "feesOwed0"),
1167
+ feesOwed1: parseString(fees.feesOwed1, "feesOwed1")
1168
+ };
1169
+ }
1170
+ }
1171
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", "V4 position fee result is malformed", { result });
1172
+ }
1173
+ function liquidityFromPercentage(totalLiquidity, percentage) {
1174
+ const total = BigInt(normalizeBaseUnitAmount(totalLiquidity, "currentLiquidity"));
1175
+ const numerator = BigInt(percentage.numerator.toString());
1176
+ const denominator = BigInt(percentage.denominator.toString());
1177
+ const liquidity = total * numerator / denominator;
1178
+ if (liquidity <= 0n) {
1179
+ throw new import_sun_sdk_core14.SDKError("SDK_INVALID_ARGUMENT", "percentage resolves to zero liquidity", {
1180
+ totalLiquidity: total.toString(),
1181
+ percentage: percentage.toSignificant()
1182
+ });
1183
+ }
1184
+ return liquidity.toString();
1185
+ }
1186
+ function resolveRemoveLiquidity(input, snapshotLiquidity) {
1187
+ const normalizedSnapshotLiquidity = normalizeBaseUnitAmount(snapshotLiquidity, "position liquidity");
1188
+ if (input.currentLiquidity !== void 0 && input.validationMode !== "legacy") {
1189
+ const expectedLiquidity = normalizeBaseUnitAmount(input.currentLiquidity, "currentLiquidity");
1190
+ if (expectedLiquidity !== normalizedSnapshotLiquidity) {
1191
+ throw new import_sun_sdk_core14.SDKError("SDK_INVALID_ARGUMENT", "currentLiquidity is stale and does not match the on-chain position", {
1192
+ currentLiquidity: expectedLiquidity,
1193
+ positionLiquidity: normalizedSnapshotLiquidity
1194
+ });
1195
+ }
1196
+ }
1197
+ const liquidity = input.liquidity !== void 0 ? normalizeBaseUnitAmount(input.liquidity, "liquidity") : liquidityFromPercentage(normalizedSnapshotLiquidity, normalizeLiquidityPercentage(input.percentage, "percentage"));
1198
+ if (BigInt(liquidity) > BigInt(normalizedSnapshotLiquidity) && input.validationMode === "legacy") {
1199
+ return normalizedSnapshotLiquidity;
1200
+ }
1201
+ if (BigInt(liquidity) > BigInt(normalizedSnapshotLiquidity)) {
1202
+ throw new import_sun_sdk_core14.SDKError("SDK_INVALID_ARGUMENT", "liquidity cannot exceed on-chain position liquidity", {
1203
+ liquidity,
1204
+ positionLiquidity: normalizedSnapshotLiquidity
1205
+ });
1206
+ }
1207
+ return liquidity;
1208
+ }
1209
+ function parseSqrtPriceX96(result) {
1210
+ const value = Array.isArray(result) ? result[0] : typeof result === "object" && result !== null ? result.sqrtPriceX96 : void 0;
1211
+ try {
1212
+ const parsed = BigInt(String(value));
1213
+ if (parsed <= 0n) throw new Error("non-positive");
1214
+ return parsed;
1215
+ } catch {
1216
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", "V4 slot0 result has an invalid sqrtPriceX96", { result });
1217
+ }
1218
+ }
1219
+ function removalAmounts(snapshot, liquidity, sqrtPriceX96) {
1220
+ if (snapshot.tickLower === void 0 || snapshot.tickUpper === void 0) {
1221
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", "V4 position is missing ticks required to derive removal minimums", {
1222
+ tokenId: snapshot.tokenId
1223
+ });
1224
+ }
1225
+ const sqrtA = BigInt(import_sun_sdk_sunswap_v33.TickMath.getSqrtRatioAtTick(snapshot.tickLower).toString());
1226
+ const sqrtB = BigInt(import_sun_sdk_sunswap_v33.TickMath.getSqrtRatioAtTick(snapshot.tickUpper).toString());
1227
+ const positionLiquidity = BigInt(liquidity);
1228
+ if (sqrtPriceX96 <= sqrtA) {
1229
+ return [positionLiquidity * (sqrtB - sqrtA) * Q96 / (sqrtA * sqrtB), 0n];
1230
+ }
1231
+ if (sqrtPriceX96 < sqrtB) {
1232
+ return [
1233
+ positionLiquidity * (sqrtB - sqrtPriceX96) * Q96 / (sqrtPriceX96 * sqrtB),
1234
+ positionLiquidity * (sqrtPriceX96 - sqrtA) / Q96
1235
+ ];
1236
+ }
1237
+ return [0n, positionLiquidity * (sqrtB - sqrtA) / Q96];
1238
+ }
1239
+ function resolvePositionPoolKey(tokenId, supplied, snapshot) {
1240
+ if (snapshot.poolKey === void 0) {
1241
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", "V4 position does not include a poolKey", { tokenId });
1242
+ }
1243
+ if (supplied !== void 0) {
1244
+ const suppliedPoolId = (0, import_sun_sdk_sunswap_v4.computeV4PoolId)(supplied);
1245
+ const positionPoolId = (0, import_sun_sdk_sunswap_v4.computeV4PoolId)(snapshot.poolKey);
1246
+ if (suppliedPoolId !== positionPoolId) {
1247
+ throw new import_sun_sdk_core14.SDKError("SDK_INVALID_ARGUMENT", "V4 poolKey does not match the tokenId position", {
1248
+ tokenId,
1249
+ suppliedPoolId,
1250
+ positionPoolId
1251
+ });
1252
+ }
1253
+ return { poolKey: supplied, derived: false };
1254
+ }
1255
+ return { poolKey: snapshot.poolKey, derived: true };
1256
+ }
1257
+ function assertTriggerRecipient(wallet, recipient, operation) {
1258
+ if (wallet !== recipient) {
1259
+ throw new import_sun_sdk_core14.SDKError("SDK_INVALID_ARGUMENT", `${operation} recipient must match the triggering wallet`, {
1260
+ wallet,
1261
+ recipient
1262
+ });
1263
+ }
1264
+ }
1265
+ function metadata(input) {
1266
+ return {
1267
+ protocol: "sunswap-v4",
1268
+ operation: input.operation,
1269
+ tokenId: input.tokenId,
1270
+ ...input.owner !== void 0 ? { owner: input.owner } : {},
1271
+ ...input.recipient !== void 0 ? { recipient: input.recipient } : {},
1272
+ ...input.deadline !== void 0 ? { deadline: input.deadline } : {},
1273
+ ...input.slippageBips !== void 0 ? { slippageBips: input.slippageBips } : {},
1274
+ ...input.poolKeyDerived !== void 0 ? { poolKeyDerived: input.poolKeyDerived } : {}
1275
+ };
1276
+ }
1277
+ var V4PositionsClient = class {
1278
+ constructor(context) {
1279
+ this.context = context;
1280
+ }
1281
+ context;
1282
+ async read(input) {
1283
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
1284
+ const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager");
1285
+ const reads = (0, import_sun_sdk_sunswap_v4.buildV4PositionReads)({ network: this.context.network, tokenId, positionManager });
1286
+ const [poolInfoResult, liquidityResult, ownerResult, approvedResult] = await readMulticallRequired(
1287
+ this.context,
1288
+ reads,
1289
+ "V4 position read"
1290
+ );
1291
+ const owner = parseAddress(ownerResult, "owner");
1292
+ const approved = approvedResult ? parseAddress(approvedResult, "approved") : void 0;
1293
+ const operator = input.operator ? (0, import_sun_sdk_core14.assertTronAddress)(input.operator, "operator") : void 0;
1294
+ const operatorApproved = operator ? Boolean(await readRequiredContract(
1295
+ this.context,
1296
+ (0, import_sun_sdk_sunswap_v4.buildV4PositionApprovalForAllRead)({ network: this.context.network, owner, operator, positionManager }),
1297
+ "V4 position operator approval read"
1298
+ ).then(unwrapSingle2)) : void 0;
1299
+ return {
1300
+ protocol: "sunswap-v4",
1301
+ tokenId,
1302
+ owner,
1303
+ ...approved !== void 0 ? { approved } : {},
1304
+ ...operatorApproved !== void 0 ? { operatorApproved } : {},
1305
+ ...parseOptionalPoolInfo(poolInfoResult, this.context.network),
1306
+ liquidity: parseString(unwrapSingle2(liquidityResult), "liquidity")
1307
+ };
1308
+ }
1309
+ async fees(input) {
1310
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
1311
+ const snapshot = await this.read(input);
1312
+ if (snapshot.poolKey === void 0 || snapshot.tickLower === void 0 || snapshot.tickUpper === void 0) {
1313
+ throw new import_sun_sdk_core14.SDKError("SDK_CONTRACT_ERROR", "V4 position does not include the context required to read fees", {
1314
+ tokenId
1315
+ });
1316
+ }
1317
+ const result = await readRequiredContract(
1318
+ this.context,
1319
+ (0, import_sun_sdk_sunswap_v4.buildV4PositionFeesRead)({
1320
+ network: this.context.network,
1321
+ tokenId,
1322
+ poolId: (0, import_sun_sdk_sunswap_v4.computeV4PoolId)(snapshot.poolKey),
1323
+ tickLower: snapshot.tickLower,
1324
+ tickUpper: snapshot.tickUpper,
1325
+ poolManager: resolveProtocolContract(this.context, input.contracts, "sunswapV4PoolManager"),
1326
+ positionManager: resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager"),
1327
+ lpFeeHelper: resolveProtocolContract(this.context, input.contracts, "sunswapV4LpFeeHelper")
1328
+ }),
1329
+ "V4 position fee read"
1330
+ );
1331
+ return {
1332
+ protocol: "sunswap-v4",
1333
+ tokenId,
1334
+ ...parseFeesResult(result)
1335
+ };
1336
+ }
1337
+ remove = {
1338
+ plan: async (input) => this.planRemove(input),
1339
+ execute: async (input) => executeTransactionPlan(await this.planRemove(input), createContextExecutor(this.context))
1340
+ };
1341
+ collect = {
1342
+ plan: async (input) => this.planCollect(input),
1343
+ execute: async (input) => executeTransactionPlan(await this.planCollect(input), createContextExecutor(this.context))
1344
+ };
1345
+ async readAuthorizedPosition(tokenId, operation, contracts, validationMode) {
1346
+ const wallet = await requireWalletAddress(this.context, operation);
1347
+ const snapshot = await this.read({
1348
+ tokenId,
1349
+ ...validationMode === "legacy" ? {} : { operator: wallet },
1350
+ ...contracts !== void 0 ? { contracts } : {}
1351
+ });
1352
+ if (validationMode !== "legacy") {
1353
+ assertPositionAuthorized({
1354
+ tokenId,
1355
+ wallet,
1356
+ owner: snapshot.owner,
1357
+ ...snapshot.approved !== void 0 ? { approved: snapshot.approved } : {},
1358
+ ...snapshot.operatorApproved !== void 0 ? { operatorApproved: snapshot.operatorApproved } : {}
1359
+ });
1360
+ }
1361
+ return { wallet, snapshot };
1362
+ }
1363
+ async planRemove(input) {
1364
+ const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager");
1365
+ const planId = nextPlanId(this.context, "position-v4-remove");
1366
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
1367
+ const { wallet, snapshot } = await this.readAuthorizedPosition(
1368
+ tokenId,
1369
+ "V4 remove position",
1370
+ input.contracts,
1371
+ input.validationMode
1372
+ );
1373
+ const poolKey = resolvePositionPoolKey(tokenId, input.poolKey, snapshot);
1374
+ const recipient = await normalizeRecipient(this.context, input.recipient, "V4 remove position", wallet);
1375
+ assertTriggerRecipient(wallet, recipient, "V4 remove position");
1376
+ const deadline = normalizeDeadline(this.context, input);
1377
+ const slippageBips = slippageToBips(input.slippage ?? "0.5%");
1378
+ const liquidity = resolveRemoveLiquidity(input, snapshot.liquidity);
1379
+ const derivedAmounts = input.amount0Min === void 0 || input.amount1Min === void 0 ? removalAmounts(
1380
+ snapshot,
1381
+ liquidity,
1382
+ parseSqrtPriceX96(await readRequiredContract(
1383
+ this.context,
1384
+ (0, import_sun_sdk_sunswap_v4.buildV4PoolSlot0Read)({
1385
+ network: this.context.network,
1386
+ poolId: (0, import_sun_sdk_sunswap_v4.computeV4PoolId)(poolKey.poolKey),
1387
+ poolManager: resolveProtocolContract(this.context, input.contracts, "sunswapV4PoolManager")
1388
+ }),
1389
+ "V4 removal minimum quote"
1390
+ ))
1391
+ ) : void 0;
1392
+ const amount0Min = input.amount0Min !== void 0 ? normalizeBaseUnitAmount(input.amount0Min, "amount0Min", { allowZero: true }) : input.roundingMode === "half-up" ? (((derivedAmounts?.[0] ?? 0n) * BigInt(1e4 - slippageBips) + 5000n) / 10000n).toString() : applySlippageMin(derivedAmounts?.[0] ?? 0n, slippageBips).toString();
1393
+ const amount1Min = input.amount1Min !== void 0 ? normalizeBaseUnitAmount(input.amount1Min, "amount1Min", { allowZero: true }) : input.roundingMode === "half-up" ? (((derivedAmounts?.[1] ?? 0n) * BigInt(1e4 - slippageBips) + 5000n) / 10000n).toString() : applySlippageMin(derivedAmounts?.[1] ?? 0n, slippageBips).toString();
1394
+ const decreaseAction = (0, import_sun_sdk_sunswap_v4.buildV4DecreaseLiquidityAction)({
1395
+ network: this.context.network,
1396
+ positionManager,
1397
+ poolKey: poolKey.poolKey,
1398
+ tokenId,
1399
+ liquidity,
1400
+ amount0Min,
1401
+ amount1Min,
1402
+ recipient,
1403
+ deadline,
1404
+ ...input.settlementMode !== void 0 ? { settlementMode: input.settlementMode } : {},
1405
+ ...input.hookData !== void 0 ? { hookData: input.hookData } : {},
1406
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
1407
+ id: `${planId}-tx`
1408
+ });
1409
+ const transactionAction = input.transactionMode === "multicall" ? (0, import_sun_sdk_sunswap_v4.buildV4MulticallAction)({
1410
+ network: this.context.network,
1411
+ positionManager,
1412
+ calls: [(0, import_sun_sdk_sunswap_v4.encodeV4ContractCallAction)(decreaseAction)],
1413
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
1414
+ id: `${planId}-tx`
1415
+ }) : decreaseAction;
1416
+ const action = {
1417
+ ...transactionAction,
1418
+ intent: {
1419
+ kind: "remove-liquidity",
1420
+ scope: positionIntentScope(SUNSWAP_V4_POSITION_PROTOCOL_ID, "remove-position"),
1421
+ positionId: tokenId
1422
+ }
1423
+ };
1424
+ return {
1425
+ id: planId,
1426
+ kind: "position",
1427
+ network: this.context.network,
1428
+ owner: wallet,
1429
+ summary: {
1430
+ title: "Remove SunSwap V4 position liquidity",
1431
+ lines: [`Position ${tokenId}`, `Recipient ${recipient}`]
1432
+ },
1433
+ approvals: [],
1434
+ transactions: [action],
1435
+ metadata: metadata({
1436
+ operation: "remove-position",
1437
+ tokenId,
1438
+ owner: snapshot.owner,
1439
+ recipient,
1440
+ deadline,
1441
+ slippageBips,
1442
+ poolKeyDerived: poolKey.derived
1443
+ })
1444
+ };
1445
+ }
1446
+ async planCollect(input) {
1447
+ const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager");
1448
+ const planId = nextPlanId(this.context, "position-v4-collect");
1449
+ const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
1450
+ const { wallet, snapshot } = await this.readAuthorizedPosition(
1451
+ tokenId,
1452
+ "V4 collect position",
1453
+ input.contracts,
1454
+ input.validationMode
1455
+ );
1456
+ const poolKey = resolvePositionPoolKey(tokenId, input.poolKey, snapshot);
1457
+ const recipient = await normalizeRecipient(this.context, input.recipient, "V4 collect position", wallet);
1458
+ assertTriggerRecipient(wallet, recipient, "V4 collect position");
1459
+ const deadline = normalizeDeadline(this.context, input);
1460
+ const action = (0, import_sun_sdk_sunswap_v4.buildV4CollectAction)({
1461
+ network: this.context.network,
1462
+ positionManager,
1463
+ poolKey: poolKey.poolKey,
1464
+ tokenId,
1465
+ recipient,
1466
+ deadline,
1467
+ ...input.settlementMode !== void 0 ? { settlementMode: input.settlementMode } : {},
1468
+ ...input.hookData !== void 0 ? { hookData: input.hookData } : {},
1469
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
1470
+ id: `${planId}-tx`
1471
+ });
1472
+ const transactionAction = input.transactionMode === "multicall" ? (0, import_sun_sdk_sunswap_v4.buildV4MulticallAction)({
1473
+ network: this.context.network,
1474
+ positionManager,
1475
+ calls: [(0, import_sun_sdk_sunswap_v4.encodeV4ContractCallAction)(action)],
1476
+ ...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
1477
+ id: `${planId}-tx`
1478
+ }) : action;
1479
+ const transaction = {
1480
+ ...transactionAction,
1481
+ intent: {
1482
+ kind: "collect-fees",
1483
+ scope: positionIntentScope(SUNSWAP_V4_POSITION_PROTOCOL_ID, "collect-position"),
1484
+ positionId: tokenId
1485
+ }
1486
+ };
1487
+ return {
1488
+ id: planId,
1489
+ kind: "position",
1490
+ network: this.context.network,
1491
+ owner: wallet,
1492
+ summary: {
1493
+ title: "Collect SunSwap V4 position fees",
1494
+ lines: [`Position ${tokenId}`, `Recipient ${recipient}`]
1495
+ },
1496
+ approvals: [],
1497
+ transactions: [transaction],
1498
+ metadata: metadata({
1499
+ operation: "collect-position",
1500
+ tokenId,
1501
+ owner: snapshot.owner,
1502
+ recipient,
1503
+ deadline,
1504
+ poolKeyDerived: poolKey.derived
1505
+ })
1506
+ };
1507
+ }
1508
+ };
1509
+
1510
+ // src/positions/client.ts
1511
+ var PositionsClient = class {
1512
+ v3;
1513
+ v4;
1514
+ constructor(context) {
1515
+ const v3Client = new V3PositionsClient(context);
1516
+ const v4Client = new V4PositionsClient(context);
1517
+ this.v3 = {
1518
+ read: (input) => v3Client.read(input),
1519
+ remove: v3Client.remove,
1520
+ collect: v3Client.collect
1521
+ };
1522
+ this.v4 = {
1523
+ read: (input) => v4Client.read(input),
1524
+ fees: (input) => v4Client.fees(input),
1525
+ remove: v4Client.remove,
1526
+ collect: v4Client.collect
1527
+ };
1528
+ }
1529
+ };
1530
+ function createPositionsClient(context) {
1531
+ return new PositionsClient(context);
1532
+ }
1533
+ // Annotate the CommonJS export names for ESM import in node:
1534
+ 0 && (module.exports = {
1535
+ PositionsClient,
1536
+ SUNSWAP_V3_POSITION_PROTOCOL_ID,
1537
+ SUNSWAP_V4_POSITION_PROTOCOL_ID,
1538
+ V3PositionsClient,
1539
+ V4PositionsClient,
1540
+ assertV3PositionUsdtTransfer,
1541
+ createPositionsClient,
1542
+ createV3PositionsExecutor
1543
+ });
1544
+ //# sourceMappingURL=index.cjs.map