Why This Tutorial Exists

Cross-chain agent development has a reputation for being hard. And historically, it was. You'd need to maintain RPC connections across chains, handle independent nonce tracking, write your own coordination layer, and debug failures that only happened in production on the one chain you hadn't tested.

Valence changes that by providing the orchestration layer as a service. You write the agent logic. Valence handles chain connectivity, state synchronization, trigger evaluation, and coordination. The result is an agent that runs cross-chain in hours, not weeks.

By the end of this tutorial, you'll have a working arbitrage agent running across Ethereum and Arbitrum on Valence's testnet. The same pattern scales to 6 chains and arbitrary complexity.

Prerequisites

Before you start, make sure you have:

You don't need Solidity or Rust. Valence abstracts chain-specific mechanics. If you can write JavaScript, you can build cross-chain agents.

Step 1: Install the SDK and Initialize Your Agent

The Valence JavaScript SDK is the fastest way to get started. Install it from npm, then initialize a client with your API key.

Terminal
# Install the Valence SDK
npm install @valence/sdk

# Initialize your agent project
mkdir my-cross-chain-agent && cd my-cross-chain-agent
node -e "const { Valence } = require('@valence/sdk'); const v = new Valence({ apiKey: 'your-api-key' }); console.log('Connected to', v.chains.length, 'chains');"

Your API key is available in the Valence dashboard under Settings → API Keys. The SDK authenticates automatically and maps your account's connected chains.

Initialize and list connected chains
const { Valence } = require('@valence/sdk');

const valence = new Valence({
  apiKey: process.env.VALENCE_API_KEY,
});

// List all chains available to your account
const chains = valence.chains.list();
console.log("Available chains:", chains);

// The full list on testnet includes:
// ethereum, arbitrum, base, avalanche, solana, chromia

Step 2: Define Your Agent Strategy

Agents on Valence are defined by a configuration object — not a running process you monitor manually. You describe what the agent should do, how it should monitor conditions, and what actions to take. Valence handles the rest.

For this tutorial, we'll build a simple arbitrage agent. The strategy: watch the ETH/USDC price on Ethereum and Arbitrum. When the spread exceeds 0.5%, buy on the cheaper chain and sell on the expensive one.

Define your agent strategy
const agent = {
  name: "eth-arb-agent-v1",
  chains: ["ethereum", "arbitrum"],

  // The agent's core logic: called on every evaluation tick
  evaluate: async (ctx) => {
    const { prices, balances } = ctx.state;

    // Get current ETH/USDC price on each chain
    const ethPrice   = prices.get("ethereum", "ETH");
    const arbPrice  = prices.get("arbitrum", "ETH");

    const spread = Math.abs(arbPrice - ethPrice) / ethPrice;

    // Only act if spread exceeds 0.5%
    if (spread < 0.005) return { action: "wait" };

    // Determine direction: buy on cheaper, sell on expensive
    const buyChain  = ethPrice < arbPrice ? "ethereum"   : "arbitrum";
    const sellChain = ethPrice < arbPrice ? "arbitrum"  : "ethereum";

    // Execute cross-chain arbitrage sequence
    return {
      action: "arbitrage",
      buyChain,
      sellChain,
      buyAsset:  "ETH",
      sellAsset: "ETH",
      amount: balances.min(buyChain, "USDC", 100), // use up to $100 of USDC
      maxSlippage: 0.01, // 1% max slippage tolerance
    };
  },

  // Gas budget: prevent agents from spending more than configured
  gasBudget: {
    maxFeePerGas: 50, // gwei — skip execution if fees too high
    maxPriorityFeePerGas: 2,
  },
};

The agent's evaluate function is called on a schedule — you configure the frequency when you register the agent. The context object (ctx) provides real-time state: prices, balances, gas costs. The function returns either { action: "wait" } (do nothing) or an action object (execute the arbitrage).

Step 3: Register Triggers and Deploy

Triggers are the event conditions that fire your agent's execution cycle. Valence supports price triggers, balance triggers, time-based schedules, and cross-chain ratio conditions. You can combine multiple triggers on a single agent.

Register a price trigger and deploy the agent
// Create the trigger
const trigger = await valence.triggers.create({
  name: "eth-arb-price-spread",
  type: "price_spread",
  chains: ["ethereum", "arbitrum"],
  asset: "ETH",
  quote: "USDC",
  threshold: 0.005, // fire when spread exceeds 0.5%
  evaluationInterval: 30, // check every 30 seconds
});

