@pafi-dev/core 0.6.2 → 0.7.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
@@ -100,6 +100,22 @@ declare class ApiError extends PafiSDKError {
100
100
  status?: number | undefined;
101
101
  constructor(message: string, status?: number | undefined);
102
102
  }
103
+ /**
104
+ * Thrown by `quoteOperatorFee*` when an upstream price source
105
+ * (Chainlink ETH/USD, PAFI subgraph) is unavailable or stale and the
106
+ * caller did not opt in to the hardcoded fallback prices.
107
+ *
108
+ * v0.7.1 — previously `quoteOperatorFeePt` silently fell back to
109
+ * ETH=$3000 / PT=$0.10 with `console.warn`. That caused mass
110
+ * `INSUFFICIENT_FEE` rejects during Chainlink incidents, or worse,
111
+ * accepted under-priced fees. Now opt-in via
112
+ * `allowStaleFallback: true`. See SDK_CORE_TRADING_AUDIT.md C2.
113
+ */
114
+ declare class OracleStaleError extends PafiSDKError {
115
+ readonly source: "chainlink" | "subgraph";
116
+ readonly reason: string;
117
+ constructor(source: "chainlink" | "subgraph", reason: string);
118
+ }
103
119
 
104
120
  /**
105
121
  * Orderly Network Vault — entrypoint for **perp deposit** flow on
@@ -505,14 +521,20 @@ interface BuildPerpDepositViaRelayParams {
505
521
  /** Deposit request (token, receiver, brokerHash, totalAmount, maxFee). */
506
522
  request: OrderlyRelayDepositRequest;
507
523
  /**
508
- * Optional PT gas-fee transfer prepended to the batch. Set both
509
- * `gasFeePtRecipient` and `gasFeePt` together for sponsored flows
510
- * (PAFI gas reimbursement). Pass `0n` / `undefined` for the fallback
511
- * path where the user pays ERC-4337 gas in ETH directly.
524
+ * Optional USDC (input-token) gas-fee transfer prepended to the batch.
525
+ * The user holds USDC at the start of the batch, so the fee comes out
526
+ * of the same input token no second-token requirement. Set both
527
+ * `gasFeeUsdcRecipient` and `gasFeeUsdc` together for sponsored
528
+ * flows (PAFI gas reimbursement). Pass `0n` / `undefined` for the
529
+ * fallback path where the user pays ERC-4337 gas in ETH directly.
530
+ *
531
+ * v0.7 — input-token fee position rule: user holds USDC BEFORE
532
+ * deposit (token-availability), so charge there. Replaces the old
533
+ * `gasFeePt` / `gasFeePtRecipient` / `pointTokenAddress` triple from
534
+ * v0.6.
512
535
  */
