@pafi-dev/issuer 0.5.11 → 0.5.13
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 +116 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +107 -12
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
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,110 @@ 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 raw = parseBigDecimalTo18(ptPerUsdtStr);
|
|
1858
|
+
if (raw === 0n) throw new Error(`pool price parsed to zero: ${ptPerUsdtStr}`);
|
|
1859
|
+
const value = 10n ** 24n / raw;
|
|
1860
|
+
ptPriceCache = { value, expiresAt: ts + cacheTtlMs };
|
|
1861
|
+
return value;
|
|
1862
|
+
} catch (err) {
|
|
1863
|
+
console.warn("[nativePtQuoter] subgraph unavailable, using fallback:", err.message);
|
|
1864
|
+
const ptPerUsdtHuman = 1 / fallbackPtPriceUsdt;
|
|
1865
|
+
return parseBigDecimalTo18(ptPerUsdtHuman.toFixed(18));
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return async (amountNative) => {
|
|
1869
|
+
if (amountNative === 0n) return 0n;
|
|
1870
|
+
const [ethPrice8dec, ptPerUsdt18dec] = await Promise.all([
|
|
1871
|
+
getEthPrice8dec(),
|
|
1872
|
+
getPtPerUsdt18dec()
|
|
1873
|
+
]);
|
|
1874
|
+
return amountNative * ethPrice8dec * ptPerUsdt18dec / 10n ** 26n;
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
function parseBigDecimalTo18(s) {
|
|
1878
|
+
const SCALE = 18;
|
|
1879
|
+
const [whole = "0", frac = ""] = s.split(".");
|
|
1880
|
+
const padded = (frac + "0".repeat(SCALE)).slice(0, SCALE);
|
|
1881
|
+
return BigInt(whole + padded);
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1779
1884
|
// src/balance/balanceAggregator.ts
|
|
1780
1885
|
var import_core7 = require("@pafi-dev/core");
|
|
1781
1886
|
var BalanceAggregator = class {
|
|
@@ -1981,7 +2086,7 @@ var PafiBackendClient = class {
|
|
|
1981
2086
|
};
|
|
1982
2087
|
|
|
1983
2088
|
// src/config.ts
|
|
1984
|
-
var
|
|
2089
|
+
var import_viem11 = require("viem");
|
|
1985
2090
|
var import_core8 = require("@pafi-dev/core");
|
|
1986
2091
|
function createIssuerService(config) {
|
|
1987
2092
|
if (!config.provider) {
|
|
@@ -2002,7 +2107,7 @@ function createIssuerService(config) {
|
|
|
2002
2107
|
"createIssuerService: at least one of pointTokenAddress / pointTokenAddresses is required"
|
|
2003
2108
|
);
|
|
2004
2109
|
}
|
|
2005
|
-
const tokenAddresses = rawAddresses.map((a) => (0,
|
|
2110
|
+
const tokenAddresses = rawAddresses.map((a) => (0, import_viem11.getAddress)(a));
|
|
2006
2111
|
const ledger = config.ledger;
|
|
2007
2112
|
const sessionStore = config.sessionStore ?? new MemorySessionStore();
|
|
2008
2113
|
const policy = config.policy ?? new DefaultPolicyEngine({ ledger });
|
|
@@ -2119,7 +2224,7 @@ function serializeEntryToJsonRpc(entry, signature) {
|
|
|
2119
2224
|
}
|
|
2120
2225
|
|
|
2121
2226
|
// src/issuer-state/validator.ts
|
|
2122
|
-
var
|
|
2227
|
+
var import_viem12 = require("viem");
|
|
2123
2228
|
var import_core10 = require("@pafi-dev/core");
|
|
2124
2229
|
|
|
2125
2230
|
// src/issuer-state/types.ts
|
|
@@ -2160,7 +2265,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2160
2265
|
*/
|
|
2161
2266
|
invalidate(pointToken) {
|
|
2162
2267
|
if (pointToken) {
|
|
2163
|
-
const key = (0,
|
|
2268
|
+
const key = (0, import_viem12.getAddress)(pointToken);
|
|
2164
2269
|
this.pointTokenIssuerCache.delete(key);
|
|
2165
2270
|
this.stateCache.delete(key);
|
|
2166
2271
|
this.inflight.delete(key);
|
|
@@ -2175,7 +2280,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2175
2280
|
* The issuer field is set at `initialize()` and never changes.
|
|
2176
2281
|
*/
|
|
2177
2282
|
async getIssuerAddressForPointToken(pointToken) {
|
|
2178
|
-
const key = (0,
|
|
2283
|
+
const key = (0, import_viem12.getAddress)(pointToken);
|
|
2179
2284
|
const cached = this.pointTokenIssuerCache.get(key);
|
|
2180
2285
|
if (cached) return cached;
|
|
2181
2286
|
const issuer = await this.provider.readContract({
|
|
@@ -2183,15 +2288,15 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2183
2288
|
abi: import_core10.POINT_TOKEN_V2_ABI,
|
|
2184
2289
|
functionName: "issuer"
|
|
2185
2290
|
});
|
|
2186
|
-
this.pointTokenIssuerCache.set(key, (0,
|
|
2187
|
-
return (0,
|
|
2291
|
+
this.pointTokenIssuerCache.set(key, (0, import_viem12.getAddress)(issuer));
|
|
2292
|
+
return (0, import_viem12.getAddress)(issuer);
|
|
2188
2293
|
}
|
|
2189
2294
|
/**
|
|
2190
2295
|
* Read registry record + totalSupply, with 30s cache and in-flight
|
|
2191
2296
|
* deduplication. Does NOT throw on inactive/missing — returns raw state.
|
|
2192
2297
|
*/
|
|
2193
2298
|
async getIssuerState(pointToken) {
|
|
2194
|
-
const tokenAddr = (0,
|
|
2299
|
+
const tokenAddr = (0, import_viem12.getAddress)(pointToken);
|
|
2195
2300
|
const now = Date.now();
|
|
2196
2301
|
const cached = this.stateCache.get(tokenAddr);
|
|
2197
2302
|
if (cached && cached.expiresAt > now) return cached.value;
|
|
@@ -2258,7 +2363,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2258
2363
|
}
|
|
2259
2364
|
async fetchIssuerState(tokenAddr) {
|
|
2260
2365
|
const issuerAddr = await this.getIssuerAddressForPointToken(tokenAddr);
|
|
2261
|
-
const [
|
|
2366
|
+
const [issuerStruct, totalSupply] = await Promise.all([
|
|
2262
2367
|
this.provider.readContract({
|
|
2263
2368
|
address: this.registryAddress,
|
|
2264
2369
|
abi: import_core10.issuerRegistryAbi,
|
|
@@ -2271,17 +2376,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
2271
2376
|
functionName: "totalSupply"
|
|
2272
2377
|
})
|
|
2273
2378
|
]);
|
|
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
|
-
};
|
|
2379
|
+
const issuer = issuerStruct;
|
|
2285
2380
|
const hardCap = issuer.declaredTotalSupply * BigInt(issuer.capBasisPoints) / 10000n;
|
|
2286
2381
|
const remaining = hardCap > totalSupply ? hardCap - totalSupply : 0n;
|
|
2287
2382
|
return { issuer, totalSupply, hardCap, remaining };
|
|
@@ -2317,6 +2412,7 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
|
|
|
2317
2412
|
TopUpRedemptionHandler,
|
|
2318
2413
|
authenticateRequest,
|
|
2319
2414
|
createIssuerService,
|
|
2415
|
+
createNativePtQuoter,
|
|
2320
2416
|
createSubgraphNativeUsdtQuoter,
|
|
2321
2417
|
createSubgraphPoolsProvider,
|
|
2322
2418
|
serializeEntryToJsonRpc
|