@pafi-dev/issuer 0.18.0 → 0.19.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.js CHANGED
@@ -862,172 +862,22 @@ var RelayService = class {
862
862
  }
863
863
  });
864
864
  }
865
- // =========================================================================
866
- // Preview methods — produce bundler-ready partial UserOps WITHOUT signing.
867
- //
868
- // These exist so callers can compute an accurate gas estimate via
869
- // `bundlerClient.estimateUserOperationGas(...)` BEFORE committing to a
870
- // signed MintRequest / BurnRequest (signing is HSM-backed and expensive
871
- // in prod). The returned `callData` matches the SHAPE of the real call;
872
- // the EIP-712 signature bytes are placeholder. Bundler simulation
873
- // doesn't validate the signature, so the gas units come back accurate.
874
- //
875
- // Cache-wise: same SC version + same scenario → same calldata shape →
876
- // same bundler-returned gas units. The first call seeds the cache; the
877
- // rest hit it.
878
- // =========================================================================
879
- /**
880
- * Build a dummy `PartialUserOperation` for the mint scenario, suitable
881
- * for `feeManager.estimateGasFee({ partialUserOp, ... })`. NO signing —
882
- * uses a 65-byte zero signature in place of the real minter sig.
883
- */
884
- previewMintUserOp(params) {
885
- const useWrapper = params.mintFeeWrapperAddress !== void 0;
886
- let mintCallData;
887
- let mintTarget;
888
- if (useWrapper) {
889
- mintCallData = encodeFunctionData({
890
- abi: mintFeeWrapperAbi,
891
- functionName: "mintWithFee",
892
- args: [
893
- params.pointTokenAddress,
894
- params.userAddress,
895
- params.amount,
896
- params.deadline,
897
- PLACEHOLDER_SIG_65
898
- ]
899
- });
900
- mintTarget = params.mintFeeWrapperAddress;
901
- } else {
902
- mintCallData = encodeFunctionData({
903
- abi: POINT_TOKEN_ABI,
904
- functionName: "mint",
905
- args: [
906
- params.userAddress,
907
- params.amount,
908
- params.deadline,
909
- PLACEHOLDER_SIG_65
910
- ]
911
- });
912
- mintTarget = params.pointTokenAddress;
913
- }
914
- return buildPartialUserOperation({
915
- sender: params.userAddress,
916
- nonce: params.aaNonce,
917
- operations: [{ target: mintTarget, value: 0n, data: mintCallData }],
918
- // Gas limits ignored by bundler estimate — it computes them.
919
- gasLimits: { callGasLimit: 1n, verificationGasLimit: 1n, preVerificationGas: 1n }
920
- });
921
- }
922
- /** Burn-side mirror of `previewMintUserOp`. */
923
- previewBurnUserOp(params) {
924
- const burnCallData = encodeFunctionData({
925
- abi: POINT_TOKEN_ABI,
926
- functionName: "burn",
927
- args: [
928
- params.userAddress,
929
- params.amount,
930
- params.deadline,
931
- PLACEHOLDER_SIG_65
932
- ]
933
- });
934
- return buildPartialUserOperation({
935
- sender: params.userAddress,
936
- nonce: params.aaNonce,
937
- operations: [
938
- { target: params.pointTokenAddress, value: 0n, data: burnCallData }
939
- ],
940
- gasLimits: { callGasLimit: 1n, verificationGasLimit: 1n, preVerificationGas: 1n }
941
- });
942
- }
943
865
  };
944
- var PLACEHOLDER_SIG_65 = `0x${"00".repeat(65)}`;
945
866
  function errorMessage(err) {
946
867
  return err instanceof Error ? err.message : String(err);
947
868
  }
948
869
 