513
- pointTokenAddress?: Address;
514
- gasFeePt?: bigint;
515
- gasFeePtRecipient?: Address;
536
+ gasFeeUsdc?: bigint;
537
+ gasFeeUsdcRecipient?: Address;
516
538
  gasLimits?: {
517
539
  callGasLimit?: bigint;
518
540
  verificationGasLimit?: bigint;
@@ -522,10 +544,14 @@ interface BuildPerpDepositViaRelayParams {
522
544
  /**
523
545
  * Build a UserOp for Orderly perp deposit via the PAFI Relay.
524
546
  *
525
- * Sponsored ops: `[PT.transfer(feeRecipient, gasFeePt), USDC.approve(relay, total), Relay.deposit(req)]`
526
- * Fallback ops: `[ USDC.approve(relay, total), Relay.deposit(req)]`
547
+ * Sponsored ops: `[USDC.transfer(feeRecipient, gasFeeUsdc), USDC.approve(relay, total), Relay.deposit(req)]`
548
+ * Fallback ops: `[ USDC.approve(relay, total), Relay.deposit(req)]`
527
549
  *
528
550
  * No `msg.value` — the Relay covers LayerZero out of its own ETH reserve.
551
+ *
552
+ * Fee position rule: user holds USDC at start of batch → fee transfer
553
+ * runs FIRST in the same token. User must hold `totalAmount + gasFeeUsdc`
554
+ * USDC; net deposit to Orderly is `totalAmount - relayTokenFee`.
529
555
  */
530
556
  declare function buildPerpDepositViaRelay(params: BuildPerpDepositViaRelayParams): PartialUserOperation;
531
557
 
@@ -1159,13 +1185,18 @@ interface SmartAccountSender {
1159
1185
  * Returns true when `err` originates from the **paymaster layer** rather
1160
1186
  * than the contract or bundler layer. Covers:
1161
1187
  *
1162
- * - ERC-4337 AA3x validation errors (AA31–AA34)
1163
- * - Pimlico sponsorship rejections (`pm_*` methods, "sponsorship" messages)
1164
- * - PAFI proxy HTTP errors (401, 403, 429, 503)
1188
+ * - ERC-4337 AA3x validation errors (AA31–AA34, word-boundary match)
1189
+ * - Pimlico sponsorship rejections (`pm_*` methods, "sponsorship" / "paymaster")
1190
+ * - PAFI proxy HTTP errors checked via typed `status` / `statusCode`
1191
+ * field when present, NOT substring match
1165
1192
  * - Generic "rate limit" / "unauthorized" strings
1166
1193
  *
1167
1194
  * Use this to decide whether retrying without a paymaster makes sense.
1168
1195
  * Contract reverts (AA23, AA24, AA25) and bundler errors are NOT matched.
1196
+ *
1197
+ * v0.7.1 — replaced naive substring matching that false-positived on
1198
+ * arbitrary text containing "503"/"403"/"429" (e.g. address/transit ID).
1199
+ * See SDK_CORE_TRADING_AUDIT.md C3.
1169
1200
  */
1170
1201
  declare function isPaymasterError(err: unknown): boolean;
1171
1202
  interface SendWithPaymasterFallbackParams {
@@ -1241,9 +1272,20 @@ interface QuoteOperatorFeePtConfig {
1241
1272
  subgraphUrl?: string;
1242
1273
  /** USDT token decimals. Default 6 (USDC/USDT on Base/Ethereum). */
1243
1274
  usdtDecimals?: number;
1244
- /** Fallback ETH price (USD) when Chainlink is unreachable. Default 3000. */
1275
+ /**
1276
+ * Opt-in fallback prices used when Chainlink / subgraph is
1277
+ * unavailable. Default `false` — throw `OracleStaleError`. Set
1278
+ * `true` AND configure `fallbackEthPriceUsd` / `fallbackPtPriceUsdt`
1279
+ * to absorb oracle outages instead of surfacing them.
1280
+ *
1281
+ * v0.7.1 — previously fallback was always-on with hardcoded
1282
+ * defaults (ETH=$3000, PT=$0.10), causing under-priced fees during
1283
+ * incidents. See SDK_CORE_TRADING_AUDIT.md C2.
1284
+ */
1285
+ allowStaleFallback?: boolean;
1286
+ /** Fallback ETH price (USD) when Chainlink is unreachable. Only used when `allowStaleFallback: true`. Default 3000. */
1245
1287
  fallbackEthPriceUsd?: number;
1246
- /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Default 0.1. */
1288
+ /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Only used when `allowStaleFallback: true`. Default 0.1. */
1247
1289
  fallbackPtPriceUsdt?: number;
1248
1290
  fetchImpl?: typeof fetch;
1249
1291
  }
@@ -1260,6 +1302,11 @@ interface QuoteOperatorFeeUsdtConfig {
1260
1302
  premiumBps?: number;
1261
1303
  chainlinkFeedAddress?: Address;
1262
1304
  usdtDecimals?: number;
1305
+ /**
1306
+ * Opt-in fallback price when Chainlink is unavailable. Default
1307
+ * `false` — throw `OracleStaleError`. v0.7.1 — see C2.
1308
+ */
1309
+ allowStaleFallback?: boolean;
1263
1310
  fallbackEthPriceUsd?: number;
1264
1311
  }
1265
1312
  /**
@@ -1703,4 +1750,4 @@ declare class PafiSDK {
1703
1750
  signLoginMessage(message: string): Promise<Hex>;
1704
1751
  }
1705
1752
 
1706
- export { ApiError, BATCH_EXECUTOR_7702_IMPL, BATCH_EXECUTOR_ABI, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, BROKER_HASHES, type BuildDelegationUserOpParams, type BuildPartialUserOpParams, type BuildPerpDepositViaRelayParams, type BuildPerpDepositWithGasDeductionParams, COMMON_POOLS, COMMON_TOKENS, CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, DUMMY_SIGNATURE_V07, type DelegateImpl, EIP712Signature, ENTRY_POINT_V07, ENTRY_POINT_V08, type Eip7702AuthorizationJsonRpc, LoginMessageParams, MintRequest, type ModalOpenOptions, ORDERLY_RELAY_ABI, ORDERLY_VAULT_ABI, ORDERLY_VAULT_ADDRESSES, ORDERLY_VAULT_BASE_MAINNET, type Operation, type OrderlyRelayDepositRequest, PAFI_SUBGRAPH_URL, PERMIT2_ADDRESS, POINT_TOKEN_FACTORY_ADDRESSES, POINT_TOKEN_IMPL_ADDRESSES, POINT_TOKEN_POOLS, type PackedUserOperationMessage, type PafiProxyTransportParams, PafiSDK, PafiSDKConfig, PafiSDKError, type PafiWebModalAdapter, type PafiWebModalHandle, type PartialUserOperation, type PaymasterConfig, type PaymasterFields, PointTokenDomainConfig, PoolKey, type QuoteOperatorFeePtConfig, type QuoteOperatorFeeUsdtConfig, ReceiverConsent, SIMPLE_7702_IMPL_BASE_MAINNET, SUPPORTED_CHAINS, type SendWithPaymasterFallbackParams, type SignatureStruct, SignatureVerification, SigningError, SimulationError, type SmartAccountSender, type SponsorshipScenario, type SubmissionPath, TOKEN_HASHES, UNIVERSAL_ROUTER_ADDRESSES, type UserOpReceipt, type UserOpTypedData, type UserOperation, V4_QUOTER_ADDRESSES, type VaultDepositFE, ZERO_VALUE, _resetPaymasterConfigForTests, assembleUserOperation, buildDelegationUserOp, buildEip7702Authorization, buildPartialUserOperation, buildPerpDepositViaRelay, buildPerpDepositWithGasDeduction, buildUserOpTypedData, burnRequestTypes, checkDelegation, checkEthAndBranch, computeAccountId, computeAuthorizationHash, computeUserOpHash, createPafiProxyTransport, decodeBatchExecuteCalls, detectDelegateImpl, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, fetchPafiPools, getAaNonce, getContractAddresses, getDummySignatureFor7702, getPafiWebModalAdapter, getPaymasterConfig, isDelegatedTo, isDelegatedToTarget, isPaymasterConfigured, isPaymasterError, mintRequestTypes, openPafiWebModal, openWebPopup, parseEip7702DelegatedAddress, quoteOperatorFeePt, quoteOperatorFeeUsdt, rawCallOp, receiverConsentTypes, sendWithPaymasterFallback, serializeUserOpToJsonRpc, setPafiWebModalAdapter, setPaymasterConfig, splitAuthorizationSig, webPopupAdapter };
1753
+ export { ApiError, BATCH_EXECUTOR_7702_IMPL, BATCH_EXECUTOR_ABI, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, BROKER_HASHES, type BuildDelegationUserOpParams, type BuildPartialUserOpParams, type BuildPerpDepositViaRelayParams, type BuildPerpDepositWithGasDeductionParams, COMMON_POOLS, COMMON_TOKENS, CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, DUMMY_SIGNATURE_V07, type DelegateImpl, EIP712Signature, ENTRY_POINT_V07, ENTRY_POINT_V08, type Eip7702AuthorizationJsonRpc, LoginMessageParams, MintRequest, type ModalOpenOptions, ORDERLY_RELAY_ABI, ORDERLY_VAULT_ABI, ORDERLY_VAULT_ADDRESSES, ORDERLY_VAULT_BASE_MAINNET, type Operation, OracleStaleError, type OrderlyRelayDepositRequest, PAFI_SUBGRAPH_URL, PERMIT2_ADDRESS, POINT_TOKEN_FACTORY_ADDRESSES, POINT_TOKEN_IMPL_ADDRESSES, POINT_TOKEN_POOLS, type PackedUserOperationMessage, type PafiProxyTransportParams, PafiSDK, PafiSDKConfig, PafiSDKError, type PafiWebModalAdapter, type PafiWebModalHandle, type PartialUserOperation, type PaymasterConfig, type PaymasterFields, PointTokenDomainConfig, PoolKey, type QuoteOperatorFeePtConfig, type QuoteOperatorFeeUsdtConfig, ReceiverConsent, SIMPLE_7702_IMPL_BASE_MAINNET, SUPPORTED_CHAINS, type SendWithPaymasterFallbackParams, type SignatureStruct, SignatureVerification, SigningError, SimulationError, type SmartAccountSender, type SponsorshipScenario, type SubmissionPath, TOKEN_HASHES, UNIVERSAL_ROUTER_ADDRESSES, type UserOpReceipt, type UserOpTypedData, type UserOperation, V4_QUOTER_ADDRESSES, type VaultDepositFE, ZERO_VALUE, _resetPaymasterConfigForTests, assembleUserOperation, buildDelegationUserOp, buildEip7702Authorization, buildPartialUserOperation, buildPerpDepositViaRelay, buildPerpDepositWithGasDeduction, buildUserOpTypedData, burnRequestTypes, checkDelegation, checkEthAndBranch, computeAccountId, computeAuthorizationHash, computeUserOpHash, createPafiProxyTransport, decodeBatchExecuteCalls, detectDelegateImpl, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, fetchPafiPools, getAaNonce, getContractAddresses, getDummySignatureFor7702, getPafiWebModalAdapter, getPaymasterConfig, isDelegatedTo, isDelegatedToTarget, isPaymasterConfigured, isPaymasterError, mintRequestTypes, openPafiWebModal, openWebPopup, parseEip7702DelegatedAddress, quoteOperatorFeePt, quoteOperatorFeeUsdt, rawCallOp, receiverConsentTypes, sendWithPaymasterFallback, serializeUserOpToJsonRpc, setPafiWebModalAdapter, setPaymasterConfig, splitAuthorizationSig, webPopupAdapter };
package/dist/index.d.ts CHANGED
@@ -100,6 +100,22 @@ declare class ApiError extends PafiSDKError {
100
100
  status?: number | undefined;
101
101
  constructor(message: string, status?: number | undefined);
102
102
  }
103
+ /**
104
+ * Thrown by `quoteOperatorFee*` when an upstream price source
105
+ * (Chainlink ETH/USD, PAFI subgraph) is unavailable or stale and the
106
+ * caller did not opt in to the hardcoded fallback prices.
107
+ *
108
+ * v0.7.1 — previously `quoteOperatorFeePt` silently fell back to
109
+ * ETH=$3000 / PT=$0.10 with `console.warn`. That caused mass
110
+ * `INSUFFICIENT_FEE` rejects during Chainlink incidents, or worse,
111
+ * accepted under-priced fees. Now opt-in via
112
+ * `allowStaleFallback: true`. See SDK_CORE_TRADING_AUDIT.md C2.
113
+ */
114
+ declare class OracleStaleError extends PafiSDKError {
115
+ readonly source: "chainlink" | "subgraph";
116
+ readonly reason: string;
117
+ constructor(source: "chainlink" | "subgraph", reason: string);
118
+ }
103
119
 
104
120
  /**
105
121
  * Orderly Network Vault — entrypoint for **perp deposit** flow on
@@ -505,14 +521,20 @@ interface BuildPerpDepositViaRelayParams {
505
521
  /** Deposit request (token, receiver, brokerHash, totalAmount, maxFee). */
506
522
  request: OrderlyRelayDepositRequest;
507
523
  /**
508
- * Optional PT gas-fee transfer prepended to the batch. Set both
509
- * `gasFeePtRecipient` and `gasFeePt` together for sponsored flows
510
- * (PAFI gas reimbursement). Pass `0n` / `undefined` for the fallback
511
- * path where the user pays ERC-4337 gas in ETH directly.
524
+ * Optional USDC (input-token) gas-fee transfer prepended to the batch.
525
+ * The user holds USDC at the start of the batch, so the fee comes out
526
+ * of the same input token no second-token requirement. Set both
527
+ * `gasFeeUsdcRecipient` and `gasFeeUsdc` together for sponsored
528
+ * flows (PAFI gas reimbursement). Pass `0n` / `undefined` for the
529
+ * fallback path where the user pays ERC-4337 gas in ETH directly.
530
+ *
531
+ * v0.7 — input-token fee position rule: user holds USDC BEFORE
532
+ * deposit (token-availability), so charge there. Replaces the old
533
+ * `gasFeePt` / `gasFeePtRecipient` / `pointTokenAddress` triple from
534
+ * v0.6.
512
535
  */
513
- pointTokenAddress?: Address;
514
- gasFeePt?: bigint;
515
- gasFeePtRecipient?: Address;
536
+ gasFeeUsdc?: bigint;
537
+ gasFeeUsdcRecipient?: Address;
516
538
  gasLimits?: {
517
539
  callGasLimit?: bigint;
518
540
  verificationGasLimit?: bigint;
@@ -522,10 +544,14 @@ interface BuildPerpDepositViaRelayParams {
522
544
  /**
523
545
  * Build a UserOp for Orderly perp deposit via the PAFI Relay.
524
546
  *
525
- * Sponsored ops: `[PT.transfer(feeRecipient, gasFeePt), USDC.approve(relay, total), Relay.deposit(req)]`
526
- * Fallback ops: `[ USDC.approve(relay, total), Relay.deposit(req)]`
547
+ * Sponsored ops: `[USDC.transfer(feeRecipient, gasFeeUsdc), USDC.approve(relay, total), Relay.deposit(req)]`
548
+ * Fallback ops: `[ USDC.approve(relay, total), Relay.deposit(req)]`
527
549
  *
528
550
  * No `msg.value` — the Relay covers LayerZero out of its own ETH reserve.
551
+ *
552
+ * Fee position rule: user holds USDC at start of batch → fee transfer
553
+ * runs FIRST in the same token. User must hold `totalAmount + gasFeeUsdc`
554
+ * USDC; net deposit to Orderly is `totalAmount - relayTokenFee`.
529
555
  */
530
556
  declare function buildPerpDepositViaRelay(params: BuildPerpDepositViaRelayParams): PartialUserOperation;
531
557
 
@@ -1159,13 +1185,18 @@ interface SmartAccountSender {
1159
1185
  * Returns true when `err` originates from the **paymaster layer** rather
1160
1186
  * than the contract or bundler layer. Covers:
1161
1187
  *
1162
- * - ERC-4337 AA3x validation errors (AA31–AA34)
1163
- * - Pimlico sponsorship rejections (`pm_*` methods, "sponsorship" messages)
1164
- * - PAFI proxy HTTP errors (401, 403, 429, 503)
1188
+ * - ERC-4337 AA3x validation errors (AA31–AA34, word-boundary match)
1189
+ * - Pimlico sponsorship rejections (`pm_*` methods, "sponsorship" / "paymaster")
1190
+ * - PAFI proxy HTTP errors checked via typed `status` / `statusCode`
1191
+ * field when present, NOT substring match
1165
1192
  * - Generic "rate limit" / "unauthorized" strings
1166
1193
  *
1167
1194
  * Use this to decide whether retrying without a paymaster makes sense.
1168
1195
  * Contract reverts (AA23, AA24, AA25) and bundler errors are NOT matched.
1196
+ *
1197
+ * v0.7.1 — replaced naive substring matching that false-positived on
1198
+ * arbitrary text containing "503"/"403"/"429" (e.g. address/transit ID).
1199
+ * See SDK_CORE_TRADING_AUDIT.md C3.
1169
1200
  */
1170
1201
  declare function isPaymasterError(err: unknown): boolean;
1171
1202
  interface SendWithPaymasterFallbackParams {
@@ -1241,9 +1272,20 @@ interface QuoteOperatorFeePtConfig {
1241
1272
  subgraphUrl?: string;
1242
1273
  /** USDT token decimals. Default 6 (USDC/USDT on Base/Ethereum). */
1243
1274
  usdtDecimals?: number;
1244
- /** Fallback ETH price (USD) when Chainlink is unreachable. Default 3000. */
1275
+ /**
1276
+ * Opt-in fallback prices used when Chainlink / subgraph is
1277
+ * unavailable. Default `false` — throw `OracleStaleError`. Set
1278
+ * `true` AND configure `fallbackEthPriceUsd` / `fallbackPtPriceUsdt`
1279
+ * to absorb oracle outages instead of surfacing them.
1280
+ *
1281
+ * v0.7.1 — previously fallback was always-on with hardcoded
1282
+ * defaults (ETH=$3000, PT=$0.10), causing under-priced fees during
1283
+ * incidents. See SDK_CORE_TRADING_AUDIT.md C2.
1284
+ */
1285
+ allowStaleFallback?: boolean;
1286
+ /** Fallback ETH price (USD) when Chainlink is unreachable. Only used when `allowStaleFallback: true`. Default 3000. */
1245
1287
  fallbackEthPriceUsd?: number;
1246
- /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Default 0.1. */
1288
+ /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Only used when `allowStaleFallback: true`. Default 0.1. */
1247
1289
  fallbackPtPriceUsdt?: number;
1248
1290
  fetchImpl?: typeof fetch;
1249
1291
  }
@@ -1260,6 +1302,11 @@ interface QuoteOperatorFeeUsdtConfig {
1260
1302
  premiumBps?: number;
1261
1303
  chainlinkFeedAddress?: Address;
1262
1304
  usdtDecimals?: number;
1305
+ /**
1306
+ * Opt-in fallback price when Chainlink is unavailable. Default
1307
+ * `false` — throw `OracleStaleError`. v0.7.1 — see C2.
1308
+ */
1309
+ allowStaleFallback?: boolean;
1263
1310
  fallbackEthPriceUsd?: number;
1264
1311
  }
1265
1312
  /**
@@ -1703,4 +1750,4 @@ declare class PafiSDK {
1703
1750
  signLoginMessage(message: string): Promise<Hex>;
1704
1751
  }
1705
1752
 
1706
- export { ApiError, BATCH_EXECUTOR_7702_IMPL, BATCH_EXECUTOR_ABI, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, BROKER_HASHES, type BuildDelegationUserOpParams, type BuildPartialUserOpParams, type BuildPerpDepositViaRelayParams, type BuildPerpDepositWithGasDeductionParams, COMMON_POOLS, COMMON_TOKENS, CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, DUMMY_SIGNATURE_V07, type DelegateImpl, EIP712Signature, ENTRY_POINT_V07, ENTRY_POINT_V08, type Eip7702AuthorizationJsonRpc, LoginMessageParams, MintRequest, type ModalOpenOptions, ORDERLY_RELAY_ABI, ORDERLY_VAULT_ABI, ORDERLY_VAULT_ADDRESSES, ORDERLY_VAULT_BASE_MAINNET, type Operation, type OrderlyRelayDepositRequest, PAFI_SUBGRAPH_URL, PERMIT2_ADDRESS, POINT_TOKEN_FACTORY_ADDRESSES, POINT_TOKEN_IMPL_ADDRESSES, POINT_TOKEN_POOLS, type PackedUserOperationMessage, type PafiProxyTransportParams, PafiSDK, PafiSDKConfig, PafiSDKError, type PafiWebModalAdapter, type PafiWebModalHandle, type PartialUserOperation, type PaymasterConfig, type PaymasterFields, PointTokenDomainConfig, PoolKey, type QuoteOperatorFeePtConfig, type QuoteOperatorFeeUsdtConfig, ReceiverConsent, SIMPLE_7702_IMPL_BASE_MAINNET, SUPPORTED_CHAINS, type SendWithPaymasterFallbackParams, type SignatureStruct, SignatureVerification, SigningError, SimulationError, type SmartAccountSender, type SponsorshipScenario, type SubmissionPath, TOKEN_HASHES, UNIVERSAL_ROUTER_ADDRESSES, type UserOpReceipt, type UserOpTypedData, type UserOperation, V4_QUOTER_ADDRESSES, type VaultDepositFE, ZERO_VALUE, _resetPaymasterConfigForTests, assembleUserOperation, buildDelegationUserOp, buildEip7702Authorization, buildPartialUserOperation, buildPerpDepositViaRelay, buildPerpDepositWithGasDeduction, buildUserOpTypedData, burnRequestTypes, checkDelegation, checkEthAndBranch, computeAccountId, computeAuthorizationHash, computeUserOpHash, createPafiProxyTransport, decodeBatchExecuteCalls, detectDelegateImpl, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, fetchPafiPools, getAaNonce, getContractAddresses, getDummySignatureFor7702, getPafiWebModalAdapter, getPaymasterConfig, isDelegatedTo, isDelegatedToTarget, isPaymasterConfigured, isPaymasterError, mintRequestTypes, openPafiWebModal, openWebPopup, parseEip7702DelegatedAddress, quoteOperatorFeePt, quoteOperatorFeeUsdt, rawCallOp, receiverConsentTypes, sendWithPaymasterFallback, serializeUserOpToJsonRpc, setPafiWebModalAdapter, setPaymasterConfig, splitAuthorizationSig, webPopupAdapter };
1753
+ export { ApiError, BATCH_EXECUTOR_7702_IMPL, BATCH_EXECUTOR_ABI, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, BROKER_HASHES, type BuildDelegationUserOpParams, type BuildPartialUserOpParams, type BuildPerpDepositViaRelayParams, type BuildPerpDepositWithGasDeductionParams, COMMON_POOLS, COMMON_TOKENS, CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, DUMMY_SIGNATURE_V07, type DelegateImpl, EIP712Signature, ENTRY_POINT_V07, ENTRY_POINT_V08, type Eip7702AuthorizationJsonRpc, LoginMessageParams, MintRequest, type ModalOpenOptions, ORDERLY_RELAY_ABI, ORDERLY_VAULT_ABI, ORDERLY_VAULT_ADDRESSES, ORDERLY_VAULT_BASE_MAINNET, type Operation, OracleStaleError, type OrderlyRelayDepositRequest, PAFI_SUBGRAPH_URL, PERMIT2_ADDRESS, POINT_TOKEN_FACTORY_ADDRESSES, POINT_TOKEN_IMPL_ADDRESSES, POINT_TOKEN_POOLS, type PackedUserOperationMessage, type PafiProxyTransportParams, PafiSDK, PafiSDKConfig, PafiSDKError, type PafiWebModalAdapter, type PafiWebModalHandle, type PartialUserOperation, type PaymasterConfig, type PaymasterFields, PointTokenDomainConfig, PoolKey, type QuoteOperatorFeePtConfig, type QuoteOperatorFeeUsdtConfig, ReceiverConsent, SIMPLE_7702_IMPL_BASE_MAINNET, SUPPORTED_CHAINS, type SendWithPaymasterFallbackParams, type SignatureStruct, SignatureVerification, SigningError, SimulationError, type SmartAccountSender, type SponsorshipScenario, type SubmissionPath, TOKEN_HASHES, UNIVERSAL_ROUTER_ADDRESSES, type UserOpReceipt, type UserOpTypedData, type UserOperation, V4_QUOTER_ADDRESSES, type VaultDepositFE, ZERO_VALUE, _resetPaymasterConfigForTests, assembleUserOperation, buildDelegationUserOp, buildEip7702Authorization, buildPartialUserOperation, buildPerpDepositViaRelay, buildPerpDepositWithGasDeduction, buildUserOpTypedData, burnRequestTypes, checkDelegation, checkEthAndBranch, computeAccountId, computeAuthorizationHash, computeUserOpHash, createPafiProxyTransport, decodeBatchExecuteCalls, detectDelegateImpl, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, fetchPafiPools, getAaNonce, getContractAddresses, getDummySignatureFor7702, getPafiWebModalAdapter, getPaymasterConfig, isDelegatedTo, isDelegatedToTarget, isPaymasterConfigured, isPaymasterError, mintRequestTypes, openPafiWebModal, openWebPopup, parseEip7702DelegatedAddress, quoteOperatorFeePt, quoteOperatorFeeUsdt, rawCallOp, receiverConsentTypes, sendWithPaymasterFallback, serializeUserOpToJsonRpc, setPafiWebModalAdapter, setPaymasterConfig, splitAuthorizationSig, webPopupAdapter };
package/dist/index.js CHANGED
@@ -102,6 +102,16 @@ var ApiError = class extends PafiSDKError {
102
102
  }
103
103
  status;
104
104
  };
105
+ var OracleStaleError = class extends PafiSDKError {
106
+ source;
107
+ reason;
108
+ constructor(source, reason) {
109
+ super(`Oracle ${source} unavailable: ${reason}`);
110
+ this.name = "OracleStaleError";
111
+ this.source = source;
112
+ this.reason = reason;
113
+ }
114
+ };
105
115
 
106
116
  // src/perp/buildPerpDepositWithGasDeduction.ts
107
117
  import { encodeFunctionData as encodeFunctionData3 } from "viem";
@@ -344,7 +354,7 @@ function buildPerpDepositWithGasDeduction(params) {
344
354
  }
345
355
 
346
356
  // src/perp/buildPerpDepositViaRelay.ts
347
- import { encodeFunctionData as encodeFunctionData4, erc20Abi as erc20Abi3 } from "viem";
357
+ import { encodeFunctionData as encodeFunctionData4 } from "viem";
348
358
  var ORDERLY_RELAY_ABI = [
349
359
  {
350
360
  type: "function",
@@ -396,26 +406,19 @@ function buildPerpDepositViaRelay(params) {
396
406
  throw new Error("buildPerpDepositViaRelay: relayAddress required");
397
407
  }
398
408
  const operations = [];
399
- if (params.gasFeePt && params.gasFeePt > 0n) {
400
- if (!params.pointTokenAddress) {
401
- throw new Error(
402
- "buildPerpDepositViaRelay: pointTokenAddress required when gasFeePt > 0"
403
- );
404
- }
405
- if (!params.gasFeePtRecipient) {
409
+ if (params.gasFeeUsdc && params.gasFeeUsdc > 0n) {
410
+ if (!params.gasFeeUsdcRecipient) {
406
411
  throw new Error(
407
- "buildPerpDepositViaRelay: gasFeePtRecipient required when gasFeePt > 0"
412
+ "buildPerpDepositViaRelay: gasFeeUsdcRecipient required when gasFeeUsdc > 0"
408
413
  );
409
414
  }
410
- operations.push({
411
- target: params.pointTokenAddress,
412
- value: 0n,
413
- data: encodeFunctionData4({
414
- abi: erc20Abi3,
415
- functionName: "transfer",
416
- args: [params.gasFeePtRecipient, params.gasFeePt]
417
- })
418
- });
415
+ operations.push(
416
+ erc20TransferOp(
417
+ params.request.token,
418
+ params.gasFeeUsdcRecipient,
419
+ params.gasFeeUsdc
420
+ )
421
+ );
419
422
  }
420
423
  operations.push(
421
424
  erc20ApproveOp(
@@ -601,11 +604,9 @@ function parseEip7702DelegatedAddress(code) {
601
604
  if (!code || code === "0x" || code === "0x0") return null;
602
605
  const normalized = code.toLowerCase();
603
606
  const magic = EIP7702_MAGIC.toLowerCase();
604
- const idx = normalized.indexOf(magic);
605
- if (idx === -1) return null;
606
- const raw = normalized.slice(idx + magic.length, idx + magic.length + 40);
607
- if (raw.length !== 40) return null;
608
- return `0x${raw}`;
607
+ if (!normalized.startsWith(magic)) return null;
608
+ if (normalized.length !== magic.length + 40) return null;
609
+ return `0x${normalized.slice(magic.length)}`;
609
610
  }
610
611
  async function checkDelegation(client, address) {
611
612
  const code = await client.getCode({ address });
@@ -734,9 +735,24 @@ function createPafiProxyTransport(params) {
734
735
  }
735
736
 
736
737
  // src/transport/paymasterFallback.ts
738
+ var PAYMASTER_HTTP_STATUSES = /* @__PURE__ */ new Set([401, 403, 429, 503]);
739
+ var PAYMASTER_PATTERNS = [
740
+ /\bAA3[1-4]\b/i,
741
+ /\bpaymaster\b/i,
742
+ /\bsponsorship\b/i,
743
+ /\bpm_\w+/i,
744
+ /\brate ?limit\b/i,
745
+ /\bunauthorized\b/i
746
+ ];
737
747
  function isPaymasterError(err) {
738
- const msg = (err?.message ?? String(err)).toLowerCase();
739
- return msg.includes("paymaster") || msg.includes("sponsorship") || msg.includes("aa31") || msg.includes("aa32") || msg.includes("aa33") || msg.includes("aa34") || msg.includes("pm_") || msg.includes("rate limit") || msg.includes("unauthorized") || msg.includes("403") || msg.includes("429") || msg.includes("503");
748
+ if (err == null || typeof err !== "object") return false;
749
+ const e = err;
750
+ const status = e.status ?? e.statusCode ?? e.response?.status ?? e.cause?.status;
751
+ if (typeof status === "number" && PAYMASTER_HTTP_STATUSES.has(status)) {
752
+ return true;
753
+ }
754
+ const msg = e.message ?? String(err);
755
+ return PAYMASTER_PATTERNS.some((re) => re.test(msg));
740
756
  }
741
757
  async function sendWithPaymasterFallback(params) {
742
758
  const { primaryClient, fallbackClient, txParams, txParamsFallback, onFallback } = params;
@@ -906,6 +922,7 @@ async function quoteOperatorFeeUsdt(config) {
906
922
  gasUnits = DEFAULT_GAS_UNITS,
907
923
  premiumBps = DEFAULT_PREMIUM_BPS,
908
924
  usdtDecimals = DEFAULT_USDT_DECIMALS,
925
+ allowStaleFallback = false,
909
926
  fallbackEthPriceUsd = 3e3
910
927
  } = config;
911
928
  const chainlinkFeedAddress = config.chainlinkFeedAddress ?? getContractAddresses(chainId).chainlinkEthUsd;
@@ -915,7 +932,7 @@ async function quoteOperatorFeeUsdt(config) {
915
932
  const ethPrice8dec = await getEthPrice8dec(
916
933
  provider,
917
934
  chainlinkFeedAddress,
918
- fallbackEthPriceUsd
935
+ allowStaleFallback ? fallbackEthPriceUsd : null
919
936
  );
920
937
  const denomExp = 18 + 8 - usdtDecimals;
921
938
  return withPremium * ethPrice8dec / 10n ** BigInt(denomExp);
@@ -929,6 +946,7 @@ async function quoteOperatorFeePt(config) {
929
946
  premiumBps = DEFAULT_PREMIUM_BPS,
930
947
  subgraphUrl = PAFI_SUBGRAPH_URL,
931
948
  usdtDecimals = DEFAULT_USDT_DECIMALS,
949
+ allowStaleFallback = false,
932
950
  fallbackEthPriceUsd = 3e3,
933
951
  fallbackPtPriceUsdt = 0.1,
934
952
  fetchImpl = globalThis.fetch
@@ -938,12 +956,16 @@ async function quoteOperatorFeePt(config) {
938
956
  const nativeCost = gasPrice * gasUnits;
939
957
  const withPremium = nativeCost * BigInt(premiumBps) / 10000n;
940
958
  const [ethPrice8dec, ptPerUsdt18dec] = await Promise.all([
941
- getEthPrice8dec(provider, chainlinkFeedAddress, fallbackEthPriceUsd),
959
+ getEthPrice8dec(
960
+ provider,
961
+ chainlinkFeedAddress,
962
+ allowStaleFallback ? fallbackEthPriceUsd : null
963
+ ),
942
964
  getPtPerUsdt18dec(
943
965
  fetchImpl,
944
966
  subgraphUrl,
945
967
  pointTokenAddress,
946
- fallbackPtPriceUsdt
968
+ allowStaleFallback ? fallbackPtPriceUsdt : null
947
969
  )
948
970
  ]);
949
971
  return withPremium * ethPrice8dec * ptPerUsdt18dec / 10n ** 26n;
@@ -964,9 +986,13 @@ async function getEthPrice8dec(provider, feed, fallback) {
964
986
  }
965
987
  return answer;
966
988
  } catch (err) {
989
+ const reason = err instanceof Error ? err.message : String(err);
990
+ if (fallback === null) {
991
+ throw new OracleStaleError("chainlink", reason);
992
+ }
967
993
  console.warn(
968
- "[quoteOperatorFeePt] Chainlink unavailable, using fallback:",
969
- err.message
994
+ "[quoteOperatorFee] Chainlink unavailable, using opt-in fallback:",
995
+ reason
970
996
  );
971
997
  return BigInt(Math.round(fallback * 1e8));
972
998
  }
@@ -999,9 +1025,13 @@ async function getPtPerUsdt18dec(fetchImpl, subgraphUrl, pointTokenAddress, fall
999
1025
  }
1000
1026
  return 10n ** 24n / raw;
1001
1027
  } catch (err) {
1028
+ const reason = err instanceof Error ? err.message : String(err);
1029
+ if (fallbackPtPriceUsdt === null) {
1030
+ throw new OracleStaleError("subgraph", reason);
1031
+ }
1002
1032
  console.warn(
1003
- "[quoteOperatorFeePt] subgraph unavailable, using fallback:",
1004
- err.message
1033
+ "[quoteOperatorFeePt] subgraph unavailable, using opt-in fallback:",
1034
+ reason
1005
1035
  );
1006
1036
  const ptPerUsdtHuman = 1 / fallbackPtPriceUsdt;
1007
1037
  return parseBigDecimalTo18(ptPerUsdtHuman.toFixed(18));
@@ -1314,6 +1344,7 @@ export {
1314
1344
  ORDERLY_VAULT_ABI,
1315
1345
  ORDERLY_VAULT_ADDRESSES,
1316
1346
  ORDERLY_VAULT_BASE_MAINNET,
1347
+ OracleStaleError,
1317
1348
  PAFI_SUBGRAPH_URL,
1318
1349
  PERMIT2_ADDRESS,
1319
1350
  POINT_TOKEN_FACTORY_ADDRESSES,