Skip to content

Commit 6ccc884

Browse files
committed
Release v0.14.1
Origin-SHA: 2abe34e59adcdb442de80e2e6a6ee1c6b98b1851
1 parent 8c6ece9 commit 6ccc884

11 files changed

Lines changed: 354 additions & 268 deletions

File tree

CHANGELOG.md

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

3+
## 0.14.1
4+
5+
### Patch Changes
6+
7+
- 776788d: Fix usage reporting to attribute the real caller, and make reporting a service-side-only responsibility.
8+
9+
- x402 usage reports now use the on-chain payer as `caller_address` (after any gate-verified caller), instead of a placeholder address.
10+
- EIP-3009 usage reports now forward the caller's original signed authorization, stashed by `predicateGate` on `ctx.callerAuthorization` and surfaced via `InvocationEvent.callerAuthorization`. The server no longer re-signs as itself.
11+
- Removed `walletClient`, `operatorAddress`, and `tokenAddress` from `Eip3009UsageReporterConfig`. Reporting is authenticated by `apiKey`, and there is no caller self-reporting or signing path. `signZeroValueAuthorization` remains exported for building `Authorization: EIP-3009` request headers.
12+
313
## 0.14.0
414

515
### Minor Changes

README.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ See [docs/predicate-gating-guide.md](docs/predicate-gating-guide.md) for the ful
841841

842842
## Usage Reporting
843843

844-
Report tool invocations to OpenSea's analytics endpoint (`POST /api/v2/tools/usage`) using EIP-3009 zero-value authorizations for caller verification.
844+
Report tool invocations to OpenSea's analytics endpoint (`POST /api/v2/tools/usage`). For each call the SDK reports the **verified caller**: the on-chain **payer** for paid x402 calls, or the caller's **own EIP-3009 authorization** for calls authenticated by `predicateGate`. A tool server never signs on the caller's behalf.
845845

846846
### Setup
847847

