@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.js
CHANGED
|
@@ -1698,6 +1698,683 @@ async function handleRedeemStatus(params) {
|
|
|
1698
1698
|
};
|
|
1699
1699
|
}
|
|
1700
1700
|
|
|
1701
|
+
// src/api/mobileHandlers.ts
|
|
1702
|
+
import {
|
|
1703
|
+
ENTRY_POINT_V08,
|
|
1704
|
+
parseEip7702DelegatedAddress
|
|
1705
|
+
} from "@pafi-dev/core";
|
|
1706
|
+
|
|
1707
|
+
// src/userop-store/serialize.ts
|
|
1708
|
+
import { serializeUserOpToJsonRpc } from "@pafi-dev/core";
|
|
1709
|
+
function serializeEntryToJsonRpc(entry, signature, variant = "sponsored") {
|
|
1710
|
+
if (variant === "fallback") {
|
|
1711
|
+
if (!entry.fallback) {
|
|
1712
|
+
throw new Error(
|
|
1713
|
+
"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."
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
return serializeUserOpToJsonRpc(
|
|
1717
|
+
{
|
|
1718
|
+
sender: entry.sender,
|
|
1719
|
+
nonce: BigInt(entry.nonce),
|
|
1720
|
+
callData: entry.fallback.callData,
|
|
1721
|
+
callGasLimit: BigInt(entry.fallback.callGasLimit),
|
|
1722
|
+
verificationGasLimit: BigInt(entry.fallback.verificationGasLimit),
|
|
1723
|
+
preVerificationGas: BigInt(entry.fallback.preVerificationGas),
|
|
1724
|
+
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
1725
|
+
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas)
|
|
1726
|
+
// intentionally no paymaster — user pays ETH gas
|
|
1727
|
+
},
|
|
1728
|
+
signature
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1731
|
+
return serializeUserOpToJsonRpc(
|
|
1732
|
+
{
|
|
1733
|
+
sender: entry.sender,
|
|
1734
|
+
nonce: BigInt(entry.nonce),
|
|
1735
|
+
callData: entry.callData,
|
|
1736
|
+
callGasLimit: BigInt(entry.callGasLimit),
|
|
1737
|
+
verificationGasLimit: BigInt(entry.verificationGasLimit),
|
|
1738
|
+
preVerificationGas: BigInt(entry.preVerificationGas),
|
|
1739
|
+
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
1740
|
+
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas),
|
|
1741
|
+
paymaster: entry.paymaster,
|
|
1742
|
+
paymasterVerificationGasLimit: entry.paymasterVerificationGasLimit != null ? BigInt(entry.paymasterVerificationGasLimit) : void 0,
|
|
1743
|
+
paymasterPostOpGasLimit: entry.paymasterPostOpGasLimit != null ? BigInt(entry.paymasterPostOpGasLimit) : void 0,
|
|
1744
|
+
paymasterData: entry.paymasterData
|
|
1745
|
+
},
|
|
1746
|
+
signature
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// src/userop-store/prepareUserOp.ts
|
|
1751
|
+
import {
|
|
1752
|
+
buildUserOpTypedData,
|
|
1753
|
+
computeUserOpHash
|
|
1754
|
+
} from "@pafi-dev/core";
|
|
1755
|
+
function serializeUserOpTypedData(td) {
|
|
1756
|
+
return {
|
|
1757
|
+
domain: td.domain,
|
|
1758
|
+
types: td.types,
|
|
1759
|
+
primaryType: td.primaryType,
|
|
1760
|
+
message: {
|
|
1761
|
+
sender: td.message.sender,
|
|
1762
|
+
nonce: `0x${td.message.nonce.toString(16)}`,
|
|
1763
|
+
initCode: td.message.initCode,
|
|
1764
|
+
callData: td.message.callData,
|
|
1765
|
+
accountGasLimits: td.message.accountGasLimits,
|
|
1766
|
+
preVerificationGas: `0x${td.message.preVerificationGas.toString(
|
|
1767
|
+
16
|
|
1768
|
+
)}`,
|
|
1769
|
+
gasFees: td.message.gasFees,
|
|
1770
|
+
paymasterAndData: td.message.paymasterAndData
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
function mergePaymasterFields(userOp, paymasterFields) {
|
|
1775
|
+
if (!paymasterFields) return userOp;
|
|
1776
|
+
const merged = {
|
|
1777
|
+
...userOp
|
|
1778
|
+
};
|
|
1779
|
+
for (const [k, v] of Object.entries(paymasterFields)) {
|
|
1780
|
+
if (v !== void 0) merged[k] = v;
|
|
1781
|
+
}
|
|
1782
|
+
return merged;
|
|
1783
|
+
}
|
|
1784
|
+
async function prepareMobileUserOp(params) {
|
|
1785
|
+
const userOp = mergePaymasterFields(
|
|
1786
|
+
params.partialUserOp,
|
|
1787
|
+
params.paymasterFields
|
|
1788
|
+
);
|
|
1789
|
+
const userOpHash = computeUserOpHash(userOp, params.chainId);
|
|
1790
|
+
const typedData = serializeUserOpTypedData(
|
|
1791
|
+
buildUserOpTypedData(userOp, params.chainId)
|
|
1792
|
+
);
|
|
1793
|
+
let fallback;
|
|
1794
|
+
let fallbackEntry;
|
|
1795
|
+
if (params.partialUserOpFallback) {
|
|
1796
|
+
const fallbackUserOp = {
|
|
1797
|
+
...params.partialUserOpFallback,
|
|
1798
|
+
maxFeePerGas: userOp.maxFeePerGas,
|
|
1799
|
+
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas
|
|
1800
|
+
};
|
|
1801
|
+
const fallbackHash = computeUserOpHash(fallbackUserOp, params.chainId);
|
|
1802
|
+
const fallbackTypedData = serializeUserOpTypedData(
|
|
1803
|
+
buildUserOpTypedData(fallbackUserOp, params.chainId)
|
|
1804
|
+
);
|
|
1805
|
+
fallback = {
|
|
1806
|
+
userOp: fallbackUserOp,
|
|
1807
|
+
userOpHash: fallbackHash,
|
|
1808
|
+
typedData: fallbackTypedData
|
|
1809
|
+
};
|
|
1810
|
+
fallbackEntry = {
|
|
1811
|
+
callData: fallbackUserOp.callData,
|
|
1812
|
+
callGasLimit: fallbackUserOp.callGasLimit.toString(),
|
|
1813
|
+
verificationGasLimit: fallbackUserOp.verificationGasLimit.toString(),
|
|
1814
|
+
preVerificationGas: fallbackUserOp.preVerificationGas.toString(),
|
|
1815
|
+
userOpHash: fallbackHash
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
const entry = {
|
|
1819
|
+
sender: userOp.sender,
|
|
1820
|
+
nonce: userOp.nonce.toString(),
|
|
1821
|
+
callData: userOp.callData,
|
|
1822
|
+
callGasLimit: userOp.callGasLimit.toString(),
|
|
1823
|
+
verificationGasLimit: userOp.verificationGasLimit.toString(),
|
|
1824
|
+
preVerificationGas: userOp.preVerificationGas.toString(),
|
|
1825
|
+
maxFeePerGas: userOp.maxFeePerGas.toString(),
|
|
1826
|
+
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas.toString(),
|
|
1827
|
+
paymaster: userOp.paymaster,
|
|
1828
|
+
paymasterVerificationGasLimit: userOp.paymasterVerificationGasLimit?.toString(),
|
|
1829
|
+
paymasterPostOpGasLimit: userOp.paymasterPostOpGasLimit?.toString(),
|
|
1830
|
+
paymasterData: userOp.paymasterData,
|
|
1831
|
+
chainId: params.chainId,
|
|
1832
|
+
userOpHash,
|
|
1833
|
+
fallback: fallbackEntry
|
|
1834
|
+
};
|
|
1835
|
+
await params.store.save(params.lockId, entry, params.ttlSeconds);
|
|
1836
|
+
return {
|
|
1837
|
+
sponsored: { userOp, userOpHash, typedData },
|
|
1838
|
+
fallback,
|
|
1839
|
+
entry
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// src/pafi-backend/helpers.ts
|
|
1844
|
+
var BundlerNotConfiguredError = class extends Error {
|
|
1845
|
+
code = "BUNDLER_NOT_CONFIGURED";
|
|
1846
|
+
constructor() {
|
|
1847
|
+
super(
|
|
1848
|
+
"PAFI backend client not configured \u2014 set PAFI_BACKEND_URL, PAFI_ISSUER_ID, PAFI_API_KEY to enable mobile submit."
|
|
1849
|
+
);
|
|
1850
|
+
this.name = "BundlerNotConfiguredError";
|
|
1851
|
+
}
|
|
1852
|
+
};
|
|
1853
|
+
var BundlerRejectedError = class extends Error {
|
|
1854
|
+
code = "BUNDLER_REJECTED";
|
|
1855
|
+
cause;
|
|
1856
|
+
constructor(message, cause) {
|
|
1857
|
+
super(message);
|
|
1858
|
+
this.name = "BundlerRejectedError";
|
|
1859
|
+
this.cause = cause;
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
async function requestPaymaster(params) {
|
|
1863
|
+
if (!params.client) return void 0;
|
|
1864
|
+
const fn = params.functionName ?? defaultFunctionForScenario(params.scenario);
|
|
1865
|
+
try {
|
|
1866
|
+
return await params.client.requestSponsorship({
|
|
1867
|
+
chainId: params.chainId,
|
|
1868
|
+
scenario: params.scenario,
|
|
1869
|
+
userOp: params.userOp,
|
|
1870
|
+
target: {
|
|
1871
|
+
contract: params.pointTokenAddress,
|
|
1872
|
+
function: fn,
|
|
1873
|
+
pointToken: params.pointTokenAddress
|
|
1874
|
+
}
|
|
1875
|
+
});
|
|
1876
|
+
} catch (err) {
|
|
1877
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1878
|
+
params.onWarning?.(`Paymaster sponsorship declined: ${msg}`);
|
|
1879
|
+
return void 0;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
function defaultFunctionForScenario(scenario) {
|
|
1883
|
+
switch (scenario) {
|
|
1884
|
+
case "mint":
|
|
1885
|
+
return "mint";
|
|
1886
|
+
case "burn":
|
|
1887
|
+
return "burn";
|
|
1888
|
+
case "swap":
|
|
1889
|
+
return "swap";
|
|
1890
|
+
case "perp-deposit":
|
|
1891
|
+
return "deposit";
|
|
1892
|
+
default:
|
|
1893
|
+
return scenario;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
async function relayUserOp(params) {
|
|
1897
|
+
if (!params.client) {
|
|
1898
|
+
throw new BundlerNotConfiguredError();
|
|
1899
|
+
}
|
|
1900
|
+
try {
|
|
1901
|
+
const result = await params.client.relayUserOperation({
|
|
1902
|
+
userOp: params.userOp,
|
|
1903
|
+
entryPoint: params.entryPoint,
|
|
1904
|
+
eip7702Auth: params.eip7702Auth
|
|
1905
|
+
});
|
|
1906
|
+
return { userOpHash: result.userOpHash };
|
|
1907
|
+
} catch (err) {
|
|
1908
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1909
|
+
throw new BundlerRejectedError(msg, err);
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
// src/api/mobileHandlers.ts
|
|
1914
|
+
var PendingUserOpNotFoundError = class extends Error {
|
|
1915
|
+
code = "PENDING_USEROP_NOT_FOUND";
|
|
1916
|
+
constructor(lockId) {
|
|
1917
|
+
super(
|
|
1918
|
+
`No pending UserOp found for lockId ${lockId} \u2014 it may have expired or already been submitted.`
|
|
1919
|
+
);
|
|
1920
|
+
this.name = "PendingUserOpNotFoundError";
|
|
1921
|
+
}
|
|
1922
|
+
};
|
|
1923
|
+
async function handleMobilePrepare(params) {
|
|
1924
|
+
const [fees, userCode] = await Promise.all([
|
|
1925
|
+
params.provider.estimateFeesPerGas(),
|
|
1926
|
+
params.provider.getCode({ address: params.userAddress })
|
|
1927
|
+
]);
|
|
1928
|
+
const needsDelegation = parseEip7702DelegatedAddress(userCode) === null;
|
|
1929
|
+
const sponsoredOp = {
|
|
1930
|
+
...params.partialUserOp,
|
|
1931
|
+
maxFeePerGas: fees.maxFeePerGas ?? params.partialUserOp.maxFeePerGas ?? 0n,
|
|
1932
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? params.partialUserOp.maxPriorityFeePerGas ?? 0n
|
|
1933
|
+
};
|
|
1934
|
+
const paymasterFields = await requestPaymaster({
|
|
1935
|
+
client: params.pafiBackendClient,
|
|
1936
|
+
chainId: params.chainId,
|
|
1937
|
+
scenario: params.scenario,
|
|
1938
|
+
userOp: sponsoredOp,
|
|
1939
|
+
pointTokenAddress: params.pointTokenAddress,
|
|
1940
|
+
onWarning: params.onWarning
|
|
1941
|
+
});
|
|
1942
|
+
const prepared = await prepareMobileUserOp({
|
|
1943
|
+
lockId: params.lockId,
|
|
1944
|
+
partialUserOp: sponsoredOp,
|
|
1945
|
+
partialUserOpFallback: params.partialUserOpFallback,
|
|
1946
|
+
paymasterFields,
|
|
1947
|
+
chainId: params.chainId,
|
|
1948
|
+
store: params.store,
|
|
1949
|
+
ttlSeconds: params.ttlSeconds
|
|
1950
|
+
});
|
|
1951
|
+
return {
|
|
1952
|
+
...prepared,
|
|
1953
|
+
isSponsored: !!paymasterFields,
|
|
1954
|
+
needsDelegation
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
async function handleMobileSubmit(params) {
|
|
1958
|
+
const entry = await params.store.get(params.lockId);
|
|
1959
|
+
if (!entry) {
|
|
1960
|
+
throw new PendingUserOpNotFoundError(params.lockId);
|
|
1961
|
+
}
|
|
1962
|
+
const variant = params.variant ?? "sponsored";
|
|
1963
|
+
const userOpJson = serializeEntryToJsonRpc(entry, params.signature, variant);
|
|
1964
|
+
const result = await relayUserOp({
|
|
1965
|
+
client: params.pafiBackendClient,
|
|
1966
|
+
userOp: userOpJson,
|
|
1967
|
+
entryPoint: params.entryPoint ?? ENTRY_POINT_V08
|
|
1968
|
+
});
|
|
1969
|
+
await params.bindUserOpHash(params.lockId, result.userOpHash);
|
|
1970
|
+
await params.store.delete(params.lockId);
|
|
1971
|
+
return { userOpHash: result.userOpHash };
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
// src/api/handlers/ptClaimHandler.ts
|
|
1975
|
+
import { getAddress as getAddress8 } from "viem";
|
|
1976
|
+
import {
|
|
1977
|
+
decodeBatchExecuteCalls,
|
|
1978
|
+
getContractAddresses as getContractAddresses2
|
|
1979
|
+
} from "@pafi-dev/core";
|
|
1980
|
+
|
|
1981
|
+
// src/issuer-state/types.ts
|
|
1982
|
+
var IssuerStateError = class extends Error {
|
|
1983
|
+
constructor(code, message, details) {
|
|
1984
|
+
super(message);
|
|
1985
|
+
this.code = code;
|
|
1986
|
+
this.details = details;
|
|
1987
|
+
this.name = "IssuerStateError";
|
|
1988
|
+
}
|
|
1989
|
+
code;
|
|
1990
|
+
details;
|
|
1991
|
+
};
|
|
1992
|
+
|
|
1993
|
+
// src/api/handlers/ptClaimHandler.ts
|
|
1994
|
+
var PTClaimError = class extends Error {
|
|
1995
|
+
constructor(code, message, details) {
|
|
1996
|
+
super(message);
|
|
1997
|
+
this.code = code;
|
|
1998
|
+
this.details = details;
|
|
1999
|
+
this.name = "PTClaimError";
|
|
2000
|
+
}
|
|
2001
|
+
code;
|
|
2002
|
+
details;
|
|
2003
|
+
};
|
|
2004
|
+
var DEFAULT_LOCK_MS = 15 * 60 * 1e3;
|
|
2005
|
+
var DEFAULT_SIG_DEADLINE_SEC2 = 15 * 60;
|
|
2006
|
+
var PTClaimHandler = class {
|
|
2007
|
+
cfg;
|
|
2008
|
+
constructor(config) {
|
|
2009
|
+
this.cfg = {
|
|
2010
|
+
...config,
|
|
2011
|
+
lockDurationMs: config.lockDurationMs ?? DEFAULT_LOCK_MS,
|
|
2012
|
+
signatureDeadlineSeconds: config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC2,
|
|
2013
|
+
now: config.now ?? (() => Date.now())
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
async handle(request) {
|
|
2017
|
+
if (getAddress8(request.authenticatedAddress) !== getAddress8(request.userAddress)) {
|
|
2018
|
+
throw new PTClaimError(
|
|
2019
|
+
"VALIDATION_FAILED",
|
|
2020
|
+
`userAddress (${request.userAddress}) does not match authenticated session (${request.authenticatedAddress})`
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
if (request.amount <= 0n) {
|
|
2024
|
+
throw new PTClaimError("INVALID_AMOUNT", "claim amount must be positive");
|
|
2025
|
+
}
|
|
2026
|
+
if (this.cfg.issuerStateValidator) {
|
|
2027
|
+
try {
|
|
2028
|
+
await this.cfg.issuerStateValidator.preValidateMint(
|
|
2029
|
+
request.pointTokenAddress,
|
|
2030
|
+
request.amount
|
|
2031
|
+
);
|
|
2032
|
+
} catch (err) {
|
|
2033
|
+
if (err instanceof IssuerStateError) throw err;
|
|
2034
|
+
throw new PTClaimError(
|
|
2035
|
+
"VALIDATION_FAILED",
|
|
2036
|
+
`issuer-state pre-validate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2037
|
+
);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
const { batchExecutor: batchExecutorAddress } = getContractAddresses2(
|
|
2041
|
+
request.chainId
|
|
2042
|
+
);
|
|
2043
|
+
const lockId = await this.cfg.ledger.lockForMinting(
|
|
2044
|
+
request.userAddress,
|
|
2045
|
+
request.amount,
|
|
2046
|
+
this.cfg.lockDurationMs,
|
|
2047
|
+
request.pointTokenAddress
|
|
2048
|
+
);
|
|
2049
|
+
const signatureDeadline = BigInt(
|
|
2050
|
+
Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
|
|
2051
|
+
);
|
|
2052
|
+
const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
|
|
2053
|
+
const domain = {
|
|
2054
|
+
name: this.cfg.pointTokenDomainName,
|
|
2055
|
+
chainId: request.chainId,
|
|
2056
|
+
verifyingContract: request.pointTokenAddress
|
|
2057
|
+
};
|
|
2058
|
+
let userOp;
|
|
2059
|
+
try {
|
|
2060
|
+
userOp = await this.cfg.relayService.prepareMint({
|
|
2061
|
+
userAddress: request.userAddress,
|
|
2062
|
+
aaNonce: request.aaNonce,
|
|
2063
|
+
batchExecutorAddress,
|
|
2064
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2065
|
+
amount: request.amount,
|
|
2066
|
+
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2067
|
+
domain,
|
|
2068
|
+
mintRequestNonce: request.mintRequestNonce,
|
|
2069
|
+
deadline: signatureDeadline
|
|
2070
|
+
// No feeAmount/feeRecipient — RelayService auto-resolves.
|
|
2071
|
+
});
|
|
2072
|
+
} catch (err) {
|
|
2073
|
+
throw new PTClaimError(
|
|
2074
|
+
"BUILD_FAILED",
|
|
2075
|
+
`prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
2078
|
+
let fallback;
|
|
2079
|
+
if (feeAmount > 0n) {
|
|
2080
|
+
try {
|
|
2081
|
+
fallback = await this.cfg.relayService.prepareMint({
|
|
2082
|
+
userAddress: request.userAddress,
|
|
2083
|
+
aaNonce: request.aaNonce,
|
|
2084
|
+
batchExecutorAddress,
|
|
2085
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2086
|
+
amount: request.amount,
|
|
2087
|
+
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2088
|
+
domain,
|
|
2089
|
+
mintRequestNonce: request.mintRequestNonce,
|
|
2090
|
+
deadline: signatureDeadline,
|
|
2091
|
+
feeAmount: 0n
|
|
2092
|
+
});
|
|
2093
|
+
} catch (err) {
|
|
2094
|
+
throw new PTClaimError(
|
|
2095
|
+
"BUILD_FAILED",
|
|
2096
|
+
`prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
const calls = decodeBatchExecuteCalls(userOp.callData);
|
|
2101
|
+
const callsFallback = fallback ? decodeBatchExecuteCalls(fallback.callData) : void 0;
|
|
2102
|
+
return {
|
|
2103
|
+
userOp,
|
|
2104
|
+
fallback,
|
|
2105
|
+
lockId,
|
|
2106
|
+
feeAmount,
|
|
2107
|
+
signatureDeadline,
|
|
2108
|
+
expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
|
|
2109
|
+
calls,
|
|
2110
|
+
callsFallback
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
|
|
2115
|
+
// src/api/handlers/swapHandler.ts
|
|
2116
|
+
import {
|
|
2117
|
+
buildSwapWithGasDeduction,
|
|
2118
|
+
decodeBatchExecuteCalls as decodeBatchExecuteCalls2,
|
|
2119
|
+
findBestQuote,
|
|
2120
|
+
getContractAddresses as getContractAddresses3
|
|
2121
|
+
} from "@pafi-dev/core";
|
|
2122
|
+
var SwapError = class extends Error {
|
|
2123
|
+
constructor(code, message) {
|
|
2124
|
+
super(message);
|
|
2125
|
+
this.code = code;
|
|
2126
|
+
this.name = "SwapError";
|
|
2127
|
+
}
|
|
2128
|
+
code;
|
|
2129
|
+
};
|
|
2130
|
+
var DEFAULT_SLIPPAGE_BPS = 50;
|
|
2131
|
+
var DEFAULT_SWAP_DEADLINE_SEC = 5 * 60;
|
|
2132
|
+
var SwapHandler = class {
|
|
2133
|
+
cfg;
|
|
2134
|
+
constructor(config) {
|
|
2135
|
+
this.cfg = {
|
|
2136
|
+
...config,
|
|
2137
|
+
defaultSlippageBps: config.defaultSlippageBps ?? DEFAULT_SLIPPAGE_BPS,
|
|
2138
|
+
defaultSwapDeadlineSeconds: config.defaultSwapDeadlineSeconds ?? DEFAULT_SWAP_DEADLINE_SEC,
|
|
2139
|
+
now: config.now ?? (() => Date.now())
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
async handle(request) {
|
|
2143
|
+
if (request.amountIn <= 0n) {
|
|
2144
|
+
throw new SwapError("INVALID_AMOUNT", "amountIn must be positive");
|
|
2145
|
+
}
|
|
2146
|
+
const slippageBps = request.slippageBps ?? this.cfg.defaultSlippageBps;
|
|
2147
|
+
const { usdt, pafiFeeRecipient, universalRouter } = getContractAddresses3(
|
|
2148
|
+
request.chainId
|
|
2149
|
+
);
|
|
2150
|
+
const poolsResponse = await this.cfg.poolsProvider({
|
|
2151
|
+
chainId: request.chainId,
|
|
2152
|
+
pointTokenAddress: request.pointTokenAddress
|
|
2153
|
+
});
|
|
2154
|
+
if (poolsResponse.pools.length === 0) {
|
|
2155
|
+
throw new SwapError(
|
|
2156
|
+
"QUOTE_UNAVAILABLE",
|
|
2157
|
+
"no liquidity pool found for this point token"
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
let fallbackQuote;
|
|
2161
|
+
try {
|
|
2162
|
+
fallbackQuote = await findBestQuote(
|
|
2163
|
+
this.cfg.provider,
|
|
2164
|
+
request.chainId,
|
|
2165
|
+
request.pointTokenAddress,
|
|
2166
|
+
usdt,
|
|
2167
|
+
request.amountIn,
|
|
2168
|
+
poolsResponse.pools
|
|
2169
|
+
);
|
|
2170
|
+
} catch {
|
|
2171
|
+
throw new SwapError(
|
|
2172
|
+
"QUOTE_UNAVAILABLE",
|
|
2173
|
+
"no swap path found for this point token"
|
|
2174
|
+
);
|
|
2175
|
+
}
|
|
2176
|
+
const estimatedUsdtOutFallback = fallbackQuote.bestRoute.amountOut;
|
|
2177
|
+
const minAmountOutFallback = estimatedUsdtOutFallback * BigInt(1e4 - slippageBps) / 10000n;
|
|
2178
|
+
const deadline = request.deadline ?? BigInt(
|
|
2179
|
+
Math.floor(this.cfg.now() / 1e3) + this.cfg.defaultSwapDeadlineSeconds
|
|
2180
|
+
);
|
|
2181
|
+
const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
|
|
2182
|
+
if (feeAmount > 0n && feeAmount >= request.amountIn) {
|
|
2183
|
+
throw new SwapError(
|
|
2184
|
+
"FEE_EXCEEDS_AMOUNT",
|
|
2185
|
+
`gas fee (${feeAmount}) must be strictly less than swap amount (${request.amountIn})`
|
|
2186
|
+
);
|
|
2187
|
+
}
|
|
2188
|
+
const sponsoredAmountIn = request.amountIn - feeAmount;
|
|
2189
|
+
let estimatedUsdtOutSponsored = estimatedUsdtOutFallback;
|
|
2190
|
+
let sponsoredPath = fallbackQuote.bestRoute.path;
|
|
2191
|
+
if (feeAmount > 0n) {
|
|
2192
|
+
try {
|
|
2193
|
+
const sponsoredQuote = await findBestQuote(
|
|
2194
|
+
this.cfg.provider,
|
|
2195
|
+
request.chainId,
|
|
2196
|
+
request.pointTokenAddress,
|
|
2197
|
+
usdt,
|
|
2198
|
+
sponsoredAmountIn,
|
|
2199
|
+
poolsResponse.pools
|
|
2200
|
+
);
|
|
2201
|
+
estimatedUsdtOutSponsored = sponsoredQuote.bestRoute.amountOut;
|
|
2202
|
+
sponsoredPath = sponsoredQuote.bestRoute.path;
|
|
2203
|
+
} catch {
|
|
2204
|
+
throw new SwapError(
|
|
2205
|
+
"QUOTE_UNAVAILABLE",
|
|
2206
|
+
"no swap path found for sponsored amount (after fee deduction)"
|
|
2207
|
+
);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
const minAmountOutSponsored = estimatedUsdtOutSponsored * BigInt(1e4 - slippageBps) / 10000n;
|
|
2211
|
+
const sponsoredOp = buildSwapWithGasDeduction({
|
|
2212
|
+
userAddress: request.userAddress,
|
|
2213
|
+
aaNonce: request.aaNonce,
|
|
2214
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2215
|
+
outputTokenAddress: usdt,
|
|
2216
|
+
universalRouterAddress: universalRouter,
|
|
2217
|
+
amountIn: sponsoredAmountIn,
|
|
2218
|
+
minAmountOut: minAmountOutSponsored,
|
|
2219
|
+
swapPath: sponsoredPath,
|
|
2220
|
+
deadline,
|
|
2221
|
+
gasFeePt: feeAmount,
|
|
2222
|
+
feeRecipient: pafiFeeRecipient
|
|
2223
|
+
});
|
|
2224
|
+
const fallbackOp = feeAmount > 0n ? buildSwapWithGasDeduction({
|
|
2225
|
+
userAddress: request.userAddress,
|
|
2226
|
+
aaNonce: request.aaNonce,
|
|
2227
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2228
|
+
outputTokenAddress: usdt,
|
|
2229
|
+
universalRouterAddress: universalRouter,
|
|
2230
|
+
amountIn: request.amountIn,
|
|
2231
|
+
minAmountOut: minAmountOutFallback,
|
|
2232
|
+
swapPath: fallbackQuote.bestRoute.path,
|
|
2233
|
+
deadline,
|
|
2234
|
+
gasFeePt: 0n,
|
|
2235
|
+
feeRecipient: pafiFeeRecipient
|
|
2236
|
+
}) : void 0;
|
|
2237
|
+
return {
|
|
2238
|
+
userOp: sponsoredOp,
|
|
2239
|
+
fallback: fallbackOp,
|
|
2240
|
+
feeAmount,
|
|
2241
|
+
estimatedUsdtOut: estimatedUsdtOutSponsored,
|
|
2242
|
+
minAmountOut: minAmountOutSponsored,
|
|
2243
|
+
estimatedUsdtOutFallback: fallbackOp ? estimatedUsdtOutFallback : void 0,
|
|
2244
|
+
minAmountOutFallback: fallbackOp ? minAmountOutFallback : void 0,
|
|
2245
|
+
deadline,
|
|
2246
|
+
calls: decodeBatchExecuteCalls2(sponsoredOp.callData),
|
|
2247
|
+
callsFallback: fallbackOp ? decodeBatchExecuteCalls2(fallbackOp.callData) : void 0
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
};
|
|
2251
|
+
|
|
2252
|
+
// src/api/handlers/perpDepositHandler.ts
|
|
2253
|
+
import {
|
|
2254
|
+
BROKER_HASHES,
|
|
2255
|
+
ORDERLY_RELAY_ABI,
|
|
2256
|
+
ORDERLY_VAULT_ABI,
|
|
2257
|
+
ORDERLY_VAULT_ADDRESSES,
|
|
2258
|
+
TOKEN_HASHES,
|
|
2259
|
+
buildPerpDepositViaRelay,
|
|
2260
|
+
computeAccountId,
|
|
2261
|
+
decodeBatchExecuteCalls as decodeBatchExecuteCalls3,
|
|
2262
|
+
getContractAddresses as getContractAddresses4
|
|
2263
|
+
} from "@pafi-dev/core";
|
|
2264
|
+
var PerpDepositError = class extends Error {
|
|
2265
|
+
constructor(code, message) {
|
|
2266
|
+
super(message);
|
|
2267
|
+
this.code = code;
|
|
2268
|
+
this.name = "PerpDepositError";
|
|
2269
|
+
}
|
|
2270
|
+
code;
|
|
2271
|
+
};
|
|
2272
|
+
var DEFAULT_MAX_FEE_PREMIUM_BPS = 5e3;
|
|
2273
|
+
var PerpDepositHandler = class {
|
|
2274
|
+
cfg;
|
|
2275
|
+
constructor(config) {
|
|
2276
|
+
this.cfg = {
|
|
2277
|
+
...config,
|
|
2278
|
+
maxFeePremiumBps: config.maxFeePremiumBps ?? DEFAULT_MAX_FEE_PREMIUM_BPS
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
async handle(request) {
|
|
2282
|
+
if (request.amount <= 0n) {
|
|
2283
|
+
throw new PerpDepositError("INVALID_AMOUNT", "amount must be positive");
|
|
2284
|
+
}
|
|
2285
|
+
const brokerHash = BROKER_HASHES[request.brokerId];
|
|
2286
|
+
const tokenHash = TOKEN_HASHES.USDC;
|
|
2287
|
+
const vault = ORDERLY_VAULT_ADDRESSES[request.chainId];
|
|
2288
|
+
if (!vault) {
|
|
2289
|
+
throw new PerpDepositError(
|
|
2290
|
+
"PERP_DEPOSIT_UNAVAILABLE",
|
|
2291
|
+
`no Orderly Vault for chainId ${request.chainId}`
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
const { orderlyRelay: relayAddress, pafiFeeRecipient } = getContractAddresses4(request.chainId);
|
|
2295
|
+
const [usdcAddress, brokerAllowed] = await Promise.all([
|
|
2296
|
+
this.cfg.provider.readContract({
|
|
2297
|
+
address: vault,
|
|
2298
|
+
abi: ORDERLY_VAULT_ABI,
|
|
2299
|
+
functionName: "getAllowedToken",
|
|
2300
|
+
args: [tokenHash]
|
|
2301
|
+
}),
|
|
2302
|
+
this.cfg.provider.readContract({
|
|
2303
|
+
address: vault,
|
|
2304
|
+
abi: ORDERLY_VAULT_ABI,
|
|
2305
|
+
functionName: "getAllowedBroker",
|
|
2306
|
+
args: [brokerHash]
|
|
2307
|
+
})
|
|
2308
|
+
]);
|
|
2309
|
+
if (!brokerAllowed) {
|
|
2310
|
+
throw new PerpDepositError(
|
|
2311
|
+
"BROKER_NOT_WHITELISTED",
|
|
2312
|
+
`broker "${request.brokerId}" is not whitelisted on Orderly Vault`
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
const accountId = computeAccountId(request.userAddress, brokerHash);
|
|
2316
|
+
const requestForQuote = {
|
|
2317
|
+
token: usdcAddress,
|
|
2318
|
+
receiver: request.userAddress,
|
|
2319
|
+
brokerHash,
|
|
2320
|
+
totalAmount: request.amount,
|
|
2321
|
+
maxFee: 0n
|
|
2322
|
+
};
|
|
2323
|
+
const [relayTokenFee, ptGasFee] = await Promise.all([
|
|
2324
|
+
this.cfg.provider.readContract({
|
|
2325
|
+
address: relayAddress,
|
|
2326
|
+
abi: ORDERLY_RELAY_ABI,
|
|
2327
|
+
functionName: "quoteTokenFee",
|
|
2328
|
+
args: [requestForQuote]
|
|
2329
|
+
}),
|
|
2330
|
+
this.cfg.feeService ? this.cfg.feeService.estimateGasFee() : Promise.resolve(0n)
|
|
2331
|
+
]);
|
|
2332
|
+
if (relayTokenFee >= request.amount) {
|
|
2333
|
+
throw new PerpDepositError(
|
|
2334
|
+
"RELAY_FEE_EXCEEDS_AMOUNT",
|
|
2335
|
+
`Relay quoted fee ${relayTokenFee} >= deposit amount ${request.amount}`
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
const maxFee = relayTokenFee * BigInt(1e4 + this.cfg.maxFeePremiumBps) / 10000n;
|
|
2339
|
+
const depositReq = {
|
|
2340
|
+
token: usdcAddress,
|
|
2341
|
+
receiver: request.userAddress,
|
|
2342
|
+
brokerHash,
|
|
2343
|
+
totalAmount: request.amount,
|
|
2344
|
+
maxFee
|
|
2345
|
+
};
|
|
2346
|
+
const sponsoredOp = buildPerpDepositViaRelay({
|
|
2347
|
+
userAddress: request.userAddress,
|
|
2348
|
+
aaNonce: request.aaNonce,
|
|
2349
|
+
relayAddress,
|
|
2350
|
+
request: depositReq,
|
|
2351
|
+
pointTokenAddress: this.cfg.pointTokenAddress,
|
|
2352
|
+
gasFeePt: ptGasFee,
|
|
2353
|
+
gasFeePtRecipient: pafiFeeRecipient
|
|
2354
|
+
});
|
|
2355
|
+
const fallbackOp = ptGasFee > 0n ? buildPerpDepositViaRelay({
|
|
2356
|
+
userAddress: request.userAddress,
|
|
2357
|
+
aaNonce: request.aaNonce,
|
|
2358
|
+
relayAddress,
|
|
2359
|
+
request: depositReq
|
|
2360
|
+
}) : void 0;
|
|
2361
|
+
return {
|
|
2362
|
+
userOp: sponsoredOp,
|
|
2363
|
+
fallback: fallbackOp,
|
|
2364
|
+
feeAmount: ptGasFee,
|
|
2365
|
+
relayTokenFee,
|
|
2366
|
+
maxFee,
|
|
2367
|
+
netDeposit: request.amount - relayTokenFee,
|
|
2368
|
+
accountId,
|
|
2369
|
+
brokerHash,
|
|
2370
|
+
usdcAddress,
|
|
2371
|
+
relayAddress,
|
|
2372
|
+
calls: decodeBatchExecuteCalls3(sponsoredOp.callData),
|
|
2373
|
+
callsFallback: fallbackOp ? decodeBatchExecuteCalls3(fallbackOp.callData) : void 0
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
|
|
1701
2378
|
// src/pools/subgraphPoolsProvider.ts
|
|
1702
2379
|
import { isAddress } from "viem";
|
|
1703
2380
|
import { PAFI_SUBGRAPH_URL } from "@pafi-dev/core";
|
|
@@ -2315,79 +2992,9 @@ var PafiBackendClient = class {
|
|
|
2315
2992
|
}
|
|
2316
2993
|
};
|
|
2317
2994
|
|
|
2318
|
-
// src/pafi-backend/helpers.ts
|
|
2319
|
-
var BundlerNotConfiguredError = class extends Error {
|
|
2320
|
-
code = "BUNDLER_NOT_CONFIGURED";
|
|
2321
|
-
constructor() {
|
|
2322
|
-
super(
|
|
2323
|
-
"PAFI backend client not configured \u2014 set PAFI_BACKEND_URL, PAFI_ISSUER_ID, PAFI_API_KEY to enable mobile submit."
|
|
2324
|
-
);
|
|
2325
|
-
this.name = "BundlerNotConfiguredError";
|
|
2326
|
-
}
|
|
2327
|
-
};
|
|
2328
|
-
var BundlerRejectedError = class extends Error {
|
|
2329
|
-
code = "BUNDLER_REJECTED";
|
|
2330
|
-
cause;
|
|
2331
|
-
constructor(message, cause) {
|
|
2332
|
-
super(message);
|
|
2333
|
-
this.name = "BundlerRejectedError";
|
|
2334
|
-
this.cause = cause;
|
|
2335
|
-
}
|
|
2336
|
-
};
|
|
2337
|
-
async function requestPaymaster(params) {
|
|
2338
|
-
if (!params.client) return void 0;
|
|
2339
|
-
const fn = params.functionName ?? defaultFunctionForScenario(params.scenario);
|
|
2340
|
-
try {
|
|
2341
|
-
return await params.client.requestSponsorship({
|
|
2342
|
-
chainId: params.chainId,
|
|
2343
|
-
scenario: params.scenario,
|
|
2344
|
-
userOp: params.userOp,
|
|
2345
|
-
target: {
|
|
2346
|
-
contract: params.pointTokenAddress,
|
|
2347
|
-
function: fn,
|
|
2348
|
-
pointToken: params.pointTokenAddress
|
|
2349
|
-
}
|
|
2350
|
-
});
|
|
2351
|
-
} catch (err) {
|
|
2352
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2353
|
-
params.onWarning?.(`Paymaster sponsorship declined: ${msg}`);
|
|
2354
|
-
return void 0;
|
|
2355
|
-
}
|
|
2356
|
-
}
|
|
2357
|
-
function defaultFunctionForScenario(scenario) {
|
|
2358
|
-
switch (scenario) {
|
|
2359
|
-
case "mint":
|
|
2360
|
-
return "mint";
|
|
2361
|
-
case "burn":
|
|
2362
|
-
return "burn";
|
|
2363
|
-
case "swap":
|
|
2364
|
-
return "swap";
|
|
2365
|
-
case "perp-deposit":
|
|
2366
|
-
return "deposit";
|
|
2367
|
-
default:
|
|
2368
|
-
return scenario;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
async function relayUserOp(params) {
|
|
2372
|
-
if (!params.client) {
|
|
2373
|
-
throw new BundlerNotConfiguredError();
|
|
2374
|
-
}
|
|
2375
|
-
try {
|
|
2376
|
-
const result = await params.client.relayUserOperation({
|
|
2377
|
-
userOp: params.userOp,
|
|
2378
|
-
entryPoint: params.entryPoint,
|
|
2379
|
-
eip7702Auth: params.eip7702Auth
|
|
2380
|
-
});
|
|
2381
|
-
return { userOpHash: result.userOpHash };
|
|
2382
|
-
} catch (err) {
|
|
2383
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2384
|
-
throw new BundlerRejectedError(msg, err);
|
|
2385
|
-
}
|
|
2386
|
-
}
|
|
2387
|
-
|
|
2388
2995
|
// src/config.ts
|
|
2389
|
-
import { getAddress as
|
|
2390
|
-
import { getContractAddresses as
|
|
2996
|
+
import { getAddress as getAddress9 } from "viem";
|
|
2997
|
+
import { getContractAddresses as getContractAddresses5 } from "@pafi-dev/core";
|
|
2391
2998
|
function createIssuerService(config) {
|
|
2392
2999
|
if (!config.provider) {
|
|
2393
3000
|
throw new Error("createIssuerService: provider is required");
|
|
@@ -2407,7 +3014,7 @@ function createIssuerService(config) {
|
|
|
2407
3014
|
"createIssuerService: at least one of pointTokenAddress / pointTokenAddresses is required"
|
|
2408
3015
|
);
|
|
2409
3016
|
}
|
|
2410
|
-
const tokenAddresses = rawAddresses.map((a) =>
|
|
3017
|
+
const tokenAddresses = rawAddresses.map((a) => getAddress9(a));
|
|
2411
3018
|
const ledger = config.ledger;
|
|
2412
3019
|
const sessionStore = config.sessionStore ?? new MemorySessionStore();
|
|
2413
3020
|
const policy = config.policy ?? new DefaultPolicyEngine({ ledger });
|
|
@@ -2457,7 +3064,7 @@ function createIssuerService(config) {
|
|
|
2457
3064
|
indexers.set(tokenAddress, new PointIndexer(indexerConfig));
|
|
2458
3065
|
}
|
|
2459
3066
|
const firstIndexer = indexers.get(tokenAddresses[0]);
|
|
2460
|
-
const chainAddresses =
|
|
3067
|
+
const chainAddresses = getContractAddresses5(config.chainId);
|
|
2461
3068
|
const resolvedContracts = {
|
|
2462
3069
|
batchExecutor: chainAddresses.batchExecutor,
|
|
2463
3070
|
usdt: chainAddresses.usdt,
|
|
@@ -2504,163 +3111,13 @@ function createIssuerService(config) {
|
|
|
2504
3111
|
};
|
|
2505
3112
|
}
|
|
2506
3113
|
|
|
2507
|
-
// src/userop-store/serialize.ts
|
|
2508
|
-
import { serializeUserOpToJsonRpc } from "@pafi-dev/core";
|
|
2509
|
-
function serializeEntryToJsonRpc(entry, signature, variant = "sponsored") {
|
|
2510
|
-
if (variant === "fallback") {
|
|
2511
|
-
if (!entry.fallback) {
|
|
2512
|
-
throw new Error(
|
|
2513
|
-
"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."
|
|
2514
|
-
);
|
|
2515
|
-
}
|
|
2516
|
-
return serializeUserOpToJsonRpc(
|
|
2517
|
-
{
|
|
2518
|
-
sender: entry.sender,
|
|
2519
|
-
nonce: BigInt(entry.nonce),
|
|
2520
|
-
callData: entry.fallback.callData,
|
|
2521
|
-
callGasLimit: BigInt(entry.fallback.callGasLimit),
|
|
2522
|
-
verificationGasLimit: BigInt(entry.fallback.verificationGasLimit),
|
|
2523
|
-
preVerificationGas: BigInt(entry.fallback.preVerificationGas),
|
|
2524
|
-
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
2525
|
-
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas)
|
|
2526
|
-
// intentionally no paymaster — user pays ETH gas
|
|
2527
|
-
},
|
|
2528
|
-
signature
|
|
2529
|
-
);
|
|
2530
|
-
}
|
|
2531
|
-
return serializeUserOpToJsonRpc(
|
|
2532
|
-
{
|
|
2533
|
-
sender: entry.sender,
|
|
2534
|
-
nonce: BigInt(entry.nonce),
|
|
2535
|
-
callData: entry.callData,
|
|
2536
|
-
callGasLimit: BigInt(entry.callGasLimit),
|
|
2537
|
-
verificationGasLimit: BigInt(entry.verificationGasLimit),
|
|
2538
|
-
preVerificationGas: BigInt(entry.preVerificationGas),
|
|
2539
|
-
maxFeePerGas: BigInt(entry.maxFeePerGas),
|
|
2540
|
-
maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas),
|
|
2541
|
-
paymaster: entry.paymaster,
|
|
2542
|
-
paymasterVerificationGasLimit: entry.paymasterVerificationGasLimit != null ? BigInt(entry.paymasterVerificationGasLimit) : void 0,
|
|
2543
|
-
paymasterPostOpGasLimit: entry.paymasterPostOpGasLimit != null ? BigInt(entry.paymasterPostOpGasLimit) : void 0,
|
|
2544
|
-
paymasterData: entry.paymasterData
|
|
2545
|
-
},
|
|
2546
|
-
signature
|
|
2547
|
-
);
|
|
2548
|
-
}
|
|
2549
|
-
|
|
2550
|
-
// src/userop-store/prepareUserOp.ts
|
|
2551
|
-
import {
|
|
2552
|
-
buildUserOpTypedData,
|
|
2553
|
-
computeUserOpHash
|
|
2554
|
-
} from "@pafi-dev/core";
|
|
2555
|
-
function serializeUserOpTypedData(td) {
|
|
2556
|
-
return {
|
|
2557
|
-
domain: td.domain,
|
|
2558
|
-
types: td.types,
|
|
2559
|
-
primaryType: td.primaryType,
|
|
2560
|
-
message: {
|
|
2561
|
-
sender: td.message.sender,
|
|
2562
|
-
nonce: `0x${td.message.nonce.toString(16)}`,
|
|
2563
|
-
initCode: td.message.initCode,
|
|
2564
|
-
callData: td.message.callData,
|
|
2565
|
-
accountGasLimits: td.message.accountGasLimits,
|
|
2566
|
-
preVerificationGas: `0x${td.message.preVerificationGas.toString(
|
|
2567
|
-
16
|
|
2568
|
-
)}`,
|
|
2569
|
-
gasFees: td.message.gasFees,
|
|
2570
|
-
paymasterAndData: td.message.paymasterAndData
|
|
2571
|
-
}
|
|
2572
|
-
};
|
|
2573
|
-
}
|
|
2574
|
-
function mergePaymasterFields(userOp, paymasterFields) {
|
|
2575
|
-
if (!paymasterFields) return userOp;
|
|
2576
|
-
const merged = {
|
|
2577
|
-
...userOp
|
|
2578
|
-
};
|
|
2579
|
-
for (const [k, v] of Object.entries(paymasterFields)) {
|
|
2580
|
-
if (v !== void 0) merged[k] = v;
|
|
2581
|
-
}
|
|
2582
|
-
return merged;
|
|
2583
|
-
}
|
|
2584
|
-
async function prepareMobileUserOp(params) {
|
|
2585
|
-
const userOp = mergePaymasterFields(
|
|
2586
|
-
params.partialUserOp,
|
|
2587
|
-
params.paymasterFields
|
|
2588
|
-
);
|
|
2589
|
-
const userOpHash = computeUserOpHash(userOp, params.chainId);
|
|
2590
|
-
const typedData = serializeUserOpTypedData(
|
|
2591
|
-
buildUserOpTypedData(userOp, params.chainId)
|
|
2592
|
-
);
|
|
2593
|
-
let fallback;
|
|
2594
|
-
let fallbackEntry;
|
|
2595
|
-
if (params.partialUserOpFallback) {
|
|
2596
|
-
const fallbackUserOp = {
|
|
2597
|
-
...params.partialUserOpFallback,
|
|
2598
|
-
maxFeePerGas: userOp.maxFeePerGas,
|
|
2599
|
-
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas
|
|
2600
|
-
};
|
|
2601
|
-
const fallbackHash = computeUserOpHash(fallbackUserOp, params.chainId);
|
|
2602
|
-
const fallbackTypedData = serializeUserOpTypedData(
|
|
2603
|
-
buildUserOpTypedData(fallbackUserOp, params.chainId)
|
|
2604
|
-
);
|
|
2605
|
-
fallback = {
|
|
2606
|
-
userOp: fallbackUserOp,
|
|
2607
|
-
userOpHash: fallbackHash,
|
|
2608
|
-
typedData: fallbackTypedData
|
|
2609
|
-
};
|
|
2610
|
-
fallbackEntry = {
|
|
2611
|
-
callData: fallbackUserOp.callData,
|
|
2612
|
-
callGasLimit: fallbackUserOp.callGasLimit.toString(),
|
|
2613
|
-
verificationGasLimit: fallbackUserOp.verificationGasLimit.toString(),
|
|
2614
|
-
preVerificationGas: fallbackUserOp.preVerificationGas.toString(),
|
|
2615
|
-
userOpHash: fallbackHash
|
|
2616
|
-
};
|
|
2617
|
-
}
|
|
2618
|
-
const entry = {
|
|
2619
|
-
sender: userOp.sender,
|
|
2620
|
-
nonce: userOp.nonce.toString(),
|
|
2621
|
-
callData: userOp.callData,
|
|
2622
|
-
callGasLimit: userOp.callGasLimit.toString(),
|
|
2623
|
-
verificationGasLimit: userOp.verificationGasLimit.toString(),
|
|
2624
|
-
preVerificationGas: userOp.preVerificationGas.toString(),
|
|
2625
|
-
maxFeePerGas: userOp.maxFeePerGas.toString(),
|
|
2626
|
-
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas.toString(),
|
|
2627
|
-
paymaster: userOp.paymaster,
|
|
2628
|
-
paymasterVerificationGasLimit: userOp.paymasterVerificationGasLimit?.toString(),
|
|
2629
|
-
paymasterPostOpGasLimit: userOp.paymasterPostOpGasLimit?.toString(),
|
|
2630
|
-
paymasterData: userOp.paymasterData,
|
|
2631
|
-
chainId: params.chainId,
|
|
2632
|
-
userOpHash,
|
|
2633
|
-
fallback: fallbackEntry
|
|
2634
|
-
};
|
|
2635
|
-
await params.store.save(params.lockId, entry, params.ttlSeconds);
|
|
2636
|
-
return {
|
|
2637
|
-
sponsored: { userOp, userOpHash, typedData },
|
|
2638
|
-
fallback,
|
|
2639
|
-
entry
|
|
2640
|
-
};
|
|
2641
|
-
}
|
|
2642
|
-
|
|
2643
3114
|
// src/issuer-state/validator.ts
|
|
2644
|
-
import { getAddress as
|
|
3115
|
+
import { getAddress as getAddress10 } from "viem";
|
|
2645
3116
|
import {
|
|
2646
3117
|
POINT_TOKEN_V2_ABI as POINT_TOKEN_V2_ABI3,
|
|
2647
3118
|
issuerRegistryGetIssuerFlatAbi,
|
|
2648
|
-
getContractAddresses as
|
|
3119
|
+
getContractAddresses as getContractAddresses6
|
|
2649
3120
|
} from "@pafi-dev/core";
|
|
2650
|
-
|
|
2651
|
-
// src/issuer-state/types.ts
|
|
2652
|
-
var IssuerStateError = class extends Error {
|
|
2653
|
-
constructor(code, message, details) {
|
|
2654
|
-
super(message);
|
|
2655
|
-
this.code = code;
|
|
2656
|
-
this.details = details;
|
|
2657
|
-
this.name = "IssuerStateError";
|
|
2658
|
-
}
|
|
2659
|
-
code;
|
|
2660
|
-
details;
|
|
2661
|
-
};
|
|
2662
|
-
|
|
2663
|
-
// src/issuer-state/validator.ts
|
|
2664
3121
|
var ISSUER_RECORD_TTL_MS = 3e4;
|
|
2665
3122
|
var IssuerStateValidator = class _IssuerStateValidator {
|
|
2666
3123
|
constructor(provider, registryAddress) {
|
|
@@ -2677,7 +3134,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2677
3134
|
* `CONTRACT_ADDRESSES` map for the given chain.
|
|
2678
3135
|
*/
|
|
2679
3136
|
static forChain(provider, chainId) {
|
|
2680
|
-
const { issuerRegistry } =
|
|
3137
|
+
const { issuerRegistry } = getContractAddresses6(chainId);
|
|
2681
3138
|
return new _IssuerStateValidator(provider, issuerRegistry);
|
|
2682
3139
|
}
|
|
2683
3140
|
/**
|
|
@@ -2686,7 +3143,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2686
3143
|
*/
|
|
2687
3144
|
invalidate(pointToken) {
|
|
2688
3145
|
if (pointToken) {
|
|
2689
|
-
const key =
|
|
3146
|
+
const key = getAddress10(pointToken);
|
|
2690
3147
|
this.pointTokenIssuerCache.delete(key);
|
|
2691
3148
|
this.stateCache.delete(key);
|
|
2692
3149
|
this.inflight.delete(key);
|
|
@@ -2701,7 +3158,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2701
3158
|
* The issuer field is set at `initialize()` and never changes.
|
|
2702
3159
|
*/
|
|
2703
3160
|
async getIssuerAddressForPointToken(pointToken) {
|
|
2704
|
-
const key =
|
|
3161
|
+
const key = getAddress10(pointToken);
|
|
2705
3162
|
const cached = this.pointTokenIssuerCache.get(key);
|
|
2706
3163
|
if (cached) return cached;
|
|
2707
3164
|
const issuer = await this.provider.readContract({
|
|
@@ -2709,15 +3166,15 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2709
3166
|
abi: POINT_TOKEN_V2_ABI3,
|
|
2710
3167
|
functionName: "issuer"
|
|
2711
3168
|
});
|
|
2712
|
-
this.pointTokenIssuerCache.set(key,
|
|
2713
|
-
return
|
|
3169
|
+
this.pointTokenIssuerCache.set(key, getAddress10(issuer));
|
|
3170
|
+
return getAddress10(issuer);
|
|
2714
3171
|
}
|
|
2715
3172
|
/**
|
|
2716
3173
|
* Read registry record + totalSupply, with 30s cache and in-flight
|
|
2717
3174
|
* deduplication. Does NOT throw on inactive/missing — returns raw state.
|
|
2718
3175
|
*/
|
|
2719
3176
|
async getIssuerState(pointToken) {
|
|
2720
|
-
const tokenAddr =
|
|
3177
|
+
const tokenAddr = getAddress10(pointToken);
|
|
2721
3178
|
const now = Date.now();
|
|
2722
3179
|
const cached = this.stateCache.get(tokenAddr);
|
|
2723
3180
|
if (cached && cached.expiresAt > now) return cached.value;
|
|
@@ -2834,13 +3291,20 @@ export {
|
|
|
2834
3291
|
NonceManager,
|
|
2835
3292
|
PAFI_ISSUER_SDK_VERSION,
|
|
2836
3293
|
PAFI_SUBGRAPH_URL,
|
|
3294
|
+
PTClaimError,
|
|
3295
|
+
PTClaimHandler,
|
|
2837
3296
|
PTRedeemError,
|
|
2838
3297
|
PTRedeemHandler,
|
|
2839
3298
|
PafiBackendClient,
|
|
2840
3299
|
PafiBackendError,
|
|
3300
|
+
PendingUserOpNotFoundError,
|
|
3301
|
+
PerpDepositError,
|
|
3302
|
+
PerpDepositHandler,
|
|
2841
3303
|
PointIndexer,
|
|
2842
3304
|
RelayError,
|
|
2843
3305
|
RelayService,
|
|
3306
|
+
SwapError,
|
|
3307
|
+
SwapHandler,
|
|
2844
3308
|
TopUpRedemptionError,
|
|
2845
3309
|
TopUpRedemptionHandler,
|
|
2846
3310
|
authenticateRequest,
|
|
@@ -2849,6 +3313,8 @@ export {
|
|
|
2849
3313
|
createSubgraphNativeUsdtQuoter,
|
|
2850
3314
|
createSubgraphPoolsProvider,
|
|
2851
3315
|
handleClaimStatus,
|
|
3316
|
+
handleMobilePrepare,
|
|
3317
|
+
handleMobileSubmit,
|
|
2852
3318
|
handleRedeemStatus,
|
|
2853
3319
|
mergePaymasterFields,
|
|
2854
3320
|
prepareMobileUserOp,
|