Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.silvana.one/llms.txt

Use this file to discover all available pages before exploring further.

Now, let’s see how we can build an agent.
The same crates the CLI uses are available as Rust libraries. Import them from a path or git and build custom agents, batch tools, or test harnesses.

Example - Buy CC

We take a canonical example – buying CantonCoins. The agent lives at examples/buy_cc. It buys CC on CC-USDC. examples/buy_cc/Cargo.toml:
{
  "name": "buy-cc-example",
  "version": "0.1.0",
  "type": "module",
  "dependencies": {
    "cloud-agent": "file:../crates/cloud-agent",
    "agent-logic": "file:../crates/agent-logic",
    "orderbook-proto": "file:../crates/orderbook-proto",
    "dotenv": "^0.15.0",
    "commander": "^4.0.0",
    "pino": "^0.3.0"
  }
}
examples/buy_cc/src/main.rs (abridged):
import "dotenv/config";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";

import { BaseConfig } from "agent-logic/config";
import { newConfirmLock } from "agent-logic/confirm";
import { LiquidityManager } from "agent-logic/liquidity";
import { MulticallSettler } from "cloud-agent/accept-settle";
import { CloudSettlementBackend } from "cloud-agent/backend";
import { runFillLoop, FillDirection, type FillParams } from "cloud-agent/fill-loop";
import { populateInstruments } from "cloud-agent";

type Args = {
  amount: number;
  maxPrice?: number;
  pollPeriod: number;
  minSettlement: number;
};

async function parseArgs(): Promise<Args> {
  const argv = await yargs(hideBin(process.argv))
    .option("amount", {
      type: "number",
      demandOption: true,
      describe: "Amount to buy",
    })
    .option("max_price", {
      type: "number",
      describe: "Maximum acceptable price",
    })
    .option("poll_period", {
      type: "number",
      default: 600,
      describe: "Polling period in seconds",
    })
    .option("min_settlement", {
      type: "number",
      default: 5.0,
      describe: "Minimum settlement amount",
    })
    .strict()
    .parse();

  return {
    amount: argv.amount,
    maxPrice: argv.max_price,
    pollPeriod: argv.poll_period,
    minSettlement: argv.min_settlement,
  };
}

async function main(): Promise<void> {
  const args = await parseArgs();

  console.info("Starting buy flow");

  // 1. Load config from .env + agent.toml
  const config = await BaseConfig.loadOrDefaults("agent.toml");

  // 2. Fetch instrument registry from orderbook-rpc
  await populateInstruments(config);

  // 3. Create backend
  const confirmLock = newConfirmLock();
  const lm = new LiquidityManager(
    config.feeReserveCc,
    config.liquidityMargin,
    config.flowEmaWindowHours,
    config.depletionMaxHours,
    config.depletionMinHours
  );

  const backend = new CloudSettlementBackend(
    structuredClone(config),
    false,
    false,
    false,
    false,
    confirmLock,
    lm
  );

  // 4. Create settler for atomic multicall settlement
  const settler = new MulticallSettler({
    config: structuredClone(config),
    amuletCache: backend.amuletCache(),
    verbose: false,
    dryRun: false,
    force: false,
    confirm: false,
    confirmLock,
  });

  // 5. Run the fill loop
  const params: FillParams = {
    direction: FillDirection.Buy,
    marketId: "CC-USDC",
    totalAmount: args.amount,
    priceLimit: args.maxPrice,
    minSettlement: args.minSettlement,
    maxSettlement: args.amount,
    intervalSecs: args.pollPeriod,
  };

  const _backendGuard = backend;

  await runFillLoop(config, settler, params, null, null);
}

main().catch((error) => {
  console.error("Fatal error:", error);
  process.exit(1);
})
To launch the agent, run this command:
cargo run -p buy-cc-example -- --amount 10.0 --max-price 0.16 --poll-period 600
CC Buying agent is launched! Great job!