import { z } from "zod"
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import type { ChainlinkApiClient } from "../utils/api-client.js"
import { validateNetwork, validateAddress } from "../utils/validators.js"
import { formatNetworkName, formatTimestamp, formatAddress } from "../utils/formatters.js"
export function registerProofOfReserveTools(server: McpServer, apiClient: ChainlinkApiClient) {
// Tool: Get Proof of Reserve
server.tool(
"get_proof_of_reserve",
"Get the latest proof of reserve data for a specific asset. Shows total supply, backing assets, and collateralization ratio.",
{
asset: z.string().describe("Asset symbol (e.g., 'WBTC', 'USDC', 'PAXG')"),
network: z.string().optional().describe("Blockchain network (default: ethereum)")
},
async ({ asset, network = "ethereum" }) => {
try {
const networkValidation = validateNetwork(network)
if (!networkValidation.valid) {
throw new Error(networkValidation.error)
}
// Mock proof of reserve data
const assetData = {
"WBTC": {
totalSupply: "164,123.45 WBTC",
backingAssets: "164,156.22 BTC",
collateralizationRatio: "100.02%",
reserveAddress: "bc1qjl8uwezzlech723lpnyuza0h2cdkvxvh54v3dn",
lastAudit: "2024-01-20T10:30:00Z"
},
"USDC": {
totalSupply: "28,456,789,123.45 USDC",
backingAssets: "$28,456,823,067.89 USD",
collateralizationRatio: "100.00%",
reserveAddress: "Multiple bank accounts",
lastAudit: "2024-01-20T08:00:00Z"
},
"PAXG": {
totalSupply: "234,567.89 PAXG",
backingAssets: "234,567.89 oz Gold",
collateralizationRatio: "100.00%",
reserveAddress: "Brink's vaults (London)",
lastAudit: "2024-01-19T16:45:00Z"
}
}
const data = assetData[asset.toUpperCase() as keyof typeof assetData]
if (!data) {
throw new Error(`Proof of Reserve data not available for asset: ${asset}`)
}
const result = {
asset: asset.toUpperCase(),
network: formatNetworkName(network),
...data,
lastAudit: formatTimestamp(data.lastAudit),
dataFeed: "0x" + Math.random().toString(16).slice(2).padStart(40, '0'),
status: "healthy",
lastUpdated: formatTimestamp(Date.now() / 1000),
attestationProvider: "Chainlink Proof of Reserve"
}
return {
content: [
{
type: "text",
text: `Proof of Reserve for ${asset.toUpperCase()}\n\n` +
`Total Supply: ${result.totalSupply}\n` +
`Backing Assets: ${result.backingAssets}\n` +
`Collateralization: ${result.collateralizationRatio}\n` +
`Status: ${result.status}\n` +
`Last Audit: ${result.lastAudit}\n` +
`Network: ${result.network}\n\n` +
`Full Details:\n${JSON.stringify(result, null, 2)}`
}
]
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error getting proof of reserve: ${error instanceof Error ? error.message : String(error)}`
}
]
}
}
}
)
// Tool: Verify Reserve Proof
server.tool(
"verify_reserve_proof",
"Verify the cryptographic proof for reserve attestations. Ensures data integrity and authenticity.",
{
asset: z.string().describe("Asset symbol to verify"),
proofData: z.string().optional().describe("Proof data (if not provided, latest will be fetched)"),
network: z.string().optional().describe("Blockchain network")
},
async ({ asset, proofData, network = "ethereum" }) => {
try {
const networkValidation = validateNetwork(network)
if (!networkValidation.valid) {
throw new Error(networkValidation.error)
}
// Mock proof verification
const isValid = Math.random() > 0.02 // 98% valid rate
const result = {
asset: asset.toUpperCase(),
network: formatNetworkName(network),
proofHash: proofData || `0x${Math.random().toString(16).slice(2).padStart(64, '0')}`,
isValid,
verificationStatus: isValid ? "verified" : "invalid",
verificationMethod: "Merkle tree proof",
attestationTimestamp: formatTimestamp(Date.now() / 1000 - Math.random() * 3600),
verifiedAt: formatTimestamp(Date.now() / 1000),
signatureValid: isValid,
merkleRootValid: isValid,
dataIntegrity: isValid ? "intact" : "compromised",
attestor: "Chainlink Decentralized Oracle Network"
}
return {
content: [
{
type: "text",
text: `Proof verification ${isValid ? 'successful' : 'failed'} for ${asset.toUpperCase()}\n\n` +
`Verification Status: ${result.verificationStatus}\n` +
`Data Integrity: ${result.dataIntegrity}\n` +
`Signature Valid: ${result.signatureValid}\n` +
`Merkle Root Valid: ${result.merkleRootValid}\n` +
`Network: ${result.network}\n` +
`Verified At: ${result.verifiedAt}\n\n` +
`Full Details:\n${JSON.stringify(result, null, 2)}`
}
]
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error verifying reserve proof: ${error instanceof Error ? error.message : String(error)}`
}
]
}
}
}
)
// Tool: List Supported Assets
server.tool(
"list_supported_assets",
"List all assets with available Proof of Reserve feeds. Shows asset details and data availability.",
{
category: z.enum(["stablecoins", "wrapped_tokens", "precious_metals", "all"]).default("all").describe("Asset category filter"),
network: z.string().optional().describe("Filter by network"),
includeTestnets: z.boolean().default(false).describe("Include testnet assets")
},
async ({ category = "all", network, includeTestnets = false }) => {
try {
if (network) {
const networkValidation = validateNetwork(network)
if (!networkValidation.valid) {
throw new Error(networkValidation.error)
}
}
// Mock supported assets
const allAssets = [
{
symbol: "WBTC",
name: "Wrapped Bitcoin",
category: "wrapped_tokens",
network: "ethereum",
feedAddress: "0x8dD1C9421A7674bDADE7F33dDA5725317EEdB723",
updateFrequency: "Daily",
attestor: "BitGo",
status: "active"
},
{
symbol: "USDC",
name: "USD Coin",
category: "stablecoins",
network: "ethereum",
feedAddress: "0x3b2b7DA4b1c3A7B8F5e5eA3b58b1b9b8c8e8f8a8",
updateFrequency: "Daily",
attestor: "Centre",
status: "active"
},
{
symbol: "PAXG",
name: "PAX Gold",
category: "precious_metals",
network: "ethereum",
feedAddress: "0x9b5dE3bD5eE6BfB2d5D9E8b1b5f5e5D8c8e8f8a8",
updateFrequency: "Daily",
attestor: "Paxos",
status: "active"
},
{
symbol: "TUSD",
name: "TrueUSD",
category: "stablecoins",
network: "ethereum",
feedAddress: "0x1b5dE3bD5eE6BfB2d5D9E8b1b5f5e5D8c8e8f8a8",
updateFrequency: "Daily",
attestor: "TrustToken",
status: "active"
}
]
let filteredAssets = allAssets
if (category !== "all") {
filteredAssets = allAssets.filter(asset => asset.category === category)
}
if (network) {
filteredAssets = filteredAssets.filter(asset => asset.network.toLowerCase() === network.toLowerCase())
}
const result = {
totalAssets: filteredAssets.length,
category,
network: network ? formatNetworkName(network) : "all",
includeTestnets,
supportedCategories: ["stablecoins", "wrapped_tokens", "precious_metals"],
assets: filteredAssets.map(asset => ({
...asset,
network: formatNetworkName(asset.network),
feedAddress: formatAddress(asset.feedAddress, true)
}))
}
return {
content: [
{
type: "text",
text: `Proof of Reserve supported assets\n\n` +
`Total Assets: ${result.totalAssets}\n` +
`Category: ${category}\n` +
`Network: ${result.network}\n` +
`Supported Categories: ${result.supportedCategories.join(", ")}\n\n` +
`Assets:\n${filteredAssets.map(a => `- ${a.symbol} (${a.name})`).join("\n")}\n\n` +
`Full Details:\n${JSON.stringify(result, null, 2)}`
}
]
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error listing supported assets: ${error instanceof Error ? error.message : String(error)}`
}
]
}
}
}
)
// Tool: Get Reserve History
server.tool(
"get_reserve_history",
"Get historical reserve data for an asset. Shows reserve levels over time and collateralization trends.",
{
asset: z.string().describe("Asset symbol"),
startDate: z.string().optional().describe("Start date (ISO format, default: 30 days ago)"),
endDate: z.string().optional().describe("End date (ISO format, default: now)"),
network: z.string().optional().describe("Blockchain network")
},
async ({ asset, startDate, endDate, network = "ethereum" }) => {
try {
const networkValidation = validateNetwork(network)
if (!networkValidation.valid) {
throw new Error(networkValidation.error)
}
// Mock historical data
const daysBack = startDate ? Math.floor((Date.now() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24)) : 30
const dataPoints = Math.min(daysBack, 30)
const historicalData = []
for (let i = dataPoints; i >= 0; i--) {
const date = new Date(Date.now() - i * 24 * 60 * 60 * 1000)
const baseSupply = 164123.45
const variance = (Math.random() - 0.5) * 0.02 // ±1% variance
const supply = baseSupply * (1 + variance)
const backing = supply * (1 + Math.random() * 0.001) // Slightly over-collateralized
historicalData.push({
date: formatTimestamp(date.getTime() / 1000),
totalSupply: `${supply.toFixed(2)} ${asset.toUpperCase()}`,
backingAssets: asset.toUpperCase() === "WBTC" ? `${backing.toFixed(2)} BTC` : `$${(backing * 43000).toFixed(2)} USD`,
collateralizationRatio: `${((backing / supply) * 100).toFixed(3)}%`,
reserveChange: i === dataPoints ? "0.00%" : `${((Math.random() - 0.5) * 0.5).toFixed(2)}%`
})
}
const result = {
asset: asset.toUpperCase(),
network: formatNetworkName(network),
timeRange: {
startDate: startDate || formatTimestamp((Date.now() / 1000) - (daysBack * 24 * 60 * 60)),
endDate: endDate || formatTimestamp(Date.now() / 1000)
},
dataPoints: historicalData.length,
summary: {
averageCollateralization: "100.02%",
maxCollateralization: "100.08%",
minCollateralization: "99.98%",
totalAudits: dataPoints
},
history: historicalData
}
return {
content: [
{
type: "text",
text: `Reserve history for ${asset.toUpperCase()}\n\n` +
`Time Range: ${result.timeRange.startDate} to ${result.timeRange.endDate}\n` +
`Data Points: ${result.dataPoints}\n` +
`Network: ${result.network}\n\n` +
`Summary:\n` +
`- Average Collateralization: ${result.summary.averageCollateralization}\n` +
`- Max Collateralization: ${result.summary.maxCollateralization}\n` +
`- Min Collateralization: ${result.summary.minCollateralization}\n\n` +
`Recent Data Points:\n${historicalData.slice(-5).map(h => `${h.date}: ${h.collateralizationRatio}`).join("\n")}\n\n` +
`Full Details:\n${JSON.stringify(result, null, 2)}`
}
]
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error getting reserve history: ${error instanceof Error ? error.message : String(error)}`
}
]
}
}
}
)
}