@pafi-dev/issuer 0.5.11 → 0.5.12

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 CHANGED
@@ -45,6 +45,7 @@ __export(index_exports, {
45
45
  TopUpRedemptionHandler: () => TopUpRedemptionHandler,
46
46
  authenticateRequest: () => authenticateRequest,
47
47
  createIssuerService: () => createIssuerService,
48
+ createNativePtQuoter: () => createNativePtQuoter,
48
49
  createSubgraphNativeUsdtQuoter: () => createSubgraphNativeUsdtQuoter,
49
50
  createSubgraphPoolsProvider: () => createSubgraphPoolsProvider,
50
51
  serializeEntryToJsonRpc: () => serializeEntryToJsonRpc
@@ -1776,6 +1777,107 @@ function toUsdtPerNative(priceFloat, usdtDecimals) {
1776
1777
  return BigInt(whole + padded);
1777
1778
  }
1778
1779
 
1780
+ // src/pools/nativePtQuoter.ts
1781
+ var import_viem10 = require("viem");
1782
+ var CHAINLINK_ABI = (0, import_viem10.parseAbi)([
1783
+ "function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)"
1784
+ ]);
1785
+ var CHAINLINK_MAX_AGE_S = 3600n;
1786
+ var POOL_PRICE_QUERY = `
1787
+ query GetPoolPrice($id: ID!) {
1788
+ pafiToken(id: $id) {
1789
+ pool {
1790
+ token0 { id }
1791
+ token1 { id }
1792
+ token0Price
1793
+ token1Price
1794
+ }
1795
+ }
1796
+ }
1797
+ `;
1798
+ function createNativePtQuoter(config) {
1799
+ const {
1800
+ provider,
1801
+ pointTokenAddress,
1802
+ chainlinkFeedAddress = "0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70",
1803
+ subgraphUrl = import_core6.PAFI_SUBGRAPH_URL,
1804
+ cacheTtlMs = 3e4,
1805
+ fallbackEthPriceUsd = 3e3,
1806
+ fallbackPtPriceUsdt = 0.1,
1807
+ fetchImpl = globalThis.fetch,
1808
+ now = () => Date.now()
1809
+ } = config;
1810
+ let ethPriceCache;
1811
+ let ptPriceCache;
1812
+ async function getEthPrice8dec() {
1813
+ const ts = now();
1814
+ if (ethPriceCache && ethPriceCache.expiresAt > ts) return ethPriceCache.value;
1815
+ try {
1816
+ const result = await provider.readContract({
1817
+ address: chainlinkFeedAddress,
1818
+ abi: CHAINLINK_ABI,
1819
+ functionName: "latestRoundData"
1820
+ });
1821
+ const answer = result[1];
1822
+ const updatedAt = result[3];
1823
+ if (answer <= 0n) throw new Error("Chainlink: non-positive price");
1824
+ const ageS = BigInt(Math.floor(ts / 1e3)) - updatedAt;
1825
+ if (ageS > CHAINLINK_MAX_AGE_S) {
1826
+ throw new Error(`Chainlink: price stale by ${ageS}s`);
1827
+ }
1828
+ ethPriceCache = { value: answer, expiresAt: ts + cacheTtlMs };
1829
+ return answer;
1830
+ } catch (err) {
1831
+ console.warn("[nativePtQuoter] Chainlink unavailable, using fallback:", err.message);
1832
+ return BigInt(Math.round(fallbackEthPriceUsd * 1e8));
1833
+ }
1834
+ }
1835
+ async function getPtPerUsdt18dec() {
1836
+ const ts = now();
1837
+ if (ptPriceCache && ptPriceCache.expiresAt > ts) return ptPriceCache.value;
1838
+ try {
1839
+ const response = await fetchImpl(subgraphUrl, {
1840
+ method: "POST",
1841
+ headers: { "Content-Type": "application/json" },
1842
+ body: JSON.stringify({
1843
+ query: POOL_PRICE_QUERY,
1844
+ variables: { id: pointTokenAddress.toLowerCase() }
1845
+ })
1846
+ });
1847
+ if (!response.ok) throw new Error(`subgraph HTTP ${response.status}`);
1848
+ const json = await response.json();
1849
+ if (json.errors?.length) throw new Error(json.errors.map((e) => e.message).join("; "));
1850
+ const pool = json.data?.pafiToken?.pool;
1851
+ if (!pool) throw new Error("pafiToken or pool not found in subgraph");
1852
+ const isPtToken0 = pool.token0.id.toLowerCase() === pointTokenAddress.toLowerCase();
1853
+ const ptPerUsdtStr = isPtToken0 ? pool.token0Price : pool.token1Price;
1854
+ if (!ptPerUsdtStr || Number(ptPerUsdtStr) <= 0) {
1855
+ throw new Error(`invalid PT/USDT price from subgraph: ${ptPerUsdtStr}`);
1856
+ }
1857
+ const value = parseBigDecimalTo18(ptPerUsdtStr);
1858
+ ptPriceCache = { value, expiresAt: ts + cacheTtlMs };
1859
+ return value;
1860
+ } catch (err) {
1861
+ console.warn("[nativePtQuoter] subgraph unavailable, using fallback:", err.message);
1862
+ return parseBigDecimalTo18(fallbackPtPriceUsdt.toString());
1863
+ }
1864
+ }
1865
+ return async (amountNative) => {
1866
+ if (amountNative === 0n) return 0n;
1867
+ const [ethPrice8dec, ptPerUsdt18dec] = await Promise.all([
1868
+ getEthPrice8dec(),
1869
+ getPtPerUsdt18dec()
1870
+ ]);
1871
+ return amountNative * ethPrice8dec * ptPerUsdt18dec / 10n ** 26n;
1872
+ };
1873
+ }
1874
+ function parseBigDecimalTo18(s) {
1875
+ const SCALE = 18;
1876
+ const [whole = "0", frac = ""] = s.split(".");
1877
+ const padded = (frac + "0".repeat(SCALE)).slice(0, SCALE);
1878
+ return BigInt(whole + padded);
1879
+ }
1880
+
1779
1881
  // src/balance/balanceAggregator.ts
1780
1882
  var import_core7 = require("@pafi-dev/core");
1781
1883
  var BalanceAggregator = class {
@@ -1981,7 +2083,7 @@ var PafiBackendClient = class {
1981
2083
  };
1982
2084
 
1983
2085
  // src/config.ts
1984
- var import_viem10 = require("viem");
2086
+ var import_viem11 = require("viem");
1985
2087
  var import_core8 = require("@pafi-dev/core");
1986
2088
  function createIssuerService(config) {
1987
2089
  if (!config.provider) {
@@ -2002,7 +2104,7 @@ function createIssuerService(config) {
2002
2104
  "createIssuerService: at least one of pointTokenAddress / pointTokenAddresses is required"
2003
2105
  );
2004
2106
  }
2005
- const tokenAddresses = rawAddresses.map((a) => (0, import_viem10.getAddress)(a));
2107
+ const tokenAddresses = rawAddresses.map((a) => (0, import_viem11.getAddress)(a));
2006
2108
  const ledger = config.ledger;
2007
2109
  const sessionStore = config.sessionStore ?? new MemorySessionStore();
2008
2110
  const policy = config.policy ?? new DefaultPolicyEngine({ ledger });
@@ -2119,7 +2221,7 @@ function serializeEntryToJsonRpc(entry, signature) {
2119
2221
  }
2120
2222
 
2121
2223
  // src/issuer-state/validator.ts
2122
- var import_viem11 = require("viem");
2224
+ var import_viem12 = require("viem");
2123
2225
  var import_core10 = require("@pafi-dev/core");
2124
2226
 
2125
2227
  // src/issuer-state/types.ts
@@ -2160,7 +2262,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
2160
2262
  */
2161
2263
  invalidate(pointToken) {
2162
2264
  if (pointToken) {
2163
- const key = (0, import_viem11.getAddress)(pointToken);
2265
+ const key = (0, import_viem12.getAddress)(pointToken);
2164
2266
  this.pointTokenIssuerCache.delete(key);
2165
2267
  this.stateCache.delete(key);
2166
2268
  this.inflight.delete(key);
@@ -2175,7 +2277,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
2175
2277
  * The issuer field is set at `initialize()` and never changes.
2176
2278
  */
2177
2279
  async getIssuerAddressForPointToken(pointToken) {
2178
- const key = (0, import_viem11.getAddress)(pointToken);
2280
+ const key = (0, import_viem12.getAddress)(pointToken);
2179
2281
  const cached = this.pointTokenIssuerCache.get(key);
2180
2282
  if (cached) return cached;
2181
2283
  const issuer = await this.provider.readContract({
@@ -2183,15 +2285,15 @@ var IssuerStateValidator = class _IssuerStateValidator {
2183
2285
  abi: import_core10.POINT_TOKEN_V2_ABI,
2184
2286
  functionName: "issuer"
2185
2287
  });
2186
- this.pointTokenIssuerCache.set(key, (0, import_viem11.getAddress)(issuer));
2187
- return (0, import_viem11.getAddress)(issuer);
2288
+ this.pointTokenIssuerCache.set(key, (0, import_viem12.getAddress)(issuer));
2289
+ return (0, import_viem12.getAddress)(issuer);
2188
2290
  }
2189
2291
  /**
2190
2292
  * Read registry record + totalSupply, with 30s cache and in-flight
2191
2293
  * deduplication. Does NOT throw on inactive/missing — returns raw state.
2192
2294
  */
2193
2295
  async getIssuerState(pointToken) {
2194
- const tokenAddr = (0, import_viem11.getAddress)(pointToken);
2296
+ const tokenAddr = (0, import_viem12.getAddress)(pointToken);
2195
2297
  const now = Date.now();
2196
2298
  const cached = this.stateCache.get(tokenAddr);
2197
2299
  if (cached && cached.expiresAt > now) return cached.value;
@@ -2258,7 +2360,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
2258
2360
  }
2259
2361
  async fetchIssuerState(tokenAddr) {
2260
2362
  const issuerAddr = await this.getIssuerAddressForPointToken(tokenAddr);
2261
- const [tuple, totalSupply] = await Promise.all([
2363
+ const [issuerStruct, totalSupply] = await Promise.all([
2262
2364
  this.provider.readContract({
2263
2365
  address: this.registryAddress,
2264
2366
  abi: import_core10.issuerRegistryAbi,
@@ -2271,17 +2373,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
2271
2373
  functionName: "totalSupply"
2272
2374
  })
2273
2375
  ]);
2274
- const issuer = {
2275
- issuerAddress: tuple[0],
2276
- signerAddress: tuple[1],
2277
- name: tuple[2],
2278
- symbol: tuple[3],
2279
- declaredTotalSupply: tuple[4],
2280
- capBasisPoints: tuple[5],
2281
- active: tuple[6],
2282
- pointToken: tuple[7],
2283
- mintingOracle: tuple[8]
2284
- };
2376
+ const issuer = issuerStruct;
2285
2377
  const hardCap = issuer.declaredTotalSupply * BigInt(issuer.capBasisPoints) / 10000n;
2286
2378
  const remaining = hardCap > totalSupply ? hardCap - totalSupply : 0n;
2287
2379
  return { issuer, totalSupply, hardCap, remaining };
@@ -2317,6 +2409,7 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
2317
2409
  TopUpRedemptionHandler,
2318
2410
  authenticateRequest,
2319
2411
  createIssuerService,
2412
+ createNativePtQuoter,
2320
2413
  createSubgraphNativeUsdtQuoter,
2321
2414
  createSubgraphPoolsProvider,
2322
2415
  serializeEntryToJsonRpc