uvd-x402-sdk 2.107.0 → 2.108.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 +2 -0
- package/dist/providers/near/index.d.mts +97 -1
- package/dist/providers/near/index.d.ts +97 -1
- package/dist/providers/near/index.js +281 -11
- package/dist/providers/near/index.js.map +1 -1
- package/dist/providers/near/index.mjs +266 -13
- package/dist/providers/near/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/providers/near/escrow.ts +288 -0
- package/src/providers/near/index.ts +2 -0
- package/src/providers/near/vectors/arras-v1.json +129 -0
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Users sign a message or transaction, and the Ultravioleta facilitator handles on
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
+
**Arras NEAR escrow (v2.108.0):** offline local-key NEP-366 authorization, canonical Rust payment IDs and pull lifecycle helpers through `uvd-x402-sdk/near`. [Guide and agent example](docs/near-escrow.md). As of 2026-11-02 the facilitator advertises escrow only on testnet, and the SDK's escrow contract registry has no mainnet row yet.
|
|
14
|
+
|
|
13
15
|
- **31 Networks**: EVM (19 including HashKey Chain, Arc, Scroll, SKALE Base, Robinhood Chain), Solana, Fogo, Stellar, NEAR, Algorand, Sui, XRP Ledger, Hedera (mainnet + testnet)
|
|
14
16
|
- **Multi-Stablecoin**: USDC, EURC, AUSD, PYUSD, USDT, USDG (Robinhood Chain)
|
|
15
17
|
- **x402 v1 & v2**: Protocol auto-detection; native Hedera supports v2/exact only
|
|
@@ -1,5 +1,101 @@
|
|
|
1
1
|
import { W as WalletAdapter, C as ChainConfig, P as PaymentInfo, X as X402Version } from '../../index-DARXHuQl.mjs';
|
|
2
2
|
|
|
3
|
+
type NearEscrowNetwork = 'near:mainnet' | 'near:testnet';
|
|
4
|
+
/** Numbers must be safe integers; use decimal strings or bigint for nanoseconds and u128. */
|
|
5
|
+
type NearUnsigned = string | bigint | number;
|
|
6
|
+
interface EscrowMsgParams {
|
|
7
|
+
operator_id: string;
|
|
8
|
+
receiver: string;
|
|
9
|
+
release_deadline: NearUnsigned;
|
|
10
|
+
reclaim_after: NearUnsigned;
|
|
11
|
+
fee_bps_max: number;
|
|
12
|
+
terms_hash: string;
|
|
13
|
+
salt: string;
|
|
14
|
+
}
|
|
15
|
+
interface PaymentIdParams extends EscrowMsgParams {
|
|
16
|
+
token: string;
|
|
17
|
+
payer: string;
|
|
18
|
+
amount: NearUnsigned;
|
|
19
|
+
}
|
|
20
|
+
interface NearLocalSigner {
|
|
21
|
+
readonly publicKey: Uint8Array;
|
|
22
|
+
/** Sign the NEP-366 SHA-256 digest directly, without a NEP-413 envelope. */
|
|
23
|
+
sign(digest: Uint8Array): Uint8Array | Promise<Uint8Array>;
|
|
24
|
+
}
|
|
25
|
+
interface NearEscrowDelegateOptions {
|
|
26
|
+
network: NearEscrowNetwork;
|
|
27
|
+
signer: NearLocalSigner;
|
|
28
|
+
senderId: string;
|
|
29
|
+
escrowContract: string;
|
|
30
|
+
/** The next access-key nonce, not the current nonce. */
|
|
31
|
+
nonce: NearUnsigned;
|
|
32
|
+
maxBlockHeight: NearUnsigned;
|
|
33
|
+
/** Gas units (1 TGas = 10^12), not a floating point TGas count. */
|
|
34
|
+
gas?: NearUnsigned;
|
|
35
|
+
}
|
|
36
|
+
interface EscrowAuthorizationOptions extends NearEscrowDelegateOptions {
|
|
37
|
+
token: string;
|
|
38
|
+
amount: NearUnsigned;
|
|
39
|
+
msg: EscrowMsgParams;
|
|
40
|
+
}
|
|
41
|
+
interface NearEscrowPayment {
|
|
42
|
+
x402Version: 2;
|
|
43
|
+
scheme: 'escrow';
|
|
44
|
+
network: NearEscrowNetwork;
|
|
45
|
+
payload: {
|
|
46
|
+
signedDelegateAction: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface NearEscrowFunctionCall {
|
|
50
|
+
methodName: string;
|
|
51
|
+
args: string;
|
|
52
|
+
gas: NearUnsigned;
|
|
53
|
+
deposit: NearUnsigned;
|
|
54
|
+
}
|
|
55
|
+
interface NearEscrowDelegate {
|
|
56
|
+
senderId: string;
|
|
57
|
+
receiverId: string;
|
|
58
|
+
actions: NearEscrowFunctionCall[];
|
|
59
|
+
nonce: NearUnsigned;
|
|
60
|
+
maxBlockHeight: NearUnsigned;
|
|
61
|
+
}
|
|
62
|
+
declare const NEAR_ESCROW_MIN_GAS = 38000000000000n;
|
|
63
|
+
declare const NEAR_ESCROW_MAX_GAS = 100000000000000n;
|
|
64
|
+
declare const NEAR_ESCROW_TOKENS: Readonly<Record<NearEscrowNetwork, string>>;
|
|
65
|
+
/**
|
|
66
|
+
* The Arras escrow deployments this SDK signs for, per network. Any other escrowContract is refused before the
|
|
67
|
+
* signer is called, for authorization and lifecycle alike: a signed delegate can be relayed by anyone, so a 402
|
|
68
|
+
* server must not be able to point it at its own account. Mainnet stays empty until its contract ships in a release.
|
|
69
|
+
*/
|
|
70
|
+
declare const NEAR_ESCROW_CONTRACTS: Readonly<Record<NearEscrowNetwork, readonly string[]>>;
|
|
71
|
+
/** Canonical Arras JSON: field order, decimal-string timestamps, lowercase hex, no spaces. */
|
|
72
|
+
declare function buildEscrowMsg(p: EscrowMsgParams): string;
|
|
73
|
+
/** Exact Rust Borsh preimage, exposed for cross-language conformance. */
|
|
74
|
+
declare function paymentIdPreimage(p: PaymentIdParams): Uint8Array;
|
|
75
|
+
declare function computePaymentId(p: PaymentIdParams): string;
|
|
76
|
+
/** A 32-byte Ed25519 seed, or a NEAR ed25519: base58 secret (seed + public key, 64 bytes). */
|
|
77
|
+
declare function createNearLocalSigner(secret: Uint8Array | string): NearLocalSigner;
|
|
78
|
+
/** Build the one allowed FT action. The contract must be in NEAR_ESCROW_CONTRACTS; the operator comes from trusted /supported configuration. */
|
|
79
|
+
declare function buildEscrowAuthorizationDelegate(o: EscrowAuthorizationOptions): NearEscrowDelegate;
|
|
80
|
+
/** Validate before signing, including strict byte binding to the expected canonical FT arguments. */
|
|
81
|
+
declare function validateEscrowAuthorizationDelegate(d: NearEscrowDelegate, o: EscrowAuthorizationOptions): void;
|
|
82
|
+
declare function signEscrowAuthorization(options: EscrowAuthorizationOptions): Promise<NearEscrowPayment>;
|
|
83
|
+
type NearEscrowLifecycleMethod = 'release' | 'refund' | 'reclaim' | 'withdraw' | 'withdraw_for';
|
|
84
|
+
declare function signEscrowLifecycle(options: NearEscrowDelegateOptions, method: NearEscrowLifecycleMethod, args?: {
|
|
85
|
+
payment_id?: string;
|
|
86
|
+
amount?: NearUnsigned | null;
|
|
87
|
+
account?: string;
|
|
88
|
+
}): Promise<NearEscrowPayment>;
|
|
89
|
+
declare const release: (o: NearEscrowDelegateOptions, paymentId: string, amount?: NearUnsigned | null) => Promise<NearEscrowPayment>;
|
|
90
|
+
declare const refund: (o: NearEscrowDelegateOptions, paymentId: string) => Promise<NearEscrowPayment>;
|
|
91
|
+
declare const reclaim: (o: NearEscrowDelegateOptions, paymentId: string) => Promise<NearEscrowPayment>;
|
|
92
|
+
declare const withdraw: (o: NearEscrowDelegateOptions) => Promise<NearEscrowPayment>;
|
|
93
|
+
declare const withdrawFor: (o: NearEscrowDelegateOptions, account: string) => Promise<NearEscrowPayment>;
|
|
94
|
+
/** v2 boundary only: no budget wire format or signing is defined until Arras v2 supplies its vectors. */
|
|
95
|
+
interface AuthorizeFromBudget {
|
|
96
|
+
authorizeFromBudget(request: unknown): Promise<NearEscrowPayment>;
|
|
97
|
+
}
|
|
98
|
+
|
|
3
99
|
/**
|
|
4
100
|
* uvd-x402-sdk - NEAR Provider
|
|
5
101
|
*
|
|
@@ -138,4 +234,4 @@ declare class NEARProvider implements WalletAdapter {
|
|
|
138
234
|
private base58Encode;
|
|
139
235
|
}
|
|
140
236
|
|
|
141
|
-
export { NEARProvider, type WalletSelectorOptions, NEARProvider as default };
|
|
237
|
+
export { type AuthorizeFromBudget, type EscrowAuthorizationOptions, type EscrowMsgParams, NEARProvider, NEAR_ESCROW_CONTRACTS, NEAR_ESCROW_MAX_GAS, NEAR_ESCROW_MIN_GAS, NEAR_ESCROW_TOKENS, type NearEscrowDelegate, type NearEscrowDelegateOptions, type NearEscrowFunctionCall, type NearEscrowLifecycleMethod, type NearEscrowNetwork, type NearEscrowPayment, type NearLocalSigner, type NearUnsigned, type PaymentIdParams, type WalletSelectorOptions, buildEscrowAuthorizationDelegate, buildEscrowMsg, computePaymentId, createNearLocalSigner, NEARProvider as default, paymentIdPreimage, reclaim, refund, release, signEscrowAuthorization, signEscrowLifecycle, validateEscrowAuthorizationDelegate, withdraw, withdrawFor };
|
|
@@ -1,5 +1,101 @@
|
|
|
1
1
|
import { W as WalletAdapter, C as ChainConfig, P as PaymentInfo, X as X402Version } from '../../index-DARXHuQl.js';
|
|
2
2
|
|
|
3
|
+
type NearEscrowNetwork = 'near:mainnet' | 'near:testnet';
|
|
4
|
+
/** Numbers must be safe integers; use decimal strings or bigint for nanoseconds and u128. */
|
|
5
|
+
type NearUnsigned = string | bigint | number;
|
|
6
|
+
interface EscrowMsgParams {
|
|
7
|
+
operator_id: string;
|
|
8
|
+
receiver: string;
|
|
9
|
+
release_deadline: NearUnsigned;
|
|
10
|
+
reclaim_after: NearUnsigned;
|
|
11
|
+
fee_bps_max: number;
|
|
12
|
+
terms_hash: string;
|
|
13
|
+
salt: string;
|
|
14
|
+
}
|
|
15
|
+
interface PaymentIdParams extends EscrowMsgParams {
|
|
16
|
+
token: string;
|
|
17
|
+
payer: string;
|
|
18
|
+
amount: NearUnsigned;
|
|
19
|
+
}
|
|
20
|
+
interface NearLocalSigner {
|
|
21
|
+
readonly publicKey: Uint8Array;
|
|
22
|
+
/** Sign the NEP-366 SHA-256 digest directly, without a NEP-413 envelope. */
|
|
23
|
+
sign(digest: Uint8Array): Uint8Array | Promise<Uint8Array>;
|
|
24
|
+
}
|
|
25
|
+
interface NearEscrowDelegateOptions {
|
|
26
|
+
network: NearEscrowNetwork;
|
|
27
|
+
signer: NearLocalSigner;
|
|
28
|
+
senderId: string;
|
|
29
|
+
escrowContract: string;
|
|
30
|
+
/** The next access-key nonce, not the current nonce. */
|
|
31
|
+
nonce: NearUnsigned;
|
|
32
|
+
maxBlockHeight: NearUnsigned;
|
|
33
|
+
/** Gas units (1 TGas = 10^12), not a floating point TGas count. */
|
|
34
|
+
gas?: NearUnsigned;
|
|
35
|
+
}
|
|
36
|
+
interface EscrowAuthorizationOptions extends NearEscrowDelegateOptions {
|
|
37
|
+
token: string;
|
|
38
|
+
amount: NearUnsigned;
|
|
39
|
+
msg: EscrowMsgParams;
|
|
40
|
+
}
|
|
41
|
+
interface NearEscrowPayment {
|
|
42
|
+
x402Version: 2;
|
|
43
|
+
scheme: 'escrow';
|
|
44
|
+
network: NearEscrowNetwork;
|
|
45
|
+
payload: {
|
|
46
|
+
signedDelegateAction: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface NearEscrowFunctionCall {
|
|
50
|
+
methodName: string;
|
|
51
|
+
args: string;
|
|
52
|
+
gas: NearUnsigned;
|
|
53
|
+
deposit: NearUnsigned;
|
|
54
|
+
}
|
|
55
|
+
interface NearEscrowDelegate {
|
|
56
|
+
senderId: string;
|
|
57
|
+
receiverId: string;
|
|
58
|
+
actions: NearEscrowFunctionCall[];
|
|
59
|
+
nonce: NearUnsigned;
|
|
60
|
+
maxBlockHeight: NearUnsigned;
|
|
61
|
+
}
|
|
62
|
+
declare const NEAR_ESCROW_MIN_GAS = 38000000000000n;
|
|
63
|
+
declare const NEAR_ESCROW_MAX_GAS = 100000000000000n;
|
|
64
|
+
declare const NEAR_ESCROW_TOKENS: Readonly<Record<NearEscrowNetwork, string>>;
|
|
65
|
+
/**
|
|
66
|
+
* The Arras escrow deployments this SDK signs for, per network. Any other escrowContract is refused before the
|
|
67
|
+
* signer is called, for authorization and lifecycle alike: a signed delegate can be relayed by anyone, so a 402
|
|
68
|
+
* server must not be able to point it at its own account. Mainnet stays empty until its contract ships in a release.
|
|
69
|
+
*/
|
|
70
|
+
declare const NEAR_ESCROW_CONTRACTS: Readonly<Record<NearEscrowNetwork, readonly string[]>>;
|
|
71
|
+
/** Canonical Arras JSON: field order, decimal-string timestamps, lowercase hex, no spaces. */
|
|
72
|
+
declare function buildEscrowMsg(p: EscrowMsgParams): string;
|
|
73
|
+
/** Exact Rust Borsh preimage, exposed for cross-language conformance. */
|
|
74
|
+
declare function paymentIdPreimage(p: PaymentIdParams): Uint8Array;
|
|
75
|
+
declare function computePaymentId(p: PaymentIdParams): string;
|
|
76
|
+
/** A 32-byte Ed25519 seed, or a NEAR ed25519: base58 secret (seed + public key, 64 bytes). */
|
|
77
|
+
declare function createNearLocalSigner(secret: Uint8Array | string): NearLocalSigner;
|
|
78
|
+
/** Build the one allowed FT action. The contract must be in NEAR_ESCROW_CONTRACTS; the operator comes from trusted /supported configuration. */
|
|
79
|
+
declare function buildEscrowAuthorizationDelegate(o: EscrowAuthorizationOptions): NearEscrowDelegate;
|
|
80
|
+
/** Validate before signing, including strict byte binding to the expected canonical FT arguments. */
|
|
81
|
+
declare function validateEscrowAuthorizationDelegate(d: NearEscrowDelegate, o: EscrowAuthorizationOptions): void;
|
|
82
|
+
declare function signEscrowAuthorization(options: EscrowAuthorizationOptions): Promise<NearEscrowPayment>;
|
|
83
|
+
type NearEscrowLifecycleMethod = 'release' | 'refund' | 'reclaim' | 'withdraw' | 'withdraw_for';
|
|
84
|
+
declare function signEscrowLifecycle(options: NearEscrowDelegateOptions, method: NearEscrowLifecycleMethod, args?: {
|
|
85
|
+
payment_id?: string;
|
|
86
|
+
amount?: NearUnsigned | null;
|
|
87
|
+
account?: string;
|
|
88
|
+
}): Promise<NearEscrowPayment>;
|
|
89
|
+
declare const release: (o: NearEscrowDelegateOptions, paymentId: string, amount?: NearUnsigned | null) => Promise<NearEscrowPayment>;
|
|
90
|
+
declare const refund: (o: NearEscrowDelegateOptions, paymentId: string) => Promise<NearEscrowPayment>;
|
|
91
|
+
declare const reclaim: (o: NearEscrowDelegateOptions, paymentId: string) => Promise<NearEscrowPayment>;
|
|
92
|
+
declare const withdraw: (o: NearEscrowDelegateOptions) => Promise<NearEscrowPayment>;
|
|
93
|
+
declare const withdrawFor: (o: NearEscrowDelegateOptions, account: string) => Promise<NearEscrowPayment>;
|
|
94
|
+
/** v2 boundary only: no budget wire format or signing is defined until Arras v2 supplies its vectors. */
|
|
95
|
+
interface AuthorizeFromBudget {
|
|
96
|
+
authorizeFromBudget(request: unknown): Promise<NearEscrowPayment>;
|
|
97
|
+
}
|
|
98
|
+
|
|
3
99
|
/**
|
|
4
100
|
* uvd-x402-sdk - NEAR Provider
|
|
5
101
|
*
|
|
@@ -138,4 +234,4 @@ declare class NEARProvider implements WalletAdapter {
|
|
|
138
234
|
private base58Encode;
|
|
139
235
|
}
|
|
140
236
|
|
|
141
|
-
export { NEARProvider, type WalletSelectorOptions, NEARProvider as default };
|
|
237
|
+
export { type AuthorizeFromBudget, type EscrowAuthorizationOptions, type EscrowMsgParams, NEARProvider, NEAR_ESCROW_CONTRACTS, NEAR_ESCROW_MAX_GAS, NEAR_ESCROW_MIN_GAS, NEAR_ESCROW_TOKENS, type NearEscrowDelegate, type NearEscrowDelegateOptions, type NearEscrowFunctionCall, type NearEscrowLifecycleMethod, type NearEscrowNetwork, type NearEscrowPayment, type NearLocalSigner, type NearUnsigned, type PaymentIdParams, type WalletSelectorOptions, buildEscrowAuthorizationDelegate, buildEscrowMsg, computePaymentId, createNearLocalSigner, NEARProvider as default, paymentIdPreimage, reclaim, refund, release, signEscrowAuthorization, signEscrowLifecycle, validateEscrowAuthorizationDelegate, withdraw, withdrawFor };
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var ethers = require('ethers');
|
|
6
|
+
var ed25519 = require('@noble/curves/ed25519');
|
|
7
|
+
var sha256 = require('@noble/hashes/sha256');
|
|
6
8
|
|
|
7
9
|
// src/types/index.ts
|
|
8
10
|
var CAIP2_IDENTIFIERS = {
|
|
@@ -1298,6 +1300,257 @@ function chainToCAIP2(chainName) {
|
|
|
1298
1300
|
}
|
|
1299
1301
|
return chainName;
|
|
1300
1302
|
}
|
|
1303
|
+
var NEAR_ESCROW_MIN_GAS = 38000000000000n;
|
|
1304
|
+
var NEAR_ESCROW_MAX_GAS = 100000000000000n;
|
|
1305
|
+
var NEAR_ESCROW_TOKENS = Object.freeze({
|
|
1306
|
+
"near:mainnet": "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
|
|
1307
|
+
"near:testnet": "3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af"
|
|
1308
|
+
});
|
|
1309
|
+
var NEAR_ESCROW_CONTRACTS = Object.freeze({
|
|
1310
|
+
"near:testnet": Object.freeze(["arras-v1b-1101.testnet"]),
|
|
1311
|
+
"near:mainnet": Object.freeze([])
|
|
1312
|
+
});
|
|
1313
|
+
var NONCE_RANGE_MULTIPLIER = 1000000n;
|
|
1314
|
+
function fullMatch(pattern, value) {
|
|
1315
|
+
return pattern.exec(value)?.[0] === value;
|
|
1316
|
+
}
|
|
1317
|
+
function uint(value, bits, name) {
|
|
1318
|
+
if (typeof value !== "bigint" && typeof value !== "number" && typeof value !== "string" || typeof value === "number" && !Number.isSafeInteger(value) || typeof value === "string" && !fullMatch(/^(0|[1-9][0-9]*)$/, value)) {
|
|
1319
|
+
throw new Error(`${name}: expected an exact unsigned integer`);
|
|
1320
|
+
}
|
|
1321
|
+
const n = BigInt(value);
|
|
1322
|
+
if (n < 0n || n >= 1n << BigInt(bits)) throw new Error(`${name}: out of u${bits} range`);
|
|
1323
|
+
return n;
|
|
1324
|
+
}
|
|
1325
|
+
function account(value, name) {
|
|
1326
|
+
if (typeof value !== "string" || value.length < 2 || value.length > 64 || !fullMatch(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/, value)) throw new Error(`${name}: invalid NEAR account`);
|
|
1327
|
+
}
|
|
1328
|
+
function hex(value, size, name) {
|
|
1329
|
+
if (typeof value !== "string" || value.length !== size * 2 || !fullMatch(/^[0-9a-f]+$/, value)) {
|
|
1330
|
+
throw new Error(`${name}: expected ${size} bytes of lowercase hex without 0x`);
|
|
1331
|
+
}
|
|
1332
|
+
return Uint8Array.from(value.match(/../g), (v) => parseInt(v, 16));
|
|
1333
|
+
}
|
|
1334
|
+
function concat(...parts) {
|
|
1335
|
+
const out = new Uint8Array(parts.reduce((sum, p) => sum + p.length, 0));
|
|
1336
|
+
let at = 0;
|
|
1337
|
+
for (const part of parts) {
|
|
1338
|
+
out.set(part, at);
|
|
1339
|
+
at += part.length;
|
|
1340
|
+
}
|
|
1341
|
+
return out;
|
|
1342
|
+
}
|
|
1343
|
+
function le(n, size) {
|
|
1344
|
+
return Uint8Array.from({ length: size }, (_, i) => Number(n >> BigInt(i * 8) & 255n));
|
|
1345
|
+
}
|
|
1346
|
+
function str(s) {
|
|
1347
|
+
const bytes = new TextEncoder().encode(s);
|
|
1348
|
+
return concat(le(BigInt(bytes.length), 4), bytes);
|
|
1349
|
+
}
|
|
1350
|
+
function unbase58(value) {
|
|
1351
|
+
const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1352
|
+
if (!value || value.length > 128) throw new Error("Invalid base58 length");
|
|
1353
|
+
let n = 0n;
|
|
1354
|
+
for (const c of value) {
|
|
1355
|
+
const digit = alphabet.indexOf(c);
|
|
1356
|
+
if (digit < 0) throw new Error("Invalid base58 character");
|
|
1357
|
+
n = n * 58n + BigInt(digit);
|
|
1358
|
+
}
|
|
1359
|
+
const bytes = [];
|
|
1360
|
+
while (n > 0n) {
|
|
1361
|
+
bytes.push(Number(n & 255n));
|
|
1362
|
+
n >>= 8n;
|
|
1363
|
+
}
|
|
1364
|
+
const zeros = value.match(/^1*/u)[0].length;
|
|
1365
|
+
return concat(new Uint8Array(zeros), Uint8Array.from(bytes.reverse()));
|
|
1366
|
+
}
|
|
1367
|
+
function msgValues(p) {
|
|
1368
|
+
if (typeof p.operator_id !== "string" || !fullMatch(/^[a-z0-9_-]{1,32}$/, p.operator_id)) {
|
|
1369
|
+
throw new Error("operator_id: expected [a-z0-9_-]{1,32}");
|
|
1370
|
+
}
|
|
1371
|
+
account(p.receiver, "receiver");
|
|
1372
|
+
const release2 = uint(p.release_deadline, 64, "release_deadline");
|
|
1373
|
+
const reclaim2 = uint(p.reclaim_after, 64, "reclaim_after");
|
|
1374
|
+
if (release2 >= reclaim2) throw new Error("release_deadline must precede reclaim_after");
|
|
1375
|
+
if (typeof p.fee_bps_max !== "number") throw new Error("fee_bps_max: expected a number");
|
|
1376
|
+
const fee = uint(p.fee_bps_max, 16, "fee_bps_max");
|
|
1377
|
+
return { release: release2, reclaim: reclaim2, fee, terms: hex(p.terms_hash, 32, "terms_hash"), salt: hex(p.salt, 16, "salt") };
|
|
1378
|
+
}
|
|
1379
|
+
function buildEscrowMsg(p) {
|
|
1380
|
+
const v = msgValues(p);
|
|
1381
|
+
return JSON.stringify({
|
|
1382
|
+
v: 1,
|
|
1383
|
+
action: "authorize",
|
|
1384
|
+
operator_id: p.operator_id,
|
|
1385
|
+
receiver: p.receiver,
|
|
1386
|
+
release_deadline: v.release.toString(),
|
|
1387
|
+
reclaim_after: v.reclaim.toString(),
|
|
1388
|
+
fee_bps_max: Number(v.fee),
|
|
1389
|
+
terms_hash: p.terms_hash,
|
|
1390
|
+
salt: p.salt
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
function paymentIdPreimage(p) {
|
|
1394
|
+
const v = msgValues(p);
|
|
1395
|
+
account(p.token, "token");
|
|
1396
|
+
account(p.payer, "payer");
|
|
1397
|
+
return concat(
|
|
1398
|
+
Uint8Array.of(1),
|
|
1399
|
+
str(p.operator_id),
|
|
1400
|
+
str(p.token),
|
|
1401
|
+
str(p.payer),
|
|
1402
|
+
str(p.receiver),
|
|
1403
|
+
le(uint(p.amount, 128, "amount"), 16),
|
|
1404
|
+
le(v.release, 8),
|
|
1405
|
+
le(v.reclaim, 8),
|
|
1406
|
+
le(v.fee, 2),
|
|
1407
|
+
v.terms,
|
|
1408
|
+
v.salt
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
function computePaymentId(p) {
|
|
1412
|
+
return ethers.encodeBase58(sha256.sha256(paymentIdPreimage(p)));
|
|
1413
|
+
}
|
|
1414
|
+
function createNearLocalSigner(secret) {
|
|
1415
|
+
let raw;
|
|
1416
|
+
if (typeof secret === "string") {
|
|
1417
|
+
if (!secret.startsWith("ed25519:")) throw new Error("Expected ed25519: secret key");
|
|
1418
|
+
raw = unbase58(secret.slice(8));
|
|
1419
|
+
if (raw.length !== 64) throw new Error("NEAR secret key must contain 64 bytes");
|
|
1420
|
+
} else if (secret instanceof Uint8Array && secret.length === 32) {
|
|
1421
|
+
raw = new Uint8Array(secret);
|
|
1422
|
+
} else throw new Error("Expected a 32-byte seed or NEAR secret key");
|
|
1423
|
+
const seed = raw.slice(0, 32);
|
|
1424
|
+
const publicKey = ed25519.ed25519.getPublicKey(seed);
|
|
1425
|
+
if (raw.length === 64 && !raw.slice(32).every((b, i) => b === publicKey[i])) {
|
|
1426
|
+
throw new Error("NEAR secret key public half does not match seed");
|
|
1427
|
+
}
|
|
1428
|
+
return { get publicKey() {
|
|
1429
|
+
return publicKey.slice();
|
|
1430
|
+
}, sign: (digest) => ed25519.ed25519.sign(digest, seed) };
|
|
1431
|
+
}
|
|
1432
|
+
function delegateOptions(o) {
|
|
1433
|
+
if (o.network !== "near:mainnet" && o.network !== "near:testnet") throw new Error("Unsupported NEAR network");
|
|
1434
|
+
account(o.senderId, "senderId");
|
|
1435
|
+
account(o.escrowContract, "escrowContract");
|
|
1436
|
+
if (!NEAR_ESCROW_CONTRACTS[o.network].includes(o.escrowContract)) {
|
|
1437
|
+
throw new Error(`escrowContract: not a registered Arras escrow for ${o.network}`);
|
|
1438
|
+
}
|
|
1439
|
+
const nonce = uint(o.nonce, 64, "nonce");
|
|
1440
|
+
if (nonce === 0n) throw new Error("nonce must be positive");
|
|
1441
|
+
const height = uint(o.maxBlockHeight, 64, "maxBlockHeight");
|
|
1442
|
+
if (height === 0n) throw new Error("maxBlockHeight must be positive");
|
|
1443
|
+
if (nonce >= height * NONCE_RANGE_MULTIPLIER) throw new Error("nonce must be below maxBlockHeight * 10^6");
|
|
1444
|
+
}
|
|
1445
|
+
function buildEscrowAuthorizationDelegate(o) {
|
|
1446
|
+
delegateOptions(o);
|
|
1447
|
+
if (o.token !== NEAR_ESCROW_TOKENS[o.network]) throw new Error("token does not match network USDC");
|
|
1448
|
+
if (o.msg.receiver === o.senderId || o.msg.receiver === o.escrowContract) throw new Error("receiver equals payer or escrow");
|
|
1449
|
+
const amount = uint(o.amount, 128, "amount");
|
|
1450
|
+
if (amount === 0n) throw new Error("amount must be positive");
|
|
1451
|
+
return {
|
|
1452
|
+
senderId: o.senderId,
|
|
1453
|
+
receiverId: o.token,
|
|
1454
|
+
nonce: o.nonce,
|
|
1455
|
+
maxBlockHeight: o.maxBlockHeight,
|
|
1456
|
+
actions: [{ methodName: "ft_transfer_call", args: JSON.stringify({
|
|
1457
|
+
receiver_id: o.escrowContract,
|
|
1458
|
+
amount: amount.toString(),
|
|
1459
|
+
msg: buildEscrowMsg(o.msg)
|
|
1460
|
+
}), gas: o.gas ?? NEAR_ESCROW_MAX_GAS, deposit: 1n }]
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
function validateEscrowAuthorizationDelegate(d, o) {
|
|
1464
|
+
const expected = buildEscrowAuthorizationDelegate(o);
|
|
1465
|
+
if (d.senderId !== expected.senderId || d.receiverId !== expected.receiverId || uint(d.nonce, 64, "nonce") !== uint(expected.nonce, 64, "nonce") || uint(d.maxBlockHeight, 64, "maxBlockHeight") !== uint(expected.maxBlockHeight, 64, "maxBlockHeight")) {
|
|
1466
|
+
throw new Error("Delegate does not match authorization");
|
|
1467
|
+
}
|
|
1468
|
+
if (d.actions.length !== 1) throw new Error("Expected exactly one action");
|
|
1469
|
+
const a = d.actions[0];
|
|
1470
|
+
if (a.methodName !== "ft_transfer_call" || a.args !== expected.actions[0].args) throw new Error("FT method or arguments mismatch");
|
|
1471
|
+
if (uint(a.deposit, 128, "deposit") !== 1n) throw new Error("FT deposit must be 1 yocto");
|
|
1472
|
+
const gas = uint(a.gas, 64, "gas");
|
|
1473
|
+
if (gas < NEAR_ESCROW_MIN_GAS || gas > NEAR_ESCROW_MAX_GAS) throw new Error("FT gas outside 38..100 TGas");
|
|
1474
|
+
}
|
|
1475
|
+
async function signDelegate(o, d) {
|
|
1476
|
+
const network = o.network;
|
|
1477
|
+
const pk = new Uint8Array(o.signer.publicKey);
|
|
1478
|
+
if (pk.length !== 32) throw new Error("Expected 32-byte Ed25519 public key");
|
|
1479
|
+
const a = d.actions[0];
|
|
1480
|
+
const bytes = concat(
|
|
1481
|
+
str(d.senderId),
|
|
1482
|
+
str(d.receiverId),
|
|
1483
|
+
le(1n, 4),
|
|
1484
|
+
Uint8Array.of(2),
|
|
1485
|
+
str(a.methodName),
|
|
1486
|
+
str(a.args),
|
|
1487
|
+
le(uint(a.gas, 64, "gas"), 8),
|
|
1488
|
+
le(uint(a.deposit, 128, "deposit"), 16),
|
|
1489
|
+
le(uint(d.nonce, 64, "nonce"), 8),
|
|
1490
|
+
le(uint(d.maxBlockHeight, 64, "maxBlockHeight"), 8),
|
|
1491
|
+
Uint8Array.of(0),
|
|
1492
|
+
pk
|
|
1493
|
+
);
|
|
1494
|
+
const digest = sha256.sha256(concat(Uint8Array.of(110, 1, 0, 64), bytes));
|
|
1495
|
+
const signature = await o.signer.sign(digest.slice());
|
|
1496
|
+
if (!(signature instanceof Uint8Array) || signature.length !== 64 || !ed25519.ed25519.verify(signature, digest, pk)) {
|
|
1497
|
+
throw new Error("Invalid Ed25519 delegate signature");
|
|
1498
|
+
}
|
|
1499
|
+
const signed = concat(bytes, Uint8Array.of(0), signature);
|
|
1500
|
+
return {
|
|
1501
|
+
x402Version: 2,
|
|
1502
|
+
scheme: "escrow",
|
|
1503
|
+
network,
|
|
1504
|
+
payload: { signedDelegateAction: btoa(Array.from(signed, (b) => String.fromCharCode(b)).join("")) }
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
async function signEscrowAuthorization(options) {
|
|
1508
|
+
const o = { ...options };
|
|
1509
|
+
const d = buildEscrowAuthorizationDelegate(o);
|
|
1510
|
+
validateEscrowAuthorizationDelegate(d, o);
|
|
1511
|
+
return signDelegate(o, d);
|
|
1512
|
+
}
|
|
1513
|
+
var lifecycleGas = Object.freeze({
|
|
1514
|
+
release: 30000000000000n,
|
|
1515
|
+
refund: 30000000000000n,
|
|
1516
|
+
reclaim: 30000000000000n,
|
|
1517
|
+
withdraw: 50000000000000n,
|
|
1518
|
+
withdraw_for: 50000000000000n
|
|
1519
|
+
});
|
|
1520
|
+
async function signEscrowLifecycle(options, method, args = {}) {
|
|
1521
|
+
const o = { ...options };
|
|
1522
|
+
delegateOptions(o);
|
|
1523
|
+
if (!Object.hasOwn(lifecycleGas, method)) throw new Error("Escrow method not allowed");
|
|
1524
|
+
const gas = uint(o.gas ?? lifecycleGas[method], 64, "gas");
|
|
1525
|
+
const minGas = method === "withdraw" || method === "withdraw_for" ? 29000000000000n : 3000000000000n;
|
|
1526
|
+
if (gas < minGas || gas > lifecycleGas[method]) throw new Error("Lifecycle gas outside method limit");
|
|
1527
|
+
const allowed = method === "release" ? ["payment_id", "amount"] : method === "withdraw" ? [] : method === "withdraw_for" ? ["account"] : ["payment_id"];
|
|
1528
|
+
if (Object.keys(args).some((k) => !allowed.includes(k))) throw new Error("Unexpected lifecycle argument");
|
|
1529
|
+
const params = {};
|
|
1530
|
+
if (method === "withdraw_for") {
|
|
1531
|
+
account(args.account, "account");
|
|
1532
|
+
params.account = args.account;
|
|
1533
|
+
} else if (method !== "withdraw") {
|
|
1534
|
+
if (typeof args.payment_id !== "string" || args.payment_id.length < 32 || args.payment_id.length > 44 || unbase58(args.payment_id).length !== 32) throw new Error("Invalid payment_id");
|
|
1535
|
+
params.payment_id = args.payment_id;
|
|
1536
|
+
if (method === "release") {
|
|
1537
|
+
params.amount = args.amount == null ? null : uint(args.amount, 128, "amount").toString();
|
|
1538
|
+
if (params.amount === "0") throw new Error("release amount must be positive");
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
return signDelegate(o, {
|
|
1542
|
+
senderId: o.senderId,
|
|
1543
|
+
receiverId: o.escrowContract,
|
|
1544
|
+
nonce: o.nonce,
|
|
1545
|
+
maxBlockHeight: o.maxBlockHeight,
|
|
1546
|
+
actions: [{ methodName: method, args: JSON.stringify(params), gas, deposit: 0n }]
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
var release = (o, paymentId, amount) => signEscrowLifecycle(o, "release", { payment_id: paymentId, amount });
|
|
1550
|
+
var refund = (o, paymentId) => signEscrowLifecycle(o, "refund", { payment_id: paymentId });
|
|
1551
|
+
var reclaim = (o, paymentId) => signEscrowLifecycle(o, "reclaim", { payment_id: paymentId });
|
|
1552
|
+
var withdraw = (o) => signEscrowLifecycle(o, "withdraw");
|
|
1553
|
+
var withdrawFor = (o, account2) => signEscrowLifecycle(o, "withdraw_for", { account: account2 });
|
|
1301
1554
|
|
|
1302
1555
|
// src/providers/near/index.ts
|
|
1303
1556
|
var NEAR_CONFIG = {
|
|
@@ -1378,7 +1631,7 @@ function serializeSignedDelegateAction(delegateActionBytes, signatureBytes) {
|
|
|
1378
1631
|
ser.writeFixedBytes(signatureBytes);
|
|
1379
1632
|
return ser.getBytes();
|
|
1380
1633
|
}
|
|
1381
|
-
async function
|
|
1634
|
+
async function sha2562(data) {
|
|
1382
1635
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
1383
1636
|
return new Uint8Array(hashBuffer);
|
|
1384
1637
|
}
|
|
@@ -1622,7 +1875,7 @@ var NEARProvider = class {
|
|
|
1622
1875
|
const hashInput = new Uint8Array(NEP366_PREFIX.length + delegateActionBytes.length);
|
|
1623
1876
|
hashInput.set(NEP366_PREFIX, 0);
|
|
1624
1877
|
hashInput.set(delegateActionBytes, NEP366_PREFIX.length);
|
|
1625
|
-
const delegateHash = await
|
|
1878
|
+
const delegateHash = await sha2562(hashInput);
|
|
1626
1879
|
const signature = await this.signMessage(delegateHash);
|
|
1627
1880
|
const signedDelegateActionBytes = serializeSignedDelegateAction(
|
|
1628
1881
|
delegateActionBytes,
|
|
@@ -1764,17 +2017,17 @@ var NEARProvider = class {
|
|
|
1764
2017
|
/**
|
|
1765
2018
|
* Base58 decode (NEAR style)
|
|
1766
2019
|
*/
|
|
1767
|
-
base58Decode(
|
|
2020
|
+
base58Decode(str2) {
|
|
1768
2021
|
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1769
2022
|
const ALPHABET_MAP = {};
|
|
1770
2023
|
for (let i = 0; i < ALPHABET.length; i++) {
|
|
1771
2024
|
ALPHABET_MAP[ALPHABET[i]] = i;
|
|
1772
2025
|
}
|
|
1773
2026
|
let bytes = [0];
|
|
1774
|
-
for (let i = 0; i <
|
|
1775
|
-
const value = ALPHABET_MAP[
|
|
2027
|
+
for (let i = 0; i < str2.length; i++) {
|
|
2028
|
+
const value = ALPHABET_MAP[str2[i]];
|
|
1776
2029
|
if (value === void 0) {
|
|
1777
|
-
throw new Error(`Invalid base58 character: ${
|
|
2030
|
+
throw new Error(`Invalid base58 character: ${str2[i]}`);
|
|
1778
2031
|
}
|
|
1779
2032
|
for (let j = 0; j < bytes.length; j++) {
|
|
1780
2033
|
bytes[j] *= 58;
|
|
@@ -1791,7 +2044,7 @@ var NEARProvider = class {
|
|
|
1791
2044
|
carry >>= 8;
|
|
1792
2045
|
}
|
|
1793
2046
|
}
|
|
1794
|
-
for (let i = 0; i <
|
|
2047
|
+
for (let i = 0; i < str2.length && str2[i] === "1"; i++) {
|
|
1795
2048
|
bytes.push(0);
|
|
1796
2049
|
}
|
|
1797
2050
|
return new Uint8Array(bytes.reverse());
|
|
@@ -1818,19 +2071,36 @@ var NEARProvider = class {
|
|
|
1818
2071
|
carry = carry / 58 | 0;
|
|
1819
2072
|
}
|
|
1820
2073
|
}
|
|
1821
|
-
let
|
|
2074
|
+
let str2 = "";
|
|
1822
2075
|
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
1823
|
-
|
|
2076
|
+
str2 += "1";
|
|
1824
2077
|
}
|
|
1825
2078
|
for (let i = digits.length - 1; i >= 0; i--) {
|
|
1826
|
-
|
|
2079
|
+
str2 += ALPHABET[digits[i]];
|
|
1827
2080
|
}
|
|
1828
|
-
return
|
|
2081
|
+
return str2;
|
|
1829
2082
|
}
|
|
1830
2083
|
};
|
|
1831
2084
|
var near_default = NEARProvider;
|
|
1832
2085
|
|
|
1833
2086
|
exports.NEARProvider = NEARProvider;
|
|
2087
|
+
exports.NEAR_ESCROW_CONTRACTS = NEAR_ESCROW_CONTRACTS;
|
|
2088
|
+
exports.NEAR_ESCROW_MAX_GAS = NEAR_ESCROW_MAX_GAS;
|
|
2089
|
+
exports.NEAR_ESCROW_MIN_GAS = NEAR_ESCROW_MIN_GAS;
|
|
2090
|
+
exports.NEAR_ESCROW_TOKENS = NEAR_ESCROW_TOKENS;
|
|
2091
|
+
exports.buildEscrowAuthorizationDelegate = buildEscrowAuthorizationDelegate;
|
|
2092
|
+
exports.buildEscrowMsg = buildEscrowMsg;
|
|
2093
|
+
exports.computePaymentId = computePaymentId;
|
|
2094
|
+
exports.createNearLocalSigner = createNearLocalSigner;
|
|
1834
2095
|
exports.default = near_default;
|
|
2096
|
+
exports.paymentIdPreimage = paymentIdPreimage;
|
|
2097
|
+
exports.reclaim = reclaim;
|
|
2098
|
+
exports.refund = refund;
|
|
2099
|
+
exports.release = release;
|
|
2100
|
+
exports.signEscrowAuthorization = signEscrowAuthorization;
|
|
2101
|
+
exports.signEscrowLifecycle = signEscrowLifecycle;
|
|
2102
|
+
exports.validateEscrowAuthorizationDelegate = validateEscrowAuthorizationDelegate;
|
|
2103
|
+
exports.withdraw = withdraw;
|
|
2104
|
+
exports.withdrawFor = withdrawFor;
|
|
1835
2105
|
//# sourceMappingURL=index.js.map
|
|
1836
2106
|
//# sourceMappingURL=index.js.map
|