diff --git a/cli/client/collect-escrow.ts b/cli/client/collect-escrow.ts index b600ed3..5ed3f7c 100644 --- a/cli/client/collect-escrow.ts +++ b/cli/client/collect-escrow.ts @@ -6,7 +6,7 @@ */ import { parseArgs } from "util"; -import { createWalletClient, http, publicActions } from "viem"; +import { createWalletClient, http, publicActions, formatEther } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { existsSync, readFileSync } from "fs"; import { resolve, dirname, join } from "path"; @@ -85,7 +85,7 @@ async function main() { const escrowUid = args["escrow-uid"]; const fulfillmentUid = args["fulfillment-uid"]; const privateKey = args["private-key"] || process.env.PRIVATE_KEY; - const deploymentPath = args.deployment || "./cli/deployments/devnet.json"; + const deploymentPath = args.deployment; // Validate required parameters if (!escrowUid) { @@ -137,7 +137,7 @@ async function main() { // Check balance const balance = await walletClient.getBalance({ address: account.address }); - console.log(`💰 ETH balance: ${parseFloat((balance / 10n ** 18n).toString()).toFixed(4)} ETH\n`); + console.log(`💰 ETH balance: ${parseFloat(formatEther(balance)).toFixed(4)} ETH\n`); if (balance === 0n) { console.error("❌ Error: Account has no ETH for gas. Please fund the account first."); diff --git a/cli/client/create-escrow.ts b/cli/client/create-escrow.ts index c15ca20..2d1b6cd 100644 --- a/cli/client/create-escrow.ts +++ b/cli/client/create-escrow.ts @@ -7,7 +7,7 @@ */ import { parseArgs } from "util"; -import { createWalletClient, http, publicActions, parseEther } from "viem"; +import { createWalletClient, http, publicActions, parseEther, formatEther } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { existsSync, readFileSync } from "fs"; import { resolve, dirname, join } from "path"; @@ -182,7 +182,7 @@ Fulfillment: {{obligation}}`; // Check balance const balance = await walletClient.getBalance({ address: account.address }); - console.log(`💰 ETH balance: ${parseFloat((balance / 10n ** 18n).toString()).toFixed(4)} ETH\n`); + console.log(`💰 ETH balance: ${parseFloat(formatEther(balance)).toFixed(4)} ETH\n`); if (balance === 0n) { console.error("❌ Error: Account has no ETH for gas. Please fund the account first."); diff --git a/cli/client/fulfill-escrow.ts b/cli/client/fulfill-escrow.ts index 721e1c0..e3c33de 100644 --- a/cli/client/fulfill-escrow.ts +++ b/cli/client/fulfill-escrow.ts @@ -7,7 +7,7 @@ */ import { parseArgs } from "util"; -import { createWalletClient, http, publicActions } from "viem"; +import { createWalletClient, http, publicActions, formatEther } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { existsSync, readFileSync } from "fs"; import { resolve, dirname, join } from "path"; @@ -151,7 +151,7 @@ async function main() { // Check balance const balance = await walletClient.getBalance({ address: account.address }); - console.log(`💰 ETH balance: ${parseFloat((balance / 10n ** 18n).toString()).toFixed(4)} ETH\n`); + console.log(`💰 ETH balance: ${parseFloat(formatEther(balance)).toFixed(4)} ETH\n`); if (balance === 0n) { console.error("❌ Error: Account has no ETH for gas. Please fund the account first."); diff --git a/cli/server/oracle.ts b/cli/server/oracle.ts index 38ab48e..59eea41 100644 --- a/cli/server/oracle.ts +++ b/cli/server/oracle.ts @@ -2,7 +2,6 @@ import { parseArgs } from "util"; import { parseAbiParameters, createWalletClient, http, publicActions } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -import { foundry } from "viem/chains"; import { makeLLMClient } from "../.."; import { existsSync, readFileSync } from "fs"; import { resolve, dirname, join } from "path"; @@ -15,7 +14,8 @@ import { getCurrentEnvironment, getDeploymentPath, loadEnvFile, - loadDeploymentWithDefaults + loadDeploymentWithDefaults, + getChainFromNetwork } from "../utils.js"; // Get the directory name for ESM modules @@ -187,10 +187,11 @@ async function main() { console.log(` ⏱️ Polling Interval: ${pollingInterval}ms\n`); // Create wallet client + const chain = getChainFromNetwork(deployment.network); const account = privateKeyToAccount(privateKey as `0x${string}`); const walletClient = createWalletClient({ account, - chain: foundry, + chain, transport: http(deployment.rpcUrl), }).extend(publicActions) as any; @@ -256,12 +257,25 @@ async function main() { console.log(` Obligation: "${obligationItem}"`); const trustedOracleDemandData = client.arbiters.general.trustedOracle.decodeDemand(demand); + console.log(` DEBUG - trustedOracleDemandData:`, trustedOracleDemandData); + const nlaDemandData = llmClient.llm.decodeDemand(trustedOracleDemandData.data); + console.log(` DEBUG - nlaDemandData:`, nlaDemandData); + console.log(` Demand: "${nlaDemandData.demand}"`); + console.log(` Provider: ${nlaDemandData.arbitrationProvider}`); console.log(` Model: ${nlaDemandData.arbitrationModel}`); + // Validate the demand data before proceeding + if (!nlaDemandData.demand || !nlaDemandData.arbitrationModel || nlaDemandData.arbitrationModel.includes('\u0000')) { + console.error(` ❌ Invalid demand data - contains null bytes or empty fields`); + console.error(` This usually means the demand was encoded incorrectly`); + console.error(` Skipping this attestation (throwing error to avoid on-chain recording)...\n`); + throw new Error('Invalid demand data - skipping attestation'); + } + // Perform arbitration using LLM - console.log(` 🤔 Arbitrating with AI...`); + console.log(` 🤔 Arbitrating with ${nlaDemandData.arbitrationProvider}...`); const result = await llmClient.llm.arbitrate( nlaDemandData, obligationItem @@ -271,14 +285,21 @@ async function main() { return result; } catch (error) { console.error(` ❌ Error during arbitration:`, error); - throw error; + console.error(` Continuing to listen for new requests...\n`); + return false; // Return false instead of throwing to keep oracle running } }, { onAfterArbitrate: async (decision: any) => { - console.log(` 📝 Arbitration decision recorded on-chain`); - console.log(` Decision UID: ${decision.attestation.uid}`); - console.log(` Result: ${decision.decision ? "✅ Fulfilled" : "❌ Not Fulfilled"}\n`); + try { + console.log(` 📝 Arbitration decision recorded on-chain`); + console.log(` Decision UID: ${decision.attestation.uid}`); + console.log(` Result: ${decision.decision ? "✅ Fulfilled" : "❌ Not Fulfilled"}\n`); + } catch (error: any) { + console.error(` ⚠️ Failed to record arbitration on-chain:`, error.message); + console.error(` This may be due to transaction conflicts or gas issues`); + console.error(` Continuing to listen for new requests...\n`); + } }, pollingInterval, }, diff --git a/cli/utils.ts b/cli/utils.ts index 9a8de9e..1dd7bff 100644 --- a/cli/utils.ts +++ b/cli/utils.ts @@ -167,28 +167,22 @@ export function loadDeploymentWithDefaults(deploymentFilePath?: string): { const content = readFileSync(actualPath, "utf-8"); const deployment = JSON.parse(content); - let finalAddresses: Record = deployment.addresses || {}; - const chainId = deployment.chainId; + let finalAddresses: Record = {}; + + // Start with default addresses from contractAddresses if available + // contractAddresses is indexed by chain name (e.g., "Base Sepolia", "foundry") + const chainName = deployment.network; + if (contractAddresses[chainName]) { + finalAddresses = { ...contractAddresses[chainName] }; + } - // If deployment addresses exist, merge with defaults + // Override with deployment addresses, but only if they're not empty strings if (deployment.addresses && Object.keys(deployment.addresses).length > 0) { - // Check if we have default addresses for this chain - if (contractAddresses[chainId]) { - // Start with default addresses - finalAddresses = { ...contractAddresses[chainId] }; - - // Override with deployment addresses, but only if they're not empty strings - for (const [key, value] of Object.entries(deployment.addresses)) { - if (value && value !== "") { - finalAddresses[key] = value as string; - } + for (const [key, value] of Object.entries(deployment.addresses)) { + if (value && value !== "") { + finalAddresses[key] = value as string; } } - } else { - // If no deployment addresses at all, use defaults if available - if (contractAddresses[chainId]) { - finalAddresses = { ...contractAddresses[chainId] }; - } } return {