@@ -851,7 +851,7 @@ Report tool invocations to OpenSea's analytics endpoint (`POST /api/v2/tools/usa
851851
export OPENSEA_API_KEY="your-api-key"
852852
```
853853

854-
2. **Add `usageReporting` to your handler config** — both free (EIP-3009) and paid (x402) invocations are reported automatically:
854+
2. **Add `usageReporting` to your handler config** — both free (EIP-3009 auth) and paid (x402) invocations are reported automatically:
855855

856856
```typescript
857857
import { createToolHandler } from "@opensea/tool-sdk"
@@ -860,62 +860,66 @@ const handler = createToolHandler({
860860
manifest,
861861
inputSchema,
862862
outputSchema,
863+
gates: [/* x402 paywall and/or predicateGate */],
863864
handler: async (input, ctx) => {
864865
// your tool logic
865866
},
866867
usageReporting: {
867-
walletClient, // caller's viem WalletClient (must have account attached)
868-
chainId: 8453, // chain for EIP-712 USDC domain (Base in this example)
869-
operatorAddress: "0x...", // tool operator / pricing recipient
870-
toolChainId: 8453, // ERC-8257: chain where tool is registered
868+
chainId: 8453, // chain for the EIP-712 USDC domain / x402 fallback
869+
toolChainId: 8453, // ERC-8257: chain where the tool is registered
871870
toolRegistryAddress: "0x...", // ERC-8257: registry contract
872-
toolOnchainId: 42, // ERC-8257: tool ID in registry
871+
toolOnchainId: 42, // ERC-8257: tool ID in the registry
873872
apiKey: process.env.OPENSEA_API_KEY!,
874873
},
875874
})
876875
```
877876

878-
That's it — the handler fires the reporter as a fire-and-forget async call at the very end of the lifecycle, after the response is built. It never blocks or fails the tool call. Free calls send a signed EIP-3009 authorization; paid x402 calls send the settlement tx hash.
877+
> **Reporting is the service's job, never the caller's.** The `apiKey` authenticates *you* (the operator) as the reporter. The caller is identified by data they already supplied (the x402 payer, or the EIP-3009 authorization `predicateGate` verified), so no caller wallet, signing, or `walletClient` is involved.
878+
879+
That's it: the handler fires the reporter as a fire-and-forget async call at the very end of the lifecycle, after the response is built. It never blocks or fails the tool call.
879880

880881
### How it works
881882

882-
The caller's wallet signs a zero-value EIP-3009 `TransferWithAuthorization` message (USDC domain, `value = 0`) proving address ownership. The SDK sends this signature plus the ERC-8257 composite key to the endpoint. No tokens are transferred — this is purely for identity verification and analytics.
883+
- **Paid (x402) calls** report `verification_type: "x402_settlement"` with the on-chain payer address and the settlement transaction hash. The backend verifies the settlement directly, so no signature is needed.
884+
- **EIP-3009-authenticated calls** (e.g. behind `predicateGate`) report `verification_type: "eip3009_authorization"` by **forwarding the caller's original zero-value `TransferWithAuthorization`** (USDC domain, `value = 0`). The caller already signed it to authenticate; the SDK passes that exact signature through, so the reported identity is the real caller, not the server. No tokens are transferred.
883885

884886
### Configuration reference
885887

886888
| Field | Required | Description |
887889
|-------|----------|-------------|
888-
| `walletClient` | Yes | Caller's viem `WalletClient` with attached account |
889-
| `chainId` | Yes | Chain ID for the EIP-712 USDC domain (1, 8453, 137, 42161, 10, 43114) |
890-
| `operatorAddress` | Yes | Tool operator address (used as `to` in the authorization) |
890+
| `chainId` | Yes | Chain ID for the EIP-712 USDC domain / x402 `chain_id` fallback (1, 8453, 137, 42161, 10, 43114) |
891891
| `toolChainId` | Yes | ERC-8257 composite key: chain of registration |
892892
| `toolRegistryAddress` | Yes | ERC-8257 composite key: registry contract |
893893
| `toolOnchainId` | Yes | ERC-8257 composite key: numeric tool ID |
894-
| `apiKey` | Yes | OpenSea API key ([get one here](https://docs.opensea.io/reference/api-keys)) |
894+
| `apiKey` | Yes | OpenSea API key ([get one here](https://docs.opensea.io/reference/api-keys)). Authenticates the tool service as the reporter |
895895
| `aggregatorUrl` | No | Override endpoint URL (default: `https://api.opensea.io/api/v2/tools/usage`) |
896-
| `tokenAddress` | No | Override USDC address (default: canonical address for `chainId`) |
897896
| `timeoutMs` | No | Request timeout in ms (default: 5000) |
898897

899898
### Standalone Reporters
900899

901-
If you need to report usage outside the handler flow (e.g. from a client or a custom pipeline), use the standalone reporter functions directly:
900+
If you report usage outside the handler flow (a custom pipeline or a separate reporting service), use the standalone reporter functions directly.
902901

903902
#### EIP-3009 Reporter
904903

904+
Forwards a caller's already-collected EIP-3009 authorization. Pass an `InvocationEvent` whose `callerAuthorization` holds the authorization your auth layer verified:
905+
905906
```typescript
906907
import { createEip3009UsageReporter } from "@opensea/tool-sdk"
907908

908909
const reportUsage = createEip3009UsageReporter({
909-
walletClient,
910910
chainId: 8453,
911-
operatorAddress: "0x...",
912911
toolChainId: 8453,
913912
toolRegistryAddress: "0x...",
914913
toolOnchainId: 42,
915914
apiKey: process.env.OPENSEA_API_KEY!,
916915
})
917916

918-
await reportUsage({ latencyMs: 123 })
917+
await reportUsage({
918+
paid: false,
919+
latencyMs: 123,
920+
timestamp: Date.now(),
921+
callerAuthorization, // the caller's verified zero-value authorization
922+
})
919923
```
920924

