feat: base-sepolia

This commit is contained in:
ngoc 2026-02-01 15:10:18 +07:00
parent 226a894aa1
commit 2f1368bb9c
No known key found for this signature in database
GPG Key ID: 51FE6110113A5C32
5 changed files with 48 additions and 33 deletions

View File

@ -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.");

View File

@ -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.");

View File

@ -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.");

View File

@ -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,
},

View File

@ -167,28 +167,22 @@ export function loadDeploymentWithDefaults(deploymentFilePath?: string): {
const content = readFileSync(actualPath, "utf-8");
const deployment = JSON.parse(content);
let finalAddresses: Record<string, string> = deployment.addresses || {};
const chainId = deployment.chainId;
let finalAddresses: Record<string, string> = {};
// 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 {