Skip to content

Direct On-Chain Interaction

You can interact with the Agent Registry contracts directly using ethers.js or web3.py, without the SDK. This is useful for integrating the registry into existing applications or for read-only queries where no SDK dependency is needed.


Contract Addresses (Base Sepolia)

Contract Address
Agentenregister 0x2EFaB5B3BEf49E56a6Ce1dcB1A39EF63C312EA23
MinimalForwarder 0x70c2fdD0CDada6b43195981928D76f5D32AE29e5
Chain ID 84532

Read-Only Queries

Minimal ABI (Read Functions)

The following ABI subset covers all read-only functions:

const ABI = [
  "function getAgent(uint256 agentId) view returns (tuple(uint256 agentId, address creator, address haftungsperson, address agentWallet, bytes32 constitutionHash, bytes32 capabilityHash, string operationalScope, uint256 parentAgentId, uint256 generation, bool selfModifying, uint64 registeredAt, uint64 lastAttestation, uint64 lastRevenueReport, uint8 status))",
  "function isRegisteredAndCompliant(address agentWallet) view returns (bool)",
  "function isRegistered(address agentWallet) view returns (bool)",
  "function getAgentByWallet(address wallet) view returns (tuple(uint256 agentId, address creator, address haftungsperson, address agentWallet, bytes32 constitutionHash, bytes32 capabilityHash, string operationalScope, uint256 parentAgentId, uint256 generation, bool selfModifying, uint64 registeredAt, uint64 lastAttestation, uint64 lastRevenueReport, uint8 status))",
  "function getChildren(uint256 agentId) view returns (uint256[])",
  "function getRevenueHistory(uint256 agentId) view returns (tuple(uint256 agentId, uint256 amount, string currency, string category, uint64 periodStart, uint64 periodEnd, uint64 reportedAt)[])",
  "function complianceStatus(uint256 agentId) view returns (bool isActive, bool attestationCurrent, uint64 secondsSinceAttestation, uint256 childCount, uint8 status)",
  "function nextAgentId() view returns (uint256)",
  "function walletToAgent(address) view returns (uint256)",
  "function getChildCount(uint256 agentId) view returns (uint256)",
];
ABI = [
    {"inputs":[{"name":"agentId","type":"uint256"}],"name":"getAgent","outputs":[{"components":[{"name":"agentId","type":"uint256"},{"name":"creator","type":"address"},{"name":"haftungsperson","type":"address"},{"name":"agentWallet","type":"address"},{"name":"constitutionHash","type":"bytes32"},{"name":"capabilityHash","type":"bytes32"},{"name":"operationalScope","type":"string"},{"name":"parentAgentId","type":"uint256"},{"name":"generation","type":"uint256"},{"name":"selfModifying","type":"bool"},{"name":"registeredAt","type":"uint64"},{"name":"lastAttestation","type":"uint64"},{"name":"lastRevenueReport","type":"uint64"},{"name":"status","type":"uint8"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},
    {"inputs":[{"name":"agentWallet","type":"address"}],"name":"isRegisteredAndCompliant","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},
    {"inputs":[{"name":"agentWallet","type":"address"}],"name":"isRegistered","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},
    {"inputs":[{"name":"agentId","type":"uint256"}],"name":"getChildren","outputs":[{"name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},
    {"inputs":[{"name":"agentId","type":"uint256"}],"name":"getRevenueHistory","outputs":[{"components":[{"name":"agentId","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"currency","type":"string"},{"name":"category","type":"string"},{"name":"periodStart","type":"uint64"},{"name":"periodEnd","type":"uint64"},{"name":"reportedAt","type":"uint64"}],"name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},
    {"inputs":[{"name":"agentId","type":"uint256"}],"name":"complianceStatus","outputs":[{"name":"isActive","type":"bool"},{"name":"attestationCurrent","type":"bool"},{"name":"secondsSinceAttestation","type":"uint64"},{"name":"childCount","type":"uint256"},{"name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},
    {"inputs":[],"name":"nextAgentId","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},
    {"inputs":[{"name":"","type":"address"}],"name":"walletToAgent","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},
]

Get an Agent Record

const { ethers } = require("ethers");

const provider = new ethers.JsonRpcProvider("https://sepolia.base.org");
const registry = new ethers.Contract(
  "0x2EFaB5B3BEf49E56a6Ce1dcB1A39EF63C312EA23",
  ABI,
  provider,
);

const agent = await registry.getAgent(1);
console.log("Agent ID:", Number(agent.agentId));
console.log("Creator:", agent.creator);
console.log("Haftungsperson:", agent.haftungsperson);
console.log("Wallet:", agent.agentWallet);
console.log("Scope:", agent.operationalScope);
console.log("Generation:", Number(agent.generation));
console.log("Status:", ["Active", "Suspended", "Revoked", "Terminated"][agent.status]);
from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://sepolia.base.org"))
registry = w3.eth.contract(
    address="0x2EFaB5B3BEf49E56a6Ce1dcB1A39EF63C312EA23",
    abi=ABI,
)

agent = registry.functions.getAgent(1).call()
STATUS_NAMES = ["Active", "Suspended", "Revoked", "Terminated"]

print(f"Agent ID: {agent[0]}")
print(f"Creator: {agent[1]}")
print(f"Haftungsperson: {agent[2]}")
print(f"Wallet: {agent[3]}")
print(f"Scope: {agent[6]}")
print(f"Generation: {agent[8]}")
print(f"Status: {STATUS_NAMES[agent[13]]}")

KYA Compliance Check

The core query for infrastructure providers:

const isCompliant = await registry.isRegisteredAndCompliant("0xAgentWallet");
if (isCompliant) {
  console.log("Agent is registered and compliant -- provision services");
} else {
  console.log("DENY: agent not registered or attestation expired");
}
is_compliant = registry.functions.isRegisteredAndCompliant(
    "0xAgentWallet"
).call()

if is_compliant:
    print("Agent is registered and compliant -- provision services")
else:
    print("DENY: agent not registered or attestation expired")

Get Compliance Status

const [isActive, attestationCurrent, secondsSince, childCount, status] =
  await registry.complianceStatus(1);

console.log("Active:", isActive);
console.log("Attestation current:", attestationCurrent);
console.log("Seconds since attestation:", Number(secondsSince));
console.log("Children:", Number(childCount));
result = registry.functions.complianceStatus(1).call()
print(f"Active: {result[0]}")
print(f"Attestation current: {result[1]}")
print(f"Seconds since attestation: {result[2]}")
print(f"Children: {result[3]}")

Get Children and Revenue

// Children
const children = await registry.getChildren(1);
console.log("Children:", children.map(Number));

// Revenue history
const history = await registry.getRevenueHistory(1);
for (const report of history) {
  console.log(`${Number(report.amount)} ${report.currency} (${report.category})`);
}
# Children
children = registry.functions.getChildren(1).call()
print(f"Children: {children}")

# Revenue history
history = registry.functions.getRevenueHistory(1).call()
for report in history:
    print(f"{report[1]} {report[2]} ({report[3]})")

Direct Registration (Paying Gas)

If your agent holds ETH and you want to call the contract directly without a relayer, you can submit transactions yourself.

When to use direct mode

Direct registration is useful when:

  • Your agent already holds ETH
  • You do not want to depend on a relayer
  • You are running your own infrastructure

Write ABI

const WRITE_ABI = [
  "function registerAgent(address _haftungsperson, address _agentWallet, bytes32 _constitutionHash, bytes32 _capabilityHash, string _operationalScope, uint256 _parentAgentId, bool _selfModifying) returns (uint256 agentId)",
  "function attestCompliance(uint256 agentId)",
  "function reportRevenue(uint256 agentId, uint256 amount, string currency, string category, uint64 periodStart, uint64 periodEnd)",
  "function updateCapability(uint256 agentId, bytes32 newCapabilityHash)",
  "function updateConstitution(uint256 agentId, bytes32 newConstitutionHash)",
  "function terminateSelf(uint256 agentId)",
];

Register an Agent

const { ethers } = require("ethers");

const provider = new ethers.JsonRpcProvider("https://sepolia.base.org");
const wallet = new ethers.Wallet("0xYOUR_PRIVATE_KEY", provider);
const registry = new ethers.Contract(
  "0x2EFaB5B3BEf49E56a6Ce1dcB1A39EF63C312EA23",
  [...ABI, ...WRITE_ABI],
  wallet,
);

// Hash capabilities
const capabilities = ["web_browsing", "code_execution"];
const capHash = ethers.keccak256(
  ethers.toUtf8Bytes(JSON.stringify([...capabilities].sort())),
);

// Hash constitution
const constHash = ethers.keccak256(
  ethers.toUtf8Bytes("I shall not harm humans."),
);

const tx = await registry.registerAgent(
  "0xHaftungspersonWallet",      // haftungsperson
  "0xAgentWallet",               // agentWallet
  constHash,                     // constitutionHash
  capHash,                       // capabilityHash
  "Automated research",          // operationalScope
  0,                             // parentAgentId (0 = root)
  false,                         // selfModifying
  { gasLimit: 800000 },
);

const receipt = await tx.wait();
console.log("TX:", receipt.hash);

// Parse the AgentRegistered event to get the agent ID
const iface = new ethers.Interface([
  "event AgentRegistered(uint256 indexed agentId, address indexed creator, address haftungsperson, uint256 parentAgentId, uint256 generation)",
]);

for (const log of receipt.logs) {
  try {
    const parsed = iface.parseLog({ topics: log.topics, data: log.data });
    if (parsed?.name === "AgentRegistered") {
      console.log("Agent ID:", Number(parsed.args.agentId));
    }
  } catch {}
}
from web3 import Web3
from eth_account import Account
import json

w3 = Web3(Web3.HTTPProvider("https://sepolia.base.org"))
account = Account.from_key("0xYOUR_PRIVATE_KEY")

WRITE_ABI = [
    {"inputs":[{"name":"_haftungsperson","type":"address"},{"name":"_agentWallet","type":"address"},{"name":"_constitutionHash","type":"bytes32"},{"name":"_capabilityHash","type":"bytes32"},{"name":"_operationalScope","type":"string"},{"name":"_parentAgentId","type":"uint256"},{"name":"_selfModifying","type":"bool"}],"name":"registerAgent","outputs":[{"name":"agentId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},
]

registry = w3.eth.contract(
    address="0x2EFaB5B3BEf49E56a6Ce1dcB1A39EF63C312EA23",
    abi=ABI + WRITE_ABI,
)

# Hash capabilities
capabilities = sorted(["web_browsing", "code_execution"])
cap_hash = Web3.keccak(text=json.dumps(capabilities, separators=(",", ":")))

# Hash constitution
const_hash = Web3.keccak(text="I shall not harm humans.")

tx = registry.functions.registerAgent(
    "0xHaftungspersonWallet",
    "0xAgentWallet",
    const_hash,
    cap_hash,
    "Automated research",
    0,              # parentAgentId
    False,          # selfModifying
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "gas": 800000,
    "maxFeePerGas": w3.eth.gas_price * 2,
    "maxPriorityFeePerGas": w3.to_wei(0.001, "gwei"),
    "chainId": 84532,
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"TX: {tx_hash.hex()}, Status: {receipt.status}")

Attest Compliance

const tx = await registry.attestCompliance(1, { gasLimit: 200000 });
await tx.wait();
console.log("Compliance attested");
tx = registry.functions.attestCompliance(1).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "gas": 200000,
    "chainId": 84532,
})
signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)

Report Revenue

const now = Math.floor(Date.now() / 1000);

const tx = await registry.reportRevenue(
  1,                        // agentId
  15000,                    // amount (cents)
  "USDC",                   // currency
  "data_collection",        // category
  now - 7 * 86400,          // periodStart
  now,                      // periodEnd
  { gasLimit: 300000 },
);
await tx.wait();
import time

now = int(time.time())

tx = registry.functions.reportRevenue(
    1,                      # agentId
    15000,                  # amount (cents)
    "USDC",                 # currency
    "data_collection",      # category
    now - 7 * 86400,        # periodStart
    now,                    # periodEnd
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "gas": 300000,
    "chainId": 84532,
})
signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)

Using the REST API Instead

If you prefer HTTP over direct blockchain calls, see the REST API Reference for a full HTTP wrapper around the registry contract.