// Register the agent with the trigger
const deployedAgent = await valence.agents.deploy({
  ...agent,
  triggerId: trigger.id,
});

console.log("Agent deployed: ", deployedAgent.id);
// → Agent deployed: agent_8f3a21b9

Once deployed, the agent runs autonomously. Valence evaluates the trigger condition every 30 seconds. When the spread exceeds 0.5%, the agent's evaluate function fires, and Valence coordinates the execution across both chains.

Execution flow

When a trigger fires: (1) Valence evaluates your evaluate() function. (2) If it returns an action, Valence checks gas budgets and compliance. (3) The action is dispatched to sub-agents on each chain. (4) Execution state is published to your dashboard in real time.

Step 4: Connect Wallets

Agents need wallets to execute transactions. You connect one wallet per chain through Valence's wallet module. Each wallet is independent — separate nonces, separate gas management, same owner key.

Connect wallets across chains
// Add a wallet for each chain the agent needs
const ethWallet = await valence.wallets.connect({
  chain:   "ethereum",
  address: "0xYourEthereumWallet",
  label:   "primary-eth",
});

const arbWallet = await valence.wallets.connect({
  chain:   "arbitrum",
  address: "0xYourArbitrumWallet",
  label:   "primary-arb",
});

// Link wallets to the agent
await valence.agents.linkWallets(deployedAgent.id, [ethWallet.id, arbWallet.id]);

Wallet management is non-custodial. Valence never holds your keys. Wallets are connected via signed messages, not exported. You can revoke access at any time from the dashboard.

Step 5: Monitor and Debug

Once your agent is running, real-time execution data is visible in the Valence dashboard. Every cycle logs trigger evaluations, action decisions, transaction hashes, and gas spent. You can filter by chain, status, or time range.

For programmatic access, the SDK provides a streaming event interface:

Subscribe to agent execution events
// Stream agent execution events in real time
const stream = valence.agents.streamEvents(deployedAgent.id);

stream.on("cycle", (event) => {
  console.log("Evaluation cycle:", event.timestamp);
  console.log("  ETH price (ETH):", event.prices.ethereum);
  console.log("  ETH price (ARB):", event.prices.arbitrum);
  console.log("  Action:", event.action);
});

stream.on("transaction", (tx) => {
  console.log("Tx submitted:", tx.hash, "on", tx.chain);
});

stream.on("error", (err) => {
  console.error("Execution error:", err.message, "on", err.chain);
});

Common Pitfalls

Cross-chain execution has failure modes that don't exist in single-chain development. Here's what to watch for:

⚠ Bridge latency destroying your spread
Cross-chain arbitrage windows are typically 15–90 seconds. If bridging takes 8 minutes, your spread is gone before the second leg executes. Solution: size positions so both legs can complete within the window, or use fast bridges (Hop, Across) and set a maximum bridging time in your agent config.
⚠ Gas optimization across chains
Gas costs are wildly different across chains. Arbitrum is cheap. Ethereum can be expensive. If your agent doesn't check current gas before executing, a spike can turn a profitable arb into a net loss. Valence's gas budget fields let you set maximum acceptable fees — the agent skips execution when costs exceed your threshold.
⚠ State synchronization lag
Chain state updates are not simultaneous. If the trigger fires based on Ethereum state, but Arbitrum's price data is 20 seconds stale, your "spread" is actually a phantom. Valence's evaluation window shows you the data freshness on each chain. If one chain is lagging, add a staleness check in your evaluate() function.
⚠ Nonce conflicts on independent chains
If you submit two transactions to the same chain from the same wallet within seconds, nonces can conflict. Valence manages nonces per-chain automatically, but if you're also submitting transactions manually to those wallets, conflicts are your problem. Keep manual and agent transactions on separate addresses.

What's Next

This tutorial walked through a simple arbitrage agent, but the same pattern applies to any cross-chain strategy: portfolio rebalancing, compliance monitoring, yield optimization, market making. The difference is in the agent logic, not the infrastructure.

To go further: explore multi-chain triggers (evaluating conditions across all 6 testnet chains), compliance layer integration (entity-level position limits enforced by the coordination engine), and the coordination processor for coordinating actions across agents running in parallel.

Start Building

Your first cross-chain agent is one API key away. SDK docs, live testnet, and working examples are in the Valence dashboard.

← Back to Blog