uvd-x402-sdk 2.100.0 → 2.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -6
- package/dist/adapters/index.d.mts +3 -2
- package/dist/adapters/index.d.ts +3 -2
- package/dist/adapters/index.js +522 -126
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +522 -126
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/backend/index.d.mts +2 -2
- package/dist/backend/index.d.ts +2 -2
- package/dist/backend/index.js +490 -64
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/index.mjs +484 -65
- package/dist/backend/index.mjs.map +1 -1
- package/dist/erc8128/index.d.mts +1 -1
- package/dist/erc8128/index.d.ts +1 -1
- package/dist/{index-prkNXpLX.d.mts → index-DKUUBqZO.d.mts} +220 -16
- package/dist/{index-CYMXb5eC.d.ts → index-Di8sCYHx.d.ts} +220 -16
- package/dist/index.d.mts +11 -5
- package/dist/index.d.ts +11 -5
- package/dist/index.js +738 -165
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +735 -166
- package/dist/index.mjs.map +1 -1
- package/dist/ows-BB6Sgj0W.d.ts +342 -0
- package/dist/ows-DazT4KQH.d.mts +342 -0
- package/dist/providers/evm/index.js +31 -1
- package/dist/providers/evm/index.js.map +1 -1
- package/dist/providers/evm/index.mjs +31 -1
- package/dist/providers/evm/index.mjs.map +1 -1
- package/dist/providers/stellar/index.js +28 -0
- package/dist/providers/stellar/index.js.map +1 -1
- package/dist/providers/stellar/index.mjs +28 -0
- package/dist/providers/stellar/index.mjs.map +1 -1
- package/dist/providers/sui/index.js +27 -0
- package/dist/providers/sui/index.js.map +1 -1
- package/dist/providers/sui/index.mjs +27 -0
- package/dist/providers/sui/index.mjs.map +1 -1
- package/dist/react/index.js +49 -4
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +49 -4
- package/dist/react/index.mjs.map +1 -1
- package/dist/{wallet-w7BnImDG.d.mts → wallet-T0NFUUkT.d.mts} +3 -2
- package/dist/{wallet-w7BnImDG.d.ts → wallet-T0NFUUkT.d.ts} +3 -2
- package/package.json +3 -2
- package/src/adapters/env-key.ts +5 -1
- package/src/adapters/index.ts +8 -1
- package/src/adapters/ows.ts +664 -154
- package/src/backend/index.ts +635 -22
- package/src/client/X402Client.ts +23 -3
- package/src/escrow-preauth.ts +32 -4
- package/src/index.ts +21 -1
- package/src/lifecycle-auth.ts +37 -31
- package/src/providers/evm/index.ts +9 -1
- package/src/providers/stellar/index.ts +5 -0
- package/src/providers/sui/index.ts +4 -0
- package/src/utils/uint.ts +252 -0
- package/src/wallet.ts +3 -2
- package/dist/ows-C-KmORG9.d.ts +0 -221
- package/dist/ows-Z9v4GxOZ.d.mts +0 -221
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Users sign a message or transaction, and the Ultravioleta facilitator handles on
|
|
|
17
17
|
- **Buyer Policy**: Per-payment and cumulative budgets, payee allowlist and offer expiry, evaluated against the offer in hand **before signing** — six closed refusal codes in a fixed order
|
|
18
18
|
- **Type-Safe**: Full TypeScript support
|
|
19
19
|
- **React & Wagmi**: First-class integrations
|
|
20
|
-
- **Signing Wallet Adapters**: EnvKeyAdapter (server/CLI), OWSWalletAdapter (Open Wallet Standard), or bring your own
|
|
20
|
+
- **Signing Wallet Adapters**: EnvKeyAdapter (server/CLI), OWSWalletAdapter (Open Wallet Standard vault, Node), or bring your own
|
|
21
21
|
- **ERC-8128 Signed Requests**: Authenticate HTTP requests with a wallet (RFC 9421 + EIP-191) — no API keys
|
|
22
22
|
- **ERC-8004 Trustless Agents**: On-chain reputation and identity across 23 networks (21 EVM + 2 Solana)
|
|
23
23
|
- **Escrow & Refunds**: Hold payments with dispute resolution
|
|
@@ -560,16 +560,22 @@ const result = await wallet.signTypedData(JSON.stringify({
|
|
|
560
560
|
|
|
561
561
|
### OWSWalletAdapter (Open Wallet Standard)
|
|
562
562
|
|
|
563
|
-
|
|
563
|
+
Signs with a wallet kept in an [Open Wallet Standard](https://github.com/open-wallet-standard/core) vault. OWS stores the keys encrypted on disk and signs inside the library, so the key never reaches your process. Node only: `@open-wallet-standard/core` is a native module with prebuilt binaries for Linux (glibc) and macOS, x64 and arm64.
|
|
564
564
|
|
|
565
565
|
```bash
|
|
566
|
-
npm install @open-wallet-standard/core # optional peer dependency
|
|
566
|
+
npm install @open-wallet-standard/core # optional peer dependency, 1.4.2 or later 1.x
|
|
567
567
|
```
|
|
568
568
|
|
|
569
569
|
```typescript
|
|
570
|
+
import * as ows from '@open-wallet-standard/core';
|
|
570
571
|
import { OWSWalletAdapter } from 'uvd-x402-sdk';
|
|
571
572
|
|
|
572
|
-
const wallet = new OWSWalletAdapter(
|
|
573
|
+
const wallet = new OWSWalletAdapter(ows, {
|
|
574
|
+
wallet: 'agent-treasury', // name or id of the wallet in the vault
|
|
575
|
+
passphrase: process.env.OWS_PASSPHRASE, // or an OWS API key; this is also the default
|
|
576
|
+
network: 'base', // chain used when the payload names none
|
|
577
|
+
// vaultPath: '/path/to/vault', // default: the OWS default (~/.ows)
|
|
578
|
+
});
|
|
573
579
|
|
|
574
580
|
const auth = await wallet.signEIP3009({
|
|
575
581
|
to: '0xRecipient...',
|
|
@@ -578,6 +584,29 @@ const auth = await wallet.signEIP3009({
|
|
|
578
584
|
});
|
|
579
585
|
```
|
|
580
586
|
|
|
587
|
+
What it guarantees, tested against `@open-wallet-standard/core` 1.4.2 with an ephemeral key imported into a temporary vault:
|
|
588
|
+
|
|
589
|
+
- For inputs `EnvKeyAdapter` signs, it signs the same bytes: messages, EIP-3009 on every EVM network of the registry, typed data with uint256 up to `2**256 - 1` given as numbers, decimal strings or hex (the lifecycle order's `salt` included), and EIP-1559, EIP-2930 and legacy transactions (EIP-155 or not).
|
|
590
|
+
- Integers are checked against their EIP-712 type before anything is signed. OWS itself signs `2**256` as a uint256 as if it were `0`; the adapter throws `INVALID_AMOUNT` instead.
|
|
591
|
+
- Every signature is recovered with ethers over the digest `EnvKeyAdapter` signs. One that does not recover to `getAddress()` is not returned.
|
|
592
|
+
- `signTransaction` takes the hex ethers serializes, an `ethers.Transaction`, or a transaction object with `from`. A `from` that is not this wallet is refused before signing. A transaction without a `chainId` is signed pre-EIP-155, as `EnvKeyAdapter` signs it.
|
|
593
|
+
- The passphrase is never in the adapter's `JSON.stringify` / `util.inspect` output nor in its errors.
|
|
594
|
+
|
|
595
|
+
It refuses (`INVALID_CONFIG`, nothing signed) some inputs that ethers signs:
|
|
596
|
+
|
|
597
|
+
- Typed data: an integer string with spaces; a bool that is not a boolean (`1`, `0`, `"true"`, `"false"`; ethers signs `"false"` as true); `uint` / `int` without a width; a `primaryType` that is not the root struct (ethers ignores `primaryType` and signs the root).
|
|
598
|
+
- Transaction objects (`ethers.Wallet` signs these): a `type` given as `'0x2'`, `'2'` or a bigint; `to: ''`; `data: ''`; and any key ethers' `Transaction.from` does not read, other than `from` and `hash`. The error names the key, and for `input` / `gas` it names the ethers field (`data` / `gasLimit`).
|
|
599
|
+
|
|
600
|
+
A `vaultPath` that does not exist is created by OWS, so a typo gives "wallet not found".
|
|
601
|
+
|
|
602
|
+
**Migrating from the old form.** Up to 2.100.0 the adapter took a wallet object with `accounts` (the `OWSWallet` type). That shape never worked with `@open-wallet-standard/core` 1.x. It still compiles but is deprecated, and `new OWSWalletAdapter(wallet)` now throws `INVALID_CONFIG`. If you wrapped the library in such an object, drop the wrapper and pass the module and the wallet:
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
// before: new OWSWalletAdapter(createOWSWalletBridge(walletName, passphrase))
|
|
606
|
+
import * as ows from '@open-wallet-standard/core';
|
|
607
|
+
const wallet = new OWSWalletAdapter(ows, { wallet: walletName, passphrase });
|
|
608
|
+
```
|
|
609
|
+
|
|
581
610
|
### Custom Adapter
|
|
582
611
|
|
|
583
612
|
Implement the `SigningWalletAdapter` interface for your own signer:
|
|
@@ -1538,10 +1567,11 @@ const state = await client.queryEscrowState(paymentInfo);
|
|
|
1538
1567
|
### With SigningWalletAdapter (OWS)
|
|
1539
1568
|
|
|
1540
1569
|
```typescript
|
|
1570
|
+
import * as ows from '@open-wallet-standard/core';
|
|
1541
1571
|
import { AdvancedEscrowClient } from 'uvd-x402-sdk/backend';
|
|
1542
1572
|
import { OWSWalletAdapter } from 'uvd-x402-sdk';
|
|
1543
1573
|
|
|
1544
|
-
const wallet = new OWSWalletAdapter(
|
|
1574
|
+
const wallet = new OWSWalletAdapter(ows, { wallet: 'agent-treasury', network: 'base' });
|
|
1545
1575
|
const client = new AdvancedEscrowClient(null, {
|
|
1546
1576
|
wallet,
|
|
1547
1577
|
rpcUrl: 'https://mainnet.base.org',
|
|
@@ -1635,7 +1665,7 @@ Register and discover paid x402 resources across the network.
|
|
|
1635
1665
|
The Bazaar is served by the facilitator itself under `/discovery/*`. No API key, no separate host.
|
|
1636
1666
|
|
|
1637
1667
|
```typescript
|
|
1638
|
-
import { BazaarClient, isAlive } from 'uvd-x402-sdk/backend';
|
|
1668
|
+
import { BazaarClient, bazaarExtension, isAlive } from 'uvd-x402-sdk/backend';
|
|
1639
1669
|
|
|
1640
1670
|
const bazaar = new BazaarClient();
|
|
1641
1671
|
|
|
@@ -1657,6 +1687,16 @@ console.log(`${page.items.length} of ${page.pagination.total}`);
|
|
|
1657
1687
|
// Free-text search. The parameter is `q`; anything else is rejected with a 400.
|
|
1658
1688
|
const hits = await bazaar.listResources({ q: 'logs' });
|
|
1659
1689
|
|
|
1690
|
+
// Routing filters. Each one is sent only when you pass it.
|
|
1691
|
+
const posts = await bazaar.listResources({
|
|
1692
|
+
q: 'look up who owns a phone number, callable by an agent with a POST',
|
|
1693
|
+
method: 'POST', // GET | POST | PUT | PATCH, sent uppercased
|
|
1694
|
+
maxPriceUsd: 0.05, // price at most 5 cents
|
|
1695
|
+
hasInputSchema: true, // only resources that declare their input
|
|
1696
|
+
kind: 'api', // 'api' | 'content'
|
|
1697
|
+
excludeHost: 'tenjin.blog' // host names, comma-separated; not a URL, no port
|
|
1698
|
+
});
|
|
1699
|
+
|
|
1660
1700
|
// Walk the whole filtered catalog, one page at a time
|
|
1661
1701
|
for await (const r of bazaar.iterateResources({ health: 'alive' })) {
|
|
1662
1702
|
if (isAlive(r)) console.log(r.url);
|
|
@@ -1675,6 +1715,9 @@ await bazaar.registerResource({
|
|
|
1675
1715
|
maxTimeoutSeconds: 60,
|
|
1676
1716
|
}],
|
|
1677
1717
|
metadata: { category: 'ai', tags: ['image'] },
|
|
1718
|
+
// How to call it (see bazaarExtension below). Without it the listing
|
|
1719
|
+
// says hasInputSchema: false.
|
|
1720
|
+
extensions: bazaarExtension({ method: 'POST', body: { prompt: 'a red fox' } }),
|
|
1678
1721
|
});
|
|
1679
1722
|
|
|
1680
1723
|
// Aggregate catalog metrics
|
|
@@ -1684,6 +1727,52 @@ console.log(stats.total, stats.visible, stats.byHealth.alive);
|
|
|
1684
1727
|
|
|
1685
1728
|
Timestamps (`firstSeen`, `lastSeen`, `lastUpdated`, `health.lastChecked`) are Unix epoch **seconds**. Use `epochToDate()` to get a `Date`.
|
|
1686
1729
|
|
|
1730
|
+
**Search length.** `q` can be up to 400 characters (`DEFAULT_MAX_SEARCH_LEN`), long enough for a request in natural language. Characters are counted as the facilitator counts them (code points: an emoji is one, not two). A longer `q` is refused before the request. Change the cap with `new BazaarClient({ maxSearchLen })`; against an older facilitator whose substring search takes at most 128 (up to 2.46.1, and some 2.47.0 builds), pass `maxSearchLen: MAX_SEARCH_LEN` to fail before the request instead of getting its 400. `getResourceByUrl()` searches with the URL's first 128 characters, which every facilitator accepts.
|
|
1731
|
+
|
|
1732
|
+
**Routing filters** (`maxPriceUsd`, `method`, `hasInputSchema`, `kind`, `excludeHost`) need facilitator 2.48.0 or later (some 2.47.0 builds have them and some do not). A facilitator without them (every one up to 2.46.1) answers each, as any query parameter it does not know, with a 400 that names it, so the client sends each of these only when you pass it: a call that sets none of them sends exactly what it sent before. A value you pass is sent or refused before the request, never dropped, by the rules the facilitator reads it with: `maxPriceUsd` is a number `>= 0`, sent in decimal (`1e-7` goes out as `0.0000001`) and refused if that takes more than 32 characters; `method` is `GET`, `POST`, `PUT` or `PATCH` in any case; `kind` is `api` or `content`; `excludeHost` is a host name, or up to 20 separated by commas, each matched with its subdomains, with no scheme, path or port. `null` counts as not passed.
|
|
1733
|
+
|
|
1734
|
+
**Registering with `extensions`.** `registerResource({ ..., extensions })` sends the object as the body's `extensions`, which the facilitator keeps as it comes: from `extensions.bazaar.info.input` the listing gets `hasInputSchema: true`, and it is found by `method: 'POST'` when that is what it declares. Pass the same `bazaarExtension(...)` you put in your 402. It must be a plain object of at most 16 KiB as JSON and 64 levels deep (the facilitator drops a bigger one without an error, so the client refuses it before the request). Without `extensions` the request body is exactly what it was. `extensions` only counts on a URL's first registration: registering a URL that is already in the catalog is answered with a 409 (`registerResource` throws) and leaves its record as it was, and the facilitator serves no public route that updates one. A URL listed without `extensions` does not gain them by registering again, so pass them the first time.
|
|
1735
|
+
|
|
1736
|
+
### Declaring your endpoint to the Bazaar (`bazaarExtension`)
|
|
1737
|
+
|
|
1738
|
+
A seller can tell the facilitator how its endpoint is called inside the 402 itself, with the `bazaar` extension of x402 v2 ([spec](https://github.com/coinbase/x402/blob/main/specs/extensions/bazaar.md)). The facilitator catalogs the endpoint from it. The method travels in `info.input.method` and the example body in `info.input.body`: that is what a facilitator needs to probe a POST endpoint with a POST instead of a GET. Pass the same object as `extensions` to `BazaarClient.registerResource()` (above) when you register the endpoint yourself.
|
|
1739
|
+
|
|
1740
|
+
```typescript
|
|
1741
|
+
import { bazaarExtension, create402Response } from 'uvd-x402-sdk';
|
|
1742
|
+
|
|
1743
|
+
// POST (or PUT / PATCH) with a JSON body
|
|
1744
|
+
const { status, headers, body } = create402Response(
|
|
1745
|
+
{
|
|
1746
|
+
amount: '0.05',
|
|
1747
|
+
recipient: '0xYourWallet...',
|
|
1748
|
+
resource: 'https://api.example.com/phone-lookup',
|
|
1749
|
+
chainName: 'base',
|
|
1750
|
+
x402Version: 2,
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
extensions: bazaarExtension({
|
|
1754
|
+
method: 'POST',
|
|
1755
|
+
body: { phone: '+573001234567' }, // example body, required for POST/PUT/PATCH
|
|
1756
|
+
bodySchema: { // optional JSON Schema of the body
|
|
1757
|
+
type: 'object',
|
|
1758
|
+
properties: { phone: { type: 'string' } },
|
|
1759
|
+
required: ['phone'],
|
|
1760
|
+
},
|
|
1761
|
+
output: { example: { owner: 'ACME S.A.S.', carrier: 'Claro' } },
|
|
1762
|
+
}),
|
|
1763
|
+
}
|
|
1764
|
+
);
|
|
1765
|
+
|
|
1766
|
+
// GET (or HEAD / DELETE) with query parameters
|
|
1767
|
+
bazaarExtension({
|
|
1768
|
+
method: 'GET',
|
|
1769
|
+
queryParams: { city: 'Bogota' },
|
|
1770
|
+
output: { example: { city: 'Bogota', temperature: 18 } },
|
|
1771
|
+
});
|
|
1772
|
+
```
|
|
1773
|
+
|
|
1774
|
+
The result is `{ bazaar: { info, schema } }`: `info.input` (`type: "http"`, `method`, then `bodyType` and `body` for a body method, or `queryParams` for a query method, plus optional `headers`), `info.output` (`type`, default `json`, and `example`), and `schema`, the JSON Schema (draft 2020-12) that `info` validates against. `bodyType` is `json` (default), `form-data` or `text` (then `body` is a string). A body method without `body`, a query method with one, or a method the spec does not name (`CONNECT`, `OPTIONS`, ...) throws. `extensions` is a v2 field: `create402Response` throws if the response would be v1 rather than dropping it, and without `extensions` it returns exactly what it returned before.
|
|
1775
|
+
|
|
1687
1776
|
## x402 v2 requests (`buildVerifyRequestV2` / `buildSettleRequestV2`)
|
|
1688
1777
|
|
|
1689
1778
|
If your 402 advertises CAIP-2 networks (`eip155:8453`), you are speaking v2 and
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { X as X402Version, a as PaymentResult } from '../index-DagQ74ZQ.mjs';
|
|
2
|
-
export { E as EnvKeyAdapter, O as
|
|
3
|
-
import '../wallet-
|
|
2
|
+
export { E as EnvKeyAdapter, O as OWSAccountInfo, a as OWSCore, b as OWSSignResult, c as OWSWallet, d as OWSWalletAdapter, e as OWSWalletAdapterOptions } from '../ows-DazT4KQH.mjs';
|
|
3
|
+
import '../wallet-T0NFUUkT.mjs';
|
|
4
|
+
import 'ethers';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* uvd-x402-sdk - Wagmi/Viem Adapter
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { X as X402Version, a as PaymentResult } from '../index-DagQ74ZQ.js';
|
|
2
|
-
export { E as EnvKeyAdapter, O as
|
|
3
|
-
import '../wallet-
|
|
2
|
+
export { E as EnvKeyAdapter, O as OWSAccountInfo, a as OWSCore, b as OWSSignResult, c as OWSWallet, d as OWSWalletAdapter, e as OWSWalletAdapterOptions } from '../ows-BB6Sgj0W.js';
|
|
3
|
+
import '../wallet-T0NFUUkT.js';
|
|
4
|
+
import 'ethers';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* uvd-x402-sdk - Wagmi/Viem Adapter
|