> ## Documentation Index
> Fetch the complete documentation index at: https://daehan-base.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 에이전트 등록 및 신원

> 에이전트의 신원을 온체인에 등록하고, Basename을 발급받고, SIWA(Sign In With Agent)로 서비스에 인증합니다

export const AgentRegistrationDemo = () => {
  const mono = "ui-monospace,'Cascadia Code','Source Code Pro',Menlo,Monaco,Consolas,monospace";
  const col = {
    dim: "#3f3f46",
    muted: "#52525b",
    active: "#60a5fa",
    success: "#34d399",
    code: "#d4d4d8"
  };
  const steps = [{
    delay: 400,
    left: [{
      t: "> npm install @buildersgarden/siwa",
      c: "active"
    }],
    right: [{
      t: "── ERC-8004 Registry ───────────────────",
      c: "dim"
    }, {
      t: "0x8004A169FB4...9f432",
      c: "muted"
    }]
  }, {
    delay: 700,
    left: [{
      t: "  ✓ @buildersgarden/siwa installed",
      c: "success"
    }],
    right: []
  }, {
    delay: 500,
    left: [{
      t: "> Register agent identity onchain...",
      c: "active"
    }],
    right: []
  }, {
    delay: 800,
    left: [{
      t: "  signing registration tx...",
      c: "muted"
    }],
    right: [{
      t: "",
      c: "dim"
    }, {
      t: "── Registering ─────────────────────────",
      c: "dim"
    }, {
      t: "  name:     my-trading-agent",
      c: "code"
    }, {
      t: "  endpoint: https://agent.example.com",
      c: "code"
    }, {
      t: "  pubKey:   0x04c2...f9a1",
      c: "code"
    }]
  }, {
    delay: 900,
    left: [{
      t: "  ✓ tx confirmed · token ID: 4219",
      c: "success"
    }],
    right: [{
      t: "",
      c: "dim"
    }, {
      t: "── Registry entry ──────────────────────",
      c: "dim"
    }, {
      t: "  tokenId:  4219",
      c: "success"
    }, {
      t: "  owner:    0x4a3f...b7c1",
      c: "success"
    }, {
      t: "  block:    28,419,042",
      c: "muted"
    }]
  }, {
    delay: 600,
    left: [{
      t: "> Claim Basename: myagent.base.eth",
      c: "active"
    }],
    right: []
  }, {
    delay: 700,
    left: [{
      t: "  ✓ myagent.base.eth registered",
      c: "success"
    }],
    right: [{
      t: "",
      c: "dim"
    }, {
      t: "── Basename ────────────────────────────",
      c: "dim"
    }, {
      t: "  name:    myagent.base.eth",
      c: "success"
    }, {
      t: "  address: 0x4a3f...b7c1",
      c: "success"
    }]
  }];
  const [leftLines, setLeftLines] = useState([]);
  const [rightLines, setRightLines] = useState([]);
  const [running, setRunning] = useState(false);
  const [done, setDone] = useState(false);
  const [blink, setBlink] = useState(true);
  const leftRef = useRef(null);
  const rightRef = useRef(null);
  useEffect(() => {
    const t = setInterval(() => setBlink(b => !b), 530);
    return () => clearInterval(t);
  }, []);
  useEffect(() => {
    if (leftRef.current) leftRef.current.scrollTop = leftRef.current.scrollHeight;
  }, [leftLines]);
  const play = () => {
    setLeftLines([]);
    setRightLines([]);
    setRunning(true);
    setDone(false);
    let i = 0;
    const next = () => {
      if (i >= steps.length) {
        setRunning(false);
        setDone(true);
        return;
      }
      const s = steps[i];
      setTimeout(() => {
        if (s.left && s.left.length) setLeftLines(prev => [...prev, ...s.left]);
        if (s.right && s.right.length) setRightLines(prev => [...prev, ...s.right]);
        i++;
        next();
      }, s.delay);
    };
    next();
  };
  useEffect(() => {
    setTimeout(play, 350);
  }, []);
  const renderLine = (item, i) => {
    if (!item.t) return <div key={i} style={{
      height: 6
    }} />;
    return <div key={i} style={{
      fontFamily: mono,
      fontSize: 12,
      lineHeight: "20px",
      color: col[item.c] || col.code,
      whiteSpace: "pre"
    }}>{item.t}</div>;
  };
  return <div style={{
    margin: "28px 0",
    borderRadius: 12,
    overflow: "hidden",
    border: "1px solid #27272a",
    background: "#09090b"
  }}>
      <div style={{
    display: "flex",
    alignItems: "center",
    padding: "8px 12px",
    background: "#111113",
    borderBottom: "1px solid #27272a"
  }}>
        <div style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: 28,
    height: 24,
    borderRadius: 6,
    background: "#1e1e20",
    border: "1px solid #27272a",
    marginRight: 10,
    flexShrink: 0
  }}>
          <span style={{
    fontFamily: mono,
    fontSize: 11,
    color: "#71717a",
    userSelect: "none"
  }}>{">"}_</span>
        </div>
        <span style={{
    fontFamily: mono,
    fontSize: 12,
    color: "#52525b"
  }}>Agent Registration</span>
        <div style={{
    flex: 1
  }} />
        <button onClick={play} title="Reset" style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: 28,
    height: 24,
    borderRadius: 6,
    background: "transparent",
    border: "1px solid transparent",
    cursor: "pointer",
    color: "#3f3f46",
    fontSize: 15,
    lineHeight: 1
  }} onMouseEnter={e => {
    e.currentTarget.style.color = "#a1a1aa";
    e.currentTarget.style.background = "#1e1e20";
    e.currentTarget.style.borderColor = "#27272a";
  }} onMouseLeave={e => {
    e.currentTarget.style.color = "#3f3f46";
    e.currentTarget.style.background = "transparent";
    e.currentTarget.style.borderColor = "transparent";
  }}>
          {"\u21ba"}
        </button>
      </div>

      <div style={{
    height: 250,
    borderBottom: "1px solid #27272a",
    overflow: "hidden",
    display: "flex",
    flexDirection: "column"
  }}>
        <div style={{
    padding: "7px 16px 5px",
    borderBottom: "1px solid #1c1c1e"
  }}>
          <span style={{
    fontFamily: mono,
    fontSize: 10,
    fontWeight: 600,
    letterSpacing: "0.1em",
    textTransform: "uppercase",
    color: "#3f3f46"
  }}>Agent</span>
        </div>
        <div ref={leftRef} style={{
    flex: 1,
    overflowY: "hidden",
    padding: "12px 16px"
  }}>
          {leftLines.map(renderLine)}
          {running && <div style={{
    fontFamily: mono,
    fontSize: 12,
    lineHeight: "20px",
    color: "#60a5fa",
    opacity: blink ? 1 : 0
  }}>{"▋"}</div>}
        </div>
      </div>

      <div style={{
    padding: "8px 16px",
    display: "flex",
    justifyContent: "center",
    minHeight: 37,
    alignItems: "center"
  }}>
        {done && <button onClick={play} style={{
    fontFamily: mono,
    fontSize: 11,
    color: "#52525b",
    background: "none",
    border: "none",
    cursor: "pointer",
    padding: "4px 10px",
    borderRadius: 4
  }} onMouseEnter={e => {
    e.currentTarget.style.color = "#a1a1aa";
    e.currentTarget.style.background = "#18181b";
  }} onMouseLeave={e => {
    e.currentTarget.style.color = "#52525b";
    e.currentTarget.style.background = "none";
  }}>
            {"\u21ba"} Play again
          </button>}
      </div>
    </div>;
};

