Skip to content

Commit 51a09ac

Browse files
committed
Release v0.15.0
Origin-SHA: 63bd02560fb7f2e118f392b9cabe45c25e5f8a00
1 parent 343e6c3 commit 51a09ac

45 files changed

Lines changed: 3815 additions & 244 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# @opensea/tool-sdk
22

3+
## 0.15.0
4+
5+
### Minor Changes
6+
7+
- Unified 402 flow for free and paid predicate-gated tools.
8+
9+
`predicateGate` now speaks the x402-style 402 challenge for both free and paid tools. When no auth is provided and `operatorAddress` is configured, it returns a 402 with `PaymentRequirements` (`payTo`=operator, `maxAmountRequired`=0) instead of a 401. The gate accepts an `X-Payment` header as the auth source (taking precedence over `Authorization`), recovers the signer from the EIP-712 `TransferWithAuthorization` payload, and extracts caller identity from the `from` field. `PaymentRequirements` are chain-aware: the network name and USDC asset address are derived from the configured chain. `x402Version` and the `exact` scheme are validated.
10+
11+
**Breaking changes:**
12+
13+
- `eip3009AuthenticatedFetch` and `paidAuthenticatedFetch` no longer take `chainId` or `to` params. On a 402 they sign `X-Payment` with the advertised `payTo` and retry; the redundant `Authorization: EIP-3009` header has been removed.
14+
- `EIP3009_CHAIN_MAP` and `ZERO_ADDRESS` exports were removed.
15+
16+
**New features:**
17+
18+
- `eip3009AuthenticatedFetch` gains an `allowedRecipients` guard that prevents signing `X-Payment` for arbitrary `payTo` addresses returned by a malicious 402 response, mirroring `paidAuthenticatedFetch`'s `validatePaymentSafety`.
19+
320
## 0.14.2
421

522
### Patch Changes

examples/nft-appraisal-tool/api/holder.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { buildToolHandler } from "../src/handler.js"
88
import { buildHolderManifest } from "../src/manifest.js"
99
import { setOpenseaApiKey } from "../src/opensea.js"
1010
import { buildHolderGates, buildHolderPaywall } from "../src/paywall.js"
11+
import { buildUsageReporting } from "../src/usage.js"
1112

1213
const creator = process.env.CREATOR_ADDRESS as `0x${string}` | undefined
1314
const recipient = process.env.RECIPIENT_ADDRESS as `0x${string}` | undefined
@@ -40,7 +41,17 @@ const manifest = buildHolderManifest({
4041
endpoint: `${baseEndpoint}/api/holder`,
4142
pricing: paywall.pricing,
4243
})
43-
const vercelHandler = toVercelHandler(buildToolHandler({ manifest, gates }))
44+
const vercelHandler = toVercelHandler(
45+
buildToolHandler({
46+
manifest,
47+
gates,
48+
// Holder tier is tool id 2 on the Base ToolRegistry (HOLDER_TOOL_ID).
49+
usageReporting: buildUsageReporting({
50+
apiKey: openseaKey,
51+
toolOnchainId: Number(holderToolId),
52+
}),
53+
}),
54+
)
4455

