@permissionless-technologies/upd-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -0
- package/dist/chunk-4RBWWS2X.js +6616 -0
- package/dist/chunk-4RBWWS2X.js.map +1 -0
- package/dist/chunk-4VXNJTNQ.cjs +58 -0
- package/dist/chunk-4VXNJTNQ.cjs.map +1 -0
- package/dist/chunk-5NNXIJE4.js +16 -0
- package/dist/chunk-5NNXIJE4.js.map +1 -0
- package/dist/chunk-63FIKV36.js +49 -0
- package/dist/chunk-63FIKV36.js.map +1 -0
- package/dist/chunk-CZEDT3MS.cjs +62 -0
- package/dist/chunk-CZEDT3MS.cjs.map +1 -0
- package/dist/chunk-DF34ON56.cjs +18 -0
- package/dist/chunk-DF34ON56.cjs.map +1 -0
- package/dist/chunk-DJBU2OEB.js +57 -0
- package/dist/chunk-DJBU2OEB.js.map +1 -0
- package/dist/chunk-LNGWRYGY.js +3 -0
- package/dist/chunk-LNGWRYGY.js.map +1 -0
- package/dist/chunk-POBNO37G.cjs +4 -0
- package/dist/chunk-POBNO37G.cjs.map +1 -0
- package/dist/chunk-R64I3LAO.js +701 -0
- package/dist/chunk-R64I3LAO.js.map +1 -0
- package/dist/chunk-RIRT4JX6.js +1808 -0
- package/dist/chunk-RIRT4JX6.js.map +1 -0
- package/dist/chunk-WRPVPA7E.cjs +713 -0
- package/dist/chunk-WRPVPA7E.cjs.map +1 -0
- package/dist/chunk-ZDAHLZWC.cjs +1812 -0
- package/dist/chunk-ZDAHLZWC.cjs.map +1 -0
- package/dist/chunk-ZSWETUGH.cjs +6623 -0
- package/dist/chunk-ZSWETUGH.cjs.map +1 -0
- package/dist/constants-Bk2bGYfX.d.ts +64 -0
- package/dist/constants-BlOP_9dy.d.cts +64 -0
- package/dist/contracts/index.cjs +45 -0
- package/dist/contracts/index.cjs.map +1 -0
- package/dist/contracts/index.d.cts +6559 -0
- package/dist/contracts/index.d.ts +6559 -0
- package/dist/contracts/index.js +4 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/core/index.cjs +76 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +5 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/health-BUb4ItNt.d.ts +46 -0
- package/dist/health-DPxBqH7b.d.cts +46 -0
- package/dist/index-XNClksom.d.ts +415 -0
- package/dist/index-yRBqVOHV.d.cts +415 -0
- package/dist/index.cjs +138 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/oracle/index.cjs +30 -0
- package/dist/oracle/index.cjs.map +1 -0
- package/dist/oracle/index.d.cts +41 -0
- package/dist/oracle/index.d.ts +41 -0
- package/dist/oracle/index.js +5 -0
- package/dist/oracle/index.js.map +1 -0
- package/dist/react/index.cjs +383 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +339 -0
- package/dist/react/index.d.ts +339 -0
- package/dist/react/index.js +370 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types-DySv82My.d.cts +70 -0
- package/dist/types-DySv82My.d.ts +70 -0
- package/package.json +93 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/quote.ts
|
|
4
|
+
var PRICE_PRECISION = 10n ** 18n;
|
|
5
|
+
var SHARE_PRECISION = 10n ** 18n;
|
|
6
|
+
function quoteMintUPD(ethAmount, ethUsdPrice) {
|
|
7
|
+
return ethAmount * ethUsdPrice / PRICE_PRECISION;
|
|
8
|
+
}
|
|
9
|
+
function quoteBurnUPD(updAmount, ethUsdPrice) {
|
|
10
|
+
if (ethUsdPrice === 0n) throw new Error("Price cannot be zero");
|
|
11
|
+
return updAmount * PRICE_PRECISION / ethUsdPrice;
|
|
12
|
+
}
|
|
13
|
+
function stabilizerStEthNeeded(userEth, minCollateralRatioBps) {
|
|
14
|
+
return userEth * (minCollateralRatioBps - 10000n) / 10000n;
|
|
15
|
+
}
|
|
16
|
+
function quoteStakeUPD(updAmount, shareValue) {
|
|
17
|
+
if (shareValue === 0n) throw new Error("Share value cannot be zero");
|
|
18
|
+
return updAmount * SHARE_PRECISION / shareValue;
|
|
19
|
+
}
|
|
20
|
+
function quoteUnstakeUPD(shares, shareValue) {
|
|
21
|
+
return shares * shareValue / SHARE_PRECISION;
|
|
22
|
+
}
|
|
23
|
+
function collateralizationRatio(stEthBalance, ethUsdPrice, backedUPDAmount) {
|
|
24
|
+
if (backedUPDAmount === 0n) return BigInt(2) ** BigInt(256) - 1n;
|
|
25
|
+
const collateralValueUSD = stEthBalance * ethUsdPrice / PRICE_PRECISION;
|
|
26
|
+
return collateralValueUSD * 10000n / backedUPDAmount;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/core/health.ts
|
|
30
|
+
var DEFAULT_MIN_RATIO_BPS = 12500n;
|
|
31
|
+
function computeSystemHealth(collateral, ethUsdPrice, minRatioBps = DEFAULT_MIN_RATIO_BPS) {
|
|
32
|
+
const PRICE_PRECISION2 = 10n ** 18n;
|
|
33
|
+
const collateralValueUsd = collateral.totalStEthCollateral * ethUsdPrice / PRICE_PRECISION2;
|
|
34
|
+
const systemCollateralRatioBps = collateralizationRatio(
|
|
35
|
+
collateral.totalStEthCollateral,
|
|
36
|
+
ethUsdPrice,
|
|
37
|
+
collateral.totalUPDSupply
|
|
38
|
+
);
|
|
39
|
+
const bufferUsd = collateralValueUsd - collateral.totalUPDSupply;
|
|
40
|
+
return {
|
|
41
|
+
systemCollateralRatioBps,
|
|
42
|
+
isHealthy: systemCollateralRatioBps >= minRatioBps,
|
|
43
|
+
collateralValueUsd,
|
|
44
|
+
totalUPDSupply: collateral.totalUPDSupply,
|
|
45
|
+
bufferUsd
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
exports.DEFAULT_MIN_RATIO_BPS = DEFAULT_MIN_RATIO_BPS;
|
|
50
|
+
exports.collateralizationRatio = collateralizationRatio;
|
|
51
|
+
exports.computeSystemHealth = computeSystemHealth;
|
|
52
|
+
exports.quoteBurnUPD = quoteBurnUPD;
|
|
53
|
+
exports.quoteMintUPD = quoteMintUPD;
|
|
54
|
+
exports.quoteStakeUPD = quoteStakeUPD;
|
|
55
|
+
exports.quoteUnstakeUPD = quoteUnstakeUPD;
|
|
56
|
+
exports.stabilizerStEthNeeded = stabilizerStEthNeeded;
|
|
57
|
+
//# sourceMappingURL=chunk-4VXNJTNQ.cjs.map
|
|
58
|
+
//# sourceMappingURL=chunk-4VXNJTNQ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/quote.ts","../src/core/health.ts"],"names":["PRICE_PRECISION"],"mappings":";;;AAQA,IAAM,kBAAkB,GAAA,IAAO,GAAA;AAC/B,IAAM,kBAAkB,GAAA,IAAO,GAAA;AAexB,SAAS,YAAA,CAAa,WAAmB,WAAA,EAA6B;AAC3E,EAAA,OAAQ,YAAY,WAAA,GAAe,eAAA;AACrC;AAeO,SAAS,YAAA,CAAa,WAAmB,WAAA,EAA6B;AAC3E,EAAA,IAAI,WAAA,KAAgB,EAAA,EAAI,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAC9D,EAAA,OAAQ,YAAY,eAAA,GAAmB,WAAA;AACzC;AAeO,SAAS,qBAAA,CACd,SACA,qBAAA,EACQ;AACR,EAAA,OAAQ,OAAA,IAAW,wBAAwB,MAAA,CAAA,GAAW,MAAA;AACxD;AA+BO,SAAS,aAAA,CAAc,WAAmB,UAAA,EAA4B;AAC3E,EAAA,IAAI,UAAA,KAAe,EAAA,EAAI,MAAM,IAAI,MAAM,4BAA4B,CAAA;AACnE,EAAA,OAAQ,YAAY,eAAA,GAAmB,UAAA;AACzC;AAiBO,SAAS,eAAA,CAAgB,QAAgB,UAAA,EAA4B;AAC1E,EAAA,OAAQ,SAAS,UAAA,GAAc,eAAA;AACjC;AAEO,SAAS,sBAAA,CACd,YAAA,EACA,WAAA,EACA,eAAA,EACQ;AACR,EAAA,IAAI,eAAA,KAAoB,IAAI,OAAO,MAAA,CAAO,CAAC,CAAA,IAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAA;AAC9D,EAAA,MAAM,kBAAA,GAAsB,eAAe,WAAA,GAAe,eAAA;AAC1D,EAAA,OAAQ,qBAAqB,MAAA,GAAU,eAAA;AACzC;;;ACnHO,IAAM,qBAAA,GAAwB;AAkC9B,SAAS,mBAAA,CACd,UAAA,EACA,WAAA,EACA,WAAA,GAAsB,qBAAA,EACR;AACd,EAAA,MAAMA,mBAAkB,GAAA,IAAO,GAAA;AAE/B,EAAA,MAAM,kBAAA,GACH,UAAA,CAAW,oBAAA,GAAuB,WAAA,GAAeA,gBAAAA;AAEpD,EAAA,MAAM,wBAAA,GAA2B,sBAAA;AAAA,IAC/B,UAAA,CAAW,oBAAA;AAAA,IACX,WAAA;AAAA,IACA,UAAA,CAAW;AAAA,GACb;AAEA,EAAA,MAAM,SAAA,GAAY,qBAAqB,UAAA,CAAW,cAAA;AAElD,EAAA,OAAO;AAAA,IACL,wBAAA;AAAA,IACA,WAAW,wBAAA,IAA4B,WAAA;AAAA,IACvC,kBAAA;AAAA,IACA,gBAAgB,UAAA,CAAW,cAAA;AAAA,IAC3B;AAAA,GACF;AACF","file":"chunk-4VXNJTNQ.cjs","sourcesContent":["/**\n * UPD Quote Functions — Pure math for estimating mint/burn amounts.\n *\n * These functions require no blockchain calls. They mirror the Solidity\n * CollateralMathLib logic so integrators can show users expected amounts\n * before submitting a transaction.\n */\n\nconst PRICE_PRECISION = 10n ** 18n\nconst SHARE_PRECISION = 10n ** 18n\n\n/**\n * Estimate how much UPD a user will receive for a given ETH amount.\n *\n * @param ethAmount - ETH to deposit (in wei)\n * @param ethUsdPrice - ETH/USD price (18 decimals, e.g. 2000e18 = $2000)\n * @returns Expected UPD amount (18 decimals)\n *\n * @example\n * ```ts\n * const upd = quoteMintUPD(parseEther('1'), 2000n * 10n**18n)\n * // → 2000000000000000000000n (2000 UPD)\n * ```\n */\nexport function quoteMintUPD(ethAmount: bigint, ethUsdPrice: bigint): bigint {\n return (ethAmount * ethUsdPrice) / PRICE_PRECISION\n}\n\n/**\n * Estimate how much stETH a user will receive for burning UPD.\n *\n * @param updAmount - UPD to burn (18 decimals)\n * @param ethUsdPrice - ETH/USD price (18 decimals)\n * @returns Expected stETH amount (in wei)\n *\n * @example\n * ```ts\n * const stEth = quoteBurnUPD(parseUnits('2000', 18), 2000n * 10n**18n)\n * // → 1000000000000000000n (1 stETH)\n * ```\n */\nexport function quoteBurnUPD(updAmount: bigint, ethUsdPrice: bigint): bigint {\n if (ethUsdPrice === 0n) throw new Error('Price cannot be zero')\n return (updAmount * PRICE_PRECISION) / ethUsdPrice\n}\n\n/**\n * Calculate the stabilizer stETH needed for a given user ETH deposit.\n *\n * @param userEth - User's ETH amount (in wei)\n * @param minCollateralRatioBps - Minimum collateral ratio in basis points (e.g. 12500 = 125%)\n * @returns Stabilizer stETH required (in wei)\n *\n * @example\n * ```ts\n * const needed = stabilizerStEthNeeded(parseEther('10'), 12500n)\n * // → 2500000000000000000n (2.5 ETH worth of stETH at 125% ratio)\n * ```\n */\nexport function stabilizerStEthNeeded(\n userEth: bigint,\n minCollateralRatioBps: bigint,\n): bigint {\n return (userEth * (minCollateralRatioBps - 10000n)) / 10000n\n}\n\n/**\n * Calculate the collateralization ratio from stETH balance, price, and UPD liability.\n *\n * @param stEthBalance - stETH held in escrow (in wei)\n * @param ethUsdPrice - ETH/USD price (18 decimals)\n * @param backedUPDAmount - UPD liability (18 decimals)\n * @returns Collateralization ratio in basis points (e.g. 12500 = 125%)\n *\n * @example\n * ```ts\n * const ratio = collateralizationRatio(parseEther('1.25'), 2000n * 10n**18n, parseUnits('2000', 18))\n * // → 12500n (125%)\n * ```\n */\n/**\n * Estimate sUPD shares received for staking UPD.\n *\n * Mirrors sUPD.sol line 136: shares = updAmount * SHARE_PRECISION / shareValue\n *\n * @param updAmount - UPD to stake (18 decimals)\n * @param shareValue - Current sUPD share value (18 decimals, e.g. 1.05e18 = $1.05/share)\n * @returns Expected sUPD shares (18 decimals)\n *\n * @example\n * ```ts\n * const shares = quoteStakeUPD(parseUnits('1000', 18), 1050000000000000000n)\n * // → ~952.38e18 shares (1000 UPD at $1.05/share)\n * ```\n */\nexport function quoteStakeUPD(updAmount: bigint, shareValue: bigint): bigint {\n if (shareValue === 0n) throw new Error('Share value cannot be zero')\n return (updAmount * SHARE_PRECISION) / shareValue\n}\n\n/**\n * Estimate UPD received for unstaking sUPD shares.\n *\n * Mirrors sUPD.sol line 173: updOwed = shares * shareValue / SHARE_PRECISION\n *\n * @param shares - sUPD shares to unstake (18 decimals)\n * @param shareValue - Current sUPD share value (18 decimals)\n * @returns Expected UPD amount (18 decimals)\n *\n * @example\n * ```ts\n * const upd = quoteUnstakeUPD(parseUnits('952.38', 18), 1050000000000000000n)\n * // → ~1000e18 UPD\n * ```\n */\nexport function quoteUnstakeUPD(shares: bigint, shareValue: bigint): bigint {\n return (shares * shareValue) / SHARE_PRECISION\n}\n\nexport function collateralizationRatio(\n stEthBalance: bigint,\n ethUsdPrice: bigint,\n backedUPDAmount: bigint,\n): bigint {\n if (backedUPDAmount === 0n) return BigInt(2) ** BigInt(256) - 1n // type(uint256).max\n const collateralValueUSD = (stEthBalance * ethUsdPrice) / PRICE_PRECISION\n return (collateralValueUSD * 10000n) / backedUPDAmount\n}\n","/**\n * System Health — Pure functions for computing UPD system health metrics.\n *\n * These functions take pre-fetched data (from UPDClient or React hooks) and\n * compute derived health metrics. No blockchain calls — composable with\n * any data source.\n */\n\nimport type { CollateralInfo } from './types.js'\nimport { collateralizationRatio } from './quote.js'\n\n/** Default minimum system collateral ratio: 125% (12500 bps). */\nexport const DEFAULT_MIN_RATIO_BPS = 12500n\n\nexport interface SystemHealth {\n /** System-wide collateralization ratio in basis points (e.g. 12500 = 125%). */\n systemCollateralRatioBps: bigint\n /** Whether the system is at or above the minimum collateral threshold. */\n isHealthy: boolean\n /** USD value of total stETH collateral (18 decimals). */\n collateralValueUsd: bigint\n /** Total UPD supply (18 decimals). */\n totalUPDSupply: bigint\n /** Overcollateralization buffer in USD (collateral - supply). Can be negative. */\n bufferUsd: bigint\n}\n\n/**\n * Compute system health from collateral info and current ETH/USD price.\n *\n * @param collateral - Total stETH collateral and UPD supply (from getCollateralInfo)\n * @param ethUsdPrice - Current ETH/USD price in 18 decimals\n * @param minRatioBps - Minimum healthy ratio in basis points (default: 12500 = 125%)\n * @returns Computed system health metrics\n *\n * @example\n * ```ts\n * const info = await client.getCollateralInfo()\n * const { price } = await oracle.getEthUsdPrice()\n * const health = computeSystemHealth(info, price)\n *\n * if (!health.isHealthy) {\n * console.warn(`System undercollateralized: ${health.systemCollateralRatioBps} bps`)\n * }\n * ```\n */\nexport function computeSystemHealth(\n collateral: CollateralInfo,\n ethUsdPrice: bigint,\n minRatioBps: bigint = DEFAULT_MIN_RATIO_BPS,\n): SystemHealth {\n const PRICE_PRECISION = 10n ** 18n\n\n const collateralValueUsd =\n (collateral.totalStEthCollateral * ethUsdPrice) / PRICE_PRECISION\n\n const systemCollateralRatioBps = collateralizationRatio(\n collateral.totalStEthCollateral,\n ethUsdPrice,\n collateral.totalUPDSupply,\n )\n\n const bufferUsd = collateralValueUsd - collateral.totalUPDSupply\n\n return {\n systemCollateralRatioBps,\n isHealthy: systemCollateralRatioBps >= minRatioBps,\n collateralValueUsd,\n totalUPDSupply: collateral.totalUPDSupply,\n bufferUsd,\n }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ETH_USD_ASSET_PAIR } from './chunk-DJBU2OEB.js';
|
|
2
|
+
|
|
3
|
+
// src/oracle/mock.ts
|
|
4
|
+
function createMockAttestation(price) {
|
|
5
|
+
return {
|
|
6
|
+
price,
|
|
7
|
+
decimals: 18,
|
|
8
|
+
dataTimestamp: BigInt(Date.now()),
|
|
9
|
+
assetPair: ETH_USD_ASSET_PAIR,
|
|
10
|
+
signature: "0x"
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { createMockAttestation };
|
|
15
|
+
//# sourceMappingURL=chunk-5NNXIJE4.js.map
|
|
16
|
+
//# sourceMappingURL=chunk-5NNXIJE4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oracle/mock.ts"],"names":[],"mappings":";;;AA2BO,SAAS,sBAAsB,KAAA,EAAsC;AAC1E,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA,EAAU,EAAA;AAAA,IACV,aAAA,EAAe,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,IAChC,SAAA,EAAW,kBAAA;AAAA,IACX,SAAA,EAAW;AAAA,GACb;AACF","file":"chunk-5NNXIJE4.js","sourcesContent":["/**\n * Mock oracle helpers for testing and local development.\n *\n * WARNING: createMockAttestation produces attestations with empty signatures.\n * They only work with MockPriceOracle in tests, NOT with the real PriceOracle\n * on mainnet/testnet (which validates ECDSA signatures).\n */\n\nimport type { PriceAttestationQuery } from '../core/types.js'\nimport { ETH_USD_ASSET_PAIR } from './constants.js'\n\n/**\n * Create a mock price attestation for testing/local development.\n *\n * @param price - ETH/USD price in 18 decimals (e.g. 2000n * 10n**18n for $2000)\n * @returns A PriceAttestationQuery suitable for MockPriceOracle\n *\n * @example\n * ```ts\n * const attestation = createMockAttestation(2000n * 10n**18n)\n * await client.mint({\n * to: userAddress,\n * ethAmount: parseEther('1'),\n * priceAttestation: attestation,\n * })\n * ```\n */\nexport function createMockAttestation(price: bigint): PriceAttestationQuery {\n return {\n price,\n decimals: 18,\n dataTimestamp: BigInt(Date.now()),\n assetPair: ETH_USD_ASSET_PAIR,\n signature: '0x',\n }\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// src/core/quote.ts
|
|
2
|
+
var PRICE_PRECISION = 10n ** 18n;
|
|
3
|
+
var SHARE_PRECISION = 10n ** 18n;
|
|
4
|
+
function quoteMintUPD(ethAmount, ethUsdPrice) {
|
|
5
|
+
return ethAmount * ethUsdPrice / PRICE_PRECISION;
|
|
6
|
+
}
|
|
7
|
+
function quoteBurnUPD(updAmount, ethUsdPrice) {
|
|
8
|
+
if (ethUsdPrice === 0n) throw new Error("Price cannot be zero");
|
|
9
|
+
return updAmount * PRICE_PRECISION / ethUsdPrice;
|
|
10
|
+
}
|
|
11
|
+
function stabilizerStEthNeeded(userEth, minCollateralRatioBps) {
|
|
12
|
+
return userEth * (minCollateralRatioBps - 10000n) / 10000n;
|
|
13
|
+
}
|
|
14
|
+
function quoteStakeUPD(updAmount, shareValue) {
|
|
15
|
+
if (shareValue === 0n) throw new Error("Share value cannot be zero");
|
|
16
|
+
return updAmount * SHARE_PRECISION / shareValue;
|
|
17
|
+
}
|
|
18
|
+
function quoteUnstakeUPD(shares, shareValue) {
|
|
19
|
+
return shares * shareValue / SHARE_PRECISION;
|
|
20
|
+
}
|
|
21
|
+
function collateralizationRatio(stEthBalance, ethUsdPrice, backedUPDAmount) {
|
|
22
|
+
if (backedUPDAmount === 0n) return BigInt(2) ** BigInt(256) - 1n;
|
|
23
|
+
const collateralValueUSD = stEthBalance * ethUsdPrice / PRICE_PRECISION;
|
|
24
|
+
return collateralValueUSD * 10000n / backedUPDAmount;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/core/health.ts
|
|
28
|
+
var DEFAULT_MIN_RATIO_BPS = 12500n;
|
|
29
|
+
function computeSystemHealth(collateral, ethUsdPrice, minRatioBps = DEFAULT_MIN_RATIO_BPS) {
|
|
30
|
+
const PRICE_PRECISION2 = 10n ** 18n;
|
|
31
|
+
const collateralValueUsd = collateral.totalStEthCollateral * ethUsdPrice / PRICE_PRECISION2;
|
|
32
|
+
const systemCollateralRatioBps = collateralizationRatio(
|
|
33
|
+
collateral.totalStEthCollateral,
|
|
34
|
+
ethUsdPrice,
|
|
35
|
+
collateral.totalUPDSupply
|
|
36
|
+
);
|
|
37
|
+
const bufferUsd = collateralValueUsd - collateral.totalUPDSupply;
|
|
38
|
+
return {
|
|
39
|
+
systemCollateralRatioBps,
|
|
40
|
+
isHealthy: systemCollateralRatioBps >= minRatioBps,
|
|
41
|
+
collateralValueUsd,
|
|
42
|
+
totalUPDSupply: collateral.totalUPDSupply,
|
|
43
|
+
bufferUsd
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { DEFAULT_MIN_RATIO_BPS, collateralizationRatio, computeSystemHealth, quoteBurnUPD, quoteMintUPD, quoteStakeUPD, quoteUnstakeUPD, stabilizerStEthNeeded };
|
|
48
|
+
//# sourceMappingURL=chunk-63FIKV36.js.map
|
|
49
|
+
//# sourceMappingURL=chunk-63FIKV36.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/quote.ts","../src/core/health.ts"],"names":["PRICE_PRECISION"],"mappings":";AAQA,IAAM,kBAAkB,GAAA,IAAO,GAAA;AAC/B,IAAM,kBAAkB,GAAA,IAAO,GAAA;AAexB,SAAS,YAAA,CAAa,WAAmB,WAAA,EAA6B;AAC3E,EAAA,OAAQ,YAAY,WAAA,GAAe,eAAA;AACrC;AAeO,SAAS,YAAA,CAAa,WAAmB,WAAA,EAA6B;AAC3E,EAAA,IAAI,WAAA,KAAgB,EAAA,EAAI,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAC9D,EAAA,OAAQ,YAAY,eAAA,GAAmB,WAAA;AACzC;AAeO,SAAS,qBAAA,CACd,SACA,qBAAA,EACQ;AACR,EAAA,OAAQ,OAAA,IAAW,wBAAwB,MAAA,CAAA,GAAW,MAAA;AACxD;AA+BO,SAAS,aAAA,CAAc,WAAmB,UAAA,EAA4B;AAC3E,EAAA,IAAI,UAAA,KAAe,EAAA,EAAI,MAAM,IAAI,MAAM,4BAA4B,CAAA;AACnE,EAAA,OAAQ,YAAY,eAAA,GAAmB,UAAA;AACzC;AAiBO,SAAS,eAAA,CAAgB,QAAgB,UAAA,EAA4B;AAC1E,EAAA,OAAQ,SAAS,UAAA,GAAc,eAAA;AACjC;AAEO,SAAS,sBAAA,CACd,YAAA,EACA,WAAA,EACA,eAAA,EACQ;AACR,EAAA,IAAI,eAAA,KAAoB,IAAI,OAAO,MAAA,CAAO,CAAC,CAAA,IAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAA;AAC9D,EAAA,MAAM,kBAAA,GAAsB,eAAe,WAAA,GAAe,eAAA;AAC1D,EAAA,OAAQ,qBAAqB,MAAA,GAAU,eAAA;AACzC;;;ACnHO,IAAM,qBAAA,GAAwB;AAkC9B,SAAS,mBAAA,CACd,UAAA,EACA,WAAA,EACA,WAAA,GAAsB,qBAAA,EACR;AACd,EAAA,MAAMA,mBAAkB,GAAA,IAAO,GAAA;AAE/B,EAAA,MAAM,kBAAA,GACH,UAAA,CAAW,oBAAA,GAAuB,WAAA,GAAeA,gBAAAA;AAEpD,EAAA,MAAM,wBAAA,GAA2B,sBAAA;AAAA,IAC/B,UAAA,CAAW,oBAAA;AAAA,IACX,WAAA;AAAA,IACA,UAAA,CAAW;AAAA,GACb;AAEA,EAAA,MAAM,SAAA,GAAY,qBAAqB,UAAA,CAAW,cAAA;AAElD,EAAA,OAAO;AAAA,IACL,wBAAA;AAAA,IACA,WAAW,wBAAA,IAA4B,WAAA;AAAA,IACvC,kBAAA;AAAA,IACA,gBAAgB,UAAA,CAAW,cAAA;AAAA,IAC3B;AAAA,GACF;AACF","file":"chunk-63FIKV36.js","sourcesContent":["/**\n * UPD Quote Functions — Pure math for estimating mint/burn amounts.\n *\n * These functions require no blockchain calls. They mirror the Solidity\n * CollateralMathLib logic so integrators can show users expected amounts\n * before submitting a transaction.\n */\n\nconst PRICE_PRECISION = 10n ** 18n\nconst SHARE_PRECISION = 10n ** 18n\n\n/**\n * Estimate how much UPD a user will receive for a given ETH amount.\n *\n * @param ethAmount - ETH to deposit (in wei)\n * @param ethUsdPrice - ETH/USD price (18 decimals, e.g. 2000e18 = $2000)\n * @returns Expected UPD amount (18 decimals)\n *\n * @example\n * ```ts\n * const upd = quoteMintUPD(parseEther('1'), 2000n * 10n**18n)\n * // → 2000000000000000000000n (2000 UPD)\n * ```\n */\nexport function quoteMintUPD(ethAmount: bigint, ethUsdPrice: bigint): bigint {\n return (ethAmount * ethUsdPrice) / PRICE_PRECISION\n}\n\n/**\n * Estimate how much stETH a user will receive for burning UPD.\n *\n * @param updAmount - UPD to burn (18 decimals)\n * @param ethUsdPrice - ETH/USD price (18 decimals)\n * @returns Expected stETH amount (in wei)\n *\n * @example\n * ```ts\n * const stEth = quoteBurnUPD(parseUnits('2000', 18), 2000n * 10n**18n)\n * // → 1000000000000000000n (1 stETH)\n * ```\n */\nexport function quoteBurnUPD(updAmount: bigint, ethUsdPrice: bigint): bigint {\n if (ethUsdPrice === 0n) throw new Error('Price cannot be zero')\n return (updAmount * PRICE_PRECISION) / ethUsdPrice\n}\n\n/**\n * Calculate the stabilizer stETH needed for a given user ETH deposit.\n *\n * @param userEth - User's ETH amount (in wei)\n * @param minCollateralRatioBps - Minimum collateral ratio in basis points (e.g. 12500 = 125%)\n * @returns Stabilizer stETH required (in wei)\n *\n * @example\n * ```ts\n * const needed = stabilizerStEthNeeded(parseEther('10'), 12500n)\n * // → 2500000000000000000n (2.5 ETH worth of stETH at 125% ratio)\n * ```\n */\nexport function stabilizerStEthNeeded(\n userEth: bigint,\n minCollateralRatioBps: bigint,\n): bigint {\n return (userEth * (minCollateralRatioBps - 10000n)) / 10000n\n}\n\n/**\n * Calculate the collateralization ratio from stETH balance, price, and UPD liability.\n *\n * @param stEthBalance - stETH held in escrow (in wei)\n * @param ethUsdPrice - ETH/USD price (18 decimals)\n * @param backedUPDAmount - UPD liability (18 decimals)\n * @returns Collateralization ratio in basis points (e.g. 12500 = 125%)\n *\n * @example\n * ```ts\n * const ratio = collateralizationRatio(parseEther('1.25'), 2000n * 10n**18n, parseUnits('2000', 18))\n * // → 12500n (125%)\n * ```\n */\n/**\n * Estimate sUPD shares received for staking UPD.\n *\n * Mirrors sUPD.sol line 136: shares = updAmount * SHARE_PRECISION / shareValue\n *\n * @param updAmount - UPD to stake (18 decimals)\n * @param shareValue - Current sUPD share value (18 decimals, e.g. 1.05e18 = $1.05/share)\n * @returns Expected sUPD shares (18 decimals)\n *\n * @example\n * ```ts\n * const shares = quoteStakeUPD(parseUnits('1000', 18), 1050000000000000000n)\n * // → ~952.38e18 shares (1000 UPD at $1.05/share)\n * ```\n */\nexport function quoteStakeUPD(updAmount: bigint, shareValue: bigint): bigint {\n if (shareValue === 0n) throw new Error('Share value cannot be zero')\n return (updAmount * SHARE_PRECISION) / shareValue\n}\n\n/**\n * Estimate UPD received for unstaking sUPD shares.\n *\n * Mirrors sUPD.sol line 173: updOwed = shares * shareValue / SHARE_PRECISION\n *\n * @param shares - sUPD shares to unstake (18 decimals)\n * @param shareValue - Current sUPD share value (18 decimals)\n * @returns Expected UPD amount (18 decimals)\n *\n * @example\n * ```ts\n * const upd = quoteUnstakeUPD(parseUnits('952.38', 18), 1050000000000000000n)\n * // → ~1000e18 UPD\n * ```\n */\nexport function quoteUnstakeUPD(shares: bigint, shareValue: bigint): bigint {\n return (shares * shareValue) / SHARE_PRECISION\n}\n\nexport function collateralizationRatio(\n stEthBalance: bigint,\n ethUsdPrice: bigint,\n backedUPDAmount: bigint,\n): bigint {\n if (backedUPDAmount === 0n) return BigInt(2) ** BigInt(256) - 1n // type(uint256).max\n const collateralValueUSD = (stEthBalance * ethUsdPrice) / PRICE_PRECISION\n return (collateralValueUSD * 10000n) / backedUPDAmount\n}\n","/**\n * System Health — Pure functions for computing UPD system health metrics.\n *\n * These functions take pre-fetched data (from UPDClient or React hooks) and\n * compute derived health metrics. No blockchain calls — composable with\n * any data source.\n */\n\nimport type { CollateralInfo } from './types.js'\nimport { collateralizationRatio } from './quote.js'\n\n/** Default minimum system collateral ratio: 125% (12500 bps). */\nexport const DEFAULT_MIN_RATIO_BPS = 12500n\n\nexport interface SystemHealth {\n /** System-wide collateralization ratio in basis points (e.g. 12500 = 125%). */\n systemCollateralRatioBps: bigint\n /** Whether the system is at or above the minimum collateral threshold. */\n isHealthy: boolean\n /** USD value of total stETH collateral (18 decimals). */\n collateralValueUsd: bigint\n /** Total UPD supply (18 decimals). */\n totalUPDSupply: bigint\n /** Overcollateralization buffer in USD (collateral - supply). Can be negative. */\n bufferUsd: bigint\n}\n\n/**\n * Compute system health from collateral info and current ETH/USD price.\n *\n * @param collateral - Total stETH collateral and UPD supply (from getCollateralInfo)\n * @param ethUsdPrice - Current ETH/USD price in 18 decimals\n * @param minRatioBps - Minimum healthy ratio in basis points (default: 12500 = 125%)\n * @returns Computed system health metrics\n *\n * @example\n * ```ts\n * const info = await client.getCollateralInfo()\n * const { price } = await oracle.getEthUsdPrice()\n * const health = computeSystemHealth(info, price)\n *\n * if (!health.isHealthy) {\n * console.warn(`System undercollateralized: ${health.systemCollateralRatioBps} bps`)\n * }\n * ```\n */\nexport function computeSystemHealth(\n collateral: CollateralInfo,\n ethUsdPrice: bigint,\n minRatioBps: bigint = DEFAULT_MIN_RATIO_BPS,\n): SystemHealth {\n const PRICE_PRECISION = 10n ** 18n\n\n const collateralValueUsd =\n (collateral.totalStEthCollateral * ethUsdPrice) / PRICE_PRECISION\n\n const systemCollateralRatioBps = collateralizationRatio(\n collateral.totalStEthCollateral,\n ethUsdPrice,\n collateral.totalUPDSupply,\n )\n\n const bufferUsd = collateralValueUsd - collateral.totalUPDSupply\n\n return {\n systemCollateralRatioBps,\n isHealthy: systemCollateralRatioBps >= minRatioBps,\n collateralValueUsd,\n totalUPDSupply: collateral.totalUPDSupply,\n bufferUsd,\n }\n}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var viem = require('viem');
|
|
4
|
+
|
|
5
|
+
// src/oracle/constants.ts
|
|
6
|
+
var DEFAULT_ORACLE_URL = "https://oracle.upd.io";
|
|
7
|
+
var ETH_USD_ASSET_PAIR = viem.keccak256(viem.encodePacked(["string"], ["MORPHER:ETH_USD"]));
|
|
8
|
+
var DEFAULT_TIMEOUT = 5e3;
|
|
9
|
+
|
|
10
|
+
// src/oracle/client.ts
|
|
11
|
+
function parseOracleResponse(json) {
|
|
12
|
+
return {
|
|
13
|
+
price: BigInt(json.price),
|
|
14
|
+
decimals: json.decimals,
|
|
15
|
+
dataTimestamp: BigInt(json.dataTimestamp),
|
|
16
|
+
assetPair: json.assetPair,
|
|
17
|
+
signature: json.signature
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createOracleClient(config) {
|
|
21
|
+
const oracleUrl = config?.oracleUrl ?? DEFAULT_ORACLE_URL;
|
|
22
|
+
const timeout = config?.timeout ?? DEFAULT_TIMEOUT;
|
|
23
|
+
const fetchFn = config?.fetch ?? globalThis.fetch;
|
|
24
|
+
async function fetchAttestation() {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetchFn(`${oracleUrl}/v1/ethusd`, {
|
|
29
|
+
signal: controller.signal,
|
|
30
|
+
headers: { "Accept": "application/json" }
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Oracle request failed: ${response.status} ${response.statusText}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const json = await response.json();
|
|
38
|
+
return parseOracleResponse(json);
|
|
39
|
+
} finally {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
async getEthUsdAttestation() {
|
|
45
|
+
return fetchAttestation();
|
|
46
|
+
},
|
|
47
|
+
async getEthUsdPrice() {
|
|
48
|
+
const attestation = await fetchAttestation();
|
|
49
|
+
return {
|
|
50
|
+
price: attestation.price,
|
|
51
|
+
timestamp: attestation.dataTimestamp
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
exports.DEFAULT_ORACLE_URL = DEFAULT_ORACLE_URL;
|
|
58
|
+
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
59
|
+
exports.ETH_USD_ASSET_PAIR = ETH_USD_ASSET_PAIR;
|
|
60
|
+
exports.createOracleClient = createOracleClient;
|
|
61
|
+
//# sourceMappingURL=chunk-CZEDT3MS.cjs.map
|
|
62
|
+
//# sourceMappingURL=chunk-CZEDT3MS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oracle/constants.ts","../src/oracle/client.ts"],"names":["keccak256","encodePacked"],"mappings":";;;;;AAGO,IAAM,kBAAA,GAAqB;AAG3B,IAAM,kBAAA,GAAqBA,eAAUC,iBAAA,CAAa,CAAC,QAAQ,CAAA,EAAG,CAAC,iBAAiB,CAAC,CAAC;AAGlF,IAAM,eAAA,GAAkB;;;ACsB/B,SAAS,oBAAoB,IAAA,EAA6C;AACxE,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,IACxB,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,aAAA,EAAe,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA;AAAA,IACxC,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,WAAW,IAAA,CAAK;AAAA,GAClB;AACF;AAQO,SAAS,mBAAmB,MAAA,EAA2C;AAC5E,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,kBAAA;AACvC,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,eAAA;AACnC,EAAA,MAAM,OAAA,GAAU,MAAA,EAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AAE5C,EAAA,eAAe,gBAAA,GAAmD;AAChE,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE1D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,CAAA,EAAG,SAAS,CAAA,UAAA,CAAA,EAAc;AAAA,QACvD,QAAQ,UAAA,CAAW,MAAA;AAAA,QACnB,OAAA,EAAS,EAAE,QAAA,EAAU,kBAAA;AAAmB,OACzC,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,uBAAA,EAA0B,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,SAClE;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,MAAA,OAAO,oBAAoB,IAAI,CAAA;AAAA,IACjC,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,oBAAA,GAAuD;AAC3D,MAAA,OAAO,gBAAA,EAAiB;AAAA,IAC1B,CAAA;AAAA,IAEA,MAAM,cAAA,GAAgE;AACpE,MAAA,MAAM,WAAA,GAAc,MAAM,gBAAA,EAAiB;AAC3C,MAAA,OAAO;AAAA,QACL,OAAO,WAAA,CAAY,KAAA;AAAA,QACnB,WAAW,WAAA,CAAY;AAAA,OACzB;AAAA,IACF;AAAA,GACF;AACF","file":"chunk-CZEDT3MS.cjs","sourcesContent":["import { keccak256, encodePacked } from 'viem'\n\n/** Default oracle service URL. */\nexport const DEFAULT_ORACLE_URL = 'https://oracle.upd.io'\n\n/** The asset pair identifier used by the UPD PriceOracle for ETH/USD. */\nexport const ETH_USD_ASSET_PAIR = keccak256(encodePacked(['string'], ['MORPHER:ETH_USD']))\n\n/** Default request timeout in milliseconds. */\nexport const DEFAULT_TIMEOUT = 5000\n","/**\n * Oracle HTTP Client — Fetches signed price attestations from an oracle service.\n *\n * The oracle service returns signed ETH/USD prices in the exact format\n * that PriceOracle.sol expects. The client deserializes the response\n * into a PriceAttestationQuery that can be passed directly to\n * UPDClient.mint() or UPDClient.burn().\n *\n * @example\n * ```ts\n * import { createOracleClient } from '@permissionless-technologies/upd-sdk/oracle'\n *\n * const oracle = createOracleClient()\n * const attestation = await oracle.getEthUsdAttestation()\n *\n * // Pass directly to mint\n * await updClient.mint({ to: '0x...', ethAmount: parseEther('1'), priceAttestation: attestation })\n * ```\n *\n * @example\n * ```ts\n * // Custom oracle URL (e.g. local development)\n * const oracle = createOracleClient({ oracleUrl: 'http://localhost:3000' })\n * const { price } = await oracle.getEthUsdPrice()\n * ```\n */\n\nimport type { PriceAttestationQuery } from '../core/types.js'\nimport type { OracleClientConfig, OracleClient, OracleResponse } from './types.js'\nimport { DEFAULT_ORACLE_URL, DEFAULT_TIMEOUT } from './constants.js'\n\nfunction parseOracleResponse(json: OracleResponse): PriceAttestationQuery {\n return {\n price: BigInt(json.price),\n decimals: json.decimals,\n dataTimestamp: BigInt(json.dataTimestamp),\n assetPair: json.assetPair,\n signature: json.signature,\n }\n}\n\n/**\n * Create an oracle client that fetches signed price attestations.\n *\n * @param config - Optional configuration (URL, timeout, custom fetch)\n * @returns An OracleClient instance\n */\nexport function createOracleClient(config?: OracleClientConfig): OracleClient {\n const oracleUrl = config?.oracleUrl ?? DEFAULT_ORACLE_URL\n const timeout = config?.timeout ?? DEFAULT_TIMEOUT\n const fetchFn = config?.fetch ?? globalThis.fetch\n\n async function fetchAttestation(): Promise<PriceAttestationQuery> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetchFn(`${oracleUrl}/v1/ethusd`, {\n signal: controller.signal,\n headers: { 'Accept': 'application/json' },\n })\n\n if (!response.ok) {\n throw new Error(\n `Oracle request failed: ${response.status} ${response.statusText}`,\n )\n }\n\n const json = await response.json() as OracleResponse\n return parseOracleResponse(json)\n } finally {\n clearTimeout(timer)\n }\n }\n\n return {\n async getEthUsdAttestation(): Promise<PriceAttestationQuery> {\n return fetchAttestation()\n },\n\n async getEthUsdPrice(): Promise<{ price: bigint; timestamp: bigint }> {\n const attestation = await fetchAttestation()\n return {\n price: attestation.price,\n timestamp: attestation.dataTimestamp,\n }\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkCZEDT3MS_cjs = require('./chunk-CZEDT3MS.cjs');
|
|
4
|
+
|
|
5
|
+
// src/oracle/mock.ts
|
|
6
|
+
function createMockAttestation(price) {
|
|
7
|
+
return {
|
|
8
|
+
price,
|
|
9
|
+
decimals: 18,
|
|
10
|
+
dataTimestamp: BigInt(Date.now()),
|
|
11
|
+
assetPair: chunkCZEDT3MS_cjs.ETH_USD_ASSET_PAIR,
|
|
12
|
+
signature: "0x"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.createMockAttestation = createMockAttestation;
|
|
17
|
+
//# sourceMappingURL=chunk-DF34ON56.cjs.map
|
|
18
|
+
//# sourceMappingURL=chunk-DF34ON56.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oracle/mock.ts"],"names":["ETH_USD_ASSET_PAIR"],"mappings":";;;;;AA2BO,SAAS,sBAAsB,KAAA,EAAsC;AAC1E,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA,EAAU,EAAA;AAAA,IACV,aAAA,EAAe,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,IAChC,SAAA,EAAWA,oCAAA;AAAA,IACX,SAAA,EAAW;AAAA,GACb;AACF","file":"chunk-DF34ON56.cjs","sourcesContent":["/**\n * Mock oracle helpers for testing and local development.\n *\n * WARNING: createMockAttestation produces attestations with empty signatures.\n * They only work with MockPriceOracle in tests, NOT with the real PriceOracle\n * on mainnet/testnet (which validates ECDSA signatures).\n */\n\nimport type { PriceAttestationQuery } from '../core/types.js'\nimport { ETH_USD_ASSET_PAIR } from './constants.js'\n\n/**\n * Create a mock price attestation for testing/local development.\n *\n * @param price - ETH/USD price in 18 decimals (e.g. 2000n * 10n**18n for $2000)\n * @returns A PriceAttestationQuery suitable for MockPriceOracle\n *\n * @example\n * ```ts\n * const attestation = createMockAttestation(2000n * 10n**18n)\n * await client.mint({\n * to: userAddress,\n * ethAmount: parseEther('1'),\n * priceAttestation: attestation,\n * })\n * ```\n */\nexport function createMockAttestation(price: bigint): PriceAttestationQuery {\n return {\n price,\n decimals: 18,\n dataTimestamp: BigInt(Date.now()),\n assetPair: ETH_USD_ASSET_PAIR,\n signature: '0x',\n }\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { keccak256, encodePacked } from 'viem';
|
|
2
|
+
|
|
3
|
+
// src/oracle/constants.ts
|
|
4
|
+
var DEFAULT_ORACLE_URL = "https://oracle.upd.io";
|
|
5
|
+
var ETH_USD_ASSET_PAIR = keccak256(encodePacked(["string"], ["MORPHER:ETH_USD"]));
|
|
6
|
+
var DEFAULT_TIMEOUT = 5e3;
|
|
7
|
+
|
|
8
|
+
// src/oracle/client.ts
|
|
9
|
+
function parseOracleResponse(json) {
|
|
10
|
+
return {
|
|
11
|
+
price: BigInt(json.price),
|
|
12
|
+
decimals: json.decimals,
|
|
13
|
+
dataTimestamp: BigInt(json.dataTimestamp),
|
|
14
|
+
assetPair: json.assetPair,
|
|
15
|
+
signature: json.signature
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function createOracleClient(config) {
|
|
19
|
+
const oracleUrl = config?.oracleUrl ?? DEFAULT_ORACLE_URL;
|
|
20
|
+
const timeout = config?.timeout ?? DEFAULT_TIMEOUT;
|
|
21
|
+
const fetchFn = config?.fetch ?? globalThis.fetch;
|
|
22
|
+
async function fetchAttestation() {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetchFn(`${oracleUrl}/v1/ethusd`, {
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
headers: { "Accept": "application/json" }
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Oracle request failed: ${response.status} ${response.statusText}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
const json = await response.json();
|
|
36
|
+
return parseOracleResponse(json);
|
|
37
|
+
} finally {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
async getEthUsdAttestation() {
|
|
43
|
+
return fetchAttestation();
|
|
44
|
+
},
|
|
45
|
+
async getEthUsdPrice() {
|
|
46
|
+
const attestation = await fetchAttestation();
|
|
47
|
+
return {
|
|
48
|
+
price: attestation.price,
|
|
49
|
+
timestamp: attestation.dataTimestamp
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { DEFAULT_ORACLE_URL, DEFAULT_TIMEOUT, ETH_USD_ASSET_PAIR, createOracleClient };
|
|
56
|
+
//# sourceMappingURL=chunk-DJBU2OEB.js.map
|
|
57
|
+
//# sourceMappingURL=chunk-DJBU2OEB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oracle/constants.ts","../src/oracle/client.ts"],"names":[],"mappings":";;;AAGO,IAAM,kBAAA,GAAqB;AAG3B,IAAM,kBAAA,GAAqB,UAAU,YAAA,CAAa,CAAC,QAAQ,CAAA,EAAG,CAAC,iBAAiB,CAAC,CAAC;AAGlF,IAAM,eAAA,GAAkB;;;ACsB/B,SAAS,oBAAoB,IAAA,EAA6C;AACxE,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,IACxB,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,aAAA,EAAe,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA;AAAA,IACxC,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,WAAW,IAAA,CAAK;AAAA,GAClB;AACF;AAQO,SAAS,mBAAmB,MAAA,EAA2C;AAC5E,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,kBAAA;AACvC,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,eAAA;AACnC,EAAA,MAAM,OAAA,GAAU,MAAA,EAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AAE5C,EAAA,eAAe,gBAAA,GAAmD;AAChE,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE1D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,CAAA,EAAG,SAAS,CAAA,UAAA,CAAA,EAAc;AAAA,QACvD,QAAQ,UAAA,CAAW,MAAA;AAAA,QACnB,OAAA,EAAS,EAAE,QAAA,EAAU,kBAAA;AAAmB,OACzC,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,uBAAA,EAA0B,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,SAClE;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,MAAA,OAAO,oBAAoB,IAAI,CAAA;AAAA,IACjC,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,oBAAA,GAAuD;AAC3D,MAAA,OAAO,gBAAA,EAAiB;AAAA,IAC1B,CAAA;AAAA,IAEA,MAAM,cAAA,GAAgE;AACpE,MAAA,MAAM,WAAA,GAAc,MAAM,gBAAA,EAAiB;AAC3C,MAAA,OAAO;AAAA,QACL,OAAO,WAAA,CAAY,KAAA;AAAA,QACnB,WAAW,WAAA,CAAY;AAAA,OACzB;AAAA,IACF;AAAA,GACF;AACF","file":"chunk-DJBU2OEB.js","sourcesContent":["import { keccak256, encodePacked } from 'viem'\n\n/** Default oracle service URL. */\nexport const DEFAULT_ORACLE_URL = 'https://oracle.upd.io'\n\n/** The asset pair identifier used by the UPD PriceOracle for ETH/USD. */\nexport const ETH_USD_ASSET_PAIR = keccak256(encodePacked(['string'], ['MORPHER:ETH_USD']))\n\n/** Default request timeout in milliseconds. */\nexport const DEFAULT_TIMEOUT = 5000\n","/**\n * Oracle HTTP Client — Fetches signed price attestations from an oracle service.\n *\n * The oracle service returns signed ETH/USD prices in the exact format\n * that PriceOracle.sol expects. The client deserializes the response\n * into a PriceAttestationQuery that can be passed directly to\n * UPDClient.mint() or UPDClient.burn().\n *\n * @example\n * ```ts\n * import { createOracleClient } from '@permissionless-technologies/upd-sdk/oracle'\n *\n * const oracle = createOracleClient()\n * const attestation = await oracle.getEthUsdAttestation()\n *\n * // Pass directly to mint\n * await updClient.mint({ to: '0x...', ethAmount: parseEther('1'), priceAttestation: attestation })\n * ```\n *\n * @example\n * ```ts\n * // Custom oracle URL (e.g. local development)\n * const oracle = createOracleClient({ oracleUrl: 'http://localhost:3000' })\n * const { price } = await oracle.getEthUsdPrice()\n * ```\n */\n\nimport type { PriceAttestationQuery } from '../core/types.js'\nimport type { OracleClientConfig, OracleClient, OracleResponse } from './types.js'\nimport { DEFAULT_ORACLE_URL, DEFAULT_TIMEOUT } from './constants.js'\n\nfunction parseOracleResponse(json: OracleResponse): PriceAttestationQuery {\n return {\n price: BigInt(json.price),\n decimals: json.decimals,\n dataTimestamp: BigInt(json.dataTimestamp),\n assetPair: json.assetPair,\n signature: json.signature,\n }\n}\n\n/**\n * Create an oracle client that fetches signed price attestations.\n *\n * @param config - Optional configuration (URL, timeout, custom fetch)\n * @returns An OracleClient instance\n */\nexport function createOracleClient(config?: OracleClientConfig): OracleClient {\n const oracleUrl = config?.oracleUrl ?? DEFAULT_ORACLE_URL\n const timeout = config?.timeout ?? DEFAULT_TIMEOUT\n const fetchFn = config?.fetch ?? globalThis.fetch\n\n async function fetchAttestation(): Promise<PriceAttestationQuery> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetchFn(`${oracleUrl}/v1/ethusd`, {\n signal: controller.signal,\n headers: { 'Accept': 'application/json' },\n })\n\n if (!response.ok) {\n throw new Error(\n `Oracle request failed: ${response.status} ${response.statusText}`,\n )\n }\n\n const json = await response.json() as OracleResponse\n return parseOracleResponse(json)\n } finally {\n clearTimeout(timer)\n }\n }\n\n return {\n async getEthUsdAttestation(): Promise<PriceAttestationQuery> {\n return fetchAttestation()\n },\n\n async getEthUsdPrice(): Promise<{ price: bigint; timestamp: bigint }> {\n const attestation = await fetchAttestation()\n return {\n price: attestation.price,\n timestamp: attestation.dataTimestamp,\n }\n },\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-LNGWRYGY.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-POBNO37G.cjs"}
|