949
- // src/relay/gasUnitsCache.ts
950
- import { keccak256 } from "viem";
951
- var DEFAULT_TTL_MS = 5 * 6e4;
952
- var DEFAULT_CODEHASH_TTL_MS = 60 * 6e4;
953
- var DEFAULT_MAX_ENTRIES = 100;
954
- var GasUnitsCache = class {
955
- entries = /* @__PURE__ */ new Map();
956
- codehashEntries = /* @__PURE__ */ new Map();
957
- ttlMs;
958
- codehashTtlMs;
959
- maxEntries;
960
- constructor(config = {}) {
961
- this.ttlMs = config.ttlMs ?? DEFAULT_TTL_MS;
962
- this.codehashTtlMs = config.codehashTtlMs ?? DEFAULT_CODEHASH_TTL_MS;
963
- this.maxEntries = config.maxEntries ?? DEFAULT_MAX_ENTRIES;
964
- }
965
- async buildKey(params) {
966
- const codehash = await this.getCodehash(
967
- params.provider,
968
- params.contractAddress
969
- );
970
- const pm = params.paymasterAddress?.toLowerCase() ?? "0x0";
971
- return `${params.scenario}:${codehash}:${pm}`;
972
- }
973
- get(key, now = Date.now()) {
974
- const entry = this.entries.get(key);
975
- if (!entry) return null;
976
- if (entry.expiresAt <= now) {
977
- this.entries.delete(key);
978
- return null;
979
- }
980
- return entry.gasUnits;
981
- }
982
- set(key, gasUnits, now = Date.now()) {
983
- if (this.entries.size >= this.maxEntries && !this.entries.has(key)) {
984
- const eldest = this.entries.keys().next().value;
985
- if (eldest !== void 0) this.entries.delete(eldest);
986
- }
987
- this.entries.set(key, { gasUnits, expiresAt: now + this.ttlMs });
988
- }
989
- invalidate() {
990
- this.entries.clear();
991
- this.codehashEntries.clear();
992
- }
993
- size() {
994
- return this.entries.size;
995
- }
996
- async getCodehash(provider, address) {
997
- const lower = address.toLowerCase();
998
- const now = Date.now();
999
- const cached = this.codehashEntries.get(lower);
1000
- if (cached && cached.expiresAt > now) return cached.codehash;
1001
- const code = await provider.getCode({ address });
1002
- const codehash = code ? keccak256(code) : "0x0";
1003
- this.codehashEntries.set(lower, {
1004
- codehash,
1005
- expiresAt: now + this.codehashTtlMs
1006
- });
1007
- return codehash;
1008
- }
1009
- };
1010
-
1011
870
  // src/relay/feeManager.ts
1012
871
  var DEFAULT_GAS_UNITS = 500000n;
