const ethers = require('ethers');
const dotenv = require('dotenv');
dotenv.config();
/**
* Fetch SEI price update data from Pyth Hermes API
* @returns {Object} Price update data from Hermes
*/
async function fetchSeiPriceUpdateData() {
const seiPriceId = '0x53614f1cb0c031d4af66c04cb9c756234adad0e1cee85303795091499a4084eb'; // SEI/USD Price Feed ID
const hermesUrl = `https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D=${seiPriceId}`;
try {
console.log('Fetching SEI price data from Hermes...');
const response = await fetch(hermesUrl, {
method: 'GET',
headers: {
accept: 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Hermes API Response:', JSON.stringify(data, null, 2));
// Extract the binary data array for contract submission
const binaryData = data.binary.data;
console.log('Binary data for contract:', binaryData);
// Extract parsed price info for logging
const priceInfo = data.parsed[0];
console.log('Current SEI Price Info:');
console.log(`- Price: ${priceInfo.price.price} (expo: ${priceInfo.price.expo})`);
console.log(`- Formatted Price: ${(priceInfo.price.price * Math.pow(10, priceInfo.price.expo)).toFixed(6)}`);
console.log(`- Confidence: ${priceInfo.price.conf}`);
console.log(`- Publish Time: ${new Date(priceInfo.price.publish_time * 1000)}`);
return {
binaryData,
priceInfo
};
} catch (error) {
console.error('Error fetching SEI price data:', error);
throw error;
}
}
/**
* Update SEI price on smart contract and query the result
* @param {string} contractAddress Deployed contract address
* @param {string} privateKey Wallet private key
* @param {string} rpcUrl RPC endpoint URL
*/
async function updateAndQuerySeiPrice(contractAddress, privateKey, rpcUrl = 'https://evm-rpc.sei-apis.com') {
try {
// Setup provider and wallet
const provider = new ethers.JsonRpcProvider(rpcUrl);
const wallet = new ethers.Wallet(privateKey, provider);
// Contract ABI
const contractAbi = ['function getSeiPrice(bytes[] calldata priceUpdateData) external payable returns (tuple(int64 price, uint64 conf, int32 expo, uint256 publishTime))', 'function getLatestSeiPrice() external view returns (tuple(int64 price, uint64 conf, int32 expo, uint256 publishTime))', 'function isPriceFresh(uint256 maxAge) external view returns (bool)', 'function getUpdateFee(bytes[] calldata priceUpdateData) external view returns (uint256)', 'receive() external payable'];
const contract = new ethers.Contract(contractAddress, contractAbi, wallet);
const seiPriceId = '0x53614f1cb0c031d4af66c04cb9c756234adad0e1cee85303795091499a4084eb';
// Step 1: Fetch price update data from Hermes
const { binaryData, priceInfo } = await fetchSeiPriceUpdateData();
// Step 2: Convert binary data to bytes array format
const priceUpdateData = binaryData.map((hexData) => `0x${hexData}`);
console.log('Sending Fee Data', priceUpdateData);
// Step 3: Get update fee (should be small)
console.log('\nGetting update fee...');
const updateFee = await contract.getUpdateFee(priceUpdateData);
console.log(`Update fee: ${ethers.formatEther(updateFee)} SEI`);
// Step 4: Update price on contract with 1 SEI (as requested)
console.log('\nUpdating price on smart contract...');
const tx = await contract.getSeiPrice(priceUpdateData, {
value: updateFee
});
console.log(`Transaction submitted: ${tx.hash}`);
const receipt = await tx.wait();
console.log(`β
Transaction confirmed in block: ${receipt.blockNumber}`);
// Reads the last known price (the contract enforces a 60-second freshness window)
const onChainPrice = await contract.getLatestSeiPrice();
console.log('Onchain Query Raw', onChainPrice);
// Step 5: Log the results
console.log('\nπ On-Chain SEI Price Data:');
console.log(`- Raw Price: ${onChainPrice.price.toString()}`);
console.log(`- Confidence: ${onChainPrice.conf.toString()}`);
console.log(`- Exponent: ${onChainPrice.expo.toString()}`);
console.log(`- Publish Time: ${new Date(parseInt(onChainPrice.publishTime.toString()) * 1000)}`);
// Format the price properly
const formattedPrice = (parseInt(onChainPrice.price.toString()) * Math.pow(10, parseInt(onChainPrice.expo.toString()))).toFixed(6);
console.log(`- Formatted Price: ${formattedPrice}`);
return {
txHash: receipt.hash,
blockNumber: receipt.blockNumber,
price: formattedPrice,
rawPrice: onChainPrice
};
} catch (error) {
console.error('β Error in price update process:', error);
throw error;
}
}
/**
* Complete demonstration function
*/
async function demonstrateSeiPriceIntegration() {
// Configuration
const contractAddress = process.env.CONTRACT_ADDRESS;
const privateKey = process.env.PRIVATE_KEY;
const rpcUrl = 'https://evm-rpc.sei-apis.com';
console.log('π Starting SEI-Pyth integration demo...');
console.log(`π Contract Address: ${contractAddress}`);
console.log(`π RPC URL: ${rpcUrl}\n`);
try {
const result = await updateAndQuerySeiPrice(contractAddress, privateKey, rpcUrl);
console.log('\nπ Demo completed successfully!');
console.log(`π Summary:`);
console.log(` - Transaction: ${result.txHash}`);
console.log(` - Block: ${result.blockNumber}`);
console.log(` - Final SEI Price: ${result.price}`);
} catch (error) {
console.error('β Demo failed:', error.message);
}
}
// Export functions for use in other modules
module.exports = {
fetchSeiPriceUpdateData,
updateAndQuerySeiPrice,
demonstrateSeiPriceIntegration
};
// Run demo if this file is executed directly
if (require.main === module) {
demonstrateSeiPriceIntegration();
}