@pafi-dev/issuer 0.5.34 → 0.5.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +698 -244
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +929 -614
- package/dist/index.d.ts +929 -614
- package/dist/index.js +698 -232
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -36,14 +36,21 @@ __export(index_exports, {
|
|
|
36
36
|
MemorySessionStore: () => MemorySessionStore,
|
|
37
37
|
NonceManager: () => NonceManager,
|
|
38
38
|
PAFI_ISSUER_SDK_VERSION: () => PAFI_ISSUER_SDK_VERSION,
|
|
39
|
-
PAFI_SUBGRAPH_URL: () =>
|
|
39
|
+
PAFI_SUBGRAPH_URL: () => import_core12.PAFI_SUBGRAPH_URL,
|
|
40
|
+
PTClaimError: () => PTClaimError,
|
|
41
|
+
PTClaimHandler: () => PTClaimHandler,
|
|
40
42
|
PTRedeemError: () => PTRedeemError,
|
|
41
43
|
PTRedeemHandler: () => PTRedeemHandler,
|
|
42
44
|
PafiBackendClient: () => PafiBackendClient,
|
|
43
45
|
PafiBackendError: () => PafiBackendError,
|
|
46
|
+
PendingUserOpNotFoundError: () => PendingUserOpNotFoundError,
|
|
47
|
+
PerpDepositError: () => PerpDepositError,
|
|
48
|
+
PerpDepositHandler: () => PerpDepositHandler,
|
|
44
49
|
PointIndexer: () => PointIndexer,
|
|
45
50
|
RelayError: () => RelayError,
|
|
46
51
|
RelayService: () => RelayService,
|
|
52
|
+
SwapError: () => SwapError,
|
|
53
|
+
SwapHandler: () => SwapHandler,
|
|
47
54
|
TopUpRedemptionError: () => TopUpRedemptionError,
|
|
48
55
|
TopUpRedemptionHandler: () => TopUpRedemptionHandler,
|
|
49
56
|
authenticateRequest: () => authenticateRequest,
|
|
@@ -52,6 +59,8 @@ __export(index_exports, {
|
|
|
52
59
|
createSubgraphNativeUsdtQuoter: () => createSubgraphNativeUsdtQuoter,
|
|
53
60
|
createSubgraphPoolsProvider: () => createSubgraphPoolsProvider,
|
|
54
61
|
handleClaimStatus: () => handleClaimStatus,
|
|
62
|
+
handleMobilePrepare: () => handleMobilePrepare,
|
|
63
|
+
handleMobileSubmit: () => handleMobileSubmit,
|
|
55
64
|
handleRedeemStatus: () => handleRedeemStatus,
|
|
56
65
|
mergePaymasterFields: () => mergePaymasterFields,
|
|
57
66
|
prepareMobileUserOp: () => prepareMobileUserOp,
|
|
@@ -1747,9 +1756,662 @@ async function handleRedeemStatus(params) {
|
|
|
1747
1756
|
};
|
|
1748
1757
|
}
|
|
1749
1758
|
|
|
1759
|
+
// src/api/mobileHandlers.ts
|
|
1760
|
+
var import_core8 = require("@pafi-dev/core");
|
|
1761
|
+
|
|
1762
|
+
// src/userop-store/serialize.ts
|
|
1763
|
+
var import_core6 = require("@pafi-dev/core");
|
|
1764
|
+
function serializeEntryToJsonRpc(entry, signature, variant = "sponsored") {
|
|
1765
|
+
if (variant === "fallback") {
|
|
1766
|
+
if (!entry.fallback) {
|
|
1767
|
+
throw new Error(
|
|
1768
|
+
"serializeEntryToJsonRpc: variant=fallback requested but the stored entry has no `fallback` branch \u2014 caller should resubmit with variant='sponsored' or re-prepare with a fee configured."
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
return (0, import_core6.serializeUserOpToJsonRpc)(
|
|
1772
|
+
{
|
|
1773
|
+
sender: entry.sender,
|
|
1774
|
+
nonce: BigInt(entry.nonce),
|
|
1775
|
+
callData: entry.fallback.callData,
|
|
1776
|
+
callGasLimit: BigInt(entry.fallback.callGasLimit),
|
|
1777
|
+
verificationGasLimit: BigInt(entry.fallback.verificationGasLimit),
|
|
1778
|
+
preVerificationGas: BigInt(entry.fallback.preVerificationGas),
|
|
1779
|
+
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
1780
|
+
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas)
|
|
1781
|
+
// intentionally no paymaster — user pays ETH gas
|
|
1782
|
+
},
|
|
1783
|
+
signature
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
return (0, import_core6.serializeUserOpToJsonRpc)(
|
|
1787
|
+
{
|
|
1788
|
+
sender: entry.sender,
|
|
1789
|
+
nonce: BigInt(entry.nonce),
|
|
1790
|
+
callData: entry.callData,
|
|
1791
|
+
callGasLimit: BigInt(entry.callGasLimit),
|
|
1792
|
+
verificationGasLimit: BigInt(entry.verificationGasLimit),
|
|
1793
|
+
preVerificationGas: BigInt(entry.preVerificationGas),
|
|
1794
|
+
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
1795
|
+
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas),
|
|
1796
|
+
paymaster: entry.paymaster,
|
|
1797
|
+
paymasterVerificationGasLimit: entry.paymasterVerificationGasLimit != null ? BigInt(entry.paymasterVerificationGasLimit) : void 0,
|
|
1798
|
+
paymasterPostOpGasLimit: entry.paymasterPostOpGasLimit != null ? BigInt(entry.paymasterPostOpGasLimit) : void 0,
|
|
1799
|
+
paymasterData: entry.paymasterData
|
|
1800
|
+
},
|
|
1801
|
+
signature
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
// src/userop-store/prepareUserOp.ts
|
|
1806
|
+
var import_core7 = require("@pafi-dev/core");
|
|
1807
|
+
function serializeUserOpTypedData(td) {
|
|
1808
|
+
return {
|
|
1809
|
+
domain: td.domain,
|
|
1810
|
+
types: td.types,
|
|
1811
|
+
primaryType: td.primaryType,
|
|
1812
|
+
message: {
|
|
1813
|
+
sender: td.message.sender,
|
|
1814
|
+
nonce: `0x${td.message.nonce.toString(16)}`,
|
|
1815
|
+
initCode: td.message.initCode,
|
|
1816
|
+
callData: td.message.callData,
|
|
1817
|
+
accountGasLimits: td.message.accountGasLimits,
|
|
1818
|
+
preVerificationGas: `0x${td.message.preVerificationGas.toString(
|
|
1819
|
+
16
|
|
1820
|
+
)}`,
|
|
1821
|
+
gasFees: td.message.gasFees,
|
|
1822
|
+
paymasterAndData: td.message.paymasterAndData
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
function mergePaymasterFields(userOp, paymasterFields) {
|
|
1827
|
+
if (!paymasterFields) return userOp;
|
|
1828
|
+
const merged = {
|
|
1829
|
+
...userOp
|
|
1830
|
+
};
|
|
1831
|
+
for (const [k, v] of Object.entries(paymasterFields)) {
|
|
1832
|
+
if (v !== void 0) merged[k] = v;
|
|
1833
|
+
}
|
|
1834
|
+
return merged;
|
|
1835
|
+
}
|
|
1836
|
+
async function prepareMobileUserOp(params) {
|
|
1837
|
+
const userOp = mergePaymasterFields(
|
|
1838
|
+
params.partialUserOp,
|
|
1839
|
+
params.paymasterFields
|
|
1840
|
+
);
|
|
1841
|
+
const userOpHash = (0, import_core7.computeUserOpHash)(userOp, params.chainId);
|
|
1842
|
+
const typedData = serializeUserOpTypedData(
|
|
1843
|
+
(0, import_core7.buildUserOpTypedData)(userOp, params.chainId)
|
|
1844
|
+
);
|
|
1845
|
+
let fallback;
|
|
1846
|
+
let fallbackEntry;
|
|
1847
|
+
if (params.partialUserOpFallback) {
|
|
1848
|
+
const fallbackUserOp = {
|
|
1849
|
+
...params.partialUserOpFallback,
|
|
1850
|
+
maxFeePerGas: userOp.maxFeePerGas,
|
|
1851
|
+
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas
|
|
1852
|
+
};
|
|
1853
|
+
const fallbackHash = (0, import_core7.computeUserOpHash)(fallbackUserOp, params.chainId);
|
|
1854
|
+
const fallbackTypedData = serializeUserOpTypedData(
|
|
1855
|
+
(0, import_core7.buildUserOpTypedData)(fallbackUserOp, params.chainId)
|
|
1856
|
+
);
|
|
1857
|
+
fallback = {
|
|
1858
|
+
userOp: fallbackUserOp,
|
|
1859
|
+
userOpHash: fallbackHash,
|
|
1860
|
+
typedData: fallbackTypedData
|
|
1861
|
+
};
|
|
1862
|
+
fallbackEntry = {
|
|
1863
|
+
callData: fallbackUserOp.callData,
|
|
1864
|
+
callGasLimit: fallbackUserOp.callGasLimit.toString(),
|
|
1865
|
+
verificationGasLimit: fallbackUserOp.verificationGasLimit.toString(),
|
|
1866
|
+
preVerificationGas: fallbackUserOp.preVerificationGas.toString(),
|
|
1867
|
+
userOpHash: fallbackHash
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
const entry = {
|
|
1871
|
+
sender: userOp.sender,
|
|
1872
|
+
nonce: userOp.nonce.toString(),
|
|
1873
|
+
callData: userOp.callData,
|
|
1874
|
+
callGasLimit: userOp.callGasLimit.toString(),
|
|
1875
|
+
verificationGasLimit: userOp.verificationGasLimit.toString(),
|
|
1876
|
+
preVerificationGas: userOp.preVerificationGas.toString(),
|
|
1877
|
+
maxFeePerGas: userOp.maxFeePerGas.toString(),
|
|
1878
|
+
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas.toString(),
|
|
1879
|
+
paymaster: userOp.paymaster,
|
|
1880
|
+
paymasterVerificationGasLimit: userOp.paymasterVerificationGasLimit?.toString(),
|
|
1881
|
+
paymasterPostOpGasLimit: userOp.paymasterPostOpGasLimit?.toString(),
|
|
1882
|
+
paymasterData: userOp.paymasterData,
|
|
1883
|
+
chainId: params.chainId,
|
|
1884
|
+
userOpHash,
|
|
1885
|
+
fallback: fallbackEntry
|
|
1886
|
+
};
|
|
1887
|
+
await params.store.save(params.lockId, entry, params.ttlSeconds);
|
|
1888
|
+
return {
|
|
1889
|
+
sponsored: { userOp, userOpHash, typedData },
|
|
1890
|
+
fallback,
|
|
1891
|
+
entry
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// src/pafi-backend/helpers.ts
|
|
1896
|
+
var BundlerNotConfiguredError = class extends Error {
|
|
1897
|
+
code = "BUNDLER_NOT_CONFIGURED";
|
|
1898
|
+
constructor() {
|
|
1899
|
+
super(
|
|
1900
|
+
"PAFI backend client not configured \u2014 set PAFI_BACKEND_URL, PAFI_ISSUER_ID, PAFI_API_KEY to enable mobile submit."
|
|
1901
|
+
);
|
|
1902
|
+
this.name = "BundlerNotConfiguredError";
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1905
|
+
var BundlerRejectedError = class extends Error {
|
|
1906
|
+
code = "BUNDLER_REJECTED";
|
|
1907
|
+
cause;
|
|
1908
|
+
constructor(message, cause) {
|
|
1909
|
+
super(message);
|
|
1910
|
+
this.name = "BundlerRejectedError";
|
|
1911
|
+
this.cause = cause;
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
async function requestPaymaster(params) {
|
|
1915
|
+
if (!params.client) return void 0;
|
|
1916
|
+
const fn = params.functionName ?? defaultFunctionForScenario(params.scenario);
|
|
1917
|
+
try {
|
|
1918
|
+
return await params.client.requestSponsorship({
|
|
1919
|
+
chainId: params.chainId,
|
|
1920
|
+
scenario: params.scenario,
|
|
1921
|
+
userOp: params.userOp,
|
|
1922
|
+
target: {
|
|
1923
|
+
contract: params.pointTokenAddress,
|
|
1924
|
+
function: fn,
|
|
1925
|
+
pointToken: params.pointTokenAddress
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
} catch (err) {
|
|
1929
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1930
|
+
params.onWarning?.(`Paymaster sponsorship declined: ${msg}`);
|
|
1931
|
+
return void 0;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
function defaultFunctionForScenario(scenario) {
|
|
1935
|
+
switch (scenario) {
|
|
1936
|
+
case "mint":
|
|
1937
|
+
return "mint";
|
|
1938
|
+
case "burn":
|
|
1939
|
+
return "burn";
|
|
1940
|
+
case "swap":
|
|
1941
|
+
return "swap";
|
|
1942
|
+
case "perp-deposit":
|
|
1943
|
+
return "deposit";
|
|
1944
|
+
default:
|
|
1945
|
+
return scenario;
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
async function relayUserOp(params) {
|
|
1949
|
+
if (!params.client) {
|
|
1950
|
+
throw new BundlerNotConfiguredError();
|
|
1951
|
+
}
|
|
1952
|
+
try {
|
|
1953
|
+
const result = await params.client.relayUserOperation({
|
|
1954
|
+
userOp: params.userOp,
|
|
1955
|
+
entryPoint: params.entryPoint,
|
|
1956
|
+
eip7702Auth: params.eip7702Auth
|
|
1957
|
+
});
|
|
1958
|
+
return { userOpHash: result.userOpHash };
|
|
1959
|
+
} catch (err) {
|
|
1960
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1961
|
+
throw new BundlerRejectedError(msg, err);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
// src/api/mobileHandlers.ts
|
|
1966
|
+
var PendingUserOpNotFoundError = class extends Error {
|
|
1967
|
+
code = "PENDING_USEROP_NOT_FOUND";
|
|
1968
|
+
constructor(lockId) {
|
|
1969
|
+
super(
|
|
1970
|
+
`No pending UserOp found for lockId ${lockId} \u2014 it may have expired or already been submitted.`
|
|
1971
|
+
);
|
|
1972
|
+
this.name = "PendingUserOpNotFoundError";
|
|
1973
|
+
}
|
|
1974
|
+
};
|
|
1975
|
+
async function handleMobilePrepare(params) {
|
|
1976
|
+
const [fees, userCode] = await Promise.all([
|
|
1977
|
+
params.provider.estimateFeesPerGas(),
|
|
1978
|
+
params.provider.getCode({ address: params.userAddress })
|
|
1979
|
+
]);
|
|
1980
|
+
const needsDelegation = (0, import_core8.parseEip7702DelegatedAddress)(userCode) === null;
|
|
1981
|
+
const sponsoredOp = {
|
|
1982
|
+
...params.partialUserOp,
|
|
1983
|
+
maxFeePerGas: fees.maxFeePerGas ?? params.partialUserOp.maxFeePerGas ?? 0n,
|
|
1984
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? params.partialUserOp.maxPriorityFeePerGas ?? 0n
|
|
1985
|
+
};
|
|
1986
|
+
const paymasterFields = await requestPaymaster({
|
|
1987
|
+
client: params.pafiBackendClient,
|
|
1988
|
+
chainId: params.chainId,
|
|
1989
|
+
scenario: params.scenario,
|
|
1990
|
+
userOp: sponsoredOp,
|
|
1991
|
+
pointTokenAddress: params.pointTokenAddress,
|
|
1992
|
+
onWarning: params.onWarning
|
|
1993
|
+
});
|
|
1994
|
+
const prepared = await prepareMobileUserOp({
|
|
1995
|
+
lockId: params.lockId,
|
|
1996
|
+
partialUserOp: sponsoredOp,
|
|
1997
|
+
partialUserOpFallback: params.partialUserOpFallback,
|
|
1998
|
+
paymasterFields,
|
|
1999
|
+
chainId: params.chainId,
|
|
2000
|
+
store: params.store,
|
|
2001
|
+
ttlSeconds: params.ttlSeconds
|
|
2002
|
+
});
|
|
2003
|
+
return {
|
|
2004
|
+
...prepared,
|
|
2005
|
+
isSponsored: !!paymasterFields,
|
|
2006
|
+
needsDelegation
|
|
2007
|
+
};
|
|
2008
|
+
}
|
|
2009
|
+
async function handleMobileSubmit(params) {
|
|
2010
|
+
const entry = await params.store.get(params.lockId);
|
|
2011
|
+
if (!entry) {
|
|
2012
|
+
throw new PendingUserOpNotFoundError(params.lockId);
|
|
2013
|
+
}
|
|
2014
|
+
const variant = params.variant ?? "sponsored";
|
|
2015
|
+
const userOpJson = serializeEntryToJsonRpc(entry, params.signature, variant);
|
|
2016
|
+
const result = await relayUserOp({
|
|
2017
|
+
client: params.pafiBackendClient,
|
|
2018
|
+
userOp: userOpJson,
|
|
2019
|
+
entryPoint: params.entryPoint ?? import_core8.ENTRY_POINT_V08
|
|
2020
|
+
});
|
|
2021
|
+
await params.bindUserOpHash(params.lockId, result.userOpHash);
|
|
2022
|
+
await params.store.delete(params.lockId);
|
|
2023
|
+
return { userOpHash: result.userOpHash };
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
// src/api/handlers/ptClaimHandler.ts
|
|
2027
|
+
var import_viem9 = require("viem");
|
|
2028
|
+
var import_core9 = require("@pafi-dev/core");
|
|
2029
|
+
|
|
2030
|
+
// src/issuer-state/types.ts
|
|
2031
|
+
var IssuerStateError = class extends Error {
|
|
2032
|
+
constructor(code, message, details) {
|
|
2033
|
+
super(message);
|
|
2034
|
+
this.code = code;
|
|
2035
|
+
this.details = details;
|
|
2036
|
+
this.name = "IssuerStateError";
|
|
2037
|
+
}
|
|
2038
|
+
code;
|
|
2039
|
+
details;
|
|
2040
|
+
};
|
|
2041
|
+
|
|
2042
|
+
// src/api/handlers/ptClaimHandler.ts
|
|
2043
|
+
var PTClaimError = class extends Error {
|
|
2044
|
+
constructor(code, message, details) {
|
|
2045
|
+
super(message);
|
|
2046
|
+
this.code = code;
|
|
2047
|
+
this.details = details;
|
|
2048
|
+
this.name = "PTClaimError";
|
|
2049
|
+
}
|
|
2050
|
+
code;
|
|
2051
|
+
details;
|
|
2052
|
+
};
|
|
2053
|
+
var DEFAULT_LOCK_MS = 15 * 60 * 1e3;
|
|
2054
|
+
var DEFAULT_SIG_DEADLINE_SEC2 = 15 * 60;
|
|
2055
|
+
var PTClaimHandler = class {
|
|
2056
|
+
cfg;
|
|
2057
|
+
constructor(config) {
|
|
2058
|
+
this.cfg = {
|
|
2059
|
+
...config,
|
|
2060
|
+
lockDurationMs: config.lockDurationMs ?? DEFAULT_LOCK_MS,
|
|
2061
|
+
signatureDeadlineSeconds: config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC2,
|
|
2062
|
+
now: config.now ?? (() => Date.now())
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
async handle(request) {
|
|
2066
|
+
if ((0, import_viem9.getAddress)(request.authenticatedAddress) !== (0, import_viem9.getAddress)(request.userAddress)) {
|
|
2067
|
+
throw new PTClaimError(
|
|
2068
|
+
"VALIDATION_FAILED",
|
|
2069
|
+
`userAddress (${request.userAddress}) does not match authenticated session (${request.authenticatedAddress})`
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
if (request.amount <= 0n) {
|
|
2073
|
+
throw new PTClaimError("INVALID_AMOUNT", "claim amount must be positive");
|
|
2074
|
+
}
|
|
2075
|
+
if (this.cfg.issuerStateValidator) {
|
|
2076
|
+
try {
|
|
2077
|
+
await this.cfg.issuerStateValidator.preValidateMint(
|
|
2078
|
+
request.pointTokenAddress,
|
|
2079
|
+
request.amount
|
|
2080
|
+
);
|
|
2081
|
+
} catch (err) {
|
|
2082
|
+
if (err instanceof IssuerStateError) throw err;
|
|
2083
|
+
throw new PTClaimError(
|
|
2084
|
+
"VALIDATION_FAILED",
|
|
2085
|
+
`issuer-state pre-validate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2086
|
+
);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
const { batchExecutor: batchExecutorAddress } = (0, import_core9.getContractAddresses)(
|
|
2090
|
+
request.chainId
|
|
2091
|
+
);
|
|
2092
|
+
const lockId = await this.cfg.ledger.lockForMinting(
|
|
2093
|
+
request.userAddress,
|
|
2094
|
+
request.amount,
|
|
2095
|
+
this.cfg.lockDurationMs,
|
|
2096
|
+
request.pointTokenAddress
|
|
2097
|
+
);
|
|
2098
|
+
const signatureDeadline = BigInt(
|
|
2099
|
+
Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
|
|
2100
|
+
);
|
|
2101
|
+
const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
|
|
2102
|
+
const domain = {
|
|
2103
|
+
name: this.cfg.pointTokenDomainName,
|
|
2104
|
+
chainId: request.chainId,
|
|
2105
|
+
verifyingContract: request.pointTokenAddress
|
|
2106
|
+
};
|
|
2107
|
+
let userOp;
|
|
2108
|
+
try {
|
|
2109
|
+
userOp = await this.cfg.relayService.prepareMint({
|
|
2110
|
+
userAddress: request.userAddress,
|
|
2111
|
+
aaNonce: request.aaNonce,
|
|
2112
|
+
batchExecutorAddress,
|
|
2113
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2114
|
+
amount: request.amount,
|
|
2115
|
+
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2116
|
+
domain,
|
|
2117
|
+
mintRequestNonce: request.mintRequestNonce,
|
|
2118
|
+
deadline: signatureDeadline
|
|
2119
|
+
// No feeAmount/feeRecipient — RelayService auto-resolves.
|
|
2120
|
+
});
|
|
2121
|
+
} catch (err) {
|
|
2122
|
+
throw new PTClaimError(
|
|
2123
|
+
"BUILD_FAILED",
|
|
2124
|
+
`prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2125
|
+
);
|
|
2126
|
+
}
|
|
2127
|
+
let fallback;
|
|
2128
|
+
if (feeAmount > 0n) {
|
|
2129
|
+
try {
|
|
2130
|
+
fallback = await this.cfg.relayService.prepareMint({
|
|
2131
|
+
userAddress: request.userAddress,
|
|
2132
|
+
aaNonce: request.aaNonce,
|
|
2133
|
+
batchExecutorAddress,
|
|
2134
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2135
|
+
amount: request.amount,
|
|
2136
|
+
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2137
|
+
domain,
|
|
2138
|
+
mintRequestNonce: request.mintRequestNonce,
|
|
2139
|
+
deadline: signatureDeadline,
|
|
2140
|
+
feeAmount: 0n
|
|
2141
|
+
});
|
|
2142
|
+
} catch (err) {
|
|
2143
|
+
throw new PTClaimError(
|
|
2144
|
+
"BUILD_FAILED",
|
|
2145
|
+
`prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2146
|
+
);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
const calls = (0, import_core9.decodeBatchExecuteCalls)(userOp.callData);
|
|
2150
|
+
const callsFallback = fallback ? (0, import_core9.decodeBatchExecuteCalls)(fallback.callData) : void 0;
|
|
2151
|
+
return {
|
|
2152
|
+
userOp,
|
|
2153
|
+
fallback,
|
|
2154
|
+
lockId,
|
|
2155
|
+
feeAmount,
|
|
2156
|
+
signatureDeadline,
|
|
2157
|
+
expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
|
|
2158
|
+
calls,
|
|
2159
|
+
callsFallback
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
};
|
|
2163
|
+
|
|
2164
|
+
// src/api/handlers/swapHandler.ts
|
|
2165
|
+
var import_core10 = require("@pafi-dev/core");
|
|
2166
|
+
var SwapError = class extends Error {
|
|
2167
|
+
constructor(code, message) {
|
|
2168
|
+
super(message);
|
|
2169
|
+
this.code = code;
|
|
2170
|
+
this.name = "SwapError";
|
|
2171
|
+
}
|
|
2172
|
+
code;
|
|
2173
|
+
};
|
|
2174
|
+
var DEFAULT_SLIPPAGE_BPS = 50;
|
|
2175
|
+
var DEFAULT_SWAP_DEADLINE_SEC = 5 * 60;
|
|
2176
|
+
var SwapHandler = class {
|
|
2177
|
+
cfg;
|
|
2178
|
+
constructor(config) {
|
|
2179
|
+
this.cfg = {
|
|
2180
|
+
...config,
|
|
2181
|
+
defaultSlippageBps: config.defaultSlippageBps ?? DEFAULT_SLIPPAGE_BPS,
|
|
2182
|
+
defaultSwapDeadlineSeconds: config.defaultSwapDeadlineSeconds ?? DEFAULT_SWAP_DEADLINE_SEC,
|
|
2183
|
+
now: config.now ?? (() => Date.now())
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
async handle(request) {
|
|
2187
|
+
if (request.amountIn <= 0n) {
|
|
2188
|
+
throw new SwapError("INVALID_AMOUNT", "amountIn must be positive");
|
|
2189
|
+
}
|
|
2190
|
+
const slippageBps = request.slippageBps ?? this.cfg.defaultSlippageBps;
|
|
2191
|
+
const { usdt, pafiFeeRecipient, universalRouter } = (0, import_core10.getContractAddresses)(
|
|
2192
|
+
request.chainId
|
|
2193
|
+
);
|
|
2194
|
+
const poolsResponse = await this.cfg.poolsProvider({
|
|
2195
|
+
chainId: request.chainId,
|
|
2196
|
+
pointTokenAddress: request.pointTokenAddress
|
|
2197
|
+
});
|
|
2198
|
+
if (poolsResponse.pools.length === 0) {
|
|
2199
|
+
throw new SwapError(
|
|
2200
|
+
"QUOTE_UNAVAILABLE",
|
|
2201
|
+
"no liquidity pool found for this point token"
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
let fallbackQuote;
|
|
2205
|
+
try {
|
|
2206
|
+
fallbackQuote = await (0, import_core10.findBestQuote)(
|
|
2207
|
+
this.cfg.provider,
|
|
2208
|
+
request.chainId,
|
|
2209
|
+
request.pointTokenAddress,
|
|
2210
|
+
usdt,
|
|
2211
|
+
request.amountIn,
|
|
2212
|
+
poolsResponse.pools
|
|
2213
|
+
);
|
|
2214
|
+
} catch {
|
|
2215
|
+
throw new SwapError(
|
|
2216
|
+
"QUOTE_UNAVAILABLE",
|
|
2217
|
+
"no swap path found for this point token"
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
const estimatedUsdtOutFallback = fallbackQuote.bestRoute.amountOut;
|
|
2221
|
+
const minAmountOutFallback = estimatedUsdtOutFallback * BigInt(1e4 - slippageBps) / 10000n;
|
|
2222
|
+
const deadline = request.deadline ?? BigInt(
|
|
2223
|
+
Math.floor(this.cfg.now() / 1e3) + this.cfg.defaultSwapDeadlineSeconds
|
|
2224
|
+
);
|
|
2225
|
+
const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
|
|
2226
|
+
if (feeAmount > 0n && feeAmount >= request.amountIn) {
|
|
2227
|
+
throw new SwapError(
|
|
2228
|
+
"FEE_EXCEEDS_AMOUNT",
|
|
2229
|
+
`gas fee (${feeAmount}) must be strictly less than swap amount (${request.amountIn})`
|
|
2230
|
+
);
|
|
2231
|
+
}
|
|
2232
|
+
const sponsoredAmountIn = request.amountIn - feeAmount;
|
|
2233
|
+
let estimatedUsdtOutSponsored = estimatedUsdtOutFallback;
|
|
2234
|
+
let sponsoredPath = fallbackQuote.bestRoute.path;
|
|
2235
|
+
if (feeAmount > 0n) {
|
|
2236
|
+
try {
|
|
2237
|
+
const sponsoredQuote = await (0, import_core10.findBestQuote)(
|
|
2238
|
+
this.cfg.provider,
|
|
2239
|
+
request.chainId,
|
|
2240
|
+
request.pointTokenAddress,
|
|
2241
|
+
usdt,
|
|
2242
|
+
sponsoredAmountIn,
|
|
2243
|
+
poolsResponse.pools
|
|
2244
|
+
);
|
|
2245
|
+
estimatedUsdtOutSponsored = sponsoredQuote.bestRoute.amountOut;
|
|
2246
|
+
sponsoredPath = sponsoredQuote.bestRoute.path;
|
|
2247
|
+
} catch {
|
|
2248
|
+
throw new SwapError(
|
|
2249
|
+
"QUOTE_UNAVAILABLE",
|
|
2250
|
+
"no swap path found for sponsored amount (after fee deduction)"
|
|
2251
|
+
);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
const minAmountOutSponsored = estimatedUsdtOutSponsored * BigInt(1e4 - slippageBps) / 10000n;
|
|
2255
|
+
const sponsoredOp = (0, import_core10.buildSwapWithGasDeduction)({
|
|
2256
|
+
userAddress: request.userAddress,
|
|
2257
|
+
aaNonce: request.aaNonce,
|
|
2258
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2259
|
+
outputTokenAddress: usdt,
|
|
2260
|
+
universalRouterAddress: universalRouter,
|
|
2261
|
+
amountIn: sponsoredAmountIn,
|
|
2262
|
+
minAmountOut: minAmountOutSponsored,
|
|
2263
|
+
swapPath: sponsoredPath,
|
|
2264
|
+
deadline,
|
|
2265
|
+
gasFeePt: feeAmount,
|
|
2266
|
+
feeRecipient: pafiFeeRecipient
|
|
2267
|
+
});
|
|
2268
|
+
const fallbackOp = feeAmount > 0n ? (0, import_core10.buildSwapWithGasDeduction)({
|
|
2269
|
+
userAddress: request.userAddress,
|
|
2270
|
+
aaNonce: request.aaNonce,
|
|
2271
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2272
|
+
outputTokenAddress: usdt,
|
|
2273
|
+
universalRouterAddress: universalRouter,
|
|
2274
|
+
amountIn: request.amountIn,
|
|
2275
|
+
minAmountOut: minAmountOutFallback,
|
|
2276
|
+
swapPath: fallbackQuote.bestRoute.path,
|
|
2277
|
+
deadline,
|
|
2278
|
+
gasFeePt: 0n,
|
|
2279
|
+
feeRecipient: pafiFeeRecipient
|
|
2280
|
+
}) : void 0;
|
|
2281
|
+
return {
|
|
2282
|
+
userOp: sponsoredOp,
|
|
2283
|
+
fallback: fallbackOp,
|
|
2284
|
+
feeAmount,
|
|
2285
|
+
estimatedUsdtOut: estimatedUsdtOutSponsored,
|
|
2286
|
+
minAmountOut: minAmountOutSponsored,
|
|
2287
|
+
estimatedUsdtOutFallback: fallbackOp ? estimatedUsdtOutFallback : void 0,
|
|
2288
|
+
minAmountOutFallback: fallbackOp ? minAmountOutFallback : void 0,
|
|
2289
|
+
deadline,
|
|
2290
|
+
calls: (0, import_core10.decodeBatchExecuteCalls)(sponsoredOp.callData),
|
|
2291
|
+
callsFallback: fallbackOp ? (0, import_core10.decodeBatchExecuteCalls)(fallbackOp.callData) : void 0
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
};
|
|
2295
|
+
|
|
2296
|
+
// src/api/handlers/perpDepositHandler.ts
|
|
2297
|
+
var import_core11 = require("@pafi-dev/core");
|
|
2298
|
+
var PerpDepositError = class extends Error {
|
|
2299
|
+
constructor(code, message) {
|
|
2300
|
+
super(message);
|
|
2301
|
+
this.code = code;
|
|
2302
|
+
this.name = "PerpDepositError";
|
|
2303
|
+
}
|
|
2304
|
+
code;
|
|
2305
|
+
};
|
|
2306
|
+
var DEFAULT_MAX_FEE_PREMIUM_BPS = 5e3;
|
|
2307
|
+
var PerpDepositHandler = class {
|
|
2308
|
+
cfg;
|
|
2309
|
+
constructor(config) {
|
|
2310
|
+
this.cfg = {
|
|
2311
|
+
...config,
|
|
2312
|
+
maxFeePremiumBps: config.maxFeePremiumBps ?? DEFAULT_MAX_FEE_PREMIUM_BPS
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
async handle(request) {
|
|
2316
|
+
if (request.amount <= 0n) {
|
|
2317
|
+
throw new PerpDepositError("INVALID_AMOUNT", "amount must be positive");
|
|
2318
|
+
}
|
|
2319
|
+
const brokerHash = import_core11.BROKER_HASHES[request.brokerId];
|
|
2320
|
+
const tokenHash = import_core11.TOKEN_HASHES.USDC;
|
|
2321
|
+
const vault = import_core11.ORDERLY_VAULT_ADDRESSES[request.chainId];
|
|
2322
|
+
if (!vault) {
|
|
2323
|
+
throw new PerpDepositError(
|
|
2324
|
+
"PERP_DEPOSIT_UNAVAILABLE",
|
|
2325
|
+
`no Orderly Vault for chainId ${request.chainId}`
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
2328
|
+
const { orderlyRelay: relayAddress, pafiFeeRecipient } = (0, import_core11.getContractAddresses)(request.chainId);
|
|
2329
|
+
const [usdcAddress, brokerAllowed] = await Promise.all([
|
|
2330
|
+
this.cfg.provider.readContract({
|
|
2331
|
+
address: vault,
|
|
2332
|
+
abi: import_core11.ORDERLY_VAULT_ABI,
|
|
2333
|
+
functionName: "getAllowedToken",
|
|
2334
|
+
args: [tokenHash]
|
|
2335
|
+
}),
|
|
2336
|
+
this.cfg.provider.readContract({
|
|
2337
|
+
address: vault,
|
|
2338
|
+
abi: import_core11.ORDERLY_VAULT_ABI,
|
|
2339
|
+
functionName: "getAllowedBroker",
|
|
2340
|
+
args: [brokerHash]
|
|
2341
|
+
})
|
|
2342
|
+
]);
|
|
2343
|
+
if (!brokerAllowed) {
|
|
2344
|
+
throw new PerpDepositError(
|
|
2345
|
+
"BROKER_NOT_WHITELISTED",
|
|
2346
|
+
`broker "${request.brokerId}" is not whitelisted on Orderly Vault`
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
const accountId = (0, import_core11.computeAccountId)(request.userAddress, brokerHash);
|
|
2350
|
+
const requestForQuote = {
|
|
2351
|
+
token: usdcAddress,
|
|
2352
|
+
receiver: request.userAddress,
|
|
2353
|
+
brokerHash,
|
|
2354
|
+
totalAmount: request.amount,
|
|
2355
|
+
maxFee: 0n
|
|
2356
|
+
};
|
|
2357
|
+
const [relayTokenFee, ptGasFee] = await Promise.all([
|
|
2358
|
+
this.cfg.provider.readContract({
|
|
2359
|
+
address: relayAddress,
|
|
2360
|
+
abi: import_core11.ORDERLY_RELAY_ABI,
|
|
2361
|
+
functionName: "quoteTokenFee",
|
|
2362
|
+
args: [requestForQuote]
|
|
2363
|
+
}),
|
|
2364
|
+
this.cfg.feeService ? this.cfg.feeService.estimateGasFee() : Promise.resolve(0n)
|
|
2365
|
+
]);
|
|
2366
|
+
if (relayTokenFee >= request.amount) {
|
|
2367
|
+
throw new PerpDepositError(
|
|
2368
|
+
"RELAY_FEE_EXCEEDS_AMOUNT",
|
|
2369
|
+
`Relay quoted fee ${relayTokenFee} >= deposit amount ${request.amount}`
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2372
|
+
const maxFee = relayTokenFee * BigInt(1e4 + this.cfg.maxFeePremiumBps) / 10000n;
|
|
2373
|
+
const depositReq = {
|
|
2374
|
+
token: usdcAddress,
|
|
2375
|
+
receiver: request.userAddress,
|
|
2376
|
+
brokerHash,
|
|
2377
|
+
totalAmount: request.amount,
|
|
2378
|
+
maxFee
|
|
2379
|
+
};
|
|
2380
|
+
const sponsoredOp = (0, import_core11.buildPerpDepositViaRelay)({
|
|
2381
|
+
userAddress: request.userAddress,
|
|
2382
|
+
aaNonce: request.aaNonce,
|
|
2383
|
+
relayAddress,
|
|
2384
|
+
request: depositReq,
|
|
2385
|
+
pointTokenAddress: this.cfg.pointTokenAddress,
|
|
2386
|
+
gasFeePt: ptGasFee,
|
|
2387
|
+
gasFeePtRecipient: pafiFeeRecipient
|
|
2388
|
+
});
|
|
2389
|
+
const fallbackOp = ptGasFee > 0n ? (0, import_core11.buildPerpDepositViaRelay)({
|
|
2390
|
+
userAddress: request.userAddress,
|
|
2391
|
+
aaNonce: request.aaNonce,
|
|
2392
|
+
relayAddress,
|
|
2393
|
+
request: depositReq
|
|
2394
|
+
}) : void 0;
|
|
2395
|
+
return {
|
|
2396
|
+
userOp: sponsoredOp,
|
|
2397
|
+
fallback: fallbackOp,
|
|
2398
|
+
feeAmount: ptGasFee,
|
|
2399
|
+
relayTokenFee,
|
|
2400
|
+
maxFee,
|
|
2401
|
+
netDeposit: request.amount - relayTokenFee,
|
|
2402
|
+
accountId,
|
|
2403
|
+
brokerHash,
|
|
2404
|
+
usdcAddress,
|
|
2405
|
+
relayAddress,
|
|
2406
|
+
calls: (0, import_core11.decodeBatchExecuteCalls)(sponsoredOp.callData),
|
|
2407
|
+
callsFallback: fallbackOp ? (0, import_core11.decodeBatchExecuteCalls)(fallbackOp.callData) : void 0
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
};
|
|
2411
|
+
|
|
1750
2412
|
// src/pools/subgraphPoolsProvider.ts
|
|
1751
|
-
var
|
|
1752
|
-
var
|
|
2413
|
+
var import_viem10 = require("viem");
|
|
2414
|
+
var import_core12 = require("@pafi-dev/core");
|
|
1753
2415
|
var DEFAULT_CACHE_TTL_MS = 3e4;
|
|
1754
2416
|
var POOL_QUERY = `
|
|
1755
2417
|
query GetPoolForPointToken($id: ID!) {
|
|
@@ -1767,7 +2429,7 @@ var POOL_QUERY = `
|
|
|
1767
2429
|
}
|
|
1768
2430
|
`;
|
|
1769
2431
|
function createSubgraphPoolsProvider(config = {}) {
|
|
1770
|
-
const subgraphUrl = config.subgraphUrl ??
|
|
2432
|
+
const subgraphUrl = config.subgraphUrl ?? import_core12.PAFI_SUBGRAPH_URL;
|
|
1771
2433
|
try {
|
|
1772
2434
|
const parsed = new URL(subgraphUrl);
|
|
1773
2435
|
if (process.env.NODE_ENV === "production" && parsed.protocol !== "https:") {
|
|
@@ -1849,7 +2511,7 @@ async function fetchPoolsFromSubgraph(fetchImpl, subgraphUrl, pointTokenAddress)
|
|
|
1849
2511
|
return [];
|
|
1850
2512
|
}
|
|
1851
2513
|
const { pool } = token;
|
|
1852
|
-
if (!(0,
|
|
2514
|
+
if (!(0, import_viem10.isAddress)(pool.hooks)) {
|
|
1853
2515
|
console.error(
|
|
1854
2516
|
"[PAFI] SubgraphPoolsProvider: invalid hooks address in response:",
|
|
1855
2517
|
pool.hooks,
|
|
@@ -1857,7 +2519,7 @@ async function fetchPoolsFromSubgraph(fetchImpl, subgraphUrl, pointTokenAddress)
|
|
|
1857
2519
|
);
|
|
1858
2520
|
return [];
|
|
1859
2521
|
}
|
|
1860
|
-
if (!(0,
|
|
2522
|
+
if (!(0, import_viem10.isAddress)(pool.token0.id) || !(0, import_viem10.isAddress)(pool.token1.id)) {
|
|
1861
2523
|
console.error(
|
|
1862
2524
|
"[PAFI] SubgraphPoolsProvider: invalid token address in response \u2014 skipping pool"
|
|
1863
2525
|
);
|
|
@@ -1899,7 +2561,7 @@ var PRICE_QUERY = `
|
|
|
1899
2561
|
}
|
|
1900
2562
|
`;
|
|
1901
2563
|
function createSubgraphNativeUsdtQuoter(config = {}) {
|
|
1902
|
-
const subgraphUrl = config.subgraphUrl ??
|
|
2564
|
+
const subgraphUrl = config.subgraphUrl ?? import_core12.PAFI_SUBGRAPH_URL;
|
|
1903
2565
|
try {
|
|
1904
2566
|
const parsed = new URL(subgraphUrl);
|
|
1905
2567
|
if (process.env.NODE_ENV === "production" && parsed.protocol !== "https:") {
|
|
@@ -2007,8 +2669,8 @@ function toUsdtPerNative(priceFloat, usdtDecimals) {
|
|
|
2007
2669
|
}
|
|
2008
2670
|
|
|
2009
2671
|
// src/pools/nativePtQuoter.ts
|
|
2010
|
-
var
|
|
2011
|
-
var CHAINLINK_ABI = (0,
|
|
2672
|
+
var import_viem11 = require("viem");
|
|
2673
|
+
var CHAINLINK_ABI = (0, import_viem11.parseAbi)([
|
|
2012
2674
|
"function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)"
|
|
2013
2675
|
]);
|
|
2014
2676
|
var CHAINLINK_MAX_AGE_S = 3600n;
|
|
@@ -2029,7 +2691,7 @@ function createNativePtQuoter(config) {
|
|
|
2029
2691
|
provider,
|
|
2030
2692
|
pointTokenAddress,
|
|
2031
2693
|
chainlinkFeedAddress = "0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70",
|
|
2032
|
-
subgraphUrl =
|
|
2694
|
+
subgraphUrl = import_core12.PAFI_SUBGRAPH_URL,
|
|
2033
2695
|
cacheTtlMs = 3e4,
|
|
2034
2696
|
fallbackEthPriceUsd = 3e3,
|
|
2035
2697
|
fallbackPtPriceUsdt = 0.1,
|
|
@@ -2111,7 +2773,7 @@ function parseBigDecimalTo18(s) {
|
|
|
2111
2773
|
}
|
|
2112
2774
|
|
|
2113
2775
|
// src/balance/balanceAggregator.ts
|
|
2114
|
-
var
|
|
2776
|
+
var import_core13 = require("@pafi-dev/core");
|
|
2115
2777
|
var BalanceAggregator = class {
|
|
2116
2778
|
provider;
|
|
2117
2779
|
ledger;
|
|
@@ -2132,7 +2794,7 @@ var BalanceAggregator = class {
|
|
|
2132
2794
|
async getCombinedBalance(user, pointToken) {
|
|
2133
2795
|
const [offChain, onChain] = await Promise.all([
|
|
2134
2796
|
this.ledger.getBalance(user, pointToken),
|
|
2135
|
-
(0,
|
|
2797
|
+
(0, import_core13.getPointTokenBalance)(this.provider, pointToken, user)
|
|
2136
2798
|
]);
|
|
2137
2799
|
return {
|
|
2138
2800
|
offChain,
|
|
@@ -2364,79 +3026,9 @@ var PafiBackendClient = class {
|
|
|
2364
3026
|
}
|
|
2365
3027
|
};
|
|
2366
3028
|
|
|
2367
|
-
// src/pafi-backend/helpers.ts
|
|
2368
|
-
var BundlerNotConfiguredError = class extends Error {
|
|
2369
|
-
code = "BUNDLER_NOT_CONFIGURED";
|
|
2370
|
-
constructor() {
|
|
2371
|
-
super(
|
|
2372
|
-
"PAFI backend client not configured \u2014 set PAFI_BACKEND_URL, PAFI_ISSUER_ID, PAFI_API_KEY to enable mobile submit."
|
|
2373
|
-
);
|
|
2374
|
-
this.name = "BundlerNotConfiguredError";
|
|
2375
|
-
}
|
|
2376
|
-
};
|
|
2377
|
-
var BundlerRejectedError = class extends Error {
|
|
2378
|
-
code = "BUNDLER_REJECTED";
|
|
2379
|
-
cause;
|
|
2380
|
-
constructor(message, cause) {
|
|
2381
|
-
super(message);
|
|
2382
|
-
this.name = "BundlerRejectedError";
|
|
2383
|
-
this.cause = cause;
|
|
2384
|
-
}
|
|
2385
|
-
};
|
|
2386
|
-
async function requestPaymaster(params) {
|
|
2387
|
-
if (!params.client) return void 0;
|
|
2388
|
-
const fn = params.functionName ?? defaultFunctionForScenario(params.scenario);
|
|
2389
|
-
try {
|
|
2390
|
-
return await params.client.requestSponsorship({
|
|
2391
|
-
chainId: params.chainId,
|
|
2392
|
-
scenario: params.scenario,
|
|
2393
|
-
userOp: params.userOp,
|
|
2394
|
-
target: {
|
|
2395
|
-
contract: params.pointTokenAddress,
|
|
2396
|
-
function: fn,
|
|
2397
|
-
pointToken: params.pointTokenAddress
|
|
2398
|
-
}
|
|
2399
|
-
});
|
|
2400
|
-
} catch (err) {
|
|
2401
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2402
|
-
params.onWarning?.(`Paymaster sponsorship declined: ${msg}`);
|
|
2403
|
-
return void 0;
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
function defaultFunctionForScenario(scenario) {
|
|
2407
|
-
switch (scenario) {
|
|
2408
|
-
case "mint":
|
|
2409
|
-
return "mint";
|
|
2410
|
-
case "burn":
|
|
2411
|
-
return "burn";
|
|
2412
|
-
case "swap":
|
|
2413
|
-
return "swap";
|
|
2414
|
-
case "perp-deposit":
|
|
2415
|
-
return "deposit";
|
|
2416
|
-
default:
|
|
2417
|
-
return scenario;
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
async function relayUserOp(params) {
|
|
2421
|
-
if (!params.client) {
|
|
2422
|
-
throw new BundlerNotConfiguredError();
|
|
2423
|
-
}
|
|
2424
|
-
try {
|
|
2425
|
-
const result = await params.client.relayUserOperation({
|
|
2426
|
-
userOp: params.userOp,
|
|
2427
|
-
entryPoint: params.entryPoint,
|
|
2428
|
-
eip7702Auth: params.eip7702Auth
|
|
2429
|
-
});
|
|
2430
|
-
return { userOpHash: result.userOpHash };
|
|
2431
|
-
} catch (err) {
|
|
2432
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2433
|
-
throw new BundlerRejectedError(msg, err);
|
|
2434
|
-
}
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
3029
|
// src/config.ts
|
|
2438
|
-
var
|
|
2439
|
-
var
|
|
3030
|
+
var import_viem12 = require("viem");
|
|
3031
|
+
var import_core14 = require("@pafi-dev/core");
|
|
2440
3032
|
function createIssuerService(config) {
|
|
2441
3033
|
if (!config.provider) {
|
|
2442
3034
|
throw new Error("createIssuerService: provider is required");
|
|
@@ -2456,7 +3048,7 @@ function createIssuerService(config) {
|
|
|
2456
3048
|
"createIssuerService: at least one of pointTokenAddress / pointTokenAddresses is required"
|
|
2457
3049
|
);
|
|
2458
3050
|
}
|
|
2459
|
-
const tokenAddresses = rawAddresses.map((a) => (0,
|
|
3051
|
+
const tokenAddresses = rawAddresses.map((a) => (0, import_viem12.getAddress)(a));
|
|
2460
3052
|
const ledger = config.ledger;
|
|
2461
3053
|
const sessionStore = config.sessionStore ?? new MemorySessionStore();
|
|
2462
3054
|
const policy = config.policy ?? new DefaultPolicyEngine({ ledger });
|
|
@@ -2506,7 +3098,7 @@ function createIssuerService(config) {
|
|
|
2506
3098
|
indexers.set(tokenAddress, new PointIndexer(indexerConfig));
|
|
2507
3099
|
}
|
|
2508
3100
|
const firstIndexer = indexers.get(tokenAddresses[0]);
|
|
2509
|
-
const chainAddresses = (0,
|
|
3101
|
+
const chainAddresses = (0, import_core14.getContractAddresses)(config.chainId);
|
|
2510
3102
|
const resolvedContracts = {
|
|
2511
3103
|
batchExecutor: chainAddresses.batchExecutor,
|
|
2512
3104
|
usdt: chainAddresses.usdt,
|
|
@@ -2553,156 +3145,9 @@ function createIssuerService(config) {
|
|
|
2553
3145
|
};
|
|
2554
3146
|
}
|
|
2555
3147
|
|
|
2556
|
-
// src/userop-store/serialize.ts
|
|
2557
|
-
var import_core9 = require("@pafi-dev/core");
|
|
2558
|
-
function serializeEntryToJsonRpc(entry, signature, variant = "sponsored") {
|
|
2559
|
-
if (variant === "fallback") {
|
|
2560
|
-
if (!entry.fallback) {
|
|
2561
|
-
throw new Error(
|
|
2562
|
-
"serializeEntryToJsonRpc: variant=fallback requested but the stored entry has no `fallback` branch \u2014 caller should resubmit with variant='sponsored' or re-prepare with a fee configured."
|
|
2563
|
-
);
|
|
2564
|
-
}
|
|
2565
|
-
return (0, import_core9.serializeUserOpToJsonRpc)(
|
|
2566
|
-
{
|
|
2567
|
-
sender: entry.sender,
|
|
2568
|
-
nonce: BigInt(entry.nonce),
|
|
2569
|
-
callData: entry.fallback.callData,
|
|
2570
|
-
callGasLimit: BigInt(entry.fallback.callGasLimit),
|
|
2571
|
-
verificationGasLimit: BigInt(entry.fallback.verificationGasLimit),
|
|
2572
|
-
preVerificationGas: BigInt(entry.fallback.preVerificationGas),
|
|
2573
|
-
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
2574
|
-
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas)
|
|
2575
|
-
// intentionally no paymaster — user pays ETH gas
|
|
2576
|
-
},
|
|
2577
|
-
signature
|
|
2578
|
-
);
|
|
2579
|
-
}
|
|
2580
|
-
return (0, import_core9.serializeUserOpToJsonRpc)(
|
|
2581
|
-
{
|
|
2582
|
-
sender: entry.sender,
|
|
2583
|
-
nonce: BigInt(entry.nonce),
|
|
2584
|
-
callData: entry.callData,
|
|
2585
|
-
callGasLimit: BigInt(entry.callGasLimit),
|
|
2586
|
-
verificationGasLimit: BigInt(entry.verificationGasLimit),
|
|
2587
|
-
preVerificationGas: BigInt(entry.preVerificationGas),
|
|
2588
|
-
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
2589
|
-
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas),
|
|
2590
|
-
paymaster: entry.paymaster,
|
|
2591
|
-
paymasterVerificationGasLimit: entry.paymasterVerificationGasLimit != null ? BigInt(entry.paymasterVerificationGasLimit) : void 0,
|
|
2592
|
-
paymasterPostOpGasLimit: entry.paymasterPostOpGasLimit != null ? BigInt(entry.paymasterPostOpGasLimit) : void 0,
|
|
2593
|
-
paymasterData: entry.paymasterData
|
|
2594
|
-
},
|
|
2595
|
-
signature
|
|
2596
|
-
);
|
|
2597
|
-
}
|
|
2598
|
-
|
|
2599
|
-
// src/userop-store/prepareUserOp.ts
|
|
2600
|
-
var import_core10 = require("@pafi-dev/core");
|
|
2601
|
-
function serializeUserOpTypedData(td) {
|
|
2602
|
-
return {
|
|
2603
|
-
domain: td.domain,
|
|
2604
|
-
types: td.types,
|
|
2605
|
-
primaryType: td.primaryType,
|
|
2606
|
-
message: {
|
|
2607
|
-
sender: td.message.sender,
|
|
2608
|
-
nonce: `0x${td.message.nonce.toString(16)}`,
|
|
2609
|
-
initCode: td.message.initCode,
|
|
2610
|
-
callData: td.message.callData,
|
|
2611
|
-
accountGasLimits: td.message.accountGasLimits,
|
|
2612
|
-
preVerificationGas: `0x${td.message.preVerificationGas.toString(
|
|
2613
|
-
16
|
|
2614
|
-
)}`,
|
|
2615
|
-
gasFees: td.message.gasFees,
|
|
2616
|
-
paymasterAndData: td.message.paymasterAndData
|
|
2617
|
-
}
|
|
2618
|
-
};
|
|
2619
|
-
}
|
|
2620
|
-
function mergePaymasterFields(userOp, paymasterFields) {
|
|
2621
|
-
if (!paymasterFields) return userOp;
|
|
2622
|
-
const merged = {
|
|
2623
|
-
...userOp
|
|
2624
|
-
};
|
|
2625
|
-
for (const [k, v] of Object.entries(paymasterFields)) {
|
|
2626
|
-
if (v !== void 0) merged[k] = v;
|
|
2627
|
-
}
|
|
2628
|
-
return merged;
|
|
2629
|
-
}
|
|
2630
|
-
async function prepareMobileUserOp(params) {
|
|
2631
|
-
const userOp = mergePaymasterFields(
|
|
2632
|
-
params.partialUserOp,
|
|
2633
|
-
params.paymasterFields
|
|
2634
|
-
);
|
|
2635
|
-
const userOpHash = (0, import_core10.computeUserOpHash)(userOp, params.chainId);
|
|
2636
|
-
const typedData = serializeUserOpTypedData(
|
|
2637
|
-
(0, import_core10.buildUserOpTypedData)(userOp, params.chainId)
|
|
2638
|
-
);
|
|
2639
|
-
let fallback;
|
|
2640
|
-
let fallbackEntry;
|
|
2641
|
-
if (params.partialUserOpFallback) {
|
|
2642
|
-
const fallbackUserOp = {
|
|
2643
|
-
...params.partialUserOpFallback,
|
|
2644
|
-
maxFeePerGas: userOp.maxFeePerGas,
|
|
2645
|
-
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas
|
|
2646
|
-
};
|
|
2647
|
-
const fallbackHash = (0, import_core10.computeUserOpHash)(fallbackUserOp, params.chainId);
|
|
2648
|
-
const fallbackTypedData = serializeUserOpTypedData(
|
|
2649
|
-
(0, import_core10.buildUserOpTypedData)(fallbackUserOp, params.chainId)
|
|
2650
|
-
);
|
|
2651
|
-
fallback = {
|
|
2652
|
-
userOp: fallbackUserOp,
|
|
2653
|
-
userOpHash: fallbackHash,
|
|
2654
|
-
typedData: fallbackTypedData
|
|
2655
|
-
};
|
|
2656
|
-
fallbackEntry = {
|
|
2657
|
-
callData: fallbackUserOp.callData,
|
|
2658
|
-
callGasLimit: fallbackUserOp.callGasLimit.toString(),
|
|
2659
|
-
verificationGasLimit: fallbackUserOp.verificationGasLimit.toString(),
|
|
2660
|
-
preVerificationGas: fallbackUserOp.preVerificationGas.toString(),
|
|
2661
|
-
userOpHash: fallbackHash
|
|
2662
|
-
};
|
|
2663
|
-
}
|
|
2664
|
-
const entry = {
|
|
2665
|
-
sender: userOp.sender,
|
|
2666
|
-
nonce: userOp.nonce.toString(),
|
|
2667
|
-
callData: userOp.callData,
|
|
2668
|
-
callGasLimit: userOp.callGasLimit.toString(),
|
|
2669
|
-
verificationGasLimit: userOp.verificationGasLimit.toString(),
|
|
2670
|
-
preVerificationGas: userOp.preVerificationGas.toString(),
|
|
2671
|
-
maxFeePerGas: userOp.maxFeePerGas.toString(),
|
|
2672
|
-
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas.toString(),
|
|
2673
|
-
paymaster: userOp.paymaster,
|
|
2674
|
-
paymasterVerificationGasLimit: userOp.paymasterVerificationGasLimit?.toString(),
|
|
2675
|
-
paymasterPostOpGasLimit: userOp.paymasterPostOpGasLimit?.toString(),
|
|
2676
|
-
paymasterData: userOp.paymasterData,
|
|
2677
|
-
chainId: params.chainId,
|
|
2678
|
-
userOpHash,
|
|
2679
|
-
fallback: fallbackEntry
|
|
2680
|
-
};
|
|
2681
|
-
await params.store.save(params.lockId, entry, params.ttlSeconds);
|
|
2682
|
-
return {
|
|
2683
|
-
sponsored: { userOp, userOpHash, typedData },
|
|
2684
|
-
fallback,
|
|
2685
|
-
entry
|
|
2686
|
-
};
|
|
2687
|
-
}
|
|
2688
|
-
|
|
2689
|
-
// src/issuer-state/validator.ts
|
|
2690
|
-
var import_viem12 = require("viem");
|
|
2691
|
-
var import_core11 = require("@pafi-dev/core");
|
|
2692
|
-
|
|
2693
|
-
// src/issuer-state/types.ts
|
|
2694
|
-
var IssuerStateError = class extends Error {
|
|
2695
|
-
constructor(code, message, details) {
|
|
2696
|
-
super(message);
|
|
2697
|
-
this.code = code;
|
|
2698
|
-
this.details = details;
|
|
2699
|
-
this.name = "IssuerStateError";
|
|
2700
|
-
}
|
|
2701
|
-
code;
|
|
2702
|
-
details;
|
|
2703
|
-
};
|
|
2704
|
-
|
|
2705
3148
|
// src/issuer-state/validator.ts
|
|
3149
|
+
var import_viem13 = require("viem");
|
|
3150
|
+
var import_core15 = require("@pafi-dev/core");
|
|
2706
3151
|
var ISSUER_RECORD_TTL_MS = 3e4;
|
|
2707
3152
|
var IssuerStateValidator = class _IssuerStateValidator {
|
|
2708
3153
|
constructor(provider, registryAddress) {
|
|
@@ -2719,7 +3164,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2719
3164
|
* `CONTRACT_ADDRESSES` map for the given chain.
|
|
2720
3165
|
*/
|
|
2721
3166
|
static forChain(provider, chainId) {
|
|
2722
|
-
const { issuerRegistry } = (0,
|
|
3167
|
+
const { issuerRegistry } = (0, import_core15.getContractAddresses)(chainId);
|
|
2723
3168
|
return new _IssuerStateValidator(provider, issuerRegistry);
|
|
2724
3169
|
}
|
|
2725
3170
|
/**
|
|
@@ -2728,7 +3173,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2728
3173
|
*/
|
|
2729
3174
|
invalidate(pointToken) {
|
|
2730
3175
|
if (pointToken) {
|
|
2731
|
-
const key = (0,
|
|
3176
|
+
const key = (0, import_viem13.getAddress)(pointToken);
|
|
2732
3177
|
this.pointTokenIssuerCache.delete(key);
|
|
2733
3178
|
this.stateCache.delete(key);
|
|
2734
3179
|
this.inflight.delete(key);
|
|
@@ -2743,23 +3188,23 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2743
3188
|
* The issuer field is set at `initialize()` and never changes.
|
|
2744
3189
|
*/
|
|
2745
3190
|
async getIssuerAddressForPointToken(pointToken) {
|
|
2746
|
-
const key = (0,
|
|
3191
|
+
const key = (0, import_viem13.getAddress)(pointToken);
|
|
2747
3192
|
const cached = this.pointTokenIssuerCache.get(key);
|
|
2748
3193
|
if (cached) return cached;
|
|
2749
3194
|
const issuer = await this.provider.readContract({
|
|
2750
3195
|
address: key,
|
|
2751
|
-
abi:
|
|
3196
|
+
abi: import_core15.POINT_TOKEN_V2_ABI,
|
|
2752
3197
|
functionName: "issuer"
|
|
2753
3198
|
});
|
|
2754
|
-
this.pointTokenIssuerCache.set(key, (0,
|
|
2755
|
-
return (0,
|
|
3199
|
+
this.pointTokenIssuerCache.set(key, (0, import_viem13.getAddress)(issuer));
|
|
3200
|
+
return (0, import_viem13.getAddress)(issuer);
|
|
2756
3201
|
}
|
|
2757
3202
|
/**
|
|
2758
3203
|
* Read registry record + totalSupply, with 30s cache and in-flight
|
|
2759
3204
|
* deduplication. Does NOT throw on inactive/missing — returns raw state.
|
|
2760
3205
|
*/
|
|
2761
3206
|
async getIssuerState(pointToken) {
|
|
2762
|
-
const tokenAddr = (0,
|
|
3207
|
+
const tokenAddr = (0, import_viem13.getAddress)(pointToken);
|
|
2763
3208
|
const now = Date.now();
|
|
2764
3209
|
const cached = this.stateCache.get(tokenAddr);
|
|
2765
3210
|
if (cached && cached.expiresAt > now) return cached.value;
|
|
@@ -2829,13 +3274,13 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2829
3274
|
const [issuerTuple, totalSupply] = await Promise.all([
|
|
2830
3275
|
this.provider.readContract({
|
|
2831
3276
|
address: this.registryAddress,
|
|
2832
|
-
abi:
|
|
3277
|
+
abi: import_core15.issuerRegistryGetIssuerFlatAbi,
|
|
2833
3278
|
functionName: "getIssuer",
|
|
2834
3279
|
args: [issuerAddr]
|
|
2835
3280
|
}),
|
|
2836
3281
|
this.provider.readContract({
|
|
2837
3282
|
address: tokenAddr,
|
|
2838
|
-
abi:
|
|
3283
|
+
abi: import_core15.POINT_TOKEN_V2_ABI,
|
|
2839
3284
|
functionName: "totalSupply"
|
|
2840
3285
|
})
|
|
2841
3286
|
]);
|
|
@@ -2877,13 +3322,20 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
|
|
|
2877
3322
|
NonceManager,
|
|
2878
3323
|
PAFI_ISSUER_SDK_VERSION,
|
|
2879
3324
|
PAFI_SUBGRAPH_URL,
|
|
3325
|
+
PTClaimError,
|
|
3326
|
+
PTClaimHandler,
|
|
2880
3327
|
PTRedeemError,
|
|
2881
3328
|
PTRedeemHandler,
|
|
2882
3329
|
PafiBackendClient,
|
|
2883
3330
|
PafiBackendError,
|
|
3331
|
+
PendingUserOpNotFoundError,
|
|
3332
|
+
PerpDepositError,
|
|
3333
|
+
PerpDepositHandler,
|
|
2884
3334
|
PointIndexer,
|
|
2885
3335
|
RelayError,
|
|
2886
3336
|
RelayService,
|
|
3337
|
+
SwapError,
|
|
3338
|
+
SwapHandler,
|
|
2887
3339
|
TopUpRedemptionError,
|
|
2888
3340
|
TopUpRedemptionHandler,
|
|
2889
3341
|
authenticateRequest,
|
|
@@ -2892,6 +3344,8 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
|
|
|
2892
3344
|
createSubgraphNativeUsdtQuoter,
|
|
2893
3345
|
createSubgraphPoolsProvider,
|
|
2894
3346
|
handleClaimStatus,
|
|
3347
|
+
handleMobilePrepare,
|
|
3348
|
+
handleMobileSubmit,
|
|
2895
3349
|
handleRedeemStatus,
|
|
2896
3350
|
mergePaymasterFields,
|
|
2897
3351
|
prepareMobileUserOp,
|