UPD — Universal Private DollarSDK Reference
Oracle
Fetch signed ETH/USD price attestations for UPD mint and burn operations.
Oracle
UPD minting and burning require a signed price attestation — an ETH/USD price signed by an authorized oracle signer. The PriceOracle contract validates the signature, staleness, and deviation against Chainlink + Uniswap V3.
Oracle Client (SDK)
The SDK includes a thin HTTP client that fetches attestations from any oracle service:
import { createOracleClient } from '@permissionless-technologies/upd-sdk/oracle'
const oracle = createOracleClient({
oracleUrl: 'https://oracle.upd.io', // default
timeout: 5000, // default
})
// Get a signed attestation (ready to pass to mint/burn)
const attestation = await oracle.getEthUsdAttestation()
// Or just the price
const { price, timestamp } = await oracle.getEthUsdPrice()The attestation object matches the Solidity PriceAttestationQuery struct exactly:
interface PriceAttestationQuery {
price: bigint // 18 decimals (e.g. 2000e18 = $2000)
decimals: number // always 18
dataTimestamp: bigint // milliseconds since epoch
assetPair: Hex // keccak256("MORPHER:ETH_USD")
signature: Hex // ECDSA from authorized signer
}Mock Attestations (Testing)
For local development with MockPriceOracle:
import { createMockAttestation } from '@permissionless-technologies/upd-sdk/oracle'
const attestation = createMockAttestation(2000n * 10n ** 18n) // $2000
// signature is 0x — only works with MockPriceOracle, not productionRunning Your Own Oracle
The oracle service is published as a separate package:
npm install @permissionless-technologies/upd-oracleimport { startOracleService, BinanceFeed } from '@permissionless-technologies/upd-oracle'
await startOracleService({
config: {
signerPrivateKey: '0x...', // must match SIGNER_ROLE on PriceOracle contract
port: 3000,
},
feed: new BinanceFeed(),
})This starts an Express server with:
GET /v1/ethusd— returns a signed price attestationGET /health— signer address and feed status
Custom Price Feeds
Implement the IPriceFeed interface to use any price source:
import type { IPriceFeed, PriceFeedResult } from '@permissionless-technologies/upd-oracle'
class MyFeed implements IPriceFeed {
name = 'MyFeed'
async getPrice(pair: string): Promise<PriceFeedResult> {
// Fetch from your source
return {
price: 2000n * 10n ** 18n, // 18 decimals
timestamp: BigInt(Date.now()),
}
}
}Signature Format
The oracle signs prices in the format PriceOracle.sol expects:
messageHash = keccak256(abi.encodePacked(price, decimals, timestamp, assetPair))signMessage({ message: { raw: messageHash } })— applies\x19Ethereum Signed Message:\n32prefix- Contract recovers signer via
ECDSA.recoverand checksSIGNER_ROLE