@pafi-dev/trading 0.1.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +408 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +269 -46
- package/dist/index.d.ts +269 -46
- package/dist/index.js +378 -36
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -20,15 +20,345 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
PAFI_SUBGRAPH_URL: () =>
|
|
23
|
+
PAFI_SUBGRAPH_URL: () => import_core10.PAFI_SUBGRAPH_URL,
|
|
24
24
|
TradingHandlers: () => TradingHandlers,
|
|
25
|
-
|
|
25
|
+
buildAllPaths: () => buildAllPaths,
|
|
26
|
+
buildErc20ApprovalCalldata: () => buildErc20ApprovalCalldata,
|
|
27
|
+
buildPermit2ApprovalCalldata: () => buildPermit2ApprovalCalldata,
|
|
28
|
+
buildSwapFromQuote: () => buildSwapFromQuote,
|
|
29
|
+
buildSwapUserOp: () => buildSwapUserOp,
|
|
30
|
+
buildUniversalRouterExecuteArgs: () => buildUniversalRouterExecuteArgs,
|
|
31
|
+
buildV4SwapInput: () => buildV4SwapInput,
|
|
32
|
+
checkAllowance: () => checkAllowance,
|
|
33
|
+
combineRoutes: () => combineRoutes,
|
|
34
|
+
fetchPafiPools: () => import_core10.fetchPafiPools,
|
|
35
|
+
findBestQuote: () => findBestQuote,
|
|
36
|
+
quoteBestRoute: () => quoteBestRoute,
|
|
37
|
+
quoteExactInput: () => quoteExactInput,
|
|
38
|
+
quoteExactInputSingle: () => quoteExactInputSingle,
|
|
39
|
+
simulateSwap: () => simulateSwap
|
|
26
40
|
});
|
|
27
41
|
module.exports = __toCommonJS(index_exports);
|
|
28
42
|
|
|
29
43
|
// src/api/handlers.ts
|
|
30
|
-
var
|
|
44
|
+
var import_viem4 = require("viem");
|
|
45
|
+
var import_core9 = require("@pafi-dev/core");
|
|
46
|
+
|
|
47
|
+
// src/quoting/routes.ts
|
|
31
48
|
var import_core = require("@pafi-dev/core");
|
|
49
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
50
|
+
function combineRoutes(chainId, pointTokenAddress) {
|
|
51
|
+
const commonPools = import_core.COMMON_POOLS[chainId] ?? [];
|
|
52
|
+
const pointPools = import_core.POINT_TOKEN_POOLS[chainId]?.[pointTokenAddress] ?? [];
|
|
53
|
+
return [...pointPools, ...commonPools];
|
|
54
|
+
}
|
|
55
|
+
function buildAllPaths(pools, tokenIn, tokenOut, maxHops = 3) {
|
|
56
|
+
const results = [];
|
|
57
|
+
function dfs(currentToken, currentPath, usedPoolIndices) {
|
|
58
|
+
if (currentPath.length > maxHops) return;
|
|
59
|
+
if (currentPath.length > 0 && currentToken.toLowerCase() === tokenOut.toLowerCase()) {
|
|
60
|
+
results.push([...currentPath]);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (let i = 0; i < pools.length; i++) {
|
|
64
|
+
if (usedPoolIndices.has(i)) continue;
|
|
65
|
+
const pool = pools[i];
|
|
66
|
+
const c0 = pool.currency0.toLowerCase();
|
|
67
|
+
const c1 = pool.currency1.toLowerCase();
|
|
68
|
+
const curr = currentToken.toLowerCase();
|
|
69
|
+
let nextToken = null;
|
|
70
|
+
if (curr === c0) {
|
|
71
|
+
nextToken = pool.currency1;
|
|
72
|
+
} else if (curr === c1) {
|
|
73
|
+
nextToken = pool.currency0;
|
|
74
|
+
}
|
|
75
|
+
if (!nextToken) continue;
|
|
76
|
+
const hop = {
|
|
77
|
+
intermediateCurrency: nextToken,
|
|
78
|
+
fee: pool.fee,
|
|
79
|
+
tickSpacing: pool.tickSpacing,
|
|
80
|
+
hooks: pool.hooks ?? ZERO_ADDRESS,
|
|
81
|
+
hookData: "0x"
|
|
82
|
+
};
|
|
83
|
+
usedPoolIndices.add(i);
|
|
84
|
+
currentPath.push(hop);
|
|
85
|
+
dfs(nextToken, currentPath, usedPoolIndices);
|
|
86
|
+
currentPath.pop();
|
|
87
|
+
usedPoolIndices.delete(i);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
dfs(tokenIn, [], /* @__PURE__ */ new Set());
|
|
91
|
+
return results;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/quoting/quote.ts
|
|
95
|
+
var import_core2 = require("@pafi-dev/core");
|
|
96
|
+
var import_core3 = require("@pafi-dev/core");
|
|
97
|
+
async function quoteExactInput(client, quoterAddress, exactCurrency, path, exactAmount) {
|
|
98
|
+
const [amountOut, gasEstimate] = await client.readContract({
|
|
99
|
+
address: quoterAddress,
|
|
100
|
+
abi: import_core2.v4QuoterAbi,
|
|
101
|
+
functionName: "quoteExactInput",
|
|
102
|
+
args: [{ exactCurrency, path, exactAmount: BigInt(exactAmount) }]
|
|
103
|
+
});
|
|
104
|
+
return { amountOut, gasEstimate, path };
|
|
105
|
+
}
|
|
106
|
+
async function quoteExactInputSingle(client, quoterAddress, poolKey, zeroForOne, exactAmount, hookData) {
|
|
107
|
+
const [amountOut, gasEstimate] = await client.readContract({
|
|
108
|
+
address: quoterAddress,
|
|
109
|
+
abi: import_core2.v4QuoterAbi,
|
|
110
|
+
functionName: "quoteExactInputSingle",
|
|
111
|
+
args: [
|
|
112
|
+
{
|
|
113
|
+
poolKey,
|
|
114
|
+
zeroForOne,
|
|
115
|
+
exactAmount: BigInt(exactAmount),
|
|
116
|
+
hookData
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
});
|
|
120
|
+
return { amountOut, gasEstimate };
|
|
121
|
+
}
|
|
122
|
+
async function quoteBestRoute(client, quoterAddress, exactCurrency, routes, exactAmount) {
|
|
123
|
+
const results = await client.multicall({
|
|
124
|
+
contracts: routes.map((path) => ({
|
|
125
|
+
address: quoterAddress,
|
|
126
|
+
abi: import_core2.v4QuoterAbi,
|
|
127
|
+
functionName: "quoteExactInput",
|
|
128
|
+
args: [
|
|
129
|
+
{
|
|
130
|
+
exactCurrency,
|
|
131
|
+
path,
|
|
132
|
+
exactAmount: BigInt(exactAmount)
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
})),
|
|
136
|
+
allowFailure: true
|
|
137
|
+
});
|
|
138
|
+
const allRoutes = [];
|
|
139
|
+
for (let i = 0; i < results.length; i++) {
|
|
140
|
+
const r = results[i];
|
|
141
|
+
if (r.status === "success") {
|
|
142
|
+
const [amountOut, gasEstimate] = r.result;
|
|
143
|
+
allRoutes.push({ amountOut, gasEstimate, path: routes[i] });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (allRoutes.length === 0) {
|
|
147
|
+
throw new Error("No valid routes found");
|
|
148
|
+
}
|
|
149
|
+
const bestRoute = allRoutes.reduce(
|
|
150
|
+
(best, current) => current.amountOut > best.amountOut ? current : best
|
|
151
|
+
);
|
|
152
|
+
return { bestRoute, allRoutes };
|
|
153
|
+
}
|
|
154
|
+
async function findBestQuote(client, chainId, tokenIn, tokenOut, exactAmount, pools = [], quoterAddress, maxHops = 3) {
|
|
155
|
+
const quoter = quoterAddress ?? import_core3.V4_QUOTER_ADDRESSES[chainId];
|
|
156
|
+
if (!quoter) {
|
|
157
|
+
throw new Error(`No V4 Quoter address configured for chain ${chainId}`);
|
|
158
|
+
}
|
|
159
|
+
const commonPools = import_core3.COMMON_POOLS[chainId] ?? [];
|
|
160
|
+
const allPools = [...pools, ...commonPools];
|
|
161
|
+
const paths = buildAllPaths(allPools, tokenIn, tokenOut, maxHops);
|
|
162
|
+
if (paths.length === 0) {
|
|
163
|
+
throw new Error(`No paths found from ${tokenIn} to ${tokenOut}`);
|
|
164
|
+
}
|
|
165
|
+
return quoteBestRoute(client, quoter, tokenIn, paths, exactAmount);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/swap/approval.ts
|
|
169
|
+
var import_viem = require("viem");
|
|
170
|
+
var import_core4 = require("@pafi-dev/core");
|
|
171
|
+
var import_core5 = require("@pafi-dev/core");
|
|
172
|
+
async function checkAllowance(client, token, owner, spender) {
|
|
173
|
+
return client.readContract({
|
|
174
|
+
address: token,
|
|
175
|
+
abi: import_core4.erc20Abi,
|
|
176
|
+
functionName: "allowance",
|
|
177
|
+
args: [owner, spender]
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function buildErc20ApprovalCalldata(spender, amount) {
|
|
181
|
+
return (0, import_viem.encodeFunctionData)({
|
|
182
|
+
abi: import_core4.erc20Abi,
|
|
183
|
+
functionName: "approve",
|
|
184
|
+
args: [spender, amount]
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function buildPermit2ApprovalCalldata(token, spender, amount, expiration) {
|
|
188
|
+
return (0, import_viem.encodeFunctionData)({
|
|
189
|
+
abi: import_core5.permit2Abi,
|
|
190
|
+
functionName: "approve",
|
|
191
|
+
args: [token, spender, amount, expiration]
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/swap/universalRouter.ts
|
|
196
|
+
var import_viem2 = require("viem");
|
|
197
|
+
var V4_SWAP = 16;
|
|
198
|
+
var SWAP_EXACT_IN = 7;
|
|
199
|
+
var SETTLE_ALL = 12;
|
|
200
|
+
var TAKE_ALL = 15;
|
|
201
|
+
var PATH_KEY_ABI_COMPONENTS = [
|
|
202
|
+
{ name: "intermediateCurrency", type: "address" },
|
|
203
|
+
{ name: "fee", type: "uint256" },
|
|
204
|
+
{ name: "tickSpacing", type: "int24" },
|
|
205
|
+
{ name: "hooks", type: "address" },
|
|
206
|
+
{ name: "hookData", type: "bytes" }
|
|
207
|
+
];
|
|
208
|
+
var EXACT_INPUT_PARAMS_ABI = [
|
|
209
|
+
{ name: "currencyIn", type: "address" },
|
|
210
|
+
{
|
|
211
|
+
name: "path",
|
|
212
|
+
type: "tuple[]",
|
|
213
|
+
components: PATH_KEY_ABI_COMPONENTS
|
|
214
|
+
},
|
|
215
|
+
{ name: "amountIn", type: "uint128" },
|
|
216
|
+
{ name: "amountOutMinimum", type: "uint128" }
|
|
217
|
+
];
|
|
218
|
+
function buildV4SwapInput(currencyIn, path, amountIn, minAmountOut, outputCurrency) {
|
|
219
|
+
const actions = (0, import_viem2.encodePacked)(
|
|
220
|
+
["uint8", "uint8", "uint8"],
|
|
221
|
+
[SWAP_EXACT_IN, SETTLE_ALL, TAKE_ALL]
|
|
222
|
+
);
|
|
223
|
+
const swapParam = (0, import_viem2.encodeAbiParameters)(
|
|
224
|
+
[{ name: "swap", type: "tuple", components: EXACT_INPUT_PARAMS_ABI }],
|
|
225
|
+
[
|
|
226
|
+
{
|
|
227
|
+
currencyIn,
|
|
228
|
+
path: path.map((p) => ({
|
|
229
|
+
intermediateCurrency: p.intermediateCurrency,
|
|
230
|
+
fee: BigInt(p.fee),
|
|
231
|
+
tickSpacing: p.tickSpacing,
|
|
232
|
+
hooks: p.hooks,
|
|
233
|
+
hookData: p.hookData
|
|
234
|
+
})),
|
|
235
|
+
amountIn,
|
|
236
|
+
amountOutMinimum: minAmountOut
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
);
|
|
240
|
+
const settleParam = (0, import_viem2.encodeAbiParameters)(
|
|
241
|
+
[
|
|
242
|
+
{ name: "currency", type: "address" },
|
|
243
|
+
{ name: "maxAmount", type: "uint256" }
|
|
244
|
+
],
|
|
245
|
+
[currencyIn, amountIn]
|
|
246
|
+
);
|
|
247
|
+
const takeParam = (0, import_viem2.encodeAbiParameters)(
|
|
248
|
+
[
|
|
249
|
+
{ name: "currency", type: "address" },
|
|
250
|
+
{ name: "minAmount", type: "uint256" }
|
|
251
|
+
],
|
|
252
|
+
[outputCurrency, minAmountOut]
|
|
253
|
+
);
|
|
254
|
+
return (0, import_viem2.encodeAbiParameters)(
|
|
255
|
+
[
|
|
256
|
+
{ name: "actions", type: "bytes" },
|
|
257
|
+
{ name: "params", type: "bytes[]" }
|
|
258
|
+
],
|
|
259
|
+
[actions, [swapParam, settleParam, takeParam]]
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function buildUniversalRouterExecuteArgs(currencyIn, path, amountIn, minAmountOut, outputCurrency) {
|
|
263
|
+
const commands = (0, import_viem2.encodePacked)(["uint8"], [V4_SWAP]);
|
|
264
|
+
const inputs = [
|
|
265
|
+
buildV4SwapInput(currencyIn, path, amountIn, minAmountOut, outputCurrency)
|
|
266
|
+
];
|
|
267
|
+
return { commands, inputs };
|
|
268
|
+
}
|
|
269
|
+
function buildSwapFromQuote(params) {
|
|
270
|
+
return buildUniversalRouterExecuteArgs(
|
|
271
|
+
params.currencyIn,
|
|
272
|
+
params.quote.path,
|
|
273
|
+
params.amountIn,
|
|
274
|
+
params.minAmountOut,
|
|
275
|
+
params.currencyOut
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/swap/simulate.ts
|
|
280
|
+
var import_core6 = require("@pafi-dev/core");
|
|
281
|
+
var import_core7 = require("@pafi-dev/core");
|
|
282
|
+
async function simulateSwap(client, routerAddress, commands, inputs, deadline, from) {
|
|
283
|
+
try {
|
|
284
|
+
const gasEstimate = await client.estimateContractGas({
|
|
285
|
+
address: routerAddress,
|
|
286
|
+
abi: import_core6.universalRouterAbi,
|
|
287
|
+
functionName: "execute",
|
|
288
|
+
args: [commands, inputs, deadline],
|
|
289
|
+
account: from
|
|
290
|
+
});
|
|
291
|
+
return { success: true, gasEstimate };
|
|
292
|
+
} catch (error) {
|
|
293
|
+
const message = error instanceof Error ? error.message : "Unknown simulation error";
|
|
294
|
+
throw new import_core7.SimulationError("swap", message);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/swap/buildSwap.ts
|
|
299
|
+
var import_viem3 = require("viem");
|
|
300
|
+
var import_core8 = require("@pafi-dev/core");
|
|
301
|
+
function buildSwapUserOp(params) {
|
|
302
|
+
if (params.amountIn <= 0n) {
|
|
303
|
+
throw new Error("buildSwapUserOp: amountIn must be positive");
|
|
304
|
+
}
|
|
305
|
+
if (params.minAmountOut < 0n) {
|
|
306
|
+
throw new Error("buildSwapUserOp: minAmountOut must be non-negative");
|
|
307
|
+
}
|
|
308
|
+
if (params.gasFeeAmount < 0n) {
|
|
309
|
+
throw new Error("buildSwapUserOp: gasFeeAmount must be non-negative");
|
|
310
|
+
}
|
|
311
|
+
if (params.swapPath.length === 0) {
|
|
312
|
+
throw new Error(
|
|
313
|
+
"buildSwapUserOp: swapPath must contain at least one PathKey"
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const { commands, inputs } = buildUniversalRouterExecuteArgs(
|
|
317
|
+
params.inputTokenAddress,
|
|
318
|
+
params.swapPath,
|
|
319
|
+
params.amountIn,
|
|
320
|
+
params.minAmountOut,
|
|
321
|
+
params.outputTokenAddress
|
|
322
|
+
);
|
|
323
|
+
const swapCallData = (0, import_viem3.encodeFunctionData)({
|
|
324
|
+
abi: import_core8.universalRouterAbi,
|
|
325
|
+
functionName: "execute",
|
|
326
|
+
args: [commands, inputs, params.deadline]
|
|
327
|
+
});
|
|
328
|
+
const totalInputApproval = params.amountIn + params.gasFeeAmount;
|
|
329
|
+
const permit2ApproveData = buildPermit2ApprovalCalldata(
|
|
330
|
+
params.inputTokenAddress,
|
|
331
|
+
params.universalRouterAddress,
|
|
332
|
+
params.amountIn,
|
|
333
|
+
Number(params.deadline)
|
|
334
|
+
);
|
|
335
|
+
const operations = [
|
|
336
|
+
(0, import_core8.erc20ApproveOp)(params.inputTokenAddress, import_core8.PERMIT2_ADDRESS, totalInputApproval),
|
|
337
|
+
(0, import_core8.rawCallOp)(import_core8.PERMIT2_ADDRESS, permit2ApproveData),
|
|
338
|
+
(0, import_core8.rawCallOp)(params.universalRouterAddress, swapCallData)
|
|
339
|
+
];
|
|
340
|
+
if (params.gasFeeAmount > 0n) {
|
|
341
|
+
operations.push(
|
|
342
|
+
(0, import_core8.erc20TransferOp)(
|
|
343
|
+
params.inputTokenAddress,
|
|
344
|
+
params.feeRecipient,
|
|
345
|
+
params.gasFeeAmount
|
|
346
|
+
)
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
return (0, import_core8.buildPartialUserOperation)({
|
|
350
|
+
sender: params.userAddress,
|
|
351
|
+
nonce: params.aaNonce,
|
|
352
|
+
operations,
|
|
353
|
+
gasLimits: {
|
|
354
|
+
callGasLimit: params.gasLimits?.callGasLimit ?? 700000n,
|
|
355
|
+
verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150000n,
|
|
356
|
+
preVerificationGas: params.gasLimits?.preVerificationGas ?? 50000n
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/api/handlers.ts
|
|
32
362
|
var TradingHandlers = class {
|
|
33
363
|
provider;
|
|
34
364
|
chainId;
|
|
@@ -52,29 +382,33 @@ var TradingHandlers = class {
|
|
|
52
382
|
throw new Error(`handleQuote: unsupported chainId ${request.chainId}`);
|
|
53
383
|
}
|
|
54
384
|
if (request.amount === 0n) {
|
|
55
|
-
return {
|
|
385
|
+
return {
|
|
386
|
+
inputAmount: 0n,
|
|
387
|
+
estimatedOutputAmount: 0n,
|
|
388
|
+
gasEstimate: 0n
|
|
389
|
+
};
|
|
56
390
|
}
|
|
57
|
-
const
|
|
58
|
-
const
|
|
391
|
+
const inputTokenAddress = (0, import_viem4.getAddress)(request.inputTokenAddress);
|
|
392
|
+
const outputTokenAddress = (0, import_viem4.getAddress)(request.outputTokenAddress);
|
|
59
393
|
const pools = request.pools ?? [];
|
|
60
394
|
try {
|
|
61
|
-
const best = await
|
|
395
|
+
const best = await findBestQuote(
|
|
62
396
|
this.provider,
|
|
63
397
|
request.chainId,
|
|
64
|
-
|
|
65
|
-
|
|
398
|
+
inputTokenAddress,
|
|
399
|
+
outputTokenAddress,
|
|
66
400
|
request.amount,
|
|
67
401
|
pools
|
|
68
402
|
);
|
|
69
403
|
return {
|
|
70
|
-
|
|
71
|
-
|
|
404
|
+
inputAmount: request.amount,
|
|
405
|
+
estimatedOutputAmount: best.bestRoute.amountOut,
|
|
72
406
|
gasEstimate: best.bestRoute.gasEstimate
|
|
73
407
|
};
|
|
74
408
|
} catch {
|
|
75
409
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
410
|
+
inputAmount: request.amount,
|
|
411
|
+
estimatedOutputAmount: 0n,
|
|
78
412
|
gasEstimate: 0n,
|
|
79
413
|
quoteError: "QUOTE_UNAVAILABLE"
|
|
80
414
|
};
|
|
@@ -99,71 +433,74 @@ var TradingHandlers = class {
|
|
|
99
433
|
if (request.amount <= 0n) {
|
|
100
434
|
throw new Error("handleSwap: amount must be positive");
|
|
101
435
|
}
|
|
102
|
-
const {
|
|
103
|
-
const universalRouter =
|
|
436
|
+
const { pafiFeeRecipient } = (0, import_core9.getContractAddresses)(request.chainId);
|
|
437
|
+
const universalRouter = import_core9.UNIVERSAL_ROUTER_ADDRESSES[request.chainId];
|
|
104
438
|
if (!universalRouter) {
|
|
105
439
|
throw new Error(`handleSwap: no UniversalRouter for chainId ${request.chainId}`);
|
|
106
440
|
}
|
|
107
|
-
const
|
|
108
|
-
const
|
|
441
|
+
const inputTokenAddress = (0, import_viem4.getAddress)(request.inputTokenAddress);
|
|
442
|
+
const outputTokenAddress = (0, import_viem4.getAddress)(request.outputTokenAddress);
|
|
443
|
+
const userAddress = (0, import_viem4.getAddress)(request.userAddress);
|
|
109
444
|
const pools = request.pools ?? [];
|
|
110
|
-
const
|
|
111
|
-
const gasFeePt = request.gasFeePt !== void 0 ? request.gasFeePt : await (0, import_core.quoteOperatorFeePt)({
|
|
445
|
+
const gasFeeAmount = request.gasFeeAmount !== void 0 ? request.gasFeeAmount : await (0, import_core9.quoteOperatorFeePt)({
|
|
112
446
|
provider: this.provider,
|
|
113
447
|
chainId: request.chainId,
|
|
114
|
-
pointTokenAddress
|
|
115
|
-
});
|
|
448
|
+
pointTokenAddress: inputTokenAddress
|
|
449
|
+
}).catch(() => 0n);
|
|
116
450
|
let quoteResult;
|
|
117
451
|
try {
|
|
118
|
-
quoteResult = await
|
|
452
|
+
quoteResult = await findBestQuote(
|
|
119
453
|
this.provider,
|
|
120
454
|
request.chainId,
|
|
121
|
-
|
|
122
|
-
|
|
455
|
+
inputTokenAddress,
|
|
456
|
+
outputTokenAddress,
|
|
123
457
|
request.amount,
|
|
124
458
|
pools
|
|
125
459
|
);
|
|
126
460
|
} catch {
|
|
127
|
-
throw new Error(
|
|
461
|
+
throw new Error(
|
|
462
|
+
`handleSwap: no swap path found from ${inputTokenAddress} to ${outputTokenAddress}`
|
|
463
|
+
);
|
|
128
464
|
}
|
|
129
|
-
const
|
|
130
|
-
const
|
|
465
|
+
const hops = quoteResult.bestRoute.path.length;
|
|
466
|
+
const slippageBps = request.slippageBps ?? (hops > 1 ? 100 : 50);
|
|
467
|
+
const estimatedOutputAmount = quoteResult.bestRoute.amountOut;
|
|
468
|
+
const minAmountOut = estimatedOutputAmount * BigInt(1e4 - slippageBps) / 10000n;
|
|
131
469
|
const deadline = BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
|
|
132
|
-
const userOp = (
|
|
470
|
+
const userOp = buildSwapUserOp({
|
|
133
471
|
userAddress,
|
|
134
472
|
aaNonce: request.aaNonce,
|
|
135
|
-
|
|
136
|
-
outputTokenAddress
|
|
473
|
+
inputTokenAddress,
|
|
474
|
+
outputTokenAddress,
|
|
137
475
|
universalRouterAddress: universalRouter,
|
|
138
476
|
amountIn: request.amount,
|
|
139
477
|
minAmountOut,
|
|
140
478
|
swapPath: quoteResult.bestRoute.path,
|
|
141
479
|
deadline,
|
|
142
|
-
|
|
143
|
-
// Recipient is always PAFI's canonical address — sponsor-relayer's
|
|
144
|
-
// L1 gate will reject any other recipient anyway. No override.
|
|
480
|
+
gasFeeAmount,
|
|
145
481
|
feeRecipient: pafiFeeRecipient
|
|
146
482
|
});
|
|
147
|
-
const userOpFallback =
|
|
483
|
+
const userOpFallback = gasFeeAmount > 0n ? buildSwapUserOp({
|
|
148
484
|
userAddress,
|
|
149
485
|
aaNonce: request.aaNonce,
|
|
150
|
-
|
|
151
|
-
outputTokenAddress
|
|
486
|
+
inputTokenAddress,
|
|
487
|
+
outputTokenAddress,
|
|
152
488
|
universalRouterAddress: universalRouter,
|
|
153
489
|
amountIn: request.amount,
|
|
154
490
|
minAmountOut,
|
|
155
491
|
swapPath: quoteResult.bestRoute.path,
|
|
156
492
|
deadline,
|
|
157
|
-
|
|
158
|
-
feeRecipient:
|
|
493
|
+
gasFeeAmount: 0n,
|
|
494
|
+
feeRecipient: pafiFeeRecipient
|
|
159
495
|
}) : void 0;
|
|
160
496
|
return {
|
|
161
497
|
userOp,
|
|
162
498
|
userOpFallback,
|
|
163
|
-
|
|
499
|
+
estimatedOutputAmount,
|
|
164
500
|
minAmountOut,
|
|
501
|
+
hops,
|
|
165
502
|
deadline,
|
|
166
|
-
feeAmountUsed:
|
|
503
|
+
feeAmountUsed: gasFeeAmount,
|
|
167
504
|
feeRecipient: pafiFeeRecipient
|
|
168
505
|
};
|
|
169
506
|
}
|
|
@@ -195,26 +532,26 @@ var TradingHandlers = class {
|
|
|
195
532
|
if (request.amount <= 0n) {
|
|
196
533
|
throw new Error("handlePerpDeposit: amount must be positive");
|
|
197
534
|
}
|
|
198
|
-
const vault =
|
|
535
|
+
const vault = import_core9.ORDERLY_VAULT_ADDRESSES[request.chainId];
|
|
199
536
|
if (!vault) {
|
|
200
537
|
throw new Error(`handlePerpDeposit: no Orderly Vault for chainId ${request.chainId}`);
|
|
201
538
|
}
|
|
202
|
-
const brokerHash =
|
|
539
|
+
const brokerHash = import_core9.BROKER_HASHES[request.brokerId];
|
|
203
540
|
if (!brokerHash) {
|
|
204
541
|
throw new Error(`handlePerpDeposit: unknown brokerId "${request.brokerId}"`);
|
|
205
542
|
}
|
|
206
|
-
const tokenHash =
|
|
207
|
-
const userAddress = (0,
|
|
543
|
+
const tokenHash = import_core9.TOKEN_HASHES.USDC;
|
|
544
|
+
const userAddress = (0, import_viem4.getAddress)(request.userAddress);
|
|
208
545
|
const [usdcAddress, brokerAllowed] = await Promise.all([
|
|
209
546
|
this.provider.readContract({
|
|
210
547
|
address: vault,
|
|
211
|
-
abi:
|
|
548
|
+
abi: import_core9.ORDERLY_VAULT_ABI,
|
|
212
549
|
functionName: "getAllowedToken",
|
|
213
550
|
args: [tokenHash]
|
|
214
551
|
}),
|
|
215
552
|
this.provider.readContract({
|
|
216
553
|
address: vault,
|
|
217
|
-
abi:
|
|
554
|
+
abi: import_core9.ORDERLY_VAULT_ABI,
|
|
218
555
|
functionName: "getAllowedBroker",
|
|
219
556
|
args: [brokerHash]
|
|
220
557
|
})
|
|
@@ -224,7 +561,7 @@ var TradingHandlers = class {
|
|
|
224
561
|
`handlePerpDeposit: broker "${request.brokerId}" is not whitelisted on Orderly Vault`
|
|
225
562
|
);
|
|
226
563
|
}
|
|
227
|
-
const accountId = (0,
|
|
564
|
+
const accountId = (0, import_core9.computeAccountId)(userAddress, brokerHash);
|
|
228
565
|
const depositData = {
|
|
229
566
|
accountId,
|
|
230
567
|
brokerHash,
|
|
@@ -233,17 +570,17 @@ var TradingHandlers = class {
|
|
|
233
570
|
};
|
|
234
571
|
const layerZeroFee = await this.provider.readContract({
|
|
235
572
|
address: vault,
|
|
236
|
-
abi:
|
|
573
|
+
abi: import_core9.ORDERLY_VAULT_ABI,
|
|
237
574
|
functionName: "getDepositFee",
|
|
238
575
|
args: [userAddress, depositData]
|
|
239
576
|
});
|
|
240
577
|
const useRelay = request.viaRelay !== false;
|
|
241
|
-
const { orderlyRelay: relayAddress, pafiFeeRecipient } = (0,
|
|
578
|
+
const { orderlyRelay: relayAddress, pafiFeeRecipient } = (0, import_core9.getContractAddresses)(request.chainId);
|
|
242
579
|
const relayDeployed = !isPlaceholderAddress(relayAddress);
|
|
243
|
-
const gasFeePt = request.gasFeePt !== void 0 ? request.gasFeePt : useRelay && relayDeployed && request.pointTokenAddress ? await (0,
|
|
580
|
+
const gasFeePt = request.gasFeePt !== void 0 ? request.gasFeePt : useRelay && relayDeployed && request.pointTokenAddress ? await (0, import_core9.quoteOperatorFeePt)({
|
|
244
581
|
provider: this.provider,
|
|
245
582
|
chainId: request.chainId,
|
|
246
|
-
pointTokenAddress: (0,
|
|
583
|
+
pointTokenAddress: (0, import_viem4.getAddress)(request.pointTokenAddress)
|
|
247
584
|
}) : 0n;
|
|
248
585
|
if (useRelay && relayDeployed) {
|
|
249
586
|
const RELAY_FEE_FLOOR_USDC = 2000000n;
|
|
@@ -258,7 +595,7 @@ var TradingHandlers = class {
|
|
|
258
595
|
};
|
|
259
596
|
const relayTokenFee = await this.provider.readContract({
|
|
260
597
|
address: relayAddress,
|
|
261
|
-
abi:
|
|
598
|
+
abi: import_core9.ORDERLY_RELAY_ABI,
|
|
262
599
|
functionName: "quoteTokenFee",
|
|
263
600
|
args: [relayRequest]
|
|
264
601
|
});
|
|
@@ -274,7 +611,7 @@ var TradingHandlers = class {
|
|
|
274
611
|
`handlePerpDeposit: deposit amount ${amountUsdc} USDC is below the Relay fee ${feeUsdc} USDC \u2014 increase \`amount\` to at least ${(feeUsdc * 2).toFixed(6)} USDC so a meaningful balance reaches your Orderly account after the Relay charge.`
|
|
275
612
|
);
|
|
276
613
|
}
|
|
277
|
-
const userOp2 = (0,
|
|
614
|
+
const userOp2 = (0, import_core9.buildPerpDepositViaRelay)({
|
|
278
615
|
userAddress,
|
|
279
616
|
aaNonce: request.aaNonce,
|
|
280
617
|
relayAddress,
|
|
@@ -288,7 +625,7 @@ var TradingHandlers = class {
|
|
|
288
625
|
gasFeePt: gasFeePt > 0n ? gasFeePt : void 0,
|
|
289
626
|
gasFeePtRecipient: gasFeePt > 0n ? pafiFeeRecipient : void 0
|
|
290
627
|
});
|
|
291
|
-
const userOpFallback = gasFeePt > 0n ? (0,
|
|
628
|
+
const userOpFallback = gasFeePt > 0n ? (0, import_core9.buildPerpDepositViaRelay)({
|
|
292
629
|
userAddress,
|
|
293
630
|
aaNonce: request.aaNonce,
|
|
294
631
|
relayAddress,
|
|
@@ -308,7 +645,7 @@ var TradingHandlers = class {
|
|
|
308
645
|
feeRecipient: pafiFeeRecipient
|
|
309
646
|
};
|
|
310
647
|
}
|
|
311
|
-
const userOp = (0,
|
|
648
|
+
const userOp = (0, import_core9.buildPerpDepositWithGasDeduction)({
|
|
312
649
|
userAddress,
|
|
313
650
|
aaNonce: request.aaNonce,
|
|
314
651
|
chainId: request.chainId,
|
|
@@ -340,11 +677,25 @@ function isPlaceholderAddress(addr) {
|
|
|
340
677
|
}
|
|
341
678
|
|
|
342
679
|
// src/pools.ts
|
|
343
|
-
var
|
|
680
|
+
var import_core10 = require("@pafi-dev/core");
|
|
344
681
|
// Annotate the CommonJS export names for ESM import in node:
|
|
345
682
|
0 && (module.exports = {
|
|
346
683
|
PAFI_SUBGRAPH_URL,
|
|
347
684
|
TradingHandlers,
|
|
348
|
-
|
|
685
|
+
buildAllPaths,
|
|
686
|
+
buildErc20ApprovalCalldata,
|
|
687
|
+
buildPermit2ApprovalCalldata,
|
|
688
|
+
buildSwapFromQuote,
|
|
689
|
+
buildSwapUserOp,
|
|
690
|
+
buildUniversalRouterExecuteArgs,
|
|
691
|
+
buildV4SwapInput,
|
|
692
|
+
checkAllowance,
|
|
693
|
+
combineRoutes,
|
|
694
|
+
fetchPafiPools,
|
|
695
|
+
findBestQuote,
|
|
696
|
+
quoteBestRoute,
|
|
697
|
+
quoteExactInput,
|
|
698
|
+
quoteExactInputSingle,
|
|
699
|
+
simulateSwap
|
|
349
700
|
});
|
|
350
701
|
//# sourceMappingURL=index.cjs.map
|