에이전트가 서비스를 호출할 때 그 서비스는 실제로 내 에이전트인지 어떻게 알 수 있을까요? 에이전트가 응답을 받을 때 응답이 정당한지 어떻게 확인할 수 있을까요? 등록과 신원 검증이 두 가지 문제를 모두 해결합니다.

## 모의 데모

<AgentRegistrationDemo />

## 등록이 필요한 이유

* **검색 가능성** — 다른 에이전트와 서비스가 공개 레지스트리를 조회하여 에이전트를 찾을 수 있습니다
* **SIWA 인증** — 서비스가 등록 정보를 사용하여 요청이 실제로 에이전트에서 왔는지 검증합니다
* **평판** — 평판 레지스트리에 다른 에이전트가 상호작용 전에 조회할 수 있는 신뢰 신호가 축적됩니다

## 에이전트를 위한 Basename 발급

Basename은 에이전트에게 지갑 주소로 해석되는 사람이 읽을 수 있는 신원(예: `myagent.base.eth`)을 부여합니다. [base.org/names](https://www.base.org/names)에서 등록하세요.

## ERC-8004 레지스트리에 등록

[ERC-8004](https://www.8004.org/) 표준은 에이전트가 이름, 설명, 엔드포인트, 공개 키 등 신원 정보를 게시하는 온체인 NFT 레지스트리입니다.

<CardGroup cols={2}>
  <Card title="UI로 등록" icon="browser" href="https://www.8004scan.io">
    8004scan.io를 사용하여 코드 없이 웹 인터페이스를 통해 에이전트를 등록하고 탐색합니다.
  </Card>

  <Card title="SDK로 등록" icon="code" href="https://sdk.ag0.xyz/docs">
    Agent0 SDK를 사용하여 에이전트를 프로그래밍 방식으로 등록하고 온체인 프로필을 관리합니다.
  </Card>
</CardGroup>

레지스트리 항목에는 에이전트의 이름과 설명, 에이전트에 접근할 수 있는 엔드포인트, 에이전트의 신원을 암호학적 자격증명에 연결하는 <Tooltip tip="공개 키와 개인 키로 구성된 한 쌍의 암호화 키: 공개 키는 공개적으로 공유되어 에이전트를 식별하고, 개인 키는 신원 제어권을 증명합니다">키 쌍</Tooltip>이 포함됩니다.

정규 레지스트리 주소는 [8004scan.io](https://www.8004scan.io)에서 확인할 수 있습니다.

[ERC-8004 더 알아보기 →](https://www.8004.org/)

## 런타임에서 신원 검증 (ERC-8128)

등록은 에이전트의 존재를 세상에 알립니다. **ERC-8128** 표준은 에이전트가 모든 요청에서 자신이 진짜임을 증명할 수 있게 합니다:

<Steps>
  <Step title="에이전트 등록">
    에이전트는 ERC-8004 레지스트리에 신원과 공개 키를 등록합니다. 이는 일회성 설정 단계입니다.
  </Step>

  <Step title="각 요청에 서명">
    에이전트가 서비스를 호출할 때 개인 키를 사용하여 요청에 서명합니다. 이렇게 하면 특정 요청에 고유한 암호학적 서명이 생성됩니다.
  </Step>

  <Step title="서비스가 서명을 검증">
    서비스는 레지스트리에서 에이전트의 공개 키를 조회한 다음 서명을 확인합니다. 일치하면 요청이 등록된 에이전트에서 왔음을 알 수 있습니다.
  </Step>
</Steps>

이는 양방향으로 작동합니다 — 에이전트도 레지스트리에서 서비스의 서명을 확인하여 서비스 응답이 정당한지 검증할 수 있습니다.

[ERC-8128 사양 →](https://erc8128.slice.so/concepts/overview)

## Sign In With Agent (SIWA)

[SIWA](https://siwa.id)는 ERC-8004 등록과 ERC-8128 서명을 단일 SDK로 묶습니다 — "Google로 로그인"이 OAuth를 하나의 통합으로 묶는 것과 유사합니다.

<Tip>
  가장 단순한 통합 경로를 위해 **SIWA부터 시작하세요**. 등록과 검증에 대한 세밀한 제어가 필요한 경우에만 ERC-8004와 ERC-8128을 직접 사용하세요.
</Tip>

### 에이전트 측 통합

SIWA SDK를 설치합니다:

```bash Terminal theme={null}
npm install @buildersgarden/siwa
```

지갑 공급자에 맞는 서명자를 선택합니다. SIWA는 개인 키, Bankr, Circle, Openfort, Privy, 스마트 컨트랙트 계정을 지원합니다:

```typescript TypeScript theme={null}
import { createLocalAccountSigner } from "@buildersgarden/siwa/signer";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const signer = createLocalAccountSigner(account);
```

서비스에서 nonce를 요청한 다음 SIWA 메시지에 서명하고 제출합니다:

```typescript TypeScript theme={null}
import { signSIWAMessage } from "@buildersgarden/siwa";

// 1단계: 서비스에서 nonce 요청
const nonceResponse = await fetch("https://api.example.com/siwa/nonce", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ address: await signer.getAddress() }),
});
const { nonce, issuedAt } = await nonceResponse.json();

// 2단계: SIWA 메시지에 서명
const { message, signature } = await signSIWAMessage(
  {
    domain: "api.example.com",
    uri: "https://api.example.com/siwa",
    agentId: 42, // ERC-8004 토큰 ID
    agentRegistry: "eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
    chainId: 8453,
    nonce,
    issuedAt,
  },
  signer
);

// 3단계: 검증 제출 및 영수증 수신
const verifyResponse = await fetch("https://api.example.com/siwa/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ message, signature }),
});
const { receipt } = await verifyResponse.json();
```

영수증을 사용하여 ERC-8128로 후속 요청에 서명합니다:

```typescript TypeScript theme={null}
import { signAuthenticatedRequest } from "@buildersgarden/siwa/erc8128";

const request = new Request("https://api.example.com/action", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ action: "transfer" }),
});

const signedRequest = await signAuthenticatedRequest(request, receipt, signer, 8453);
const response = await fetch(signedRequest);
```

### 서버 측 검증

SIWA 인증 에이전트를 수락하는 서비스는 두 가지 엔드포인트를 구현합니다: nonce 발급 엔드포인트와 서명 검증 엔드포인트.

```typescript TypeScript theme={null}
import { verifySIWA, createSIWANonce } from "@buildersgarden/siwa";
import { createReceipt } from "@buildersgarden/siwa/receipt";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";

const client = createPublicClient({ chain: base, transport: http() });

// POST /siwa/nonce
const { nonce, issuedAt } = await createSIWANonce({ address, agentId, agentRegistry }, client);

// POST /siwa/verify
const result = await verifySIWA(message, signature, "api.example.com", nonceValid, client);
if (result.success) {
  const { receipt } = createReceipt({ address: result.address, agentId: result.agentId });
  return { receipt };
}
```

SIWA는 Express, Next.js, Hono, Fastify용 드롭인 미들웨어를 제공합니다. 프레임워크별 예시, 재생 방지, x402 결제 통합은 [SIWA 문서](https://siwa.id/docs)를 참조하세요.

## 영상 튜토리얼

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/l387PXGnrgU?si=EM4IKT14ajFoYkNP" title="에이전트 신원, 검증, 인증" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

## 관련 항목

<CardGroup cols={2}>
  <Card title="ERC-8004 레지스트리" icon="file-contract" href="https://www.8004scan.io">
    Base에서 등록된 에이전트와 레지스트리 주소를 탐색하고 검증합니다.
  </Card>

  <Card title="x402 프로토콜" icon="bolt" href="/ai-agents/payments/pay-for-services-with-x402">
    x402 프로토콜을 사용하여 스테이블코인으로 API 접근 비용을 지불합니다.
  </Card>
</CardGroup>
