Agent 프리컴파일
Agent 프리컴파일은 디스커버리와 인덱싱 조회를 담당합니다. ERC-8004 IdentityRegistry와 ReputationRegistry 주소를 해석하고 getAgentIds(wallet)에 응답하며, 실패는 공유 IPrecompile 오류 집합을 통해 반환됩니다.
0x100000000000000000000000000000000000000A의 Agent 프리컴파일은 view 전용 surface입니다. getParams()는 이 체인이 해석하는 ERC-8004 identityRegistry와 reputationRegistry 주소를 반환하고, getAgentIds(wallet, pageRequest)는 지갑에서 agent ID로의 페이지네이션 역방향 조회를 체인 측 인덱스에서 읽어 반환합니다. 등록, attestation, 폐지, 메타데이터 등 그 외의 agent 작업은 0x8004000000000000000000000000000000000001의 ERC-8004 IdentityRegistry preinstall을 직접 호출합니다.
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()가 런타임에 주소를 반환합니다. 둘째, 지갑에 속한 모든 agent를 찾기 위해 IdentityRegistry 스토리지를 온체인에서 순회하는 비용이 지나치게 크므로, 프리컴파일이 agent 등록과 이전 시점마다 유지되는 체인 측 역방향 인덱스에서 읽습니다. getAgentIds가 프리컴파일에 존재하는 유일한 이유이며, 그 외의 모든 agent 작업은 표준 레지스트리를 직접 호출합니다.오류 인터페이스 — 모든 마루 프리컴파일과 공유
IAgent는
IPrecompile을 상속합니다. 인자 형태 오류는 공유 오류 집합의 타입 지정 오류로 반환됩니다. 인자 개수가 틀리면 InvalidNumberOfArgs(uint256 expected, uint256 got), wallet 자리에 주소가 아닌 값이 오면 InvalidAddress(string bad), 페이지네이션 튜플 형식이 잘못되면 InvalidPageRequest(string method, uint256 index, string value), 인식하지 못하는 selector에는 UnknownMethod(string methodName)이 반환됩니다. 체인 인덱스 조회가 실패하면 QueryFailed(string queryMethod, string reason)로 반환되며, reason이 알려진 SDK 코드에 매핑되면 공유 SDK 오류 레지스트리로 정규화됩니다. 전체 목록은 precompile-shared-errors에서 확인할 수 있습니다. ABI 하나로 모든 revert 형태를 처리할 수 있습니다.import { 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: "UnknownMethod", inputs: [{ name: "methodName", type: "string" }] },
] as const;
try {
// await publicClient.readContract({ ... })
} catch (err: any) {
const decoded = decodeErrorResult({ abi: iPrecompileErrorsAbi, data: err.data });
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);