@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,935 @@
|
|
|
1
|
+
import {
|
|
2
|
+
methodParametersToAction,
|
|
3
|
+
resolveV3PoolState
|
|
4
|
+
} from "./chunk-L5TZCDPH.js";
|
|
5
|
+
import {
|
|
6
|
+
assertUsdtTransfer
|
|
7
|
+
} from "./chunk-5XDX5563.js";
|
|
8
|
+
import {
|
|
9
|
+
evmHexToTronAddress,
|
|
10
|
+
normalizeLiquidityPercentage,
|
|
11
|
+
readMulticallRequired,
|
|
12
|
+
readRequiredContract,
|
|
13
|
+
tronAddressToEvmAddress
|
|
14
|
+
} from "./chunk-C2YCVBPI.js";
|
|
15
|
+
import {
|
|
16
|
+
applySlippageMin,
|
|
17
|
+
createContextExecutor,
|
|
18
|
+
executeTransactionPlan,
|
|
19
|
+
nextPlanId,
|
|
20
|
+
normalizeBaseUnitAmount,
|
|
21
|
+
normalizeDeadline,
|
|
22
|
+
normalizeRecipient,
|
|
23
|
+
parseSlippage,
|
|
24
|
+
requireWalletAddress,
|
|
25
|
+
resolveProtocolContract,
|
|
26
|
+
slippageToBips
|
|
27
|
+
} from "./chunk-VFVKMC4H.js";
|
|
28
|
+
|
|
29
|
+
// src/positions/execute.ts
|
|
30
|
+
import { SDKError } from "@sun-protocol/sun-sdk-core";
|
|
31
|
+
async function assertV3PositionUsdtTransfer(context, action) {
|
|
32
|
+
await assertUsdtTransfer(context, action);
|
|
33
|
+
}
|
|
34
|
+
function createV3PositionsExecutor(context) {
|
|
35
|
+
const executor = createContextExecutor(context);
|
|
36
|
+
return {
|
|
37
|
+
...executor,
|
|
38
|
+
sendAction: async (action) => {
|
|
39
|
+
await assertV3PositionUsdtTransfer(context, action);
|
|
40
|
+
if (!executor.sendAction) throw new SDKError("SDK_RUNTIME_ERROR", "V3 position execution requires a runtime");
|
|
41
|
+
return executor.sendAction(action);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/positions/intents.ts
|
|
47
|
+
var SUNSWAP_V3_POSITION_PROTOCOL_ID = "sunswap-v3";
|
|
48
|
+
var SUNSWAP_V4_POSITION_PROTOCOL_ID = "sunswap-v4";
|
|
49
|
+
function positionIntentScope(protocol, operation) {
|
|
50
|
+
return { domain: "position", protocol, operation };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/positions/v3.ts
|
|
54
|
+
import {
|
|
55
|
+
CurrencyAmount,
|
|
56
|
+
Percent,
|
|
57
|
+
SDKError as SDKError3,
|
|
58
|
+
Token,
|
|
59
|
+
assertTronAddress as assertTronAddress2
|
|
60
|
+
} from "@sun-protocol/sun-sdk-core";
|
|
61
|
+
import {
|
|
62
|
+
buildV3PositionApprovalForAllRead,
|
|
63
|
+
buildV3PositionReads,
|
|
64
|
+
computeV3PoolAddress,
|
|
65
|
+
NonfungiblePositionManager,
|
|
66
|
+
Pool,
|
|
67
|
+
Position
|
|
68
|
+
} from "@sun-protocol/sun-sdk-sunswap-v3";
|
|
69
|
+
|
|
70
|
+
// src/internal/positions.ts
|
|
71
|
+
import {
|
|
72
|
+
SDKError as SDKError2,
|
|
73
|
+
assertTronAddress
|
|
74
|
+
} from "@sun-protocol/sun-sdk-core";
|
|
75
|
+
function assertPositionAuthorized(input) {
|
|
76
|
+
const wallet = assertTronAddress(input.wallet, "wallet");
|
|
77
|
+
const owner = assertTronAddress(input.owner, "owner");
|
|
78
|
+
const approved = input.approved ? assertTronAddress(input.approved, "approved") : void 0;
|
|
79
|
+
if (wallet === owner || wallet === approved || input.operatorApproved === true) return;
|
|
80
|
+
throw new SDKError2("SDK_WALLET_CAPABILITY_ERROR", "Wallet is not authorized for this position", {
|
|
81
|
+
tokenId: input.tokenId,
|
|
82
|
+
owner,
|
|
83
|
+
wallet,
|
|
84
|
+
operator: wallet
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/positions/v3.ts
|
|
89
|
+
function integerString(value, label) {
|
|
90
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint") {
|
|
91
|
+
return BigInt(value.toString()).toString();
|
|
92
|
+
}
|
|
93
|
+
throw new SDKError3("SDK_CONTRACT_ERROR", `${label} must be an integer-like contract result`, { value });
|
|
94
|
+
}
|
|
95
|
+
function integerNumber(value, label) {
|
|
96
|
+
const parsed = Number(integerString(value, label));
|
|
97
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
98
|
+
throw new SDKError3("SDK_CONTRACT_ERROR", `${label} must be a safe integer`, { value });
|
|
99
|
+
}
|
|
100
|
+
return parsed;
|
|
101
|
+
}
|
|
102
|
+
function unwrapSingle(value) {
|
|
103
|
+
return Array.isArray(value) && value.length === 1 ? value[0] : value;
|
|
104
|
+
}
|
|
105
|
+
function parsePositionAddress(value, label) {
|
|
106
|
+
const raw = String(unwrapSingle(value));
|
|
107
|
+
try {
|
|
108
|
+
return assertTronAddress2(raw, label);
|
|
109
|
+
} catch {
|
|
110
|
+
const evmHex = /^41[0-9a-fA-F]{40}$/.test(raw) ? `0x${raw.slice(2)}` : raw;
|
|
111
|
+
return evmHexToTronAddress(evmHex, label);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function normalizePositionToken(context, value, label) {
|
|
115
|
+
if (typeof value !== "string") {
|
|
116
|
+
throw new SDKError3("SDK_CONTRACT_ERROR", `${label} must be an address string`, { value });
|
|
117
|
+
}
|
|
118
|
+
const publicAddress = parsePositionAddress(value, label);
|
|
119
|
+
const evmAddress = tronAddressToEvmAddress(publicAddress, label);
|
|
120
|
+
return {
|
|
121
|
+
publicAddress,
|
|
122
|
+
token: new Token(context.chain.uniswapChainId, evmAddress, 6, void 0, void 0, true)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function parsePositionResult(context, tokenId, result, owner, approved, operatorApproved) {
|
|
126
|
+
let token0;
|
|
127
|
+
let token1;
|
|
128
|
+
let fee;
|
|
129
|
+
let tickLower;
|
|
130
|
+
let tickUpper;
|
|
131
|
+
let liquidity;
|
|
132
|
+
let tokensOwed0;
|
|
133
|
+
let tokensOwed1;
|
|
134
|
+
if (Array.isArray(result)) {
|
|
135
|
+
token0 = result[2];
|
|
136
|
+
token1 = result[3];
|
|
137
|
+
fee = result[4];
|
|
138
|
+
tickLower = result[5];
|
|
139
|
+
tickUpper = result[6];
|
|
140
|
+
liquidity = result[7];
|
|
141
|
+
tokensOwed0 = result[10];
|
|
142
|
+
tokensOwed1 = result[11];
|
|
143
|
+
} else if (typeof result === "object" && result !== null) {
|
|
144
|
+
const position = result;
|
|
145
|
+
token0 = position.token0;
|
|
146
|
+
token1 = position.token1;
|
|
147
|
+
fee = position.fee;
|
|
148
|
+
tickLower = position.tickLower;
|
|
149
|
+
tickUpper = position.tickUpper;
|
|
150
|
+
liquidity = position.liquidity;
|
|
151
|
+
tokensOwed0 = position.tokensOwed0;
|
|
152
|
+
tokensOwed1 = position.tokensOwed1;
|
|
153
|
+
} else {
|
|
154
|
+
throw new SDKError3("SDK_CONTRACT_ERROR", "V3 position result is malformed", { result });
|
|
155
|
+
}
|
|
156
|
+
const token0Info = normalizePositionToken(context, token0, "token0");
|
|
157
|
+
const token1Info = normalizePositionToken(context, token1, "token1");
|
|
158
|
+
return {
|
|
159
|
+
protocol: "sunswap-v3",
|
|
160
|
+
tokenId,
|
|
161
|
+
owner,
|
|
162
|
+
...approved !== void 0 ? { approved } : {},
|
|
163
|
+
...operatorApproved !== void 0 ? { operatorApproved } : {},
|
|
164
|
+
token0: token0Info.publicAddress,
|
|
165
|
+
token1: token1Info.publicAddress,
|
|
166
|
+
fee: integerNumber(fee, "fee"),
|
|
167
|
+
tickLower: integerNumber(tickLower, "tickLower"),
|
|
168
|
+
tickUpper: integerNumber(tickUpper, "tickUpper"),
|
|
169
|
+
liquidity: integerString(liquidity, "liquidity"),
|
|
170
|
+
tokensOwed0: integerString(tokensOwed0, "tokensOwed0"),
|
|
171
|
+
tokensOwed1: integerString(tokensOwed1, "tokensOwed1"),
|
|
172
|
+
token0Entity: token0Info.token,
|
|
173
|
+
token1Entity: token1Info.token
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function removePercentage(input, snapshot) {
|
|
177
|
+
if (input.percentage !== void 0) return normalizeLiquidityPercentage(input.percentage, "percentage");
|
|
178
|
+
const liquidity = BigInt(normalizeBaseUnitAmount(input.liquidity, "liquidity"));
|
|
179
|
+
const total = BigInt(snapshot.liquidity);
|
|
180
|
+
if (liquidity > total) {
|
|
181
|
+
throw new SDKError3("SDK_INVALID_ARGUMENT", "liquidity cannot exceed position liquidity", {
|
|
182
|
+
liquidity: liquidity.toString(),
|
|
183
|
+
totalLiquidity: total.toString()
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return new Percent(liquidity.toString(), total.toString());
|
|
187
|
+
}
|
|
188
|
+
function currencyForCollect(context, token, publicAddress, receiveNative) {
|
|
189
|
+
return receiveNative && publicAddress === context.chain.contracts.wtrx ? context.chain.nativeCurrency : token;
|
|
190
|
+
}
|
|
191
|
+
var V3PositionsClient = class {
|
|
192
|
+
constructor(context) {
|
|
193
|
+
this.context = context;
|
|
194
|
+
}
|
|
195
|
+
context;
|
|
196
|
+
async read(input) {
|
|
197
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
198
|
+
const [positionResult, ownerResult, approvedResult] = await readMulticallRequired(
|
|
199
|
+
this.context,
|
|
200
|
+
buildV3PositionReads({
|
|
201
|
+
network: this.context.network,
|
|
202
|
+
tokenId,
|
|
203
|
+
positionManager: resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager")
|
|
204
|
+
}),
|
|
205
|
+
"V3 position read"
|
|
206
|
+
);
|
|
207
|
+
const owner = parsePositionAddress(ownerResult, "owner");
|
|
208
|
+
const approved = approvedResult ? parsePositionAddress(approvedResult, "approved") : void 0;
|
|
209
|
+
const operator = input.operator ? assertTronAddress2(input.operator, "operator") : void 0;
|
|
210
|
+
const operatorApproved = operator ? Boolean(await readRequiredContract(
|
|
211
|
+
this.context,
|
|
212
|
+
buildV3PositionApprovalForAllRead({
|
|
213
|
+
network: this.context.network,
|
|
214
|
+
owner,
|
|
215
|
+
operator,
|
|
216
|
+
positionManager: resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager")
|
|
217
|
+
}),
|
|
218
|
+
"V3 position operator approval read"
|
|
219
|
+
)) : void 0;
|
|
220
|
+
const snapshot = parsePositionResult(
|
|
221
|
+
this.context,
|
|
222
|
+
tokenId,
|
|
223
|
+
positionResult,
|
|
224
|
+
owner,
|
|
225
|
+
approved,
|
|
226
|
+
operatorApproved
|
|
227
|
+
);
|
|
228
|
+
return {
|
|
229
|
+
protocol: snapshot.protocol,
|
|
230
|
+
tokenId: snapshot.tokenId,
|
|
231
|
+
owner: snapshot.owner,
|
|
232
|
+
...snapshot.approved !== void 0 ? { approved: snapshot.approved } : {},
|
|
233
|
+
...snapshot.operatorApproved !== void 0 ? { operatorApproved: snapshot.operatorApproved } : {},
|
|
234
|
+
token0: snapshot.token0,
|
|
235
|
+
token1: snapshot.token1,
|
|
236
|
+
fee: snapshot.fee,
|
|
237
|
+
tickLower: snapshot.tickLower,
|
|
238
|
+
tickUpper: snapshot.tickUpper,
|
|
239
|
+
liquidity: snapshot.liquidity,
|
|
240
|
+
tokensOwed0: snapshot.tokensOwed0,
|
|
241
|
+
tokensOwed1: snapshot.tokensOwed1
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
remove = {
|
|
245
|
+
plan: async (input) => this.planRemove(input),
|
|
246
|
+
execute: async (input) => executeTransactionPlan(await this.planRemove(input), createV3PositionsExecutor(this.context))
|
|
247
|
+
};
|
|
248
|
+
collect = {
|
|
249
|
+
plan: async (input) => this.planCollect(input),
|
|
250
|
+
execute: async (input) => executeTransactionPlan(await this.planCollect(input), createV3PositionsExecutor(this.context))
|
|
251
|
+
};
|
|
252
|
+
usdtTransferContext(snapshot, positionManager, input) {
|
|
253
|
+
const { network, chain } = this.context;
|
|
254
|
+
const usdtAddress = chain.contracts.usdt;
|
|
255
|
+
const transfersUsdt = snapshot.token0 === usdtAddress || snapshot.token1 === usdtAddress;
|
|
256
|
+
const sources = [];
|
|
257
|
+
const factory = resolveProtocolContract(this.context, input.contracts, "sunswapV3Factory");
|
|
258
|
+
if (transfersUsdt && positionManager === chain.contracts.sunswapV3PositionManager && factory === chain.contracts.sunswapV3Factory) {
|
|
259
|
+
sources.push({
|
|
260
|
+
address: computeV3PoolAddress({ network, tokenA: snapshot.token0, tokenB: snapshot.token1, fee: snapshot.fee, factory }),
|
|
261
|
+
role: "v3-pool"
|
|
262
|
+
});
|
|
263
|
+
sources.push({ address: positionManager, role: "position-manager" });
|
|
264
|
+
}
|
|
265
|
+
return { network, transfersUsdt, sources };
|
|
266
|
+
}
|
|
267
|
+
async readAuthorizedPosition(tokenId, operation, positionManager, validationMode) {
|
|
268
|
+
const wallet = await requireWalletAddress(this.context, operation);
|
|
269
|
+
const [positionResult, ownerResult, approvedResult] = await readMulticallRequired(
|
|
270
|
+
this.context,
|
|
271
|
+
buildV3PositionReads({ network: this.context.network, tokenId, positionManager }),
|
|
272
|
+
operation
|
|
273
|
+
);
|
|
274
|
+
const owner = parsePositionAddress(ownerResult, "owner");
|
|
275
|
+
const approved = approvedResult ? parsePositionAddress(approvedResult, "approved") : void 0;
|
|
276
|
+
const operatorApproved = validationMode === "legacy" ? void 0 : Boolean(await readRequiredContract(
|
|
277
|
+
this.context,
|
|
278
|
+
buildV3PositionApprovalForAllRead({ network: this.context.network, owner, operator: wallet, positionManager }),
|
|
279
|
+
`${operation} operator approval read`
|
|
280
|
+
));
|
|
281
|
+
if (validationMode !== "legacy") {
|
|
282
|
+
assertPositionAuthorized({
|
|
283
|
+
tokenId,
|
|
284
|
+
wallet,
|
|
285
|
+
owner,
|
|
286
|
+
...approved !== void 0 ? { approved } : {},
|
|
287
|
+
...operatorApproved !== void 0 ? { operatorApproved } : {}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
wallet,
|
|
292
|
+
snapshot: parsePositionResult(this.context, tokenId, positionResult, owner, approved, operatorApproved)
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
async planRemove(input) {
|
|
296
|
+
const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager");
|
|
297
|
+
const planId = nextPlanId(this.context, "position-v3-remove");
|
|
298
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
299
|
+
const { wallet, snapshot } = await this.readAuthorizedPosition(
|
|
300
|
+
tokenId,
|
|
301
|
+
"V3 remove position",
|
|
302
|
+
positionManager,
|
|
303
|
+
input.validationMode
|
|
304
|
+
);
|
|
305
|
+
const recipient = await normalizeRecipient(this.context, input.recipient, "V3 remove position", wallet);
|
|
306
|
+
const deadline = normalizeDeadline(this.context, input);
|
|
307
|
+
const slippage = parseSlippage(input.slippage ?? "0.5%");
|
|
308
|
+
const poolDerived = input.pool === void 0;
|
|
309
|
+
const poolState = input.pool ?? await resolveV3PoolState(this.context, {
|
|
310
|
+
tokenA: snapshot.token0,
|
|
311
|
+
tokenB: snapshot.token1,
|
|
312
|
+
fee: snapshot.fee,
|
|
313
|
+
contracts: input.contracts
|
|
314
|
+
});
|
|
315
|
+
const pool = new Pool({
|
|
316
|
+
tokenA: snapshot.token0Entity,
|
|
317
|
+
tokenB: snapshot.token1Entity,
|
|
318
|
+
fee: snapshot.fee,
|
|
319
|
+
sqrtRatioX96: normalizeBaseUnitAmount(poolState.sqrtRatioX96, "sqrtRatioX96"),
|
|
320
|
+
liquidity: normalizeBaseUnitAmount(poolState.liquidity, "pool liquidity", { allowZero: true }),
|
|
321
|
+
tickCurrent: poolState.tickCurrent,
|
|
322
|
+
...poolState.tickSpacing !== void 0 ? { tickSpacing: poolState.tickSpacing } : {}
|
|
323
|
+
});
|
|
324
|
+
const position = new Position({
|
|
325
|
+
pool,
|
|
326
|
+
tickLower: snapshot.tickLower,
|
|
327
|
+
tickUpper: snapshot.tickUpper,
|
|
328
|
+
liquidity: snapshot.liquidity
|
|
329
|
+
});
|
|
330
|
+
const token0 = assertTronAddress2(snapshot.token0, "token0");
|
|
331
|
+
const token1 = assertTronAddress2(snapshot.token1, "token1");
|
|
332
|
+
const expectedCurrencyOwed0 = CurrencyAmount.fromRawAmount(
|
|
333
|
+
currencyForCollect(this.context, snapshot.token0Entity, token0, input.receiveNative),
|
|
334
|
+
input.expectedCurrencyOwed0 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed0, "expectedCurrencyOwed0", { allowZero: true }) : snapshot.tokensOwed0
|
|
335
|
+
);
|
|
336
|
+
const expectedCurrencyOwed1 = CurrencyAmount.fromRawAmount(
|
|
337
|
+
currencyForCollect(this.context, snapshot.token1Entity, token1, input.receiveNative),
|
|
338
|
+
input.expectedCurrencyOwed1 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed1, "expectedCurrencyOwed1", { allowZero: true }) : snapshot.tokensOwed1
|
|
339
|
+
);
|
|
340
|
+
const methodParameters = NonfungiblePositionManager.removeCallParameters(position, {
|
|
341
|
+
tokenId,
|
|
342
|
+
liquidityPercentage: removePercentage(input, snapshot),
|
|
343
|
+
slippageTolerance: slippage,
|
|
344
|
+
deadline,
|
|
345
|
+
...input.burnToken !== void 0 ? { burnToken: input.burnToken } : {},
|
|
346
|
+
collectOptions: {
|
|
347
|
+
recipient: tronAddressToEvmAddress(recipient, "recipient"),
|
|
348
|
+
expectedCurrencyOwed0,
|
|
349
|
+
expectedCurrencyOwed1
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
const action = methodParametersToAction({
|
|
353
|
+
id: `${planId}-tx`,
|
|
354
|
+
target: positionManager,
|
|
355
|
+
methodParameters,
|
|
356
|
+
metadata: { usdtTransfer: this.usdtTransferContext(snapshot, positionManager, input) },
|
|
357
|
+
...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
|
|
358
|
+
intent: {
|
|
359
|
+
kind: "remove-liquidity",
|
|
360
|
+
scope: positionIntentScope(SUNSWAP_V3_POSITION_PROTOCOL_ID, "remove-position"),
|
|
361
|
+
positionId: tokenId
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
return {
|
|
365
|
+
id: planId,
|
|
366
|
+
kind: "position",
|
|
367
|
+
network: this.context.network,
|
|
368
|
+
owner: wallet,
|
|
369
|
+
summary: { title: "Remove SunSwap V3 position liquidity", lines: [`Position ${tokenId}`, `Recipient ${recipient}`] },
|
|
370
|
+
approvals: [],
|
|
371
|
+
transactions: [action],
|
|
372
|
+
metadata: {
|
|
373
|
+
protocol: "sunswap-v3",
|
|
374
|
+
operation: "remove-position",
|
|
375
|
+
tokenId,
|
|
376
|
+
owner: snapshot.owner,
|
|
377
|
+
recipient,
|
|
378
|
+
deadline,
|
|
379
|
+
slippageBips: slippageToBips(input.slippage ?? "0.5%"),
|
|
380
|
+
positionDerived: true,
|
|
381
|
+
poolDerived
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
async planCollect(input) {
|
|
386
|
+
const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV3PositionManager");
|
|
387
|
+
const planId = nextPlanId(this.context, "position-v3-collect");
|
|
388
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
389
|
+
const { wallet, snapshot } = await this.readAuthorizedPosition(
|
|
390
|
+
tokenId,
|
|
391
|
+
"V3 collect position",
|
|
392
|
+
positionManager,
|
|
393
|
+
input.validationMode
|
|
394
|
+
);
|
|
395
|
+
const recipient = await normalizeRecipient(this.context, input.recipient, "V3 collect position", wallet);
|
|
396
|
+
const token0 = assertTronAddress2(snapshot.token0, "token0");
|
|
397
|
+
const token1 = assertTronAddress2(snapshot.token1, "token1");
|
|
398
|
+
const methodParameters = NonfungiblePositionManager.collectCallParameters({
|
|
399
|
+
tokenId,
|
|
400
|
+
recipient: tronAddressToEvmAddress(recipient, "recipient"),
|
|
401
|
+
expectedCurrencyOwed0: CurrencyAmount.fromRawAmount(
|
|
402
|
+
currencyForCollect(this.context, snapshot.token0Entity, token0, input.receiveNative),
|
|
403
|
+
input.expectedCurrencyOwed0 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed0, "expectedCurrencyOwed0", { allowZero: true }) : snapshot.tokensOwed0
|
|
404
|
+
),
|
|
405
|
+
expectedCurrencyOwed1: CurrencyAmount.fromRawAmount(
|
|
406
|
+
currencyForCollect(this.context, snapshot.token1Entity, token1, input.receiveNative),
|
|
407
|
+
input.expectedCurrencyOwed1 !== void 0 ? normalizeBaseUnitAmount(input.expectedCurrencyOwed1, "expectedCurrencyOwed1", { allowZero: true }) : snapshot.tokensOwed1
|
|
408
|
+
)
|
|
409
|
+
});
|
|
410
|
+
const action = methodParametersToAction({
|
|
411
|
+
id: `${planId}-tx`,
|
|
412
|
+
target: positionManager,
|
|
413
|
+
methodParameters,
|
|
414
|
+
metadata: { usdtTransfer: this.usdtTransferContext(snapshot, positionManager, input) },
|
|
415
|
+
...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
|
|
416
|
+
intent: {
|
|
417
|
+
kind: "collect-fees",
|
|
418
|
+
scope: positionIntentScope(SUNSWAP_V3_POSITION_PROTOCOL_ID, "collect-position"),
|
|
419
|
+
positionId: tokenId
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
return {
|
|
423
|
+
id: planId,
|
|
424
|
+
kind: "position",
|
|
425
|
+
network: this.context.network,
|
|
426
|
+
owner: wallet,
|
|
427
|
+
summary: { title: "Collect SunSwap V3 position fees", lines: [`Position ${tokenId}`, `Recipient ${recipient}`] },
|
|
428
|
+
approvals: [],
|
|
429
|
+
transactions: [action],
|
|
430
|
+
metadata: {
|
|
431
|
+
protocol: "sunswap-v3",
|
|
432
|
+
operation: "collect-position",
|
|
433
|
+
tokenId,
|
|
434
|
+
owner: snapshot.owner,
|
|
435
|
+
recipient
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// src/positions/v4.ts
|
|
442
|
+
import {
|
|
443
|
+
SDKError as SDKError4,
|
|
444
|
+
assertTronAddress as assertTronAddress3
|
|
445
|
+
} from "@sun-protocol/sun-sdk-core";
|
|
446
|
+
import { TickMath } from "@sun-protocol/sun-sdk-sunswap-v3";
|
|
447
|
+
import {
|
|
448
|
+
buildV4CollectAction,
|
|
449
|
+
buildV4DecreaseLiquidityAction,
|
|
450
|
+
buildV4MulticallAction,
|
|
451
|
+
buildV4PositionApprovalForAllRead,
|
|
452
|
+
buildV4PositionFeesRead,
|
|
453
|
+
buildV4PositionReads,
|
|
454
|
+
buildV4PoolSlot0Read,
|
|
455
|
+
computeV4PoolId,
|
|
456
|
+
createV4PoolKey,
|
|
457
|
+
encodeV4ContractCallAction
|
|
458
|
+
} from "@sun-protocol/sun-sdk-sunswap-v4";
|
|
459
|
+
var Q96 = 1n << 96n;
|
|
460
|
+
function parseString(value, label) {
|
|
461
|
+
if (typeof value === "bigint" || typeof value === "number" || typeof value === "string") {
|
|
462
|
+
return BigInt(value.toString()).toString();
|
|
463
|
+
}
|
|
464
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", `${label} must be an integer-like contract result`, { value });
|
|
465
|
+
}
|
|
466
|
+
function parseNumber(value, label) {
|
|
467
|
+
const parsed = Number(parseString(value, label));
|
|
468
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
469
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", `${label} must be a safe integer`, { value });
|
|
470
|
+
}
|
|
471
|
+
return parsed;
|
|
472
|
+
}
|
|
473
|
+
function unwrapSingle2(value) {
|
|
474
|
+
return Array.isArray(value) && value.length === 1 ? value[0] : value;
|
|
475
|
+
}
|
|
476
|
+
function parseAddress(value, label) {
|
|
477
|
+
const raw = String(unwrapSingle2(value));
|
|
478
|
+
try {
|
|
479
|
+
return assertTronAddress3(raw, label);
|
|
480
|
+
} catch {
|
|
481
|
+
const evmHex = /^41[0-9a-fA-F]{40}$/.test(raw) ? `0x${raw.slice(2)}` : raw;
|
|
482
|
+
return evmHexToTronAddress(evmHex, label);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function parsePoolKey(value, network) {
|
|
486
|
+
if (Array.isArray(value) && value.length >= 5) {
|
|
487
|
+
return createV4PoolKey({
|
|
488
|
+
network,
|
|
489
|
+
currencyA: parseAddress(value[0], "poolKey.currency0"),
|
|
490
|
+
currencyB: parseAddress(value[1], "poolKey.currency1"),
|
|
491
|
+
hooks: parseAddress(value[2], "poolKey.hooks"),
|
|
492
|
+
fee: parseNumber(value[3], "poolKey.fee"),
|
|
493
|
+
parameters: String(value[4])
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
if (typeof value === "object" && value !== null) {
|
|
497
|
+
const key = value;
|
|
498
|
+
if (key.currency0 !== void 0 && key.currency1 !== void 0 && key.hooks !== void 0 && key.fee !== void 0 && key.parameters !== void 0) {
|
|
499
|
+
return createV4PoolKey({
|
|
500
|
+
network,
|
|
501
|
+
currencyA: parseAddress(key.currency0, "poolKey.currency0"),
|
|
502
|
+
currencyB: parseAddress(key.currency1, "poolKey.currency1"),
|
|
503
|
+
hooks: parseAddress(key.hooks, "poolKey.hooks"),
|
|
504
|
+
fee: parseNumber(key.fee, "poolKey.fee"),
|
|
505
|
+
parameters: String(key.parameters)
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return void 0;
|
|
510
|
+
}
|
|
511
|
+
function signed24(value) {
|
|
512
|
+
const masked = value & 0xffffffn;
|
|
513
|
+
return Number((masked & 0x800000n) === 0n ? masked : masked - 0x1000000n);
|
|
514
|
+
}
|
|
515
|
+
function parsePackedPositionInfo(value) {
|
|
516
|
+
const info = BigInt(String(unwrapSingle2(value)));
|
|
517
|
+
return {
|
|
518
|
+
tickLower: signed24(info >> 8n),
|
|
519
|
+
tickUpper: signed24(info >> 32n)
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function parseOptionalPoolInfo(result, network) {
|
|
523
|
+
if (Array.isArray(result)) {
|
|
524
|
+
const poolKey = parsePoolKey(result[0], network);
|
|
525
|
+
const ticks = result[2] !== void 0 ? {
|
|
526
|
+
tickLower: parseNumber(result[1], "tickLower"),
|
|
527
|
+
tickUpper: parseNumber(result[2], "tickUpper")
|
|
528
|
+
} : result[1] !== void 0 ? parsePackedPositionInfo(result[1]) : {};
|
|
529
|
+
return {
|
|
530
|
+
...poolKey !== void 0 ? { poolKey } : {},
|
|
531
|
+
...ticks
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
if (typeof result === "object" && result !== null) {
|
|
535
|
+
const info = result;
|
|
536
|
+
const poolKey = parsePoolKey(info.poolKey, network);
|
|
537
|
+
return {
|
|
538
|
+
...poolKey !== void 0 ? { poolKey } : {},
|
|
539
|
+
...info.tickLower !== void 0 ? { tickLower: parseNumber(info.tickLower, "tickLower") } : {},
|
|
540
|
+
...info.tickUpper !== void 0 ? { tickUpper: parseNumber(info.tickUpper, "tickUpper") } : {}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
return {};
|
|
544
|
+
}
|
|
545
|
+
function parseFeesResult(result) {
|
|
546
|
+
const value = unwrapSingle2(result);
|
|
547
|
+
if (Array.isArray(value) && value.length >= 2) {
|
|
548
|
+
return {
|
|
549
|
+
feesOwed0: parseString(value[0], "feesOwed0"),
|
|
550
|
+
feesOwed1: parseString(value[1], "feesOwed1")
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
if (typeof value === "object" && value !== null) {
|
|
554
|
+
const fees = value;
|
|
555
|
+
if (fees.feesOwed0 !== void 0 && fees.feesOwed1 !== void 0) {
|
|
556
|
+
return {
|
|
557
|
+
feesOwed0: parseString(fees.feesOwed0, "feesOwed0"),
|
|
558
|
+
feesOwed1: parseString(fees.feesOwed1, "feesOwed1")
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", "V4 position fee result is malformed", { result });
|
|
563
|
+
}
|
|
564
|
+
function liquidityFromPercentage(totalLiquidity, percentage) {
|
|
565
|
+
const total = BigInt(normalizeBaseUnitAmount(totalLiquidity, "currentLiquidity"));
|
|
566
|
+
const numerator = BigInt(percentage.numerator.toString());
|
|
567
|
+
const denominator = BigInt(percentage.denominator.toString());
|
|
568
|
+
const liquidity = total * numerator / denominator;
|
|
569
|
+
if (liquidity <= 0n) {
|
|
570
|
+
throw new SDKError4("SDK_INVALID_ARGUMENT", "percentage resolves to zero liquidity", {
|
|
571
|
+
totalLiquidity: total.toString(),
|
|
572
|
+
percentage: percentage.toSignificant()
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
return liquidity.toString();
|
|
576
|
+
}
|
|
577
|
+
function resolveRemoveLiquidity(input, snapshotLiquidity) {
|
|
578
|
+
const normalizedSnapshotLiquidity = normalizeBaseUnitAmount(snapshotLiquidity, "position liquidity");
|
|
579
|
+
if (input.currentLiquidity !== void 0 && input.validationMode !== "legacy") {
|
|
580
|
+
const expectedLiquidity = normalizeBaseUnitAmount(input.currentLiquidity, "currentLiquidity");
|
|
581
|
+
if (expectedLiquidity !== normalizedSnapshotLiquidity) {
|
|
582
|
+
throw new SDKError4("SDK_INVALID_ARGUMENT", "currentLiquidity is stale and does not match the on-chain position", {
|
|
583
|
+
currentLiquidity: expectedLiquidity,
|
|
584
|
+
positionLiquidity: normalizedSnapshotLiquidity
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
const liquidity = input.liquidity !== void 0 ? normalizeBaseUnitAmount(input.liquidity, "liquidity") : liquidityFromPercentage(normalizedSnapshotLiquidity, normalizeLiquidityPercentage(input.percentage, "percentage"));
|
|
589
|
+
if (BigInt(liquidity) > BigInt(normalizedSnapshotLiquidity) && input.validationMode === "legacy") {
|
|
590
|
+
return normalizedSnapshotLiquidity;
|
|
591
|
+
}
|
|
592
|
+
if (BigInt(liquidity) > BigInt(normalizedSnapshotLiquidity)) {
|
|
593
|
+
throw new SDKError4("SDK_INVALID_ARGUMENT", "liquidity cannot exceed on-chain position liquidity", {
|
|
594
|
+
liquidity,
|
|
595
|
+
positionLiquidity: normalizedSnapshotLiquidity
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
return liquidity;
|
|
599
|
+
}
|
|
600
|
+
function parseSqrtPriceX96(result) {
|
|
601
|
+
const value = Array.isArray(result) ? result[0] : typeof result === "object" && result !== null ? result.sqrtPriceX96 : void 0;
|
|
602
|
+
try {
|
|
603
|
+
const parsed = BigInt(String(value));
|
|
604
|
+
if (parsed <= 0n) throw new Error("non-positive");
|
|
605
|
+
return parsed;
|
|
606
|
+
} catch {
|
|
607
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", "V4 slot0 result has an invalid sqrtPriceX96", { result });
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
function removalAmounts(snapshot, liquidity, sqrtPriceX96) {
|
|
611
|
+
if (snapshot.tickLower === void 0 || snapshot.tickUpper === void 0) {
|
|
612
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", "V4 position is missing ticks required to derive removal minimums", {
|
|
613
|
+
tokenId: snapshot.tokenId
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
const sqrtA = BigInt(TickMath.getSqrtRatioAtTick(snapshot.tickLower).toString());
|
|
617
|
+
const sqrtB = BigInt(TickMath.getSqrtRatioAtTick(snapshot.tickUpper).toString());
|
|
618
|
+
const positionLiquidity = BigInt(liquidity);
|
|
619
|
+
if (sqrtPriceX96 <= sqrtA) {
|
|
620
|
+
return [positionLiquidity * (sqrtB - sqrtA) * Q96 / (sqrtA * sqrtB), 0n];
|
|
621
|
+
}
|
|
622
|
+
if (sqrtPriceX96 < sqrtB) {
|
|
623
|
+
return [
|
|
624
|
+
positionLiquidity * (sqrtB - sqrtPriceX96) * Q96 / (sqrtPriceX96 * sqrtB),
|
|
625
|
+
positionLiquidity * (sqrtPriceX96 - sqrtA) / Q96
|
|
626
|
+
];
|
|
627
|
+
}
|
|
628
|
+
return [0n, positionLiquidity * (sqrtB - sqrtA) / Q96];
|
|
629
|
+
}
|
|
630
|
+
function resolvePositionPoolKey(tokenId, supplied, snapshot) {
|
|
631
|
+
if (snapshot.poolKey === void 0) {
|
|
632
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", "V4 position does not include a poolKey", { tokenId });
|
|
633
|
+
}
|
|
634
|
+
if (supplied !== void 0) {
|
|
635
|
+
const suppliedPoolId = computeV4PoolId(supplied);
|
|
636
|
+
const positionPoolId = computeV4PoolId(snapshot.poolKey);
|
|
637
|
+
if (suppliedPoolId !== positionPoolId) {
|
|
638
|
+
throw new SDKError4("SDK_INVALID_ARGUMENT", "V4 poolKey does not match the tokenId position", {
|
|
639
|
+
tokenId,
|
|
640
|
+
suppliedPoolId,
|
|
641
|
+
positionPoolId
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
return { poolKey: supplied, derived: false };
|
|
645
|
+
}
|
|
646
|
+
return { poolKey: snapshot.poolKey, derived: true };
|
|
647
|
+
}
|
|
648
|
+
function assertTriggerRecipient(wallet, recipient, operation) {
|
|
649
|
+
if (wallet !== recipient) {
|
|
650
|
+
throw new SDKError4("SDK_INVALID_ARGUMENT", `${operation} recipient must match the triggering wallet`, {
|
|
651
|
+
wallet,
|
|
652
|
+
recipient
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
function metadata(input) {
|
|
657
|
+
return {
|
|
658
|
+
protocol: "sunswap-v4",
|
|
659
|
+
operation: input.operation,
|
|
660
|
+
tokenId: input.tokenId,
|
|
661
|
+
...input.owner !== void 0 ? { owner: input.owner } : {},
|
|
662
|
+
...input.recipient !== void 0 ? { recipient: input.recipient } : {},
|
|
663
|
+
...input.deadline !== void 0 ? { deadline: input.deadline } : {},
|
|
664
|
+
...input.slippageBips !== void 0 ? { slippageBips: input.slippageBips } : {},
|
|
665
|
+
...input.poolKeyDerived !== void 0 ? { poolKeyDerived: input.poolKeyDerived } : {}
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
var V4PositionsClient = class {
|
|
669
|
+
constructor(context) {
|
|
670
|
+
this.context = context;
|
|
671
|
+
}
|
|
672
|
+
context;
|
|
673
|
+
async read(input) {
|
|
674
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
675
|
+
const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager");
|
|
676
|
+
const reads = buildV4PositionReads({ network: this.context.network, tokenId, positionManager });
|
|
677
|
+
const [poolInfoResult, liquidityResult, ownerResult, approvedResult] = await readMulticallRequired(
|
|
678
|
+
this.context,
|
|
679
|
+
reads,
|
|
680
|
+
"V4 position read"
|
|
681
|
+
);
|
|
682
|
+
const owner = parseAddress(ownerResult, "owner");
|
|
683
|
+
const approved = approvedResult ? parseAddress(approvedResult, "approved") : void 0;
|
|
684
|
+
const operator = input.operator ? assertTronAddress3(input.operator, "operator") : void 0;
|
|
685
|
+
const operatorApproved = operator ? Boolean(await readRequiredContract(
|
|
686
|
+
this.context,
|
|
687
|
+
buildV4PositionApprovalForAllRead({ network: this.context.network, owner, operator, positionManager }),
|
|
688
|
+
"V4 position operator approval read"
|
|
689
|
+
).then(unwrapSingle2)) : void 0;
|
|
690
|
+
return {
|
|
691
|
+
protocol: "sunswap-v4",
|
|
692
|
+
tokenId,
|
|
693
|
+
owner,
|
|
694
|
+
...approved !== void 0 ? { approved } : {},
|
|
695
|
+
...operatorApproved !== void 0 ? { operatorApproved } : {},
|
|
696
|
+
...parseOptionalPoolInfo(poolInfoResult, this.context.network),
|
|
697
|
+
liquidity: parseString(unwrapSingle2(liquidityResult), "liquidity")
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
async fees(input) {
|
|
701
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
702
|
+
const snapshot = await this.read(input);
|
|
703
|
+
if (snapshot.poolKey === void 0 || snapshot.tickLower === void 0 || snapshot.tickUpper === void 0) {
|
|
704
|
+
throw new SDKError4("SDK_CONTRACT_ERROR", "V4 position does not include the context required to read fees", {
|
|
705
|
+
tokenId
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
const result = await readRequiredContract(
|
|
709
|
+
this.context,
|
|
710
|
+
buildV4PositionFeesRead({
|
|
711
|
+
network: this.context.network,
|
|
712
|
+
tokenId,
|
|
713
|
+
poolId: computeV4PoolId(snapshot.poolKey),
|
|
714
|
+
tickLower: snapshot.tickLower,
|
|
715
|
+
tickUpper: snapshot.tickUpper,
|
|
716
|
+
poolManager: resolveProtocolContract(this.context, input.contracts, "sunswapV4PoolManager"),
|
|
717
|
+
positionManager: resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager"),
|
|
718
|
+
lpFeeHelper: resolveProtocolContract(this.context, input.contracts, "sunswapV4LpFeeHelper")
|
|
719
|
+
}),
|
|
720
|
+
"V4 position fee read"
|
|
721
|
+
);
|
|
722
|
+
return {
|
|
723
|
+
protocol: "sunswap-v4",
|
|
724
|
+
tokenId,
|
|
725
|
+
...parseFeesResult(result)
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
remove = {
|
|
729
|
+
plan: async (input) => this.planRemove(input),
|
|
730
|
+
execute: async (input) => executeTransactionPlan(await this.planRemove(input), createContextExecutor(this.context))
|
|
731
|
+
};
|
|
732
|
+
collect = {
|
|
733
|
+
plan: async (input) => this.planCollect(input),
|
|
734
|
+
execute: async (input) => executeTransactionPlan(await this.planCollect(input), createContextExecutor(this.context))
|
|
735
|
+
};
|
|
736
|
+
async readAuthorizedPosition(tokenId, operation, contracts, validationMode) {
|
|
737
|
+
const wallet = await requireWalletAddress(this.context, operation);
|
|
738
|
+
const snapshot = await this.read({
|
|
739
|
+
tokenId,
|
|
740
|
+
...validationMode === "legacy" ? {} : { operator: wallet },
|
|
741
|
+
...contracts !== void 0 ? { contracts } : {}
|
|
742
|
+
});
|
|
743
|
+
if (validationMode !== "legacy") {
|
|
744
|
+
assertPositionAuthorized({
|
|
745
|
+
tokenId,
|
|
746
|
+
wallet,
|
|
747
|
+
owner: snapshot.owner,
|
|
748
|
+
...snapshot.approved !== void 0 ? { approved: snapshot.approved } : {},
|
|
749
|
+
...snapshot.operatorApproved !== void 0 ? { operatorApproved: snapshot.operatorApproved } : {}
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
return { wallet, snapshot };
|
|
753
|
+
}
|
|
754
|
+
async planRemove(input) {
|
|
755
|
+
const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager");
|
|
756
|
+
const planId = nextPlanId(this.context, "position-v4-remove");
|
|
757
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
758
|
+
const { wallet, snapshot } = await this.readAuthorizedPosition(
|
|
759
|
+
tokenId,
|
|
760
|
+
"V4 remove position",
|
|
761
|
+
input.contracts,
|
|
762
|
+
input.validationMode
|
|
763
|
+
);
|
|
764
|
+
const poolKey = resolvePositionPoolKey(tokenId, input.poolKey, snapshot);
|
|
765
|
+
const recipient = await normalizeRecipient(this.context, input.recipient, "V4 remove position", wallet);
|
|
766
|
+
assertTriggerRecipient(wallet, recipient, "V4 remove position");
|
|
767
|
+
const deadline = normalizeDeadline(this.context, input);
|
|
768
|
+
const slippageBips = slippageToBips(input.slippage ?? "0.5%");
|
|
769
|
+
const liquidity = resolveRemoveLiquidity(input, snapshot.liquidity);
|
|
770
|
+
const derivedAmounts = input.amount0Min === void 0 || input.amount1Min === void 0 ? removalAmounts(
|
|
771
|
+
snapshot,
|
|
772
|
+
liquidity,
|
|
773
|
+
parseSqrtPriceX96(await readRequiredContract(
|
|
774
|
+
this.context,
|
|
775
|
+
buildV4PoolSlot0Read({
|
|
776
|
+
network: this.context.network,
|
|
777
|
+
poolId: computeV4PoolId(poolKey.poolKey),
|
|
778
|
+
poolManager: resolveProtocolContract(this.context, input.contracts, "sunswapV4PoolManager")
|
|
779
|
+
}),
|
|
780
|
+
"V4 removal minimum quote"
|
|
781
|
+
))
|
|
782
|
+
) : void 0;
|
|
783
|
+
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();
|
|
784
|
+
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();
|
|
785
|
+
const decreaseAction = buildV4DecreaseLiquidityAction({
|
|
786
|
+
network: this.context.network,
|
|
787
|
+
positionManager,
|
|
788
|
+
poolKey: poolKey.poolKey,
|
|
789
|
+
tokenId,
|
|
790
|
+
liquidity,
|
|
791
|
+
amount0Min,
|
|
792
|
+
amount1Min,
|
|
793
|
+
recipient,
|
|
794
|
+
deadline,
|
|
795
|
+
...input.settlementMode !== void 0 ? { settlementMode: input.settlementMode } : {},
|
|
796
|
+
...input.hookData !== void 0 ? { hookData: input.hookData } : {},
|
|
797
|
+
...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
|
|
798
|
+
id: `${planId}-tx`
|
|
799
|
+
});
|
|
800
|
+
const transactionAction = input.transactionMode === "multicall" ? buildV4MulticallAction({
|
|
801
|
+
network: this.context.network,
|
|
802
|
+
positionManager,
|
|
803
|
+
calls: [encodeV4ContractCallAction(decreaseAction)],
|
|
804
|
+
...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
|
|
805
|
+
id: `${planId}-tx`
|
|
806
|
+
}) : decreaseAction;
|
|
807
|
+
const action = {
|
|
808
|
+
...transactionAction,
|
|
809
|
+
intent: {
|
|
810
|
+
kind: "remove-liquidity",
|
|
811
|
+
scope: positionIntentScope(SUNSWAP_V4_POSITION_PROTOCOL_ID, "remove-position"),
|
|
812
|
+
positionId: tokenId
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
return {
|
|
816
|
+
id: planId,
|
|
817
|
+
kind: "position",
|
|
818
|
+
network: this.context.network,
|
|
819
|
+
owner: wallet,
|
|
820
|
+
summary: {
|
|
821
|
+
title: "Remove SunSwap V4 position liquidity",
|
|
822
|
+
lines: [`Position ${tokenId}`, `Recipient ${recipient}`]
|
|
823
|
+
},
|
|
824
|
+
approvals: [],
|
|
825
|
+
transactions: [action],
|
|
826
|
+
metadata: metadata({
|
|
827
|
+
operation: "remove-position",
|
|
828
|
+
tokenId,
|
|
829
|
+
owner: snapshot.owner,
|
|
830
|
+
recipient,
|
|
831
|
+
deadline,
|
|
832
|
+
slippageBips,
|
|
833
|
+
poolKeyDerived: poolKey.derived
|
|
834
|
+
})
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
async planCollect(input) {
|
|
838
|
+
const positionManager = resolveProtocolContract(this.context, input.contracts, "sunswapV4PositionManager");
|
|
839
|
+
const planId = nextPlanId(this.context, "position-v4-collect");
|
|
840
|
+
const tokenId = normalizeBaseUnitAmount(input.tokenId, "tokenId");
|
|
841
|
+
const { wallet, snapshot } = await this.readAuthorizedPosition(
|
|
842
|
+
tokenId,
|
|
843
|
+
"V4 collect position",
|
|
844
|
+
input.contracts,
|
|
845
|
+
input.validationMode
|
|
846
|
+
);
|
|
847
|
+
const poolKey = resolvePositionPoolKey(tokenId, input.poolKey, snapshot);
|
|
848
|
+
const recipient = await normalizeRecipient(this.context, input.recipient, "V4 collect position", wallet);
|
|
849
|
+
assertTriggerRecipient(wallet, recipient, "V4 collect position");
|
|
850
|
+
const deadline = normalizeDeadline(this.context, input);
|
|
851
|
+
const action = buildV4CollectAction({
|
|
852
|
+
network: this.context.network,
|
|
853
|
+
positionManager,
|
|
854
|
+
poolKey: poolKey.poolKey,
|
|
855
|
+
tokenId,
|
|
856
|
+
recipient,
|
|
857
|
+
deadline,
|
|
858
|
+
...input.settlementMode !== void 0 ? { settlementMode: input.settlementMode } : {},
|
|
859
|
+
...input.hookData !== void 0 ? { hookData: input.hookData } : {},
|
|
860
|
+
...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
|
|
861
|
+
id: `${planId}-tx`
|
|
862
|
+
});
|
|
863
|
+
const transactionAction = input.transactionMode === "multicall" ? buildV4MulticallAction({
|
|
864
|
+
network: this.context.network,
|
|
865
|
+
positionManager,
|
|
866
|
+
calls: [encodeV4ContractCallAction(action)],
|
|
867
|
+
...input.feeLimit !== void 0 ? { feeLimit: input.feeLimit } : {},
|
|
868
|
+
id: `${planId}-tx`
|
|
869
|
+
}) : action;
|
|
870
|
+
const transaction = {
|
|
871
|
+
...transactionAction,
|
|
872
|
+
intent: {
|
|
873
|
+
kind: "collect-fees",
|
|
874
|
+
scope: positionIntentScope(SUNSWAP_V4_POSITION_PROTOCOL_ID, "collect-position"),
|
|
875
|
+
positionId: tokenId
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
return {
|
|
879
|
+
id: planId,
|
|
880
|
+
kind: "position",
|
|
881
|
+
network: this.context.network,
|
|
882
|
+
owner: wallet,
|
|
883
|
+
summary: {
|
|
884
|
+
title: "Collect SunSwap V4 position fees",
|
|
885
|
+
lines: [`Position ${tokenId}`, `Recipient ${recipient}`]
|
|
886
|
+
},
|
|
887
|
+
approvals: [],
|
|
888
|
+
transactions: [transaction],
|
|
889
|
+
metadata: metadata({
|
|
890
|
+
operation: "collect-position",
|
|
891
|
+
tokenId,
|
|
892
|
+
owner: snapshot.owner,
|
|
893
|
+
recipient,
|
|
894
|
+
deadline,
|
|
895
|
+
poolKeyDerived: poolKey.derived
|
|
896
|
+
})
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
// src/positions/client.ts
|
|
902
|
+
var PositionsClient = class {
|
|
903
|
+
v3;
|
|
904
|
+
v4;
|
|
905
|
+
constructor(context) {
|
|
906
|
+
const v3Client = new V3PositionsClient(context);
|
|
907
|
+
const v4Client = new V4PositionsClient(context);
|
|
908
|
+
this.v3 = {
|
|
909
|
+
read: (input) => v3Client.read(input),
|
|
910
|
+
remove: v3Client.remove,
|
|
911
|
+
collect: v3Client.collect
|
|
912
|
+
};
|
|
913
|
+
this.v4 = {
|
|
914
|
+
read: (input) => v4Client.read(input),
|
|
915
|
+
fees: (input) => v4Client.fees(input),
|
|
916
|
+
remove: v4Client.remove,
|
|
917
|
+
collect: v4Client.collect
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
function createPositionsClient(context) {
|
|
922
|
+
return new PositionsClient(context);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export {
|
|
926
|
+
assertV3PositionUsdtTransfer,
|
|
927
|
+
createV3PositionsExecutor,
|
|
928
|
+
SUNSWAP_V3_POSITION_PROTOCOL_ID,
|
|
929
|
+
SUNSWAP_V4_POSITION_PROTOCOL_ID,
|
|
930
|
+
V3PositionsClient,
|
|
931
|
+
V4PositionsClient,
|
|
932
|
+
PositionsClient,
|
|
933
|
+
createPositionsClient
|
|
934
|
+
};
|
|
935
|
+
//# sourceMappingURL=chunk-PEGREDLT.js.map
|