OpenSea 工具 SDK 是做什么的?
使用 OpenSea 工具注册表 (ERC-8257) 在 Base 网络上构建、注册和门控 AI 可调用的工具端点。
何时使用此技能 (scope_in)
在以下情况下使用 opensea-tool-sdk:
- 搭建一个 AI 可调用的工具端点(HTTPS、JSON Schema、
.well-known清单),用于 Vercel、Cloudflare 或 Express - 在 Base 网络上将工具链上注册到 ToolRegistry,以便其他智能体可以发现它
- 通过 x402 按次付费(USDC)或谓词(ERC-721/ERC-1155 所有权、订阅、特质门控、ERC-20 余额、复合条件)进行访问门控
- 调用门控或付费工具:402 支付 (
paidFetch)、谓词门控鉴权 (eip3009AuthenticatedFetch) 或同时使用 (paidAuthenticatedFetch) - 通过 OpenSea REST API 搜索和发现已注册的工具
何时不使用此技能 (scope_out, 移交)
| 需求 | 请使用 |
|---|---|
| 查询 NFT/代币数据、搜索、收藏集统计 | opensea-api |
| 买卖 NFT | opensea-marketplace |
| 交换 ERC20 代币 | opensea-swaps |
| 设置钱包签名提供者 | opensea-wallet |
此 SDK 适用于工具提供者和消费者。若要查询 OpenSea 市场数据(地板价、列表、交易),请改用 opensea-api 技能。
概念
| 术语 | 含义 |
|---|---|
| 工具 (Tool) | 一个具有 JSON Schema 接口的单一 REST API 端点,可通过 /.well-known/ai-tool/<slug>.json 发现。每个工具应执行一个聚焦的操作。 |
| 清单 (Manifest) | JCS 规范化后的 JSON,描述工具的名称、端点、输入、输出、定价和访问策略 |
| 工具注册表 (ToolRegistry) | 链上合约(Base),工具在此注册,包含清单哈希和可选的访问谓词 |
| 访问谓词 (Access Predicate) | 一个 IAccessPredicate 合约,用于门控谁可以调用工具(NFT 所有权、订阅、特质门控、ERC-20 余额、复合条件) |
| x402 | 基于 HTTP 402 的按次付费协议(调用者签署 USDC TransferWithAuthorization;服务器在执行后结算) |
| EIP-3009 鉴权 | 使用零值 USDC TransferWithAuthorization 签名来鉴权谓词门控工具的调用者 |
| 促进者 (Facilitator) | 验证和结算 x402 支付的第三方服务(PayAI 或 Coinbase CDP) |
重要约束
一个工具 = 一个端点。 每个工具注册代表一个单一的 REST API 端点,具有明确且集中的意图。清单中的端点 URL 应指向一个执行明确定义操作的特定 API 路由(例如 POST /api/price-check 或 POST /api/translate),而不是一个通用 HTML 页面、文档站点或多用途 URL。请将每个注册的工具视为一个独立的 REST API 端点。它应接受特定输入,执行特定操作,并返回特定输出。
来源绑定:清单和端点必须共享完全相同的来源。 你的 .well-known/ai-tool/<slug>.json 清单和工具的调用端点必须来自完全相同的来源(根据 RFC 6454,方案、主机和端口必须一致)。子域名不算作相同来源。 example.com 和 api.example.com 是不同的来源。这在注册时会强制执行。如果清单来源和端点来源不完全匹配,该工具将被拒绝并标记为注销。
- 有效:清单位于
https://my-tool.example.com/.well-known/ai-tool/my-tool.json,端点位于https://my-tool.example.com/api/my-tool - 无效:清单位于
https://example.com/.well-known/ai-tool/my-tool.json,端点位于https://api.example.com/api/my-tool
如果你的 API 位于子域名上,请从该子域名提供清单(例如,两者都在 api.example.com 上)。
已部署合约(以太坊主网、Base、Shape、Abstract、Monad、Robinhood Chain)
规范 v0.2 部署 — 在每个支持的链上具有相同的 CREATE2 地址。
| 合约 | 地址 |
|---|---|
| ToolRegistry (v0.2) | 0x265BB2DBFC0A8165C9A1941Eb1372F349baD2cf1 |
| ERC721OwnerPredicate (v0.2) | 0xc8721c9A776958FfFfEb602DA1b708bf1D318379 |
| ERC1155OwnerPredicate (v0.2) | 0x77373Dc3c1AE9A1e937eF3e5E08F4807D47c7c11 |
| SubscriptionPredicate (v0.2) | 0xCBe0cd9B1d99d95Baa9c58f2767246C52e461f25 |
| TraitGatedPredicate (v0.2) | 0x10abF07CfA34Bf22372C57f27e8bd9C2DCF93fA1 |
| ERC20BalancePredicate (v0.2) | 0x1a834FC48B5f6e119c62C12a98b32137bCFA77cD |
工具发现 [Beta]
通过 OpenSea REST API 搜索或查找已注册的工具。需要 OPENSEA_API_KEY。
# 如果已设置则重用 OPENSEA_API_KEY;否则获取一个瞬时免费密钥
# (无需注册 — 读限 600/小时,写限 30/小时,7 天有效期)并保存以供重用。
if [ -z "${OPENSEA_API_KEY:-}" ]; then
KEY_FILE="${OPENSEA_CONFIG_DIR:-$HOME/.opensea}/api_key"
if [ -s "$KEY_FILE" ]; then
export OPENSEA_API_KEY=$(cat "$KEY_FILE") # 重用缓存的密钥
else
api_key=$(curl -s -X POST https://api.opensea.io/api/v2/auth/keys | jq -r '.api_key')
mkdir -p "$(dirname "$KEY_FILE")"
(umask 077; printf '%s\n' "$api_key" > "$KEY_FILE") # 在使用前保存
export OPENSEA_API_KEY="${api_key}"
fi
fi
始终保存获取到的瞬时密钥并重用,而不是重新获取。opensea-api 技能附带了一个 auth/opensea-resolve-key.sh 辅助脚本,可以执行此操作(环境变量 → 缓存文件 → 获取 + 保存);请参阅其“API 密钥解析”部分。如需更高的速率限制,请在 设置 → 开发者 创建一个完整密钥。
列出工具: GET /api/v2/tools (文档)
| 参数 | 必需 | 描述 |
|---|---|---|
sort_by | 否 | 排序方式:newest(默认)、oldest |
type | 否 | 按访问类型过滤:open、nft_gated、token_gated、subscription、gated |
limit | 否 | 每页结果数(1–100) |
cursor | 否 | 分页游标 |
搜索工具: GET /api/v2/tools/search (文档)
| 参数 | 必需 | 描述 |
|---|---|---|
query | 否 | 搜索查询文本 |
registry_chain | 否 | 按注册表链 ID 过滤 |
tags | 否 | 按标签过滤 |
access_type | 否 | 按访问类型过滤:open、nft_gated、subscription |
creator | 否 | 按创建者地址过滤 |
sort_by | 否 | 排序方式:relevance(默认)、newest、most_used |
limit | 否 | 每页结果数(1–200) |
cursor.value | 否 | 分页游标 |
获取一个工具: GET /api/v2/tools/{registry_chain}/{registry_addr}/{tool_id} (文档)
| 参数 | 必需 | 描述 |
|---|---|---|
registry_chain | 是 | 注册表链 ID(例如 1、8453) |
registry_addr | 是 | 注册表合约地址 |
tool_id | 是 | 数字工具 ID |
# 列出按最新排序的工具
curl -s "https://api.opensea.io/api/v2/tools?sort_by=newest&limit=10" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# 列出按类型过滤的工具
curl -s "https://api.opensea.io/api/v2/tools?type=open&sort_by=oldest" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# 按关键词搜索工具
curl -s "https://api.opensea.io/api/v2/tools/search?query=nft" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# 获取 Base 上的特定工具
curl -s "https://api.opensea.io/api/v2/tools/8453/0x265BB2DBFC0A8165C9A1941Eb1372F349baD2cf1/1" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# 按访问类型过滤
curl -s "https://api.opensea.io/api/v2/tools/search?access_type=open&limit=10" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
1. 创建工具
1a. 搭建项目框架
npx @opensea/tool-sdk init --runtime vercel # 或:cloudflare、express
这会生成:
src/manifest.ts— 工具清单定义src/handler.ts— 包含输入/输出模式的请求处理器api/index.ts— 框架适配器入口点public/llms.txt— 智能体可读的发现页面api/well-known/[slug].ts— 在/.well-known/ai-tool/<slug>.json提供清单
1b. 定义清单
import { defineManifest } from "@opensea/tool-sdk"
export const manifest = defineManifest({
name: "我的工具",
description: "此工具的功能",
endpoint: "https://my-tool.example.com/api",
creatorAddress: "0xYOUR_WALLET_ADDRESS",
inputs: {
type: "object",
properties: {
query: { type: "string", description: "搜索查询" },
},
required: ["query"],
},
outputs: {
type: "object",
properties: {
result: { type: "string" },
},
},
// 可选:添加 x402 付费墙的定价(参见 references/x402.md)
// pricing: paywall.pricing,
// 可选:添加访问要求(参见 references/predicate-gating.md)
// access: { logic: "OR", requirements: [...] },
})
1c. 编写处理器
import { createToolHandler } from "@opensea/tool-sdk"
import { z } from "zod/v4"
import { manifest } from "./manifest.js"
const InputSchema = z.object({ query: z.string() })
const OutputSchema = z.object({ result: z.string() })
export const toolHandler = createToolHandler({
manifest,
inputSchema: InputSchema,
outputSchema: OutputSchema,
// gates: [], // 在此处添加门控(参见 references/x402.md 和 references/predicate-gating.md)
handler: async (input) => {
return { result: `处理完成:${input.query}` }
},
})
1d. 连接适配器
Vercel:
import { toVercelHandler } from "@opensea/tool-sdk"
import { toolHandler } from "../src/handler.js"
export default toVercelHandler(toolHandler)
Express:
import { toExpressHandler } from "@opensea/tool-sdk"
import { toolHandler } from "./handler.js"
app.post("/api", toExpressHandler(toolHandler))
Cloudflare Workers:
import { toolHandler } from "./handler.js"
export default { fetch: toolHandler }
2. 链上注册工具
2a. 通过 CLI
# 设置钱包
export PRIVATE_KEY=0x...
export RPC_URL=https://mainnet.base.org
# 注册(开放访问 — 无谓词)
npx @opensea/tool-sdk register \
--metadata https://my-tool.example.com/.well-known/ai-tool/my-tool.json \
--network base
# 使用访问谓词注册
npx @opensea/tool-sdk register \
--metadata https://my-tool.example.com/.well-known/ai-tool/my-tool.json \
--network base \
--access-predicate 0xPREDICATE_ADDRESS
# 试运行(不发送交易)
npx @opensea/tool-sdk register --metadata ... --network base --dry-run
该 CLI:
- 从
--metadataURL 获取清单 - 验证清单模式
- 确认
manifest.creatorAddress与你的钱包匹配 - 计算 JCS keccak256 清单哈希
- 调用
ToolRegistry.registerTool(metadataURI, manifestHash, accessPredicate) - 从
ToolRegistered事件返回toolId
2b. 通过 SDK(编程方式)
import { ToolRegistryClient, computeManifestHash } from "@opensea/tool-sdk"
import { createWalletFromEnv, walletAdapterToClient } from "@opensea/tool-sdk"
import { base } from "viem/chains"
const adapter = createWalletFromEnv()
const walletClient = await walletAdapterToClient(adapter, base)
const registry = new ToolRegistryClient({
chain: base,
rpcUrl: "https://mainnet.base.org",
walletClient,
})
const { toolId, txHash } = await registry.registerTool({
metadataURI: "https://my-tool.example.com/.well-known/ai-tool/my-tool.json",
manifest, // 你的 ToolManifest 对象
accessPredicate: "0x0000...0000", // address(0) = 开放访问
})
console.log(`已在交易 ${txHash} 中注册工具 ${toolId}`)
3. 门控工具访问
工具可以通过三种方式门控:
| 门控类型 | 机制 | 参考文档 |
|---|---|---|
| x402 付费墙 | 按次付费(USDC、EIP-3009) | references/x402.md |
| 谓词门控 | 链上检查(NFT、订阅、特质门控、ERC-20 余额、复合条件) | references/predicate-gating.md |
| 组合 | EIP-3009 鉴权与支付(先谓词后 x402) | references/predicate-gating.md |
关于已部署的谓词地址、要求编码以及 SDK 辅助函数(如 describeToolAccess / decodeRequirement),请参见 references/known-predicates.md。
4. 钱包设置
该 SDK 通过 @opensea/wallet-adapters 支持多种钱包提供者。设置环境变量后,SDK 会自动检测提供者。有关完整的提供者表、环境变量、设置指南和签名策略配置,请参见 opensea-wallet 技能。
| 提供者 | 环境变量 | 最佳适用场景 |
|---|---|---|
| 私钥 | PRIVATE_KEY | 本地开发、脚本 |
| Privy | PRIVY_APP_ID、PRIVY_APP_SECRET、PRIVY_WALLET_ID | 服务器钱包 |
| Turnkey | TURNKEY_API_PUBLIC_KEY、TURNKEY_API_PRIVATE_KEY、TURNKEY_ORGANIZATION_ID | 企业级签名 |
| Fireblocks | FIREBLOCKS_API_KEY、FIREBLOCKS_API_SECRET、FIREBLOCKS_VAULT_ACCOUNT_ID | 机构托管 |
| Bankr | BANKR_API_KEY | 智能体钱包(通过 HTTP API) |
对于任何提供者,RPC_URL(或 --rpc-url 标志)设置链上读写操作的 RPC 端点。当两者均未设置时,CLI 命令会回退到网络的默认公共 RPC,这可能会很慢或受到速率限制。
import { createWalletFromEnv } from "@opensea/tool-sdk"
// 自动检测:Privy > Fireblocks > Turnkey > Bankr > PrivateKey
const adapter = createWalletFromEnv()
const address = await adapter.getAddress()
对于 Bankr(外部签名者):
import { createBankrAccount } from "@opensea/tool-sdk"
const account = await createBankrAccount("your-bankr-api-key")
// 与 eip3009AuthenticatedFetch 或 paidAuthenticatedFetch 一起使用
5. 响应
…
[为翻译而截断]