Skip to content

Commit 8b317d5

Browse files
ryanioCodySearsOSdevin-ai-integration[bot]
committed
Release v0.28.5
Origin-SHA: 15e3931443079d979fec234c42b1a1cf8102ad74 Co-authored-by: Cody <132297275+CodySearsOS@users.noreply.github.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent ebff0f9 commit 8b317d5

9 files changed

Lines changed: 52 additions & 20 deletions

File tree

CHANGELOG.md

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

3+
## 0.28.5
4+
5+
### Patch Changes
6+
7+
- f324c6d: Normalize x402 registry references to the public usage-reporting source tokens.
8+
39
## 0.28.4
410

511
### Patch Changes

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ npx @opensea/tool-sdk pay https://my-tool.vercel.app/api/tool \
172172
| `--max-amount <baseUnits>` | Reject challenges charging more than this (token base units). Pass `unlimited` to disable |
173173
| `--no-report-usage` | Disable the caller-side usage report sent to OpenSea after a successful payment |
174174
| `--api-key <key>` | API key for usage reporting (falls back to `OPENSEA_API_KEY`, then an auto-provisioned instant key) |
175-
| `--tool-ref <ref>` | Tool coordinates as `chainId,registryAddress,onchainId` (e.g. `8453,0x265b...2cf1,65`, or `8453,x402:bazaar,123` for x402 registries). Disambiguates usage reporting when multiple tools share one endpoint |
175+
| `--tool-ref <ref>` | Tool coordinates as `chainId,registryAddress,onchainId` (e.g. `8453,0x265b...2cf1,65`, or `8453,x402_bazaar,123` for x402 registries). The legacy `x402:bazaar` / `x402:bankr` forms are also accepted and normalized. Disambiguates usage reporting when multiple tools share one endpoint |
176176

177-
When an endpoint URL maps to more than one registered tool, an endpoint-only usage report is rejected with `400 Multiple tools registered for endpoint`. Pass `--tool-ref` so the report identifies the exact tool by its composite key. The fields are comma-separated so a registry identifier that contains a colon (such as the `x402:bazaar` / `x402:bankr` registries used for tools that are not registered onchain) stays unambiguous:
177+
When an endpoint URL maps to more than one registered tool, an endpoint-only usage report is rejected with `400 Multiple tools registered for endpoint`. Pass `--tool-ref` so the report identifies the exact tool by its composite key. The canonical public source tokens are `x402_bazaar` and `x402_bankr`; the legacy colon forms are accepted and normalized. The fields are comma-separated so the registry identifier stays unambiguous:
178178

179179
```bash
180180
# Onchain (ERC-8257) registry:
@@ -185,7 +185,7 @@ npx @opensea/tool-sdk pay https://my-tool.vercel.app/api/tool \
185185
# x402 registry (not registered onchain):
186186
npx @opensea/tool-sdk pay https://my-tool.vercel.app/api/tool \
187187
--body '{"query":"hello"}' \
188-
--tool-ref 8453,x402:bazaar,8679018179619845322
188+
--tool-ref 8453,x402_bazaar,8679018179619845322
189189
```
190190

191191
### `auth <url>`

biome.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"**/*.json",
1313
"!**/.claude",
1414
"!**/typechain",
15+
"!lib",
1516
"!**/dist",
1617
"!**/coverage",
1718
"!**/.vercel",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opensea/tool-sdk",
3-
"version": "0.28.4",
3+
"version": "0.28.5",
44
"type": "module",
55
"description": "SDK and CLI for building ERC-8257 compliant AI agent tools",
66
"repository": {
@@ -55,7 +55,7 @@
5555
"tsup": "8.5.1",
5656
"typescript": "6.0.2",
5757
"vitest": "3.2.4",
58-
"@biomejs/biome": "^2.5.2"
58+
"@biomejs/biome": "2.5.2"
5959
},
6060
"engines": {
6161
"node": ">=18.0.0"

src/__tests__/caller-reporter.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ describe("reportCallerX402Usage", () => {
125125
})
126126
})
127127

