Agent 프리컴파일
Agent 프리컴파일은 디스커버리와 인덱싱 조회를 담당합니다. ERC-8004 IdentityRegistry와 ReputationRegistry 주소를 해석하고 getAgentIds(wallet)에 응답하며, 실패는 공유 IPrecompile 오류 집합을 통해 반환됩니다.
0x100000000000000000000000000000000000000A의 Agent 프리컴파일은 view 전용 surface입니다. getParams()는 이 체인이 해석하는 ERC-8004 identityRegistry와 reputationRegistry 주소를 반환하고, getAgentIds(wallet, pageRequest)는 ERC-8004 에이전트 지갑이 wallet인 agent ID를 체인 측 인덱스에서 읽어 페이지네이션으로 반환합니다. 등록, 에이전트 URI, 메타데이터, 에이전트 지갑, ERC-721 소유권 같은 그 외의 작업은 0x8004000000000000000000000000000000000001의 ERC-8004 IdentityRegistry preinstall을 직접 호출하며, 이 레지스트리에는 attest나 revoke 함수가 없습니다.
Solidity 인터페이스
IAgent.sol 그대로입니다. IAgent가 IPrecompile을 상속하므로 자체 오류 타입을 선언하지 않으며, 모든 실패는 아래에서 설명하는 공유 오류 인터페이스를 사용합니다.import {PageRequest, PageResponse} from "cosmos-evm-contracts/precompiles/common/Types.sol";
import {IPrecompile} from "../common/interfaces/IPrecompile.sol";
interface IAgent is IPrecompile {
struct Params {
address identityRegistry;
address reputationRegistry;
}
function getParams() external view returns (Params memory);
function getAgentIds(address wallet, PageRequest calldata pageRequest)
external
view
returns (uint256[] memory agentIds, PageResponse calldata pageResponse);
} 이 프리컴파일이 존재하는 이유
두 가지 문제를 해결합니다. 첫째, dApp이 ERC-8004 레지스트리 주소를 네트워크별로 하드코딩하지 않도록
getParams()가 런타임에 주소를 반환합니다. 둘째, 컨트랙트에서 IdentityRegistry 스토리지를 순회하는 비용이 지나치게 크므로, 프리컴파일은 에이전트 지갑을 키로 하는 체인 측 인덱스에서 읽습니다. 이 인덱스는 에이전트가 등록될 때(등록자가 최초 지갑입니다)와 지갑이 바뀔 때 기록되고, 에이전트 NFT가 이전되면 해당 항목이 지워집니다. 즉 "이 지갑을 쓰는 에이전트"에 답할 뿐 "이 주소가 소유한 에이전트"에는 답하지 않습니다. 소유 관계는 레지스트리의 ERC-721 balanceOf와 Transfer 이벤트로 확인합니다. 그 외의 모든 agent 작업은 레지스트리를 직접 호출합니다.오류 인터페이스 — 모든 마루 프리컴파일과 공유
IAgent는
IPrecompile을 상속합니다. 메서드와 맞지 않는 calldata는 UnknownMethod가 아니라 ABISetupFailed(string reason)로 revert됩니다. 알 수 없는 selector이면 사유가 no method with id: 0x…이고, 인자가 짧거나 pageRequest 튜플을 디코딩할 수 없으면 ABI 디코더의 메시지가 사유가 됩니다. 마지막 인자 뒤에 붙은 바이트는 무시되며, 인자 개수가 틀려도 InvalidNumberOfArgs는 발생하지 않습니다. 체인 측 인덱스가 조회를 거절하면(예: pageRequest에 key와 offset을 모두 지정한 경우) getAgentIds는 QueryFailed(string queryMethod, string reason)로 revert됩니다. 전체 목록은 precompile-shared-errors에서 확인할 수 있습니다. ABI 하나로 모든 revert 형태를 처리할 수 있습니다.import { BaseError, ContractFunctionRevertedError, decodeErrorResult } from "viem";
const iPrecompileErrorsAbi = [
{ type: "error", name: "InvalidNumberOfArgs",
inputs: [{ name: "expected", type: "uint256" }, { name: "got", type: "uint256" }] },
{ type: "error", name: "InvalidAddress", inputs: [{ name: "bad", type: "string" }] },
{ type: "error", name: "InvalidPageRequest",
inputs: [
{ name: "method", type: "string" },
{ name: "index", type: "uint256" },
{ name: "value", type: "string" },
] },
{ type: "error", name: "QueryFailed",
inputs: [{ name: "queryMethod", type: "string" }, { name: "reason", type: "string" }] },
{ type: "error", name: "ABISetupFailed", inputs: [{ name: "reason", type: "string" }] },
] as const;
try {
// await publicClient.readContract({ ... })
} catch (err) {
// viem은 revert 데이터를 err가 아니라 원인 체인의 ContractFunctionRevertedError에 둡니다.
const revert = err instanceof BaseError ? err.walk((e) => e instanceof ContractFunctionRevertedError) : null;
if (!(revert instanceof ContractFunctionRevertedError) || !revert.raw) throw err;
const decoded = decodeErrorResult({ abi: iPrecompileErrorsAbi, data: revert.raw });
console.error(decoded.errorName, decoded.args);
} 주소 해석 후 IdentityRegistry 사용
getParams()로 IdentityRegistry 주소를 얻은 뒤에는 그 외의 모든 작업이 이 주소를 직접 호출합니다. 프리컴파일은 등록, 이전, 메타데이터 호출을 별도로 노출하지 않습니다. 두 호출을 조합하면 지갑의 agent ID를 페이지네이션으로 조회한 뒤, 각 ID를 레지스트리에서 하이드레이트할 수 있습니다.import { createPublicClient, http } from "viem";
const AGENT_PRECOMPILE = "0x100000000000000000000000000000000000000A" as const;
const agentPrecompileAbi = [
{ type: "function", name: "getParams", stateMutability: "view",
inputs: [],
outputs: [{ type: "tuple", components: [
{ name: "identityRegistry", type: "address" },
{ name: "reputationRegistry", type: "address" },
]}] },
] as const;
const publicClient = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });
const { identityRegistry } = await publicClient.readContract({
address: AGENT_PRECOMPILE,
abi: agentPrecompileAbi,
functionName: "getParams",
});
// 이제 등록/이전/메타데이터는 `identityRegistry`를 직접 호출합니다.
console.log("IdentityRegistry:", identityRegistry);