Agent ウォレット
秘密鍵に触れることなく、取引を開始できるアカウントを AI Agent に提供します。
要点: API を1回呼び出すと、ERC-4337 スマートアカウントのアドレスを取得できます。秘密鍵は当サービスが保管し、デプロイのガス代を負担します。その後の送金のガス代はアカウントが負担します。
本章は、自分のシステムを BOT Chain Agent ウォレットサービスと連携させる開発者向けです。ウォレットの作成、コントラクトより先にアドレスが存在する理由、トークンの送金、送金先の制限を説明します。
まず本章を読み、その後に Agent ID を読んでください。ID の登録には作成済みのウォレットが必要です。
本章のパスはすべて、次のいずれかのベース URL を基準とします。
| 環境 | URL |
|---|---|
| BOT メインネット | https://wallet-api.botchain.ai |
| Bohr テストネット | https://wallet-api.bohr.life |
API キーは環境に紐付きます。テストネット用のキーでメインネットに送ったリクエストは拒否され、別の環境に黙って転送されることはありません。
1. 概要
| 質問 | 回答 |
|---|---|
| 何を取得できますか? | Agent が取引を開始する ERC-4337 スマートアカウントのアドレス |
| 秘密鍵を保管する必要はありますか? | ありません。当サービスが保管・使用し、連携するシステムでは署名しません |
| ガス代は誰が負担しますか? | デプロイのガス代は当サービスが負担します。作成時に Agent の残高は不要です。その後の送金のガス代はアカウントが負担します |
| アドレスはすぐ使えますか? | 入金には使えます。送金にはアカウントのデプロイが必要です |
| 送金方法は? | POST /wallets/{id}/transfers で UserOperation を送信します |
| 送金先を制限できますか? | 可能であり、必須です。実行前に許可リストを検証します |
| 対応チェーンは? | BOT メインネット(chain ID 677)と Bohr テストネット(chain ID 968) |
次の点を覚えておいてください。
アドレスはウォレット作成時に存在しますが、そのアドレスのコントラクトは後からデプロイされます。どちらも正常な状態です。コードがないアドレスでも入金を受け取れます。
2. 認証情報の取得
ウォレットと ID のサービスでは認証情報を共有します。連携する各事業者をプロジェクトとして扱い、プロジェクト ID と1つ以上の API キーを当サービスが発行します。
ak_<environment>_k_<key_id>.<secret>
中央のドットを含む文字列全体を X-API-Key ヘッダーに設定してください。secret は作成時に一度だけ返され、その後は取得できません。 すぐにシークレット管理システムへ保存してください。
キーは環境別です。テストネット用キーはメインネットでは使えません。
3. ウォレットの作成
POST /v1/wallets
Content-Type: application/json
X-API-Key: ak_…
{
"external_agent_id": "自分の-agent-id",
"chain_id": 677,
"idempotency_key": "create-agent-42",
"callback_url": "https://your-service.example/webhooks/wallet"
}
| フィールド | 必須 | 意味 |
|---|---|---|
external_agent_id | はい | 自分のシステム内の Agent 識別子 |
chain_id | はい | メインネットは 677、テストネットは 968 |
idempotency_key | はい | Idempotency-Key ヘッダーでも指定可能 |
identity_id | いいえ | 既存の ID と関連付けます。通常は ID を後から登録するため省略します |
callback_url | いいえ | 状態変更通知の送信先 |
owner アドレスもアカウントアドレスも指定する必要はありません。両方を当サービスで生成して返します。連携するシステムで生成するものはなく、鍵素材がシステム間の境界を越えることもありません。
202 を返します。
{
"wallet": {
"wallet_id": "wal_de43139cef869dc9c42ae3",
"project_id": "launchpad",
"external_agent_id": "自分の-agent-id",
"chain_id": 677,
"owner_address": "0x5f5802fA78d5eE2A3B4fD67F49CD502430C3E88C",
"account_address": "0xd9DC4F46d9da603A2A077A7190BAa85f4e2f05fe",
"deployment_status": "PREDICTED",
"status": "ACTIVE",
"created_at": "2026-09-07T09:37:40Z"
},
"replayed": false
}
レスポンスの2つのアドレスは使い分けてください。
| フィールド | 意味 |
|---|---|
account_address | Agent のアドレス。 入金先であり、オンチェーンの送信元にもなります |
owner_address | このアカウントを制御するアドレス。ID 登録時に使います。ここに入金しないでください |
以降の各 API で使うため、wallet_id を保存してください。
書き込み API はオブジェクトを wallet で包みますが、読み取り API はオブジェクトを直接返します。作成後は response.wallet.account_address、GET 後は response.account_address を参照します。
同じ冪等キーで再送すると、200、"replayed": true、元のウォレットが返ります。タイムアウト後に再試行しても、2つ目のアカウントは作られません。
自分の識別子で検索すれば、当サービスの ID を保存する必要はありません。
GET /v1/wallets/{wallet_id}
GET /v1/wallets/by-external-id/{chain_id}/{external_agent_id}
自分のプロジェクトに属さないウォレットは必ず 404 を返します。「自分のものではない」と「存在しない」のレスポンスは同じです。
4. アドレスはコントラクトより先に存在します
deployment_status の初期値は PREDICTED です。単に待てば解消する一時状態ではなく、ERC-4337 アカウントの仕組みによるものです。
CREATE2 が owner と salt からアドレスを計算するため、事前にアドレスが分かり、その後も変わりません。コントラクトは後からそこにデプロイされます。それまでは以下のようになります。
| 操作 | PREDICTED で利用可能? |
|---|---|
| ネイティブトークンや ERC-20 の受け取り | 可能。 コードのないアドレスへの送金は正常です |
| ユーザーへのアドレス表示 | 可能 |
| トークンの送金 | 不可 |
| 状態 | 意味 |
|---|---|
PREDICTED | アドレス計算済み。オンチェーンにコントラクトは未配置 |
DEPLOYING | デプロイを送信済み。オンチェーンへの取り込み待ち |
DEPLOYED | コントラクトの準備完了。送金可能 |
deployment_status が DEPLOYED でなければ送金は拒否されます。送金によってデプロイが自動的に始まることはなく、409 WALLET_NOT_READY が返るだけです。初期化処理にデプロイを組み込み、初回の支払いで自動実行されると想定しないでください。
POST /v1/wallets/{wallet_id}/deploy
{ "idempotency_key": "deploy-agent-42" }
202 と UserOperation を返します。deployment_status が DEPLOYED になるまでウォレットをポーリングしてください。その後に送金が受け付けられます。
デプロイにアカウント残高は不要です。ガス代は当サービスが負担します。
5. トークンの送金
POST /v1/wallets/{wallet_id}/transfers
Content-Type: application/json
X-API-Key: ak_…
{
"receiver": "0x1111111111111111111111111111111111111111",
"token_address": "0x2222222222222222222222222222222222222222",
"amount": "1000000",
"request_source": "API",
"idempotency_key": "payout-2026-09-08-001"
}
| フィールド | 必須 | 意味 |
|---|---|---|
receiver | はい | 送金先。このウォレットの許可リストに登録されている必要があります |
token_address | はい | ERC-20 コントラクトのアドレス。ネイティブトークンはリテラル BOT_NATIVE |
amount | はい | 最小単位、数字のみ。 小数点以下6桁の USDT では "1000000" が 1 USDT を表します |
request_source | はい | API、CONSOLE、ADMIN のいずれか。送金要求の発生元を記録します |
idempotency_key | はい | 再試行による重複送金を防止します |
以下の4つの場合は即座に拒否されます。
token_addressは省略できません。 ネイティブトークンには文字列BOT_NATIVEを使い、空値やゼロアドレスは指定しないでください。amountは数字のみです。 小数と指数表記は丸められず拒否されます。"1.5"と"1e6"はどちらも失敗します。浮動小数点変換は精度を失い、実際の送金量が変わる可能性があるため、これらの形式は受け付けません。request_sourceは必須で、上記3つの値のいずれかである必要があります。- 送金先にウォレット自身のアカウントアドレスは指定できません。 自己送金もオンチェーンで実行され、残高が変わらなくてもガスを消費するため、ここで防止します。
amount は数値ではなく文字列です。トークン数量は JavaScript が正確に扱える数値の範囲を超える場合があります。
202 と UserOperation を返します。送金は送信済みですが、まだ最終確定していません。
{
"user_op_hash": "0x…",
"wallet_id": "wal_de43139cef869dc9c42ae3",
"chain_id": 677,
"op_type": "TRANSFER",
"status": "BUILT",
"sender": "0xd9DC4F46d9da603A2A077A7190BAa85f4e2f05fe",
"attempt": 0,
"created_at": "2026-09-08T07:20:11Z"
}
送金の追跡
GET /v1/user-operations/{user_op_hash}
| 状態 | 意味 | 最終状態? |
|---|---|---|
BUILT | 構築済み、未署名 | いいえ |
SIGNED | 署名済み、未送信 | いいえ |
SUBMITTED | bundler に送信済み | いいえ |
INCLUDED | ブロックに取り込み済み、レシート未確認 | いいえ |
SUCCEEDED | 完了。 tx_hash と block_number が設定済み | はい |
REVERTED | オンチェーン実行が失敗し、ガスを消費 | はい |
FAILED | チェーンに到達していない。理由は last_error | はい |
REVERTED と FAILED は別々に扱ってください。REVERTED は残高不足やトークンコントラクトによる拒否など、チェーンに到達してから失敗した状態です。FAILED はその段階に到達していません。FAILED を新しい冪等キーで再試行するのは妥当ですが、何も変えずに REVERTED を再試行しても再び revert します。
attempt と last_error で、サービス側がすでに行った試行を確認できます。
6. 送金先の許可リスト
ウォレットは許可リストに登録されたアドレスにのみ送金できます。空の許可リストは、どのアドレスにも送金できないことを意味します。「制限なし」ではありません。各送金先を初回送金前に登録しなければ、送金は拒否されます。
これは意図的な設計です。Agent は送金のタイミングを自分で決めるため、送金可能な宛先は受け取った指示から推測するのではなく、事前に確定させる必要があります。検証はサーバー側で操作の構築前に行われるため、システムが完全に侵害されても、攻撃者が新しいアドレスへ資金を送ることはできません。
POST /v1/wallets/{wallet_id}/allowlist
GET /v1/wallets/{wallet_id}/allowlist
DELETE /v1/wallets/{wallet_id}/allowlist/{entry_id}
{
"chain_id": 677,
"address": "0x1111111111111111111111111111111111111111",
"label": "決済アカウント",
"allowed_actions": "TRANSFER",
"created_by": "ops@your-company.example",
"idempotency_key": "allow-payout-1"
}
| フィールド | 必須 | 意味 |
|---|---|---|
chain_id | はい | エントリーはチェーン別です。968 のエントリーで 677 の送金は許可できません |
address | はい | 送金先アドレス |
allowed_actions | はい | TRANSFER、PAYMENT、ALL のいずれか |
created_by | はい | 監査用に、このアドレスを承認した人を記録します |
label | いいえ | 識別しやすい名前 |
idempotency_key | はい |
エントリーは (wallet_id, chain_id, address) で照合し、ACTIVE 状態で、allowed_actions が送金を許可している必要があります。拒否時には、エントリーがない、失効済み、送金が許可されていない、のどれかが示されます。それぞれ対処が異なるため、単にアドレスを再登録せず、拒否理由を確認してください。
初期化の順序も重要です。入金前に送金先を登録してください。残高があっても許可リストが空なら、誰にも支払えません。
7. ウォレットの一時停止
POST /v1/wallets/{wallet_id}/status
{ "status": "PAUSED" }
PAUSED は新しい操作を停止し、当サービスが解除できます。REVOKED は永続的です。
この API には意図的に「再開」がありません。停止済みアカウントの再稼働は運用上の判断であり、停止処理を機械的に逆にするものではありません。再開が必要な場合はお問い合わせください。
8. コールバック(Webhook)
callback_url を指定すると、状態変更が X-Callback-Token ヘッダー付きの POST で送信されます。受信側は次の4つを守ってください。
- 最初に
X-Callback-Tokenを検証し、定数時間比較で一致を確認してから本文を処理します。 - 速やかに
2xxを返し、実際の処理は非同期で実行します。 - 重複配信に対応します。 オブジェクト ID と
updated_atを冪等キーにします。 - 再試行で順序が前後することがあります。 保存済みレコードより
updated_atが古いペイロードは無視します。
コールバックはポーリングを効率化するものであり、代替ではありません。受信側が停止していても、ポーリングですぐに現在の状態を取得できます。
9. エラー処理
エラーレスポンスにはプログラムで判定できるコードが含まれます。
{ "error_code": "WHITELIST_DENIED", "error_message": "…" }
エラーメッセージの文字列ではなく、error_code で分岐してください。
| HTTP | error_code | 意味 | 再試行? |
|---|---|---|---|
400 | INVALID_REQUEST | リクエスト形式不正、またはフィールド検証失敗 | いいえ。リクエストを修正 |
401 | — | API キー未指定または無効 | いいえ |
403 | WHITELIST_DENIED | 送金先に有効な許可リストエントリーがない | いいえ。先に登録 |
403 | TOKEN_NOT_ALLOWED | このウォレットでは当該トークンを送金できない | いいえ |
404 | NOT_FOUND | ウォレットが存在しない、または別プロジェクトに所属 | いいえ |
409 | WALLET_NOT_READY | 未デプロイ、一時停止、または失効 | 状況による。下記参照 |
409 | IDEMPOTENCY_KEY_CONFLICTS | 同じ冪等キーを異なる内容に使用 | いいえ |
422 | INSUFFICIENT_BALANCE | 残高不足 | いいえ。先に入金 |
501 | NOT_IMPLEMENTED | この環境では機能が無効 | いいえ |
5xx | INTERNAL_ERROR | サービス側のエラー | はい。バックオフ後に再試行 |
WALLET_NOT_READY は3つの状況を含み、error_message の status= と deployment= で区別できます。
deployment=PREDICTEDまたはDEPLOYING→ 一時的な状態なので、デプロイ完了後に再試行します。status=PAUSED→ ウォレット再開後に再試行します。status=REVOKED→ 永続的な失敗です。再試行しないでください。
409 をすべて永続的な競合と扱うと、デプロイ中のウォレットを誤って失敗扱いにしてしまいます。
10. 環境
| 項目 | BOT メインネット | Bohr テストネット |
|---|---|---|
| Chain ID | 677 | 968 |
| RPC | https://rpc.botchain.ai | https://rpc.bohr.life |
| ブロックエクスプローラー | https://scan.botchain.ai | https://scan.bohr.life |
| Bundler | https://bundler.botchain.ai/rpc | https://bundler.bohr.life/rpc |
| EntryPoint | 0x0000000071727De22E5E9d8BAf0edAc6f37da032 | メインネットと同じ |
| アカウント種別 | Kernel v0.3.3 | メインネットと同じ |
EntryPoint は標準の ERC-4337 v0.7 シングルトンコントラクトです。既存の ERC-4337 ツールを変更せずに利用できます。
次のステップ:ID
ウォレットは Agent にアカウントを提供します。ID は Agent を検証可能にします。誰でもチェーンから直接、所有者と使用するウォレットを確認できます。
ID 登録には、作成したウォレットの次の3つの値が必要です。
| ID API のフィールド | 取得元 |
|---|---|
wallet_id | wallet.wallet_id |
wallet_address | wallet.account_address |
owner_address | wallet.owner_address |