1013
- var DEFAULT_PREMIUM_BPS = 1e4;
1014
- var DEFAULT_PAYMASTER_OVERHEAD = 80000n;
1015
- var DUMMY_SIGNATURE = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
872
+ var DEFAULT_PREMIUM_BPS = 12e3;
1016
873
  var FeeManager = class _FeeManager {
1017
874
  provider;
1018
875
  gasUnits;
1019
876
  gasPremiumBps;
1020
877
  quoteNativeToFee;
1021
- bundlerClient;
1022
- cache;
1023
- paymasterOverheadGas;
1024
- metrics;
1025
- // Short-lived in-flight fee cache (legacy behavior). Distinct from
1026
- // `cache` — that one stores gasUnits per scenario; this one stores the
1027
- // FULL computed fee value, valid for 10s to absorb burst calls.
1028
878
  cachedFee = null;
1029
879
  cacheExpiresAt = 0;
1030
- static FEE_CACHE_TTL_MS = 1e4;
880
+ static CACHE_TTL_MS = 1e4;
1031
881
  constructor(config) {
1032
882
  if (!config.provider) throw new Error("FeeManager: provider required");
1033
883
  if (!config.quoteNativeToFee)
@@ -1036,101 +886,32 @@ var FeeManager = class _FeeManager {
1036
886
  this.gasUnits = config.gasUnits ?? DEFAULT_GAS_UNITS;
1037
887
  this.gasPremiumBps = config.gasPremiumBps ?? DEFAULT_PREMIUM_BPS;
1038
888
  this.quoteNativeToFee = config.quoteNativeToFee;
1039
- this.bundlerClient = config.bundlerClient;
1040
- this.cache = new GasUnitsCache(config.cache);
1041
- this.paymasterOverheadGas = config.paymasterOverheadGas ?? DEFAULT_PAYMASTER_OVERHEAD;
1042
- this.metrics = config.metrics;
1043
889
  }
1044
890
  /**
1045
891
  * Estimate the fee (in the caller's fee currency) to charge for the
1046
- * next sponsored UserOp.
892
+ * next sponsored UserOp:
1047
893
  *
1048
- * gasUnits = bundler-estimated (cached) or hardcoded fallback
1049
894
  * nativeCost = gasUnits × gasPrice
1050
895
  * withPremium = nativeCost × premiumBps / 10_000
1051
896
  * fee = quoteNativeToFee(withPremium)
1052
897
  *
1053
- * When `opts.partialUserOp` is omitted, behaves exactly like v0.16.x:
1054
- * uses the hardcoded `gasUnits` default.
898
+ * For backward compatibility with v0.2.x code that reads `gasFeeUsdt`
899
+ * from the response, the name `estimateGasFee` is kept — but the
900
+ * currency depends on how the caller wired `quoteNativeToFee`.
1055
901
  */
1056
- async estimateGasFee(opts = {}) {
902
+ async estimateGasFee() {
1057
903
  const now = Date.now();
1058
- const isLegacyCall = !opts.partialUserOp && !opts.scenario && !opts.contractAddress;
1059
- if (isLegacyCall && this.cachedFee !== null && now < this.cacheExpiresAt) {
904
+ if (this.cachedFee !== null && now < this.cacheExpiresAt) {
1060
905
  return this.cachedFee;
1061
906
  }
1062
- const t0 = Date.now();
1063
- const { gasUnits, source } = await this.resolveGasUnits(opts);
1064
- const latencyMs = Date.now() - t0;
1065
- this.safeEmit(
1066
- () => this.metrics?.onEstimate?.({
1067
- source,
1068
- scenario: opts.scenario,
1069
- gasUnits,
1070
- latencyMs
1071
- })
1072
- );
1073
907
  const gasPrice = await this.provider.getGasPrice();
1074
- const nativeCost = gasPrice * gasUnits;
908
+ const nativeCost = gasPrice * this.gasUnits;
1075
909
  const withPremium = nativeCost * BigInt(this.gasPremiumBps) / 10000n;
1076
910
  const fee = await this.quoteNativeToFee(withPremium);
1077
- if (isLegacyCall) {
1078
- this.cachedFee = fee;
1079
- this.cacheExpiresAt = now + _FeeManager.FEE_CACHE_TTL_MS;
1080
- }
911
+ this.cachedFee = fee;
912
+ this.cacheExpiresAt = now + _FeeManager.CACHE_TTL_MS;
1081
913
  return fee;
1082
914
  }
1083
- /**
1084
- * Manually purge the per-scenario gas-units cache. Useful after an SC
1085
- * upgrade when ops wants the next estimate to refresh immediately
1086
- * (the codehash check would catch it on the NEXT call anyway, but
1087
- * this forces it now).
1088
- */
1089
- invalidateCache() {
1090
- this.cache.invalidate();
1091
- this.cachedFee = null;
1092
- this.cacheExpiresAt = 0;
1093
- }
1094
- async resolveGasUnits(opts) {
1095
- if (!this.bundlerClient || !opts.partialUserOp || !opts.scenario || !opts.contractAddress) {
1096
- return { gasUnits: this.gasUnits, source: "fallback" };
1097
- }
1098
- try {
1099
- const cacheKey = await this.cache.buildKey({
1100
- scenario: opts.scenario,
1101
- contractAddress: opts.contractAddress,
1102
- paymasterAddress: opts.paymasterAddress,
1103
- provider: this.provider
1104
- });
1105
- const cached = this.cache.get(cacheKey);
1106
- if (cached !== null) {
1107
- return { gasUnits: cached, source: "cache" };
1108
- }
1109
- const estimate = await this.bundlerClient.estimateUserOperationGas({
1110
- sender: opts.partialUserOp.sender,
1111
- nonce: opts.partialUserOp.nonce,
1112
- callData: opts.partialUserOp.callData,
1113
- signature: opts.partialUserOp.signature ?? DUMMY_SIGNATURE
1114
- // Intentionally NO paymaster fields — avoids chicken-and-egg
1115
- // (paymasterData depends on gasLimits). Overhead added below.
1116
- });
1117
- const gasUnits = estimate.callGasLimit + estimate.verificationGasLimit + estimate.preVerificationGas + (estimate.paymasterVerificationGasLimit ?? 0n) + (estimate.paymasterPostOpGasLimit ?? 0n) + this.paymasterOverheadGas;
1118
- this.cache.set(cacheKey, gasUnits);
1119
- return { gasUnits, source: "bundler" };
1120
- } catch (err) {
1121
- const reason = err instanceof Error ? err.message : String(err);
1122
- this.safeEmit(
1123
- () => this.metrics?.onBundlerError?.({ scenario: opts.scenario, reason })
1124
- );
1125
- return { gasUnits: this.gasUnits, source: "fallback" };
1126
- }
1127
- }
1128
- safeEmit(fn) {
1129
- try {
1130
- fn();
1131
- } catch {
1132
- }
1133
- }
1134
915
  };
1135
916
 
1136
917
  // src/indexer/types.ts
@@ -2069,29 +1850,11 @@ var PTRedeemHandler = class {
2069
1850
  }
2070
1851
  }
2071
1852
  async _handleAfterNonceLock(request, burnNonce) {
2072
- const previewDeadline = BigInt(
2073
- Math.floor(this.now() / 1e3) + this.signatureDeadlineSeconds
2074
- );
2075
1853
  let fee;
2076
1854
  if (request.feeAmount !== void 0) {
2077
1855
  fee = request.feeAmount > 0n ? request.feeAmount : 0n;
2078
1856
  } else if (this.feeService) {
2079
- const previewUserOp = this.relayService.previewBurnUserOp({
2080
- userAddress: request.userAddress,
2081
- aaNonce: burnNonce,
2082
- pointTokenAddress: this.pointTokenAddress,
2083
- amount: request.amount,
2084
- deadline: previewDeadline
2085
- });
2086
- fee = await this.feeService.estimateGasFee({
2087
- scenario: "burn",
2088
- contractAddress: this.pointTokenAddress,
2089
- partialUserOp: {
2090
- sender: previewUserOp.sender,
2091
- nonce: previewUserOp.nonce,
2092
- callData: previewUserOp.callData
2093
- }
2094
- });
1857
+ fee = await this.feeService.estimateGasFee();
2095
1858
  } else {
2096
1859
  fee = 0n;
2097
1860
  }
@@ -2113,7 +1876,9 @@ var PTRedeemHandler = class {
2113
1876
  `insufficient on-chain PT balance: have ${onChainBalance}, need ${request.amount}`
2114
1877
  );
2115
1878
  }
2116
- const deadline = previewDeadline;
1879
+ const deadline = BigInt(
1880
+ Math.floor(this.now() / 1e3) + this.signatureDeadlineSeconds
1881
+ );
2117
1882
  const domain = {
2118
1883
  name: this.domain.name,
2119
1884
  chainId: this.chainId,
@@ -2785,23 +2550,7 @@ var PTClaimHandler = class {
2785
2550
  const signatureDeadline = BigInt(
2786
2551
  Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
2787
2552
  );
2788
- const previewUserOp = this.cfg.relayService.previewMintUserOp({
2789
- userAddress: request.userAddress,
2790
- aaNonce: request.aaNonce,
2791
- pointTokenAddress: request.pointTokenAddress,
2792
- amount: request.amount,
2793
- deadline: signatureDeadline,
2794
- mintFeeWrapperAddress: resolvedWrapper
2795
- });
2796
- const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee({
2797
- scenario: resolvedWrapper ? "mint-wrapped" : "mint",
2798
- contractAddress: request.pointTokenAddress,
2799
- partialUserOp: {
2800
- sender: previewUserOp.sender,
2801
- nonce: previewUserOp.nonce,
2802
- callData: previewUserOp.callData
2803
- }
2804
- }) : 0n;
2553
+ const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
2805
2554
  const domain = {
2806
2555
  name: this.cfg.pointTokenDomainName,
2807
2556
  chainId: request.chainId,
@@ -4768,7 +4517,7 @@ var MemoryRedemptionHistoryStore = class {
4768
4517
  };
4769
4518
 
4770
4519
  // src/index.ts
4771
- var PAFI_ISSUER_SDK_VERSION = true ? "0.18.0" : "dev";
4520
+ var PAFI_ISSUER_SDK_VERSION = true ? "0.19.0" : "dev";
4772
4521
  export {
4773
4522
  AdapterMisconfiguredError,
4774
4523
  AuthError,
@@ -4780,7 +4529,6 @@ export {
4780
4529
  DEFAULT_REDEMPTION_POLICY,
4781
4530
  DefaultPolicyEngine,
4782
4531
  FeeManager,
4783
- GasUnitsCache,
4784
4532
  InMemoryCursorStore,
4785
4533
  IssuerApiAdapter,
4786
4534
  IssuerApiHandlers,