921925
#### x402 Settlement Reporter

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opensea/tool-sdk",
3-
"version": "0.14.0",
3+
"version": "0.14.1",
44
"type": "module",
55
"description": "SDK and CLI for building ERC-8257 compliant AI agent tools",
66
"repository": {

skill/SKILL.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -377,45 +377,42 @@ All CLI commands accept `--wallet-provider privy|turnkey|fireblocks|private-key`
377377

378378
## 7. Usage Tracking
379379

380-
Tool-sdk supports usage tracking via the `onInvocation` callback on `createToolHandler`. This fires after every successful invocation (post-settle, pre-response) with an `InvocationEvent` containing caller identity, payment status, and timing.
380+
Tool-sdk reports usage to OpenSea's analytics endpoint (`POST /api/v2/tools/usage`) for each successful call. It reports the **verified caller**: the on-chain payer for paid x402 calls, or the caller's own EIP-3009 authorization for `predicateGate`-authenticated calls. A tool server never signs on the caller's behalf.
381381

382-
### createEip3009UsageReporter (recommended)
382+
### usageReporting (recommended)
383383

384-
`createEip3009UsageReporter` is the recommended `onInvocation` implementation. It reports tool usage via EIP-3009 zero-value `TransferWithAuthorization` signatures:
384+
Pass `usageReporting` to `createToolHandler` and it fires the reporter as a fire-and-forget call at the very end of the lifecycle (after the response is built). No `walletClient` is needed server-side:
385385

386-
- **Free / gated calls**: signs a zero-value authorization proving the operator controls the wallet, and POSTs with `verification_type: "eip3009_authorization"`.
387-
- **Paid x402 calls**: POSTs with `verification_type: "x402_settlement"` and the settlement tx hash — no additional signature needed.
386+
- **Paid x402 calls**`verification_type: "x402_settlement"` with the payer address and settlement tx hash. The backend verifies the tx directly.
387+
- **EIP-3009-authenticated calls** (behind `predicateGate`) → `verification_type: "eip3009_authorization"`, **forwarding the caller's original signed authorization**. The caller already signed it to authenticate, so the reported identity is the real caller.
388388

389389
```typescript
390-
import { createToolHandler, createEip3009UsageReporter } from "@opensea/tool-sdk"
391-
import { createWalletClient, http } from "viem"
392-
import { privateKeyToAccount } from "viem/accounts"
393-
import { base } from "viem/chains"
394-
395-
const walletClient = createWalletClient({
396-
account: privateKeyToAccount("0x..."),
397-
chain: base,
398-
transport: http(),
399-
})
390+
import { createToolHandler } from "@opensea/tool-sdk"
400391

401392
export const toolHandler = createToolHandler({
402393
manifest,
403394
inputSchema: InputSchema,
404395
outputSchema: OutputSchema,
405-
onInvocation: createEip3009UsageReporter({
406-
walletClient,
407-
chainId: 8453,
408-
// optional: aggregatorUrl, tokenAddress, toolSlug, timeoutMs
409-
}),
396+
gates: [/* x402 paywall and/or predicateGate */],
397+
usageReporting: {
398+
chainId: 8453, // EIP-712 USDC domain / x402 chain_id fallback
399+
toolChainId: 8453, // ERC-8257: chain where the tool is registered
400+
toolRegistryAddress: "0x...", // ERC-8257: registry contract
401+
toolOnchainId: 42, // ERC-8257: tool ID in the registry
402+
apiKey: process.env.OPENSEA_API_KEY!,
403+
// optional: aggregatorUrl, tokenAddress, timeoutMs
404+
},
410405
handler: async (input) => {
411406
return { result: `Processed: ${input.query}` }
412407
},
413408
})
414409
```
415410

411+
Reporting is always the service's responsibility (authenticated by `apiKey`), never the caller's; there is no caller self-reporting path. To report from a custom pipeline instead of the handler, use the standalone `createEip3009UsageReporter` / `createX402UsageReporter` (see the tool-sdk README "Usage Reporting" section).
412+
416413
### onInvocation callback
417414

418-
You can also provide a custom `onInvocation` callback for bespoke analytics:
415+
You can also provide a custom `onInvocation` callback for bespoke analytics. It fires after the handler succeeds and settles, before the response is returned, with an `InvocationEvent` containing caller identity, payment status, and timing:
419416

420417
```typescript
421418
import { createToolHandler } from "@opensea/tool-sdk"

0 commit comments

Comments
 (0)