128-
it("sends x402:bazaar registry and string onchainId in the composite key", async () => {
128+
it("normalizes x402:bazaar registry in the composite key", async () => {
129129
const result = await reportCallerX402Usage(
130130
makeX402Event({
131131
toolChainId: 8453,
@@ -138,7 +138,7 @@ describe("reportCallerX402Usage", () => {
138138

139139
const body = JSON.parse(fetchSpy.mock.calls[0]![1].body)
140140
expect(body.tool_chain_id).toBe(8453)
141-
expect(body.tool_registry_address).toBe("x402:bazaar")
141+
expect(body.tool_registry_address).toBe("x402_bazaar")
142142
expect(body.tool_onchain_id).toBe("8679018179619845322")
143143
expect(body.tool_endpoint).toBeUndefined()
144144
})

src/__tests__/pay.test.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,38 @@ describe("parseToolRef", () => {
3232
})
3333
})
3434

35-
it("parses an x402:bazaar registry whose name contains a colon", async () => {
35+
it("normalizes an x402:bazaar registry to the public source token", async () => {
3636
const { parseToolRef } = await import("../cli/commands/pay.js")
3737
expect(parseToolRef("8453,x402:bazaar,8679018179619845322")).toEqual({
3838
toolChainId: 8453,
39-
toolRegistryAddress: "x402:bazaar",
39+
toolRegistryAddress: "x402_bazaar",
4040
toolOnchainId: "8679018179619845322",
4141
})
4242
})
4343

44-
it("parses an x402:bankr registry", async () => {
44+
it("normalizes x402 registry names case-insensitively", async () => {
4545
const { parseToolRef } = await import("../cli/commands/pay.js")
46-
expect(parseToolRef("8453,x402:bankr,5311379622895099236")).toEqual({
46+
expect(parseToolRef("8453,X402:BANKR,5311379622895099236")).toEqual({
4747
toolChainId: 8453,
48-
toolRegistryAddress: "x402:bankr",
48+
toolRegistryAddress: "x402_bankr",
4949
toolOnchainId: "5311379622895099236",
5050
})
5151
})
5252

53+
it("preserves canonical x402 source tokens", async () => {
54+
const { parseToolRef } = await import("../cli/commands/pay.js")
55+
expect(parseToolRef("8453,x402_bazaar,123").toolRegistryAddress).toBe(
56+
"x402_bazaar",
57+
)
58+
expect(parseToolRef("8453,x402_bankr,123").toolRegistryAddress).toBe(
59+
"x402_bankr",
60+
)
61+
})
62+
5363
it("preserves an onchain id beyond Number.MAX_SAFE_INTEGER as a string", async () => {
5464
const { parseToolRef } = await import("../cli/commands/pay.js")
5565
const big = "9007199254740993" // 2^53 + 1, not representable as a JS number
56-
expect(parseToolRef(`8453,x402:bazaar,${big}`).toolOnchainId).toBe(big)
66+
expect(parseToolRef(`8453,x402_bazaar,${big}`).toolOnchainId).toBe(big)
5767
})
5868

5969
it("accepts onchain id 0", async () => {

src/cli/commands/pay.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from "../../lib/client/x402-payment.js"
1212
import { toX402PaymentRequired } from "../../lib/client/x402-scheme.js"
1313
import { reportCallerX402Usage } from "../../lib/usage/caller-reporter.js"
14+
import { normalizeToolRegistryAddress } from "../../lib/usage/tool-registry.js"
1415
import {
1516
createWalletForProvider,
1617
createWalletFromEnv,
@@ -42,13 +43,14 @@ export interface ToolRef {
4243
* Parse a `--tool-ref` value of the form `chainId,registryAddress,onchainId`
4344
* (comma-separated, exactly three fields).
4445
*
45-
* A comma delimiter keeps the registry identifier unambiguous even when it
46-
* contains a colon, as the x402 registries do (`x402:bazaar`, `x402:bankr`).
46+
* A comma delimiter keeps the registry identifier unambiguous, including for
47+
* the legacy colon forms of the x402 registries (`x402:bazaar`,
48+
* `x402:bankr`), which are accepted and normalized.
4749
*
4850
* Examples:
4951
* `8453,0x265bb2dbfc0a8165c9a1941eb1372f349bad2cf1,65` → onchain ERC-8257
50-
* `8453,x402:bazaar,8679018179619845322` → x402 bazaar tool
51-
* `8453,x402:bankr,5311379622895099236` → x402 bankr tool
52+
* `8453,x402_bazaar,8679018179619845322` → x402 bazaar tool
53+
* `8453,x402_bankr,5311379622895099236` → x402 bankr tool
5254
*
5355
* The onchainId is kept as a string to preserve precision for IDs that
5456
* exceed `Number.MAX_SAFE_INTEGER`.
@@ -78,7 +80,7 @@ export function parseToolRef(ref: string): ToolRef {
7880
}
7981
return {
8082
toolChainId,
81-
toolRegistryAddress: registry,
83+
toolRegistryAddress: normalizeToolRegistryAddress(registry),
8284
toolOnchainId: onchainStr,
8385
}
8486
}
@@ -116,7 +118,7 @@ export const payCommand = new Command("pay")
116118
)
117119
.option(
118120
"--tool-ref <ref>",
119-
"Tool coordinates as chainId,registryAddress,onchainId (e.g. 8453,0x265b...2cf1,65 or 8453,x402:bazaar,123). Disambiguates usage reporting when multiple tools share one endpoint.",
121+
"Tool coordinates as chainId,registryAddress,onchainId (e.g. 8453,0x265b...2cf1,65 or 8453,x402_bazaar,123). x402:bazaar and x402:bankr are also accepted and normalized. Disambiguates usage reporting when multiple tools share one endpoint.",
120122
)
121123
.action(async (url: string, options: PayOptions) => {
122124
// The x402 X-Payment signature is a gasless EIP-3009 authorization — it is

src/lib/usage/caller-reporter.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isAddress } from "viem"
2+
import { normalizeToolRegistryAddress } from "./tool-registry.js"
23

34
const NUMERIC_STRING_RE = /^\d+$/
45

@@ -151,7 +152,9 @@ function buildToolIdentity(
151152
return {
152153
fields: {
153154
tool_chain_id: event.toolChainId,
154-
tool_registry_address: event.toolRegistryAddress,
155+
tool_registry_address: normalizeToolRegistryAddress(
156+
event.toolRegistryAddress,
157+
),
155158
tool_onchain_id: event.toolOnchainId,
156159
},
157160
}

src/lib/usage/tool-registry.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function normalizeToolRegistryAddress(registry: string): string {
2+
switch (registry.toLowerCase()) {
3+
case "x402:bazaar":
4+
return "x402_bazaar"
5+
case "x402:bankr":
6+
return "x402_bankr"
7+
default:
8+
return registry
9+
}
10+
}

0 commit comments

Comments
 (0)