This page explains how to create a USD-pegged token using the Glittr SDK with oracle-based price feeds. The token's mint price will be determined by the current BTC/USD exchange rate.
We start by setting up the SDK client for the regtest network (development environment) and import necessary functions.
2. Account and Oracle Setup
// Create accounts for different rolesconstcreatorAccount=newAccount({ wif:"...", network:NETWORK,});constminterAccount=newAccount({ wif:"...", network:NETWORK,});// Setup oracle for price feedsconstoraclePrivateKey=newUint8Array([...]);constoraclePubkey=Array.from(getPublicKey(oraclePrivateKey,true)).slice(1);
We set up:
A creator account that will deploy the contract
A minter account that will mint tokens
An oracle account that will provide BTC/USD price feeds
This function allows you to check the details of minted assets.
Key Concepts
Oracle-Based Pricing: The contract uses an oracle to determine the BTC/USD exchange rate
Price Updates: Allows a 5-block window for price updates to account for network delays
USD Pegging: Tokens are minted based on the current BTC/USD rate
Example Rate: In this example, 1 satoshi = 0.0007 USD (BTC price of ~$70,000)
This implementation creates a USD-pegged token where users can mint tokens by sending BTC, with the amount of tokens received based on the current BTC/USD exchange rate provided by the oracle.
Usage Flow
Setup
// Initialize SDK and accountsconstclient=newGlittrSDK({...});constcreatorAccount=newAccount({...});constminterAccount=newAccount({...});
Create Contract
awaitdeployUsdContract();
Mint Tokens
awaitmint();
Check Asset Details
await_checkingAsset();
Full Code Example
import { Account, GlittrSDK, OpReturnMessage, electrumFetchNonGlittrUtxos, BitcoinUTXO, Output, addFeeToTx, txBuilder, BlockTxTuple,} from"@glittr-sdk/sdk";import { OracleMessage, OracleMessageSigned,} from"@glittr-sdk/sdk/dist/transaction/calltype/types";import { schnorr, getPublicKey } from"@noble/secp256k1";import { sha256 } from"bitcoinjs-lib/src/crypto";constNETWORK="regtest";constclient=newGlittrSDK({ network:NETWORK, apiKey: <yourapikeyhere>, glittrApi:"https://devnet-core-api.glittr.fi",// devnet electrumApi:"https://devnet-electrum.glittr.fi"// devnet});constcreatorAccount=newAccount({ wif:"...", network:NETWORK,});constminterAccount=newAccount({ wif:"...", network:NETWORK,});// ORACLE// Generate a random private keyconstoraclePrivateKey=newUint8Array([...]);// Get the corresponding public keyconstoraclePubkey=Array.from(getPublicKey(oraclePrivateKey,true)).slice(1);console.log("Oracle public key:",Buffer.from(oraclePubkey).toString("hex"));asyncfunctiondeployUsdContract() {consttx:OpReturnMessage= { contract_creation: { contract_type: { moa: { divisibility:1, live_time:0, mint_mechanism: { purchase: { input_asset:'raw_btc', ratio: { oracle: { setting: { pubkey: oraclePubkey, asset_id:'btc', block_height_slippage:5 } } } } } } } } }constutxos=awaitelectrumFetchNonGlittrUtxos(client.electrumApi,client.apiKey,creatorAccount.p2pkh().address)constnonFeeInputs:BitcoinUTXO[] = []constnonFeeOutputs:Output[] = [ { script:txBuilder.compile(tx), value:0 }, { address:creatorAccount.p2pkh().address, value:546 } ]const { inputs,outputs } =awaitaddFeeToTx(NETWORK,creatorAccount.p2pkh().address, utxos, nonFeeInputs, nonFeeOutputs)consttxid=awaitclient.createAndBroadcastRawTx({ account:creatorAccount.p2pkh(), inputs, outputs })console.log(`TXID : ${txid}`)}asyncfunctionmint() {constcontract:BlockTxTuple= [101999,1]// Get block heightconstblockHeightFetch=awaitfetch(`${client.electrumApi}/blocks/tip/height`)constblockHeight=awaitblockHeightFetch.json()// 1 BTC = 70000 usd// 1 sat = 0.0007// with divisibilty 8 => 1 sat = 70000// times 10**-8 for displayconstoracleMessage:OracleMessage= { asset_id:"btc", ratio: [70000,1],// 1 sats = 70000 asset block_height: blockHeight, };constsignature=awaitschnorr.sign(sha256(Buffer.from(JSON.stringify(oracleMessage),"ascii")).toString("hex"), oraclePrivateKey );constoracleSignedMessage:OracleMessageSigned= { signature:Array.from(signature), message: oracleMessage, };consttx:OpReturnMessage= { contract_call: { contract: contract, call_type: { mint: { pointer:1,// Points to the mint receiver's index in Output array oracle_message: oracleSignedMessage } } } }constutxos=awaitelectrumFetchNonGlittrUtxos(client.electrumApi,client.apiKey,minterAccount.p2pkh().address)constnonFeeInputs:BitcoinUTXO[] = []constnonFeeOutputs:Output[] = [ { script:txBuilder.compile(tx), value:0 },// Output #0 should always be OP_RETURN { address:minterAccount.p2pkh().address, value:546 }, { address:creatorAccount.p2pkh().address, value:1000 }, ]const { inputs,outputs } =awaitaddFeeToTx(NETWORK,minterAccount.p2pkh().address, utxos, nonFeeInputs, nonFeeOutputs)consttxid=awaitclient.createAndBroadcastRawTx({ account:minterAccount.p2pkh(), inputs, outputs })console.log(`TXID : ${txid}`)}/** * Call deployUsdContract() function first * wait for confirmation and indexing * then call the mint() function */deployUsdContract()/** * Function to check asset after mint * change the mintTxId and mintVout * with your mint() fnction result */asyncfunction_checkingAsset() {constmintTxid="cece25c03d7d2c1a297eab6eff89965989259953c0b55e08c3f1370a0ecdfdc8"constmintVout=0constassetFetch=awaitfetch(`${client.glittrApi}/assets/${mintTxid}/${mintVout}`)constasset=awaitassetFetch.text()console.log(`Asset : ${asset}`)}