@pafi-dev/trading 0.3.3 → 0.4.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 +95 -0
- package/dist/index.cjs +241 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +178 -3
- package/dist/index.d.ts +178 -3
- package/dist/index.js +258 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
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, BROKER_HASHES } from '@pafi-dev/core';
|
|
3
3
|
export { PAFI_SUBGRAPH_URL, fetchPafiPools } from '@pafi-dev/core';
|
|
4
4
|
|
|
5
5
|
interface ApiQuoteRequest {
|
|
@@ -508,4 +508,179 @@ declare function quoteBestRoute(client: PublicClient, quoterAddress: Address, ex
|
|
|
508
508
|
*/
|
|
509
509
|
declare function findBestQuote(client: PublicClient, chainId: number, tokenIn: Address, tokenOut: Address, exactAmount: bigint, pools?: PoolKey[], quoterAddress?: Address, maxHops?: number): Promise<BestQuote>;
|
|
510
510
|
|
|
511
|
-
|
|
511
|
+
interface SwapDirectParams {
|
|
512
|
+
/** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */
|
|
513
|
+
userAddress: Address;
|
|
514
|
+
chainId: number;
|
|
515
|
+
inputTokenAddress: Address;
|
|
516
|
+
outputTokenAddress: Address;
|
|
517
|
+
/** Input amount (raw token decimals). */
|
|
518
|
+
amount: bigint;
|
|
519
|
+
/** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */
|
|
520
|
+
pools?: PoolKey[];
|
|
521
|
+
publicClient: PublicClient;
|
|
522
|
+
walletClient: WalletClient;
|
|
523
|
+
/**
|
|
524
|
+
* Slippage tolerance in basis points. Default 50 single-hop / 100
|
|
525
|
+
* multi-hop (handler picks based on `bestRoute.path.length`).
|
|
526
|
+
*/
|
|
527
|
+
slippageBps?: number;
|
|
528
|
+
/** Swap deadline (unix seconds). Default = now + 5 minutes. */
|
|
529
|
+
deadline?: bigint;
|
|
530
|
+
/**
|
|
531
|
+
* Operator fee in OUTPUT token, paid to PAFI fee recipient.
|
|
532
|
+
*
|
|
533
|
+
* - `undefined` (default for direct path): **skip the fee transfer
|
|
534
|
+
* entirely** — PAFI is not sponsoring this swap, no reimbursement
|
|
535
|
+
* owed. Most callers want this.
|
|
536
|
+
* - `0n` — same as above, explicit.
|
|
537
|
+
* - explicit `bigint` — include the fee transfer (rare; only when
|
|
538
|
+
* issuer dev/test wants to mirror sponsored behaviour).
|
|
539
|
+
*/
|
|
540
|
+
gasFeeAmountOutput?: bigint;
|
|
541
|
+
/** Wait for receipt before returning. Default `true`. */
|
|
542
|
+
waitForReceipt?: boolean;
|
|
543
|
+
onWarning?: (msg: string) => void;
|
|
544
|
+
}
|
|
545
|
+
interface SwapDirectResult {
|
|
546
|
+
txHash: Hex;
|
|
547
|
+
receipt?: TransactionReceipt;
|
|
548
|
+
estimatedOutputAmount: bigint;
|
|
549
|
+
minAmountOut: bigint;
|
|
550
|
+
hops: number;
|
|
551
|
+
deadline: bigint;
|
|
552
|
+
feeAmountUsed: bigint;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* One-shot helper for the **FE-direct swap** path — no AA, no bundler,
|
|
556
|
+
* no PAFI sponsor-relayer. The user EOA pays gas in ETH and broadcasts
|
|
557
|
+
* a single type-2 transaction calling its own EIP-7702 delegated
|
|
558
|
+
* bytecode (`Simple7702Account.executeBatch`).
|
|
559
|
+
*
|
|
560
|
+
* Flow:
|
|
561
|
+
* 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl
|
|
562
|
+
* (Simple7702Account or Coinbase SW v2 BatchExecutor). Throw with
|
|
563
|
+
* a clear hint pointing at `delegateDirect()` if not delegated.
|
|
564
|
+
* 2. `findBestQuote` → best route + gross output.
|
|
565
|
+
* 3. `buildSwapUserOp` → encoded `executeBatch(calls)` calldata.
|
|
566
|
+
* 4. `walletClient.sendTransaction({ to: userAddress, data: callData })`
|
|
567
|
+
* — self-call into the delegated bytecode, which dispatches the
|
|
568
|
+
* batch (input.approve → Permit2.approve → UR.execute → optional
|
|
569
|
+
* fee transfer).
|
|
570
|
+
* 5. Wait for receipt (optional).
|
|
571
|
+
*
|
|
572
|
+
* Use when:
|
|
573
|
+
* - The FE doesn't have a Pimlico API key + doesn't want to depend on
|
|
574
|
+
* PAFI sponsor-relayer.
|
|
575
|
+
* - The user already has a small ETH balance.
|
|
576
|
+
* - You need a deterministic, single-tx swap (vs. AA UserOp's longer
|
|
577
|
+
* bundler round-trip).
|
|
578
|
+
*
|
|
579
|
+
* Throws when the user is NOT yet delegated — caller should run
|
|
580
|
+
* `delegateDirect` first or use the AA path (`TradingHandlers.handleSwap`
|
|
581
|
+
* + `permissionless`).
|
|
582
|
+
*
|
|
583
|
+
* @example
|
|
584
|
+
* ```ts
|
|
585
|
+
* import { swapDirect, fetchPafiPools } from "@pafi-dev/trading";
|
|
586
|
+
*
|
|
587
|
+
* const pools = await fetchPafiPools(8453, POINT_TOKEN);
|
|
588
|
+
* const result = await swapDirect({
|
|
589
|
+
* userAddress: wallet.address,
|
|
590
|
+
* chainId: 8453,
|
|
591
|
+
* inputTokenAddress: POINT_TOKEN,
|
|
592
|
+
* outputTokenAddress: USDT,
|
|
593
|
+
* amount: parseUnits("100", 18),
|
|
594
|
+
* pools,
|
|
595
|
+
* publicClient,
|
|
596
|
+
* walletClient,
|
|
597
|
+
* });
|
|
598
|
+
* console.log("Swap tx:", result.txHash);
|
|
599
|
+
* ```
|
|
600
|
+
*/
|
|
601
|
+
declare function swapDirect(params: SwapDirectParams): Promise<SwapDirectResult>;
|
|
602
|
+
|
|
603
|
+
interface PerpDepositDirectParams {
|
|
604
|
+
/** User EOA — must be EIP-7702 delegated. */
|
|
605
|
+
userAddress: Address;
|
|
606
|
+
chainId: number;
|
|
607
|
+
/** USDC amount to deposit (6-decimal raw units). */
|
|
608
|
+
amount: bigint;
|
|
609
|
+
/** Orderly broker — `'orderly' | 'woofi_pro' | 'logx'`. */
|
|
610
|
+
brokerId: keyof typeof BROKER_HASHES;
|
|
611
|
+
publicClient: PublicClient;
|
|
612
|
+
walletClient: WalletClient;
|
|
613
|
+
/**
|
|
614
|
+
* Max acceptable USDC fee charged by the Relay (slippage cap on its
|
|
615
|
+
* USD-pricing of `msg.value`). Default `max(amount * 5%, 2 USDC)` —
|
|
616
|
+
* matches `TradingHandlers.handlePerpDeposit`.
|
|
617
|
+
*/
|
|
618
|
+
maxRelayFee?: bigint;
|
|
619
|
+
/**
|
|
620
|
+
* Operator fee in USDC (input-token, BEFORE deposit). Same semantics
|
|
621
|
+
* as `swapDirect.gasFeeAmountOutput`:
|
|
622
|
+
*
|
|
623
|
+
* - `undefined` (default for direct path): **skip the fee transfer**
|
|
624
|
+
* — PAFI is not sponsoring this deposit.
|
|
625
|
+
* - explicit `bigint` — include the fee transfer.
|
|
626
|
+
*/
|
|
627
|
+
gasFeeUsdc?: bigint;
|
|
628
|
+
/** Wait for receipt before returning. Default `true`. */
|
|
629
|
+
waitForReceipt?: boolean;
|
|
630
|
+
onWarning?: (msg: string) => void;
|
|
631
|
+
}
|
|
632
|
+
interface PerpDepositDirectResult {
|
|
633
|
+
txHash: Hex;
|
|
634
|
+
receipt?: TransactionReceipt;
|
|
635
|
+
/** Resolved USDC fee charged by the Relay. */
|
|
636
|
+
relayTokenFee: bigint;
|
|
637
|
+
/** Cap applied to the Relay fee (slippage allowance). */
|
|
638
|
+
maxFee: bigint;
|
|
639
|
+
/** USDC reaching Orderly Vault after Relay's fee = amount - relayTokenFee. */
|
|
640
|
+
netDeposit: bigint;
|
|
641
|
+
/** Operator fee actually included (0n on default direct path). */
|
|
642
|
+
feeAmountUsed: bigint;
|
|
643
|
+
accountId: Hex;
|
|
644
|
+
brokerHash: Hex;
|
|
645
|
+
usdcAddress: Address;
|
|
646
|
+
relayAddress: Address;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* One-shot helper for the **FE-direct perp deposit** path — no AA, no
|
|
650
|
+
* bundler, no PAFI sponsor-relayer. The user EOA pays gas in ETH and
|
|
651
|
+
* broadcasts a single type-2 transaction calling its own EIP-7702
|
|
652
|
+
* delegated bytecode (`Simple7702Account.executeBatch`).
|
|
653
|
+
*
|
|
654
|
+
* Flow:
|
|
655
|
+
* 1. Verify EIP-7702 delegation (same precondition as `swapDirect`).
|
|
656
|
+
* 2. Resolve USDC + verify broker is whitelisted on Orderly Vault.
|
|
657
|
+
* 3. Quote `Relay.tokenFee` for the deposit; compute `netDeposit`.
|
|
658
|
+
* 4. `buildPerpDepositViaRelay` → encoded `executeBatch(calls)`
|
|
659
|
+
* (USDC.approve(relay) + Relay.deposit + optional fee transfer).
|
|
660
|
+
* 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.
|
|
661
|
+
* 6. Wait for receipt (optional).
|
|
662
|
+
*
|
|
663
|
+
* Use when: same conditions as `swapDirect` — FE doesn't have Pimlico
|
|
664
|
+
* key, doesn't want sponsor-relayer dependency, user has small ETH.
|
|
665
|
+
*
|
|
666
|
+
* Throws when the user is NOT yet delegated.
|
|
667
|
+
*
|
|
668
|
+
* @example
|
|
669
|
+
* ```ts
|
|
670
|
+
* import { perpDepositDirect } from "@pafi-dev/trading";
|
|
671
|
+
*
|
|
672
|
+
* const result = await perpDepositDirect({
|
|
673
|
+
* userAddress: wallet.address,
|
|
674
|
+
* chainId: 8453,
|
|
675
|
+
* amount: parseUnits("10", 6), // 10 USDC
|
|
676
|
+
* brokerId: "orderly",
|
|
677
|
+
* publicClient,
|
|
678
|
+
* walletClient,
|
|
679
|
+
* });
|
|
680
|
+
* console.log("Deposit tx:", result.txHash);
|
|
681
|
+
* console.log("Net deposit to Orderly:", result.netDeposit, "USDC raw");
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
declare function perpDepositDirect(params: PerpDepositDirectParams): Promise<PerpDepositDirectResult>;
|
|
685
|
+
|
|
686
|
+
export { type ApiPerpDepositRequest, type ApiPerpDepositResponse, type ApiQuoteError, type ApiQuoteRequest, type ApiQuoteResponse, type ApiSwapRequest, type ApiSwapResponse, type BuildSwapUserOpParams, type PerpDepositDirectParams, type PerpDepositDirectResult, type SwapDirectParams, type SwapDirectResult, type SwapSimulationResult, TradingHandlers, type TradingHandlersConfig, buildAllPaths, buildErc20ApprovalCalldata, buildPermit2ApprovalCalldata, buildSwapFromQuote, buildSwapUserOp, buildUniversalRouterExecuteArgs, buildV4SwapInput, checkAllowance, combineRoutes, findBestQuote, perpDepositDirect, quoteBestRoute, quoteExactInput, quoteExactInputSingle, simulateSwap, swapDirect };
|
package/dist/index.js
CHANGED
|
@@ -767,6 +767,261 @@ async function quoteOperatorFeeOutput(provider, chainId, outputTokenAddress) {
|
|
|
767
767
|
|
|
768
768
|
// src/pools.ts
|
|
769
769
|
import { fetchPafiPools, PAFI_SUBGRAPH_URL } from "@pafi-dev/core";
|
|
770
|
+
|
|
771
|
+
// src/direct/swapDirect.ts
|
|
772
|
+
import {
|
|
773
|
+
UNIVERSAL_ROUTER_ADDRESSES as UNIVERSAL_ROUTER_ADDRESSES2,
|
|
774
|
+
getContractAddresses as getContractAddresses2,
|
|
775
|
+
parseEip7702DelegatedAddress,
|
|
776
|
+
detectDelegateImpl,
|
|
777
|
+
SIMPLE_7702_IMPL_BASE_MAINNET,
|
|
778
|
+
BATCH_EXECUTOR_7702_IMPL
|
|
779
|
+
} from "@pafi-dev/core";
|
|
780
|
+
async function swapDirect(params) {
|
|
781
|
+
const code = await params.publicClient.getCode({
|
|
782
|
+
address: params.userAddress
|
|
783
|
+
});
|
|
784
|
+
const delegate = parseEip7702DelegatedAddress(code);
|
|
785
|
+
if (!delegate) {
|
|
786
|
+
throw new Error(
|
|
787
|
+
`swapDirect: user ${params.userAddress} is not EIP-7702 delegated. Run \`delegateDirect()\` first (user pays a one-time delegation tx) or use the AA path via \`TradingHandlers.handleSwap()\` + sponsor-relayer.`
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
const impl = detectDelegateImpl(delegate);
|
|
791
|
+
if (impl === "unknown") {
|
|
792
|
+
params.onWarning?.(
|
|
793
|
+
`swapDirect: user delegated to ${delegate} which is not a PAFI-recognised impl (expected ${SIMPLE_7702_IMPL_BASE_MAINNET} or ${BATCH_EXECUTOR_7702_IMPL}). Continuing \u2014 execute will revert if the impl doesn't expose executeBatch.`
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
const universalRouter = UNIVERSAL_ROUTER_ADDRESSES2[params.chainId];
|
|
797
|
+
if (!universalRouter) {
|
|
798
|
+
throw new Error(`swapDirect: no UniversalRouter for chainId ${params.chainId}`);
|
|
799
|
+
}
|
|
800
|
+
if (params.amount <= 0n) {
|
|
801
|
+
throw new Error("swapDirect: amount must be positive");
|
|
802
|
+
}
|
|
803
|
+
let quoteResult;
|
|
804
|
+
try {
|
|
805
|
+
quoteResult = await findBestQuote(
|
|
806
|
+
params.publicClient,
|
|
807
|
+
params.chainId,
|
|
808
|
+
params.inputTokenAddress,
|
|
809
|
+
params.outputTokenAddress,
|
|
810
|
+
params.amount,
|
|
811
|
+
params.pools ?? []
|
|
812
|
+
);
|
|
813
|
+
} catch (err) {
|
|
814
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
815
|
+
throw new Error(
|
|
816
|
+
`swapDirect: no swap path found from ${params.inputTokenAddress} to ${params.outputTokenAddress} (cause: ${cause})`
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
const hops = quoteResult.bestRoute.path.length;
|
|
820
|
+
const slippageBps = params.slippageBps ?? (hops > 1 ? 100 : 50);
|
|
821
|
+
const estimatedOutputAmount = quoteResult.bestRoute.amountOut;
|
|
822
|
+
const minAmountOut = estimatedOutputAmount * BigInt(1e4 - slippageBps) / 10000n;
|
|
823
|
+
const gasFeeAmountOutput = params.gasFeeAmountOutput ?? 0n;
|
|
824
|
+
if (gasFeeAmountOutput > 0n && minAmountOut < gasFeeAmountOutput) {
|
|
825
|
+
throw new Error(
|
|
826
|
+
`swapDirect: minAmountOut (${minAmountOut}) below operator fee (${gasFeeAmountOutput})`
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
const deadline = params.deadline ?? BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
|
|
830
|
+
const { pafiFeeRecipient } = getContractAddresses2(params.chainId);
|
|
831
|
+
const userOp = buildSwapUserOp({
|
|
832
|
+
userAddress: params.userAddress,
|
|
833
|
+
aaNonce: 0n,
|
|
834
|
+
// ignored on the native-tx path; nonce comes from EOA tx count
|
|
835
|
+
inputTokenAddress: params.inputTokenAddress,
|
|
836
|
+
outputTokenAddress: params.outputTokenAddress,
|
|
837
|
+
universalRouterAddress: universalRouter,
|
|
838
|
+
amountIn: params.amount,
|
|
839
|
+
minAmountOut,
|
|
840
|
+
swapPath: quoteResult.bestRoute.path,
|
|
841
|
+
deadline,
|
|
842
|
+
gasFeeAmountOutput,
|
|
843
|
+
feeRecipient: pafiFeeRecipient
|
|
844
|
+
});
|
|
845
|
+
const account = params.walletClient.account;
|
|
846
|
+
if (!account) {
|
|
847
|
+
throw new Error(
|
|
848
|
+
"swapDirect: walletClient has no account attached \u2014 cannot send tx"
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
const txHash = await params.walletClient.sendTransaction({
|
|
852
|
+
account,
|
|
853
|
+
chain: params.walletClient.chain,
|
|
854
|
+
to: params.userAddress,
|
|
855
|
+
value: 0n,
|
|
856
|
+
data: userOp.callData
|
|
857
|
+
});
|
|
858
|
+
let receipt;
|
|
859
|
+
if (params.waitForReceipt !== false) {
|
|
860
|
+
try {
|
|
861
|
+
receipt = await params.publicClient.waitForTransactionReceipt({
|
|
862
|
+
hash: txHash
|
|
863
|
+
});
|
|
864
|
+
} catch (err) {
|
|
865
|
+
params.onWarning?.(
|
|
866
|
+
`swapDirect: tx ${txHash} sent but receipt fetch failed: ${err instanceof Error ? err.message : String(err)}`
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return {
|
|
871
|
+
txHash,
|
|
872
|
+
receipt,
|
|
873
|
+
estimatedOutputAmount,
|
|
874
|
+
minAmountOut,
|
|
875
|
+
hops,
|
|
876
|
+
deadline,
|
|
877
|
+
feeAmountUsed: gasFeeAmountOutput
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// src/direct/perpDepositDirect.ts
|
|
882
|
+
import {
|
|
883
|
+
BROKER_HASHES as BROKER_HASHES2,
|
|
884
|
+
ORDERLY_RELAY_ABI as ORDERLY_RELAY_ABI2,
|
|
885
|
+
ORDERLY_VAULT_ABI as ORDERLY_VAULT_ABI2,
|
|
886
|
+
ORDERLY_VAULT_ADDRESSES as ORDERLY_VAULT_ADDRESSES2,
|
|
887
|
+
TOKEN_HASHES as TOKEN_HASHES2,
|
|
888
|
+
buildPerpDepositViaRelay as buildPerpDepositViaRelay2,
|
|
889
|
+
computeAccountId as computeAccountId2,
|
|
890
|
+
detectDelegateImpl as detectDelegateImpl2,
|
|
891
|
+
getContractAddresses as getContractAddresses3,
|
|
892
|
+
parseEip7702DelegatedAddress as parseEip7702DelegatedAddress2,
|
|
893
|
+
BATCH_EXECUTOR_7702_IMPL as BATCH_EXECUTOR_7702_IMPL2,
|
|
894
|
+
SIMPLE_7702_IMPL_BASE_MAINNET as SIMPLE_7702_IMPL_BASE_MAINNET2
|
|
895
|
+
} from "@pafi-dev/core";
|
|
896
|
+
async function perpDepositDirect(params) {
|
|
897
|
+
if (params.amount <= 0n) {
|
|
898
|
+
throw new Error("perpDepositDirect: amount must be positive");
|
|
899
|
+
}
|
|
900
|
+
const code = await params.publicClient.getCode({
|
|
901
|
+
address: params.userAddress
|
|
902
|
+
});
|
|
903
|
+
const delegate = parseEip7702DelegatedAddress2(code);
|
|
904
|
+
if (!delegate) {
|
|
905
|
+
throw new Error(
|
|
906
|
+
`perpDepositDirect: user ${params.userAddress} is not EIP-7702 delegated. Run \`delegateDirect()\` first or use the AA path via \`TradingHandlers.handlePerpDeposit()\` + sponsor-relayer.`
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
const impl = detectDelegateImpl2(delegate);
|
|
910
|
+
if (impl === "unknown") {
|
|
911
|
+
params.onWarning?.(
|
|
912
|
+
`perpDepositDirect: user delegated to ${delegate} (not a PAFI-recognised impl ${SIMPLE_7702_IMPL_BASE_MAINNET2} / ${BATCH_EXECUTOR_7702_IMPL2}). Continuing \u2014 execute will revert if the impl doesn't expose executeBatch.`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
const vault = ORDERLY_VAULT_ADDRESSES2[params.chainId];
|
|
916
|
+
if (!vault) {
|
|
917
|
+
throw new Error(
|
|
918
|
+
`perpDepositDirect: no Orderly Vault for chainId ${params.chainId}`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
const brokerHash = BROKER_HASHES2[params.brokerId];
|
|
922
|
+
if (!brokerHash) {
|
|
923
|
+
throw new Error(
|
|
924
|
+
`perpDepositDirect: unknown brokerId "${params.brokerId}"`
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
const tokenHash = TOKEN_HASHES2.USDC;
|
|
928
|
+
const [usdcAddress, brokerAllowed] = await Promise.all([
|
|
929
|
+
params.publicClient.readContract({
|
|
930
|
+
address: vault,
|
|
931
|
+
abi: ORDERLY_VAULT_ABI2,
|
|
932
|
+
functionName: "getAllowedToken",
|
|
933
|
+
args: [tokenHash]
|
|
934
|
+
}),
|
|
935
|
+
params.publicClient.readContract({
|
|
936
|
+
address: vault,
|
|
937
|
+
abi: ORDERLY_VAULT_ABI2,
|
|
938
|
+
functionName: "getAllowedBroker",
|
|
939
|
+
args: [brokerHash]
|
|
940
|
+
})
|
|
941
|
+
]);
|
|
942
|
+
if (!brokerAllowed) {
|
|
943
|
+
throw new Error(
|
|
944
|
+
`perpDepositDirect: broker "${params.brokerId}" is not whitelisted on Orderly Vault`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
const { orderlyRelay: relayAddress, pafiFeeRecipient } = getContractAddresses3(
|
|
948
|
+
params.chainId
|
|
949
|
+
);
|
|
950
|
+
const RELAY_FEE_FLOOR_USDC = 2000000n;
|
|
951
|
+
const percentCap = params.amount * 500n / 10000n;
|
|
952
|
+
const maxFee = params.maxRelayFee ?? (percentCap > RELAY_FEE_FLOOR_USDC ? percentCap : RELAY_FEE_FLOOR_USDC);
|
|
953
|
+
const relayRequest = {
|
|
954
|
+
token: usdcAddress,
|
|
955
|
+
receiver: params.userAddress,
|
|
956
|
+
brokerHash,
|
|
957
|
+
totalAmount: params.amount,
|
|
958
|
+
maxFee
|
|
959
|
+
};
|
|
960
|
+
const relayTokenFee = await params.publicClient.readContract({
|
|
961
|
+
address: relayAddress,
|
|
962
|
+
abi: ORDERLY_RELAY_ABI2,
|
|
963
|
+
functionName: "quoteTokenFee",
|
|
964
|
+
args: [relayRequest]
|
|
965
|
+
});
|
|
966
|
+
if (relayTokenFee > maxFee) {
|
|
967
|
+
throw new Error(
|
|
968
|
+
`perpDepositDirect: Relay tokenFee ${relayTokenFee} exceeds maxFee ${maxFee} \u2014 pass a larger \`maxRelayFee\` or increase \`amount\`.`
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
if (relayTokenFee >= params.amount) {
|
|
972
|
+
throw new Error(
|
|
973
|
+
`perpDepositDirect: deposit amount ${params.amount} below Relay fee ${relayTokenFee} \u2014 increase \`amount\`.`
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
const gasFeeUsdc = params.gasFeeUsdc ?? 0n;
|
|
977
|
+
const partial = buildPerpDepositViaRelay2({
|
|
978
|
+
userAddress: params.userAddress,
|
|
979
|
+
aaNonce: 0n,
|
|
980
|
+
// ignored on the native-tx path
|
|
981
|
+
relayAddress,
|
|
982
|
+
request: relayRequest,
|
|
983
|
+
gasFeeUsdc: gasFeeUsdc > 0n ? gasFeeUsdc : void 0,
|
|
984
|
+
gasFeeUsdcRecipient: gasFeeUsdc > 0n ? pafiFeeRecipient : void 0
|
|
985
|
+
});
|
|
986
|
+
const account = params.walletClient.account;
|
|
987
|
+
if (!account) {
|
|
988
|
+
throw new Error(
|
|
989
|
+
"perpDepositDirect: walletClient has no account attached \u2014 cannot send tx"
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
const txHash = await params.walletClient.sendTransaction({
|
|
993
|
+
account,
|
|
994
|
+
chain: params.walletClient.chain,
|
|
995
|
+
to: params.userAddress,
|
|
996
|
+
value: 0n,
|
|
997
|
+
data: partial.callData
|
|
998
|
+
});
|
|
999
|
+
let receipt;
|
|
1000
|
+
if (params.waitForReceipt !== false) {
|
|
1001
|
+
try {
|
|
1002
|
+
receipt = await params.publicClient.waitForTransactionReceipt({
|
|
1003
|
+
hash: txHash
|
|
1004
|
+
});
|
|
1005
|
+
} catch (err) {
|
|
1006
|
+
params.onWarning?.(
|
|
1007
|
+
`perpDepositDirect: tx ${txHash} sent but receipt fetch failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
const accountId = computeAccountId2(params.userAddress, brokerHash);
|
|
1012
|
+
return {
|
|
1013
|
+
txHash,
|
|
1014
|
+
receipt,
|
|
1015
|
+
relayTokenFee,
|
|
1016
|
+
maxFee,
|
|
1017
|
+
netDeposit: params.amount - relayTokenFee,
|
|
1018
|
+
feeAmountUsed: gasFeeUsdc,
|
|
1019
|
+
accountId,
|
|
1020
|
+
brokerHash,
|
|
1021
|
+
usdcAddress,
|
|
1022
|
+
relayAddress
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
770
1025
|
export {
|
|
771
1026
|
PAFI_SUBGRAPH_URL,
|
|
772
1027
|
TradingHandlers,
|
|
@@ -781,9 +1036,11 @@ export {
|
|
|
781
1036
|
combineRoutes,
|
|
782
1037
|
fetchPafiPools,
|
|
783
1038
|
findBestQuote,
|
|
1039
|
+
perpDepositDirect,
|
|
784
1040
|
quoteBestRoute,
|
|
785
1041
|
quoteExactInput,
|
|
786
1042
|
quoteExactInputSingle,
|
|
787
|
-
simulateSwap
|
|
1043
|
+
simulateSwap,
|
|
1044
|
+
swapDirect
|
|
788
1045
|
};
|
|
789
1046
|
//# sourceMappingURL=index.js.map
|