@pafi-dev/trading 0.3.3 → 0.4.1

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.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { Address, PublicClient, Hex } from 'viem';
2
- import { PartialUserOperation, PoolKey, QuoteResult, PathKey, BestQuote } from '@pafi-dev/core';
1
+ import { Address, PublicClient, Hex, WalletClient, TransactionReceipt } from 'viem';
2
+ import { PartialUserOperation, PoolKey, QuoteResult, PathKey, BestQuote, ExactOutputBestQuote, ExactOutputQuoteResult, BROKER_HASHES } from '@pafi-dev/core';
3
3
  export { PAFI_SUBGRAPH_URL, fetchPafiPools } from '@pafi-dev/core';
4
4
 
5
5
  interface ApiQuoteRequest {
@@ -102,6 +102,95 @@ interface ApiSwapResponse {
102
102
  feeAmountUsed: bigint;
103
103
  feeRecipient: Address;
104
104
  }
105
+ interface ApiQuoteExactOutRequest {
106
+ chainId: number;
107
+ /** Token user is spending. */
108
+ inputTokenAddress: Address;
109
+ /** Token user wants to receive. */
110
+ outputTokenAddress: Address;
111
+ /** Exact OUTPUT token amount the user wants (raw decimals). */
112
+ amount: bigint;
113
+ /** Pools to include in routing. Combined with COMMON_POOLS. */
114
+ pools?: PoolKey[];
115
+ }
116
+ interface ApiQuoteExactOutResponse {
117
+ /** Echoes `request.amount` — the exact output amount. */
118
+ outputAmount: bigint;
119
+ /**
120
+ * Gross input required from the V4 quoter — before operator fee. Use
121
+ * for "you'll pay ~X PT for exactly Y USDT" UI; do not promise this
122
+ * number without slippage bounding. 0n when `quoteError` set.
123
+ */
124
+ estimatedInputAmount: bigint;
125
+ /**
126
+ * Total input the user must hold = `estimatedInputAmount + feeAmountInput`.
127
+ * Display this as the "you pay" number alongside the exact output amount.
128
+ */
129
+ inputGross: bigint;
130
+ /**
131
+ * Operator gas fee charged on the INPUT token side, raw units. 0n on
132
+ * fallback path or when handler couldn't quote.
133
+ */
134
+ feeAmountInput: bigint;
135
+ /** V4 Quoter's gas estimate for the route. */
136
+ gasEstimate: bigint;
137
+ quoteError?: ApiQuoteError;
138
+ }
139
+ interface ApiSwapExactOutRequest {
140
+ chainId: number;
141
+ userAddress: Address;
142
+ inputTokenAddress: Address;
143
+ outputTokenAddress: Address;
144
+ /** Exact OUTPUT token amount the user wants (raw decimals). */
145
+ amount: bigint;
146
+ /** ERC-4337 account nonce for the user's EOA (from EntryPoint). */
147
+ aaNonce: bigint;
148
+ /**
149
+ * Slippage tolerance in basis points (1 bps = 0.01%). Default: 50
150
+ * for single-hop, 100 for multi-hop. Slippage caps `maxAmountIn`
151
+ * upward (ceiling division) — the user agrees to spend up to this
152
+ * much extra to lock in the exact output.
153
+ */
154
+ slippageBps?: number;
155
+ /** Pools to consider. */
156
+ pools?: PoolKey[];
157
+ /**
158
+ * Operator fee in INPUT token units, paid to PAFI fee recipient
159
+ * BEFORE the swap. Charged input-side because exact-output promises
160
+ * the user a precise output amount.
161
+ *
162
+ * - `undefined` (default): handler auto-quotes via the operator-fee
163
+ * helper appropriate to `inputTokenAddress` (USDT/USDC/PT).
164
+ * - `0n`: strip the fee transfer (unsponsored fallback path).
165
+ * - explicit `bigint`: override.
166
+ */
167
+ gasFeeAmountInput?: bigint;
168
+ }
169
+ interface ApiSwapExactOutResponse {
170
+ /** Unsigned UserOp — attach paymaster + user signature, submit to Bundler. */
171
+ userOp: PartialUserOperation;
172
+ /**
173
+ * Fee-stripped fallback variant. Emitted only when `gasFeeAmountInput > 0`.
174
+ * Submit when the paymaster refuses sponsorship.
175
+ */
176
+ userOpFallback?: PartialUserOperation;
177
+ /** Echoes `request.amount` — the exact output. */
178
+ outputAmount: bigint;
179
+ /** Raw input amount from the V4 quoter, before slippage. For display. */
180
+ estimatedInputAmount: bigint;
181
+ /** Maximum input accepted — encoded in the UserOp calldata. */
182
+ maxAmountIn: bigint;
183
+ /** Number of hops in the chosen route. */
184
+ hops: number;
185
+ /** Swap deadline (unix seconds). */
186
+ deadline: bigint;
187
+ /**
188
+ * Operator fee amount embedded — echoes auto-quote or override.
189
+ * Denominated in the INPUT token. `0n` when no-fee mode.
190
+ */
191
+ feeAmountUsed: bigint;
192
+ feeRecipient: Address;
193
+ }
105
194
  interface ApiPerpDepositRequest {
106
195
  chainId: number;
107
196
  userAddress: Address;
@@ -253,12 +342,41 @@ declare class TradingHandlers {
253
342
  * net. Quote response surfaces both `estimatedOutputAmount` (gross)
254
343
  * and `outputNet` so the FE can display reality.
255
344
  *
256
- * v0.3.1 — `authenticatedAddress` first param. Caller (issuer
257
- * controller / FE proxy) MUST pass the address extracted from the
258
- * verified session/JWT. Handler asserts it equals
259
- * `request.userAddress`. See SDK_CORE_TRADING_AUDIT.md C6.
345
+ * `authenticatedAddress` first param: caller (issuer controller / FE
346
+ * proxy) MUST pass the address extracted from the verified
347
+ * session/JWT. Handler asserts it equals `request.userAddress`.
260
348
  */
261
349
  handleSwap(authenticatedAddress: Address, request: ApiSwapRequest): Promise<ApiSwapResponse>;
350
+ /**
351
+ * Quote the input required to receive `request.amount` of the output
352
+ * token via Uniswap V4. Input-side operator fee is auto-quoted, so
353
+ * `inputGross = estimatedInputAmount + feeAmountInput` is the total
354
+ * the user must hold.
355
+ *
356
+ * Returns `quoteError: "QUOTE_UNAVAILABLE"` rather than throwing when
357
+ * no path exists.
358
+ */
359
+ handleQuoteExactOut(request: ApiQuoteExactOutRequest): Promise<ApiQuoteExactOutResponse>;
360
+ /**
361
+ * Build a V4 exact-output swap UserOp.
362
+ *
363
+ * Quotes the best exact-output route, applies slippage as a CEILING on
364
+ * `maxAmountIn` (so the cap is never silently tightened by floor
365
+ * division), then encodes a 4-step batch:
366
+ *
367
+ * inputToken.transfer(feeRecipient, gasFeeAmountInput) [if > 0]
368
+ * → input.approve(Permit2, maxAmountIn)
369
+ * → Permit2.approve(router, maxAmountIn)
370
+ * → UniversalRouter.execute (V4 SWAP_EXACT_OUT)
371
+ *
372
+ * Operator fee is INPUT-token-side (charged before swap) so the user
373
+ * receives exactly `request.amount` of output.
374
+ *
375
+ * `authenticatedAddress` first param: caller MUST pass the address
376
+ * extracted from the verified session/JWT. Handler asserts equality
377
+ * with `request.userAddress`.
378
+ */
379
+ handleSwapExactOut(authenticatedAddress: Address, request: ApiSwapExactOutRequest): Promise<ApiSwapExactOutResponse>;
262
380
  /**
263
381
  * Build an Orderly perp deposit UserOp.
264
382
  *
@@ -290,6 +408,8 @@ declare function buildErc20ApprovalCalldata(spender: Address, amount: bigint): H
290
408
  */
291
409
  declare function buildPermit2ApprovalCalldata(token: Address, spender: Address, amount: bigint, expiration: number): Hex;
292
410
 
411
+ declare const SWAP_EXACT_OUT_SINGLE: 8;
412
+ declare const SWAP_EXACT_OUT: 9;
293
413
  /**
294
414
  * Build the calldata inputs[0] (the V4_SWAP command payload) for
295
415
  * UniversalRouter.execute.
@@ -308,22 +428,33 @@ declare function buildUniversalRouterExecuteArgs(currencyIn: Address, path: Path
308
428
  inputs: Hex[];
309
429
  };
310
430
  /**
311
- * Build UniversalRouter execute args from a quote result.
431
+ * Build the calldata inputs[0] (the V4_SWAP command payload) for
432
+ * UniversalRouter.execute, using the V4 exact-output flow.
312
433
  *
313
- * Takes the output of `findBestQuote` / `quoteBestRoute` and produces
314
- * ready-to-use `{ commands, inputs }` for `UniversalRouter.execute`.
434
+ * Actions encoded: SWAP_EXACT_OUT SETTLE_ALL TAKE_ALL
315
435
  *
316
- * @param quote - Quote result containing the path
317
- * @param currencyIn - Input token address
318
- * @param currencyOut - Output token address
319
- * @param amountIn - Exact input amount (same value passed to the quoter)
320
- * @param minAmountOut - Minimum acceptable output (caller applies slippage)
436
+ * Settle/take semantics flip vs. the exact-input builder:
437
+ * - SETTLE_ALL caps the input pulled at `maxAmountIn` (router pulls
438
+ * only the actual amount the swap consumed; reverts if it exceeds
439
+ * the cap).
440
+ * - TAKE_ALL requires the user to receive *exactly* `amountOut` of
441
+ * `outputCurrency`.
321
442
  *
322
- * @deprecated Since v1.4 the Issuer App no longer handles swaps.
323
- * For the new PTUSDT batch call on PAFI Web (Scenario 4 with
324
- * EIP-7702 gas deduction), use `buildSwapWithGasDeduction()` (v1.5).
325
- * This helper is kept for legacy v0.2.x consumers; will be removed in v2.0.
443
+ * The `path` argument here is in V4 exact-output orientation i.e.
444
+ * traversed outputinput which is what `findBestQuoteExactOut`
445
+ * (and `buildAllPaths(pools, tokenOut, tokenIn, ...)`) returns.
446
+ *
447
+ * @throws if `amountOut` or `maxAmountIn` exceeds 2^128 - 1.
448
+ */
449
+ declare function buildV4SwapInputExactOut(currencyOut: Address, path: PathKey[], amountOut: bigint, maxAmountIn: bigint, inputCurrency: Address): Hex;
450
+ /**
451
+ * Build the full commands + inputs args for UniversalRouter.execute,
452
+ * using the V4 exact-output flow.
326
453
  */
454
+ declare function buildUniversalRouterExecuteArgsExactOut(currencyOut: Address, path: PathKey[], amountOut: bigint, maxAmountIn: bigint, inputCurrency: Address): {
455
+ commands: Hex;
456
+ inputs: Hex[];
457
+ };
327
458
  declare function buildSwapFromQuote(params: {
328
459
  quote: QuoteResult;
329
460
  currencyIn: Address;
@@ -452,6 +583,80 @@ interface BuildSwapUserOpParams {
452
583
  * negative, `swapPath` is empty, or `minAmountOut < gasFeeAmountOutput`.
453
584
  */
454
585
  declare function buildSwapUserOp(params: BuildSwapUserOpParams): PartialUserOperation;
586
+ /**
587
+ * Parameters for `buildSwapUserOpExactOut`.
588
+ *
589
+ * @remarks
590
+ * The user must hold **`maxAmountIn + gasFeeAmountInput`** of
591
+ * `inputTokenAddress` before this UserOp executes — the operator-fee
592
+ * transfer is pre-swap, so it cannot be paid from swap proceeds.
593
+ */
594
+ interface BuildSwapUserOpExactOutParams {
595
+ /** User's EOA (with EIP-7702 delegation to BatchExecutor). */
596
+ userAddress: Address;
597
+ /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */
598
+ aaNonce: bigint;
599
+ /** Token being spent — approved to Permit2 + UniversalRouter. */
600
+ inputTokenAddress: Address;
601
+ /** Token user receives (exactly `amountOut` of). */
602
+ outputTokenAddress: Address;
603
+ /** UniversalRouter contract address (chain-specific). */
604
+ universalRouterAddress: Address;
605
+ /** Exact OUTPUT token amount the user wants to receive. */
606
+ amountOut: bigint;
607
+ /**
608
+ * Maximum INPUT token amount the user is willing to spend on the swap
609
+ * (slippage cap). The Permit2 approval covers this amount; the swap
610
+ * settles only the actual amount consumed.
611
+ */
612
+ maxAmountIn: bigint;
613
+ /**
614
+ * V4 pool path in **output→input** orientation. Single-hop = 1 PathKey,
615
+ * multi-hop = N. Get this from `findBestQuoteExactOut().bestRoute.path`.
616
+ */
617
+ swapPath: PathKey[];
618
+ /** Unix seconds. After this, the router rejects the swap. */
619
+ deadline: bigint;
620
+ /**
621
+ * Operator gas-reimbursement fee — paid in INPUT token, transferred
622
+ * BEFORE the swap. Omitted from the batch when 0n.
623
+ *
624
+ * Charged input-side rather than output-side because exact-output
625
+ * promises the user a precise output amount; deducting from output
626
+ * would silently break that promise. Mirrors the v0.3 input-side fee
627
+ * pattern used by perp-deposit.
628
+ */
629
+ gasFeeAmountInput: bigint;
630
+ /**
631
+ * Where the gas fee lands — typically the canonical PAFI fee
632
+ * recipient from `getContractAddresses(chainId).pafiFeeRecipient`.
633
+ */
634
+ feeRecipient: Address;
635
+ /** Override ERC-4337 gas estimates. Defaults are conservative. */
636
+ gasLimits?: {
637
+ callGasLimit?: bigint;
638
+ verificationGasLimit?: bigint;
639
+ preVerificationGas?: bigint;
640
+ };
641
+ }
642
+ /**
643
+ * Build an unsigned UserOp for the V4 exact-output swap flow.
644
+ *
645
+ * UserOp shape (atomic batch via EIP-7702 BatchExecutor):
646
+ *
647
+ * 1. `inputToken.transfer(feeRecipient, gasFeeAmountInput)` — operator
648
+ * gas reimbursement, paid in INPUT token (omitted when 0).
649
+ * 2. `inputToken.approve(Permit2, maxAmountIn)` — cap, not exact.
650
+ * 3. `Permit2.approve(inputToken, router, maxAmountIn, deadline)` —
651
+ * Permit2 authorization to UniversalRouter for up to `maxAmountIn`.
652
+ * 4. `UniversalRouter.execute(commands, inputs, deadline)` — V4
653
+ * exact-output swap; user receives exactly `amountOut`.
654
+ *
655
+ * @throws when `amountOut`/`maxAmountIn` are non-positive,
656
+ * `gasFeeAmountInput` is negative, `swapPath` is empty, or `deadline`
657
+ * is out of Permit2's uint48 range.
658
+ */
659
+ declare function buildSwapUserOpExactOut(params: BuildSwapUserOpExactOutParams): PartialUserOperation;
455
660
 
456
661
  /**
457
662
  * Combine point-token-specific pools and common pools for a given chain.
@@ -507,5 +712,322 @@ declare function quoteBestRoute(client: PublicClient, quoterAddress: Address, ex
507
712
  * @param maxHops - Maximum number of hops per path (default 3)
508
713
  */
509
714
  declare function findBestQuote(client: PublicClient, chainId: number, tokenIn: Address, tokenOut: Address, exactAmount: bigint, pools?: PoolKey[], quoterAddress?: Address, maxHops?: number): Promise<BestQuote>;
715
+ /**
716
+ * Quote V4 exact-output for a multi-hop path.
717
+ *
718
+ * @param exactCurrency - The OUTPUT token (the one the user wants to
719
+ * receive a precise amount of).
720
+ * @param path - PathKey[] in output→input orientation. Use
721
+ * `buildAllPaths(pools, tokenOut, tokenIn, ...)`
722
+ * (arguments swapped vs. exact-in) to produce
723
+ * the right shape.
724
+ * @param exactAmount - Exact OUTPUT amount the user wants.
725
+ * @returns `{ amountIn, gasEstimate, path }` — the input amount required
726
+ * to receive `exactAmount` of `exactCurrency`.
727
+ */
728
+ declare function quoteExactOutput(client: PublicClient, quoterAddress: Address, exactCurrency: Address, path: PathKey[], exactAmount: bigint): Promise<ExactOutputQuoteResult>;
729
+ /**
730
+ * Quote V4 exact-output for a single-hop swap, given an explicit PoolKey
731
+ * and direction.
732
+ *
733
+ * `zeroForOne` semantics are identical to the exact-input variant —
734
+ * "trade direction" is invariant to the exactness parameter. Only
735
+ * `exactAmount` flips meaning (here: amount of *output* currency the
736
+ * user wants to receive).
737
+ */
738
+ declare function quoteExactOutputSingle(client: PublicClient, quoterAddress: Address, poolKey: PoolKey, zeroForOne: boolean, exactAmount: bigint, hookData: `0x${string}`): Promise<{
739
+ amountIn: bigint;
740
+ gasEstimate: bigint;
741
+ }>;
742
+ /**
743
+ * Try multiple PathKey[] routes for an exact-output swap and return the
744
+ * route requiring the **smallest** input amount, plus all results.
745
+ * Routes that fail (e.g. pool does not exist) are silently skipped.
746
+ *
747
+ * Uses viem multicall to batch all quotes into a single RPC call.
748
+ */
749
+ declare function quoteBestRouteExactOut(client: PublicClient, quoterAddress: Address, exactCurrency: Address, routes: PathKey[][], exactAmount: bigint): Promise<ExactOutputBestQuote>;
750
+ /**
751
+ * Find and quote the best V4 exact-output route from `tokenIn` to
752
+ * `tokenOut` for a desired output amount.
753
+ *
754
+ * Symmetric to `findBestQuote` but with two key differences:
755
+ *
756
+ * - `exactAmount` is denominated in `tokenOut` (the OUTPUT token).
757
+ * - Internally calls `buildAllPaths(allPools, tokenOut, tokenIn, ...)`
758
+ * (arguments swapped) to enumerate paths in output→input
759
+ * orientation, which is what `quoteExactOutput` expects.
760
+ *
761
+ * @param client - viem PublicClient.
762
+ * @param chainId - Chain ID (looks up COMMON_POOLS + V4_QUOTER_ADDRESSES).
763
+ * @param tokenIn - Input token address (what user pays).
764
+ * @param tokenOut - Output token address (what user wants exactly).
765
+ * @param exactAmount - Exact OUTPUT amount.
766
+ * @param pools - Additional pools (e.g. point-token-specific).
767
+ * @param quoterAddress - Override the default V4 Quoter address.
768
+ * @param maxHops - Maximum number of hops per path (default 3).
769
+ */
770
+ declare function findBestQuoteExactOut(client: PublicClient, chainId: number, tokenIn: Address, tokenOut: Address, exactAmount: bigint, pools?: PoolKey[], quoterAddress?: Address, maxHops?: number): Promise<ExactOutputBestQuote>;
771
+
772
+ interface SwapDirectParams {
773
+ /** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */
774
+ userAddress: Address;
775
+ chainId: number;
776
+ inputTokenAddress: Address;
777
+ outputTokenAddress: Address;
778
+ /** Input amount (raw token decimals). */
779
+ amount: bigint;
780
+ /** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */
781
+ pools?: PoolKey[];
782
+ publicClient: PublicClient;
783
+ walletClient: WalletClient;
784
+ /**
785
+ * Slippage tolerance in basis points. Default 50 single-hop / 100
786
+ * multi-hop (handler picks based on `bestRoute.path.length`).
787
+ */
788
+ slippageBps?: number;
789
+ /** Swap deadline (unix seconds). Default = now + 5 minutes. */
790
+ deadline?: bigint;
791
+ /**
792
+ * Operator fee in OUTPUT token, paid to PAFI fee recipient.
793
+ *
794
+ * - `undefined` (default for direct path): **skip the fee transfer
795
+ * entirely** — PAFI is not sponsoring this swap, no reimbursement
796
+ * owed. Most callers want this.
797
+ * - `0n` — same as above, explicit.
798
+ * - explicit `bigint` — include the fee transfer (rare; only when
799
+ * issuer dev/test wants to mirror sponsored behaviour).
800
+ */
801
+ gasFeeAmountOutput?: bigint;
802
+ /** Wait for receipt before returning. Default `true`. */
803
+ waitForReceipt?: boolean;
804
+ onWarning?: (msg: string) => void;
805
+ }
806
+ interface SwapDirectResult {
807
+ txHash: Hex;
808
+ receipt?: TransactionReceipt;
809
+ estimatedOutputAmount: bigint;
810
+ minAmountOut: bigint;
811
+ hops: number;
812
+ deadline: bigint;
813
+ feeAmountUsed: bigint;
814
+ }
815
+ /**
816
+ * One-shot helper for the **FE-direct swap** path — no AA, no bundler,
817
+ * no PAFI sponsor-relayer. The user EOA pays gas in ETH and broadcasts
818
+ * a single type-2 transaction calling its own EIP-7702 delegated
819
+ * bytecode (`Simple7702Account.executeBatch`).
820
+ *
821
+ * Flow:
822
+ * 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl
823
+ * (Simple7702Account or Coinbase SW v2 BatchExecutor). Throw with
824
+ * a clear hint pointing at `delegateDirect()` if not delegated.
825
+ * 2. `findBestQuote` → best route + gross output.
826
+ * 3. `buildSwapUserOp` → encoded `executeBatch(calls)` calldata.
827
+ * 4. `walletClient.sendTransaction({ to: userAddress, data: callData })`
828
+ * — self-call into the delegated bytecode, which dispatches the
829
+ * batch (input.approve → Permit2.approve → UR.execute → optional
830
+ * fee transfer).
831
+ * 5. Wait for receipt (optional).
832
+ *
833
+ * Use when:
834
+ * - The FE doesn't have a Pimlico API key + doesn't want to depend on
835
+ * PAFI sponsor-relayer.
836
+ * - The user already has a small ETH balance.
837
+ * - You need a deterministic, single-tx swap (vs. AA UserOp's longer
838
+ * bundler round-trip).
839
+ *
840
+ * Throws when the user is NOT yet delegated — caller should run
841
+ * `delegateDirect` first or use the AA path (`TradingHandlers.handleSwap`
842
+ * + `permissionless`).
843
+ *
844
+ * @example
845
+ * ```ts
846
+ * import { swapDirect, fetchPafiPools } from "@pafi-dev/trading";
847
+ *
848
+ * const pools = await fetchPafiPools(8453, POINT_TOKEN);
849
+ * const result = await swapDirect({
850
+ * userAddress: wallet.address,
851
+ * chainId: 8453,
852
+ * inputTokenAddress: POINT_TOKEN,
853
+ * outputTokenAddress: USDT,
854
+ * amount: parseUnits("100", 18),
855
+ * pools,
856
+ * publicClient,
857
+ * walletClient,
858
+ * });
859
+ * console.log("Swap tx:", result.txHash);
860
+ * ```
861
+ */
862
+ declare function swapDirect(params: SwapDirectParams): Promise<SwapDirectResult>;
863
+
864
+ interface SwapDirectExactOutParams {
865
+ /** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */
866
+ userAddress: Address;
867
+ chainId: number;
868
+ inputTokenAddress: Address;
869
+ outputTokenAddress: Address;
870
+ /** Exact OUTPUT amount the user wants to receive (raw token decimals). */
871
+ amount: bigint;
872
+ /** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */
873
+ pools?: PoolKey[];
874
+ publicClient: PublicClient;
875
+ walletClient: WalletClient;
876
+ /**
877
+ * Slippage tolerance in basis points. Default 50 single-hop / 100
878
+ * multi-hop. Slippage is applied as a CEILING on `maxAmountIn`.
879
+ */
880
+ slippageBps?: number;
881
+ /** Swap deadline (unix seconds). Default = now + 5 minutes. */
882
+ deadline?: bigint;
883
+ /**
884
+ * Operator fee in INPUT token, paid to PAFI fee recipient.
885
+ *
886
+ * - `undefined` (default for direct path): **skip the fee transfer
887
+ * entirely** — PAFI is not sponsoring this swap, no reimbursement
888
+ * owed. Most callers want this.
889
+ * - `0n` — same as above, explicit.
890
+ * - explicit `bigint` — include the fee transfer (rare; only when
891
+ * issuer dev/test wants to mirror sponsored behaviour).
892
+ */
893
+ gasFeeAmountInput?: bigint;
894
+ /** Wait for receipt before returning. Default `true`. */
895
+ waitForReceipt?: boolean;
896
+ onWarning?: (msg: string) => void;
897
+ }
898
+ interface SwapDirectExactOutResult {
899
+ txHash: Hex;
900
+ receipt?: TransactionReceipt;
901
+ /** Echoes `params.amount` — the exact output. */
902
+ outputAmount: bigint;
903
+ /** Raw input amount from the V4 quoter, before slippage. */
904
+ estimatedInputAmount: bigint;
905
+ /** Slippage-bumped cap on input — encoded in the swap calldata. */
906
+ maxAmountIn: bigint;
907
+ hops: number;
908
+ deadline: bigint;
909
+ feeAmountUsed: bigint;
910
+ }
911
+ /**
912
+ * One-shot helper for the **FE-direct exact-output swap** path — no AA,
913
+ * no bundler, no PAFI sponsor-relayer. Symmetric to `swapDirect` but
914
+ * specifies the OUTPUT amount and bumps slippage UPWARD on `maxAmountIn`.
915
+ *
916
+ * Caller pre-conditions:
917
+ *
918
+ * - User EOA already has EIP-7702 delegation (`delegateDirect` first).
919
+ * - User EOA holds **`maxAmountIn + gasFeeAmountInput`** of
920
+ * `inputTokenAddress` (not just `amount` — that's output).
921
+ *
922
+ * Flow:
923
+ * 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl.
924
+ * 2. `findBestQuoteExactOut` → best route + required input.
925
+ * 3. Slippage ceiling → `maxAmountIn`.
926
+ * 4. `buildSwapUserOpExactOut` → encoded `executeBatch(calls)` calldata.
927
+ * 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.
928
+ * 6. Wait for receipt (optional).
929
+ *
930
+ * @example
931
+ * ```ts
932
+ * import { swapDirectExactOut, fetchPafiPools } from "@pafi-dev/trading";
933
+ *
934
+ * const pools = await fetchPafiPools(8453, POINT_TOKEN);
935
+ * const result = await swapDirectExactOut({
936
+ * userAddress: wallet.address,
937
+ * chainId: 8453,
938
+ * inputTokenAddress: POINT_TOKEN,
939
+ * outputTokenAddress: USDT,
940
+ * amount: parseUnits("50", 6), // exactly 50 USDT
941
+ * pools,
942
+ * publicClient,
943
+ * walletClient,
944
+ * });
945
+ * console.log("Swap tx:", result.txHash);
946
+ * ```
947
+ */
948
+ declare function swapDirectExactOut(params: SwapDirectExactOutParams): Promise<SwapDirectExactOutResult>;
949
+
950
+ interface PerpDepositDirectParams {
951
+ /** User EOA — must be EIP-7702 delegated. */
952
+ userAddress: Address;
953
+ chainId: number;
954
+ /** USDC amount to deposit (6-decimal raw units). */
955
+ amount: bigint;
956
+ /** Orderly broker — `'orderly' | 'woofi_pro' | 'logx'`. */
957
+ brokerId: keyof typeof BROKER_HASHES;
958
+ publicClient: PublicClient;
959
+ walletClient: WalletClient;
960
+ /**
961
+ * Max acceptable USDC fee charged by the Relay (slippage cap on its
962
+ * USD-pricing of `msg.value`). Default `max(amount * 5%, 2 USDC)` —
963
+ * matches `TradingHandlers.handlePerpDeposit`.
964
+ */
965
+ maxRelayFee?: bigint;
966
+ /**
967
+ * Operator fee in USDC (input-token, BEFORE deposit). Same semantics
968
+ * as `swapDirect.gasFeeAmountOutput`:
969
+ *
970
+ * - `undefined` (default for direct path): **skip the fee transfer**
971
+ * — PAFI is not sponsoring this deposit.
972
+ * - explicit `bigint` — include the fee transfer.
973
+ */
974
+ gasFeeUsdc?: bigint;
975
+ /** Wait for receipt before returning. Default `true`. */
976
+ waitForReceipt?: boolean;
977
+ onWarning?: (msg: string) => void;
978
+ }
979
+ interface PerpDepositDirectResult {
980
+ txHash: Hex;
981
+ receipt?: TransactionReceipt;
982
+ /** Resolved USDC fee charged by the Relay. */
983
+ relayTokenFee: bigint;
984
+ /** Cap applied to the Relay fee (slippage allowance). */
985
+ maxFee: bigint;
986
+ /** USDC reaching Orderly Vault after Relay's fee = amount - relayTokenFee. */
987
+ netDeposit: bigint;
988
+ /** Operator fee actually included (0n on default direct path). */
989
+ feeAmountUsed: bigint;
990
+ accountId: Hex;
991
+ brokerHash: Hex;
992
+ usdcAddress: Address;
993
+ relayAddress: Address;
994
+ }
995
+ /**
996
+ * One-shot helper for the **FE-direct perp deposit** path — no AA, no
997
+ * bundler, no PAFI sponsor-relayer. The user EOA pays gas in ETH and
998
+ * broadcasts a single type-2 transaction calling its own EIP-7702
999
+ * delegated bytecode (`Simple7702Account.executeBatch`).
1000
+ *
1001
+ * Flow:
1002
+ * 1. Verify EIP-7702 delegation (same precondition as `swapDirect`).
1003
+ * 2. Resolve USDC + verify broker is whitelisted on Orderly Vault.
1004
+ * 3. Quote `Relay.tokenFee` for the deposit; compute `netDeposit`.
1005
+ * 4. `buildPerpDepositViaRelay` → encoded `executeBatch(calls)`
1006
+ * (USDC.approve(relay) + Relay.deposit + optional fee transfer).
1007
+ * 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.
1008
+ * 6. Wait for receipt (optional).
1009
+ *
1010
+ * Use when: same conditions as `swapDirect` — FE doesn't have Pimlico
1011
+ * key, doesn't want sponsor-relayer dependency, user has small ETH.
1012
+ *
1013
+ * Throws when the user is NOT yet delegated.
1014
+ *
1015
+ * @example
1016
+ * ```ts
1017
+ * import { perpDepositDirect } from "@pafi-dev/trading";
1018
+ *
1019
+ * const result = await perpDepositDirect({
1020
+ * userAddress: wallet.address,
1021
+ * chainId: 8453,
1022
+ * amount: parseUnits("10", 6), // 10 USDC
1023
+ * brokerId: "orderly",
1024
+ * publicClient,
1025
+ * walletClient,
1026
+ * });
1027
+ * console.log("Deposit tx:", result.txHash);
1028
+ * console.log("Net deposit to Orderly:", result.netDeposit, "USDC raw");
1029
+ * ```
1030
+ */
1031
+ declare function perpDepositDirect(params: PerpDepositDirectParams): Promise<PerpDepositDirectResult>;
510
1032
 
511
- export { type ApiPerpDepositRequest, type ApiPerpDepositResponse, type ApiQuoteError, type ApiQuoteRequest, type ApiQuoteResponse, type ApiSwapRequest, type ApiSwapResponse, type BuildSwapUserOpParams, type SwapSimulationResult, TradingHandlers, type TradingHandlersConfig, buildAllPaths, buildErc20ApprovalCalldata, buildPermit2ApprovalCalldata, buildSwapFromQuote, buildSwapUserOp, buildUniversalRouterExecuteArgs, buildV4SwapInput, checkAllowance, combineRoutes, findBestQuote, quoteBestRoute, quoteExactInput, quoteExactInputSingle, simulateSwap };
1033
+ export { type ApiPerpDepositRequest, type ApiPerpDepositResponse, type ApiQuoteError, type ApiQuoteExactOutRequest, type ApiQuoteExactOutResponse, type ApiQuoteRequest, type ApiQuoteResponse, type ApiSwapExactOutRequest, type ApiSwapExactOutResponse, type ApiSwapRequest, type ApiSwapResponse, type BuildSwapUserOpExactOutParams, type BuildSwapUserOpParams, type PerpDepositDirectParams, type PerpDepositDirectResult, SWAP_EXACT_OUT, SWAP_EXACT_OUT_SINGLE, type SwapDirectExactOutParams, type SwapDirectExactOutResult, type SwapDirectParams, type SwapDirectResult, type SwapSimulationResult, TradingHandlers, type TradingHandlersConfig, buildAllPaths, buildErc20ApprovalCalldata, buildPermit2ApprovalCalldata, buildSwapFromQuote, buildSwapUserOp, buildSwapUserOpExactOut, buildUniversalRouterExecuteArgs, buildUniversalRouterExecuteArgsExactOut, buildV4SwapInput, buildV4SwapInputExactOut, checkAllowance, combineRoutes, findBestQuote, findBestQuoteExactOut, perpDepositDirect, quoteBestRoute, quoteBestRouteExactOut, quoteExactInput, quoteExactInputSingle, quoteExactOutput, quoteExactOutputSingle, simulateSwap, swapDirect, swapDirectExactOut };