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:
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));
Get Children and Revenue¶
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¶
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¶
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.