4556
export default function (req: VercelRequest, res: VercelResponse) {
4657
return vercelHandler(req, res)

examples/nft-appraisal-tool/api/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { buildToolHandler } from "../src/handler.js"
88
import { buildPublicManifest } from "../src/manifest.js"
99
import { setOpenseaApiKey } from "../src/opensea.js"
1010
import { buildPublicPaywall } from "../src/paywall.js"
11+
import { buildUsageReporting } from "../src/usage.js"
1112

1213
// Vercel populates process.env before this module loads, so initialization
1314
// happens once at module load. The factory architecture (buildPublicPaywall
@@ -37,7 +38,15 @@ const manifest = buildPublicManifest({
3738
pricing: paywall.pricing,
3839
})
3940
const vercelHandler = toVercelHandler(
40-
buildToolHandler({ manifest, gates: [paywall.gate] }),
41+
buildToolHandler({
42+
manifest,
43+
gates: [paywall.gate],
44+
// Public tier is tool id 1 on the Base ToolRegistry (see README).
45+
usageReporting: buildUsageReporting({
46+
apiKey: openseaKey,
47+
toolOnchainId: 1,
48+
}),
49+
}),
4150
)
4251

4352
export default function (req: VercelRequest, res: VercelResponse) {

examples/nft-appraisal-tool/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
},
1919
"dependencies": {
2020
"@ai-sdk/anthropic": "^1.2.0",
21-
"@opensea/tool-sdk": "^0.13.0",
21+
"@opensea/tool-sdk": "^0.14.2",
2222
"ai": "^4.3.0",
2323
"zod": "4.3.6"
2424
},

examples/nft-appraisal-tool/pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/nft-appraisal-tool/src/handler.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
createToolHandler,
3+
type Eip3009UsageReporterConfig,
34
type GateMiddleware,
45
type ManifestDefinition,
56
ToolHandlerError,
@@ -27,6 +28,13 @@ export interface BuildToolHandlerOptions {
2728
* doesn't need to.
2829
*/
2930
gates: GateMiddleware[]
31+
/**
32+
* Optional usage-reporting config. When set, the SDK reports each
33+
* successful invocation to OpenSea at the very end of the lifecycle
34+
* (fire-and-forget). For these paid tiers it reports the x402 payer plus
35+
* the settlement tx hash. Omitted in local/dev where no API key is set.
36+
*/
37+
usageReporting?: Eip3009UsageReporterConfig
3038
}
3139

3240
/**
@@ -40,6 +48,7 @@ export function buildToolHandler(opts: BuildToolHandlerOptions) {
4048
inputSchema: InputSchema,
4149
outputSchema: AppraisalSchema,
4250
gates: opts.gates,
51+
usageReporting: opts.usageReporting,
4352
handler: async input => {
4453
try {
4554
return await runAppraisal({

examples/nft-appraisal-tool/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
buildHolderPaywall,
99
buildPublicPaywall,
1010
} from "./paywall.js"
11+
import { buildUsageReporting } from "./usage.js"
1112

1213
export interface Env {
1314
OPENSEA_API_KEY: string
@@ -64,6 +65,11 @@ function initHandlers(env: Env) {
6465
const publicHandler = buildToolHandler({
6566
manifest: publicManifest,
6667
gates: [publicPaywall.gate],
68+
// Public tier is tool id 1 on the Base ToolRegistry (see README).
69+
usageReporting: buildUsageReporting({
70+
apiKey: env.OPENSEA_API_KEY,
71+
toolOnchainId: 1,
72+
}),
6773
})
6874
const holderHandler = env.HOLDER_TOOL_ID
6975
? buildToolHandler({
@@ -72,6 +78,10 @@ function initHandlers(env: Env) {
7278
toolId: BigInt(env.HOLDER_TOOL_ID),
7379
rpcUrl: env.BASE_RPC_URL,
7480
}),
81+
usageReporting: buildUsageReporting({
82+
apiKey: env.OPENSEA_API_KEY,
83+
toolOnchainId: Number(env.HOLDER_TOOL_ID),
84+
}),
7585
})
7686
: undefined
7787

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {
2+
type Eip3009UsageReporterConfig,
3+
TOOL_REGISTRY,
4+
} from "@opensea/tool-sdk"
5+
6+
/**
7+
* Base mainnet — where this tool is registered on `ToolRegistry` v0.2 and
8+
* where x402 settlements occur.
9+
*/
10+
const TOOL_CHAIN_ID = 8453
11+
12+
/**
13+
* Build the `usageReporting` config for a tool tier (its ERC-8257 composite
14+
* key is `TOOL_CHAIN_ID` + the canonical registry address + the tier's onchain
15+
* id). The SDK reports the verified caller automatically — for these paid
16+
* tiers, the x402 payer and settlement tx hash. No wallet or signing is
17+
* involved; the OpenSea API key authenticates this service as the reporter.
18+
*/
19+
export function buildUsageReporting(opts: {
20+
apiKey: string
21+
toolOnchainId: number
22+
}): Eip3009UsageReporterConfig {
23+
return {
24+
chainId: TOOL_CHAIN_ID,
25+
toolChainId: TOOL_CHAIN_ID,
26+
toolRegistryAddress: TOOL_REGISTRY.address as `0x${string}`,
27+
toolOnchainId: opts.toolOnchainId,
28+
apiKey: opts.apiKey,
29+
}
30+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copy to .dev.vars for `wrangler dev`. Same format as .env files.
2+
3+
OPENSEA_API_KEY=
4+
CREATOR_ADDRESS=
5+
HOLDER_TOOL_ID=
6+
TOOL_ENDPOINT=http://localhost:8787
7+
# ETH_RPC_URL=
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copy to .env.local and fill in. Loaded by scripts/ and by `vercel dev`.
2+
3+
# OpenSea v2 REST API key (https://docs.opensea.io/reference/api-keys)
4+
OPENSEA_API_KEY=
5+
6+
# Creator address recorded as the manifest's `creatorAddress`.
7+
# Must match the wallet that registers the tool on the ToolRegistry (ERC-8257).
8+
CREATOR_ADDRESS=
9+
10+
# Onchain ToolRegistry tool ID (decimal string).
11+
# Obtain from the `ToolRegistered` event after registering with --nft-gate.
12+
HOLDER_TOOL_ID=
13+
14+
# Optional override for the manifest's endpoint field.
15+
# TOOL_ENDPOINT=https://token-nft-overlap-tool.vercel.app
16+
17+
# Optional Ethereum RPC override for predicate static-calls.
18+
# ETH_RPC_URL=

0 commit comments

Comments
 (0)