@zerox1/sdk 0.2.18 → 0.2.20
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/dist/index.d.ts +240 -0
- package/dist/index.js +401 -1
- package/package.json +5 -5
- package/packages/darwin-arm64/bin/zerox1-node +0 -0
- package/packages/darwin-arm64/package.json +1 -1
- package/packages/darwin-x64/bin/zerox1-node +0 -0
- package/packages/darwin-x64/package.json +1 -1
- package/packages/linux-x64/bin/zerox1-node +0 -0
- package/packages/linux-x64/package.json +1 -1
- package/packages/win32-x64/bin/zerox1-node.exe +0 -0
- package/packages/win32-x64/package.json +1 -1
- package/src/index.ts +572 -0
package/dist/index.js
CHANGED
|
@@ -36,7 +36,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.HostedAgent = exports.Zerox1Agent = void 0;
|
|
39
|
+
exports.HostedAgent = exports.Zerox1Agent = exports.DEFAULT_SWAP_WHITELIST = void 0;
|
|
40
|
+
exports.encodeProposePayload = encodeProposePayload;
|
|
41
|
+
exports.encodeCounterPayload = encodeCounterPayload;
|
|
42
|
+
exports.decodeProposePayload = decodeProposePayload;
|
|
43
|
+
exports.encodeAcceptPayload = encodeAcceptPayload;
|
|
44
|
+
exports.decodeAcceptPayload = decodeAcceptPayload;
|
|
45
|
+
exports.decodeCounterPayload = decodeCounterPayload;
|
|
40
46
|
const fs = __importStar(require("fs"));
|
|
41
47
|
const net = __importStar(require("net"));
|
|
42
48
|
const os = __importStar(require("os"));
|
|
@@ -45,6 +51,144 @@ const child_process_1 = require("child_process");
|
|
|
45
51
|
const ws_1 = __importDefault(require("ws"));
|
|
46
52
|
const ed = __importStar(require("@noble/ed25519"));
|
|
47
53
|
// ============================================================================
|
|
54
|
+
// Token swap whitelist
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Default token mint addresses allowed in agent-to-agent swaps.
|
|
58
|
+
* Prevents agents from being tricked into swapping into fraudulent tokens.
|
|
59
|
+
*
|
|
60
|
+
* Both devnet and mainnet mints are included; the node validates against
|
|
61
|
+
* whichever network it is connected to.
|
|
62
|
+
*
|
|
63
|
+
* Override per-agent with `Zerox1Agent.setSwapWhitelist()`.
|
|
64
|
+
*/
|
|
65
|
+
exports.DEFAULT_SWAP_WHITELIST = new Set([
|
|
66
|
+
// SOL (wrapped)
|
|
67
|
+
'So11111111111111111111111111111111111111112',
|
|
68
|
+
// USDC — mainnet
|
|
69
|
+
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
70
|
+
// USDC — devnet
|
|
71
|
+
'4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
72
|
+
// USDT — mainnet
|
|
73
|
+
'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
74
|
+
// JUP
|
|
75
|
+
'JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN',
|
|
76
|
+
// BONK
|
|
77
|
+
'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
|
|
78
|
+
// RAY
|
|
79
|
+
'4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
|
|
80
|
+
// WIF
|
|
81
|
+
'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm',
|
|
82
|
+
// BAGS — mainnet
|
|
83
|
+
'Bags4uLBdNscWBnHmqBozrjSScnEqPx5qZBzLiqnRVN7',
|
|
84
|
+
]);
|
|
85
|
+
// ============================================================================
|
|
86
|
+
// PROPOSE / COUNTER payload encode + decode helpers
|
|
87
|
+
// ============================================================================
|
|
88
|
+
function writeBidPrefix(amount) {
|
|
89
|
+
const buf = Buffer.alloc(16);
|
|
90
|
+
buf.writeBigUInt64LE(amount & 0xffffffffffffffffn, 0);
|
|
91
|
+
buf.writeBigUInt64LE(amount >> 64n, 8);
|
|
92
|
+
return buf;
|
|
93
|
+
}
|
|
94
|
+
function readBidPrefix(raw) {
|
|
95
|
+
const lo = raw.readBigUInt64LE(0);
|
|
96
|
+
const hi = raw.readBigUInt64LE(8);
|
|
97
|
+
return (hi << 64n) | lo;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Encode a PROPOSE payload into the structured wire format:
|
|
101
|
+
* `[16-byte LE i128 amount][JSON {"max_rounds": N, "message": "..."}]`
|
|
102
|
+
*/
|
|
103
|
+
function encodeProposePayload(message, amount = 0n, maxRounds = 2) {
|
|
104
|
+
const prefix = writeBidPrefix(amount);
|
|
105
|
+
const json = Buffer.from(JSON.stringify({ max_rounds: maxRounds, message }));
|
|
106
|
+
return Buffer.concat([prefix, json]);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Encode a COUNTER payload into the structured wire format:
|
|
110
|
+
* `[16-byte LE i128 amount][JSON {"round": N, "max_rounds": M, "message": "..."}]`
|
|
111
|
+
*/
|
|
112
|
+
function encodeCounterPayload(amount, round, maxRounds, message = '') {
|
|
113
|
+
const prefix = writeBidPrefix(amount);
|
|
114
|
+
const json = Buffer.from(JSON.stringify({ round, max_rounds: maxRounds, message }));
|
|
115
|
+
return Buffer.concat([prefix, json]);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Decode a PROPOSE envelope payload.
|
|
119
|
+
* Returns `null` if the payload is not in the structured format
|
|
120
|
+
* (e.g. a raw-string PROPOSE from an older agent).
|
|
121
|
+
*/
|
|
122
|
+
function decodeProposePayload(payloadB64) {
|
|
123
|
+
const raw = Buffer.from(payloadB64, 'base64');
|
|
124
|
+
if (raw.length < 17 || raw[16] !== 0x7b /* '{' */)
|
|
125
|
+
return null;
|
|
126
|
+
try {
|
|
127
|
+
const body = JSON.parse(raw.slice(16).toString('utf8'));
|
|
128
|
+
return {
|
|
129
|
+
amount: readBidPrefix(raw),
|
|
130
|
+
maxRounds: Number(body['max_rounds'] ?? 2),
|
|
131
|
+
message: String(body['message'] ?? ''),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Encode an ACCEPT payload.
|
|
140
|
+
* `[16-byte LE i128 amount][JSON {"message": "..."}]`
|
|
141
|
+
*
|
|
142
|
+
* Both parties must use the same `amount` — it is the agreed price that
|
|
143
|
+
* will be passed to `lockPayment` on-chain.
|
|
144
|
+
*/
|
|
145
|
+
function encodeAcceptPayload(amount, message = '') {
|
|
146
|
+
const prefix = writeBidPrefix(amount);
|
|
147
|
+
const json = Buffer.from(JSON.stringify({ message }));
|
|
148
|
+
return Buffer.concat([prefix, json]);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Decode an ACCEPT envelope payload.
|
|
152
|
+
* Returns `null` if the payload is not in the structured format
|
|
153
|
+
* (older agents may send a plain-text ACCEPT).
|
|
154
|
+
*/
|
|
155
|
+
function decodeAcceptPayload(payloadB64) {
|
|
156
|
+
const raw = Buffer.from(payloadB64, 'base64');
|
|
157
|
+
if (raw.length < 17 || raw[16] !== 0x7b /* '{' */)
|
|
158
|
+
return null;
|
|
159
|
+
try {
|
|
160
|
+
const body = JSON.parse(raw.slice(16).toString('utf8'));
|
|
161
|
+
return {
|
|
162
|
+
amount: readBidPrefix(raw),
|
|
163
|
+
message: String(body['message'] ?? ''),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Decode a COUNTER envelope payload.
|
|
172
|
+
* Returns `null` if the payload is not in the structured format.
|
|
173
|
+
*/
|
|
174
|
+
function decodeCounterPayload(payloadB64) {
|
|
175
|
+
const raw = Buffer.from(payloadB64, 'base64');
|
|
176
|
+
if (raw.length < 17 || raw[16] !== 0x7b /* '{' */)
|
|
177
|
+
return null;
|
|
178
|
+
try {
|
|
179
|
+
const body = JSON.parse(raw.slice(16).toString('utf8'));
|
|
180
|
+
return {
|
|
181
|
+
amount: readBidPrefix(raw),
|
|
182
|
+
round: Number(body['round'] ?? 1),
|
|
183
|
+
maxRounds: Number(body['max_rounds'] ?? 2),
|
|
184
|
+
message: String(body['message'] ?? ''),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// ============================================================================
|
|
48
192
|
// CBOR encoding for FEEDBACK payload
|
|
49
193
|
//
|
|
50
194
|
// FEEDBACK payloads must be CBOR-encoded. Receiving nodes run
|
|
@@ -153,6 +297,7 @@ class Zerox1Agent {
|
|
|
153
297
|
this.port = 0;
|
|
154
298
|
this.nodeUrl = '';
|
|
155
299
|
this._reconnectDelay = 1000;
|
|
300
|
+
this._swapWhitelist = exports.DEFAULT_SWAP_WHITELIST;
|
|
156
301
|
}
|
|
157
302
|
// ── Factory ───────────────────────────────────────────────────────────────
|
|
158
303
|
/**
|
|
@@ -401,6 +546,192 @@ class Zerox1Agent {
|
|
|
401
546
|
payload,
|
|
402
547
|
});
|
|
403
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Send a PROPOSE envelope.
|
|
551
|
+
*
|
|
552
|
+
* Calls POST /negotiate/propose — the node handles binary payload encoding.
|
|
553
|
+
* Returns the conversation ID used (auto-generated if not supplied)
|
|
554
|
+
* along with the send confirmation.
|
|
555
|
+
*/
|
|
556
|
+
async sendPropose(params) {
|
|
557
|
+
const res = await fetch(`${this.nodeUrl}/negotiate/propose`, {
|
|
558
|
+
method: 'POST',
|
|
559
|
+
headers: { 'Content-Type': 'application/json' },
|
|
560
|
+
body: JSON.stringify({
|
|
561
|
+
recipient: params.recipient,
|
|
562
|
+
conversation_id: params.conversationId,
|
|
563
|
+
amount_usdc_micro: params.amount !== undefined ? Number(params.amount) : undefined,
|
|
564
|
+
max_rounds: params.maxRounds,
|
|
565
|
+
message: params.message,
|
|
566
|
+
}),
|
|
567
|
+
});
|
|
568
|
+
if (!res.ok) {
|
|
569
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
570
|
+
throw new Error(err['error'] ?? `HTTP ${res.status}`);
|
|
571
|
+
}
|
|
572
|
+
const json = await res.json();
|
|
573
|
+
return {
|
|
574
|
+
conversationId: json['conversation_id'],
|
|
575
|
+
confirmation: { nonce: json['nonce'], payloadHash: json['payload_hash'] },
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Send a COUNTER envelope.
|
|
580
|
+
*
|
|
581
|
+
* Calls POST /negotiate/counter — the node handles binary payload encoding.
|
|
582
|
+
* Protocol rules: `round` must be 1-indexed and <= `maxRounds`.
|
|
583
|
+
*/
|
|
584
|
+
async sendCounter(params) {
|
|
585
|
+
if (params.round < 1 || params.round > params.maxRounds) {
|
|
586
|
+
throw new RangeError(`round ${params.round} is out of range [1, ${params.maxRounds}]`);
|
|
587
|
+
}
|
|
588
|
+
const res = await fetch(`${this.nodeUrl}/negotiate/counter`, {
|
|
589
|
+
method: 'POST',
|
|
590
|
+
headers: { 'Content-Type': 'application/json' },
|
|
591
|
+
body: JSON.stringify({
|
|
592
|
+
recipient: params.recipient,
|
|
593
|
+
conversation_id: params.conversationId,
|
|
594
|
+
amount_usdc_micro: Number(params.amount),
|
|
595
|
+
round: params.round,
|
|
596
|
+
max_rounds: params.maxRounds,
|
|
597
|
+
message: params.message,
|
|
598
|
+
}),
|
|
599
|
+
});
|
|
600
|
+
if (!res.ok) {
|
|
601
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
602
|
+
throw new Error(err['error'] ?? `HTTP ${res.status}`);
|
|
603
|
+
}
|
|
604
|
+
const json = await res.json();
|
|
605
|
+
return { nonce: json['nonce'], payloadHash: json['payload_hash'] };
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Send an ACCEPT envelope with the agreed amount.
|
|
609
|
+
*
|
|
610
|
+
* Calls POST /negotiate/accept — the node handles binary payload encoding.
|
|
611
|
+
* The `amount` must match the most-recent COUNTER (or original PROPOSE if
|
|
612
|
+
* there was no counter). Both parties use this value to call `lockPayment`.
|
|
613
|
+
*/
|
|
614
|
+
async sendAccept(params) {
|
|
615
|
+
const res = await fetch(`${this.nodeUrl}/negotiate/accept`, {
|
|
616
|
+
method: 'POST',
|
|
617
|
+
headers: { 'Content-Type': 'application/json' },
|
|
618
|
+
body: JSON.stringify({
|
|
619
|
+
recipient: params.recipient,
|
|
620
|
+
conversation_id: params.conversationId,
|
|
621
|
+
amount_usdc_micro: Number(params.amount),
|
|
622
|
+
message: params.message,
|
|
623
|
+
}),
|
|
624
|
+
});
|
|
625
|
+
if (!res.ok) {
|
|
626
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
627
|
+
throw new Error(err['error'] ?? `HTTP ${res.status}`);
|
|
628
|
+
}
|
|
629
|
+
const json = await res.json();
|
|
630
|
+
return { nonce: json['nonce'], payloadHash: json['payload_hash'] };
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Lock USDC in the escrow program on-chain.
|
|
634
|
+
*
|
|
635
|
+
* Call this after `sendAccept()` to fund the escrow account before the
|
|
636
|
+
* provider begins work. The node signs the Solana transaction using its
|
|
637
|
+
* own keypair (this agent is the requester / payer).
|
|
638
|
+
*
|
|
639
|
+
* The automatic lock triggered by `sendAccept()` (via the node loop) uses
|
|
640
|
+
* default parameters. Use this method for explicit control — e.g. a custom
|
|
641
|
+
* notary or timeout.
|
|
642
|
+
*
|
|
643
|
+
* @param params.amount — must match the amount in the ACCEPT payload exactly.
|
|
644
|
+
*/
|
|
645
|
+
async lockPayment(params) {
|
|
646
|
+
const res = await fetch(`${this.nodeUrl}/escrow/lock`, {
|
|
647
|
+
method: 'POST',
|
|
648
|
+
headers: { 'Content-Type': 'application/json' },
|
|
649
|
+
body: JSON.stringify({
|
|
650
|
+
provider: params.provider,
|
|
651
|
+
conversation_id: params.conversationId,
|
|
652
|
+
amount_usdc_micro: Number(params.amount),
|
|
653
|
+
notary_fee: params.notaryFee !== undefined ? Number(params.notaryFee) : undefined,
|
|
654
|
+
timeout_slots: params.timeoutSlots,
|
|
655
|
+
notary: params.notary,
|
|
656
|
+
}),
|
|
657
|
+
});
|
|
658
|
+
if (!res.ok) {
|
|
659
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
660
|
+
throw new Error(`lockPayment failed: ${err['error'] ?? res.status}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Approve and release a locked escrow payment to the provider.
|
|
665
|
+
*
|
|
666
|
+
* Call this after verifying the provider's DELIVER output is satisfactory.
|
|
667
|
+
* The node signs as the approver (notary or requester).
|
|
668
|
+
*
|
|
669
|
+
* @param params.notary — defaults to this agent (self-approval when no separate notary).
|
|
670
|
+
*/
|
|
671
|
+
async approvePayment(params) {
|
|
672
|
+
const res = await fetch(`${this.nodeUrl}/escrow/approve`, {
|
|
673
|
+
method: 'POST',
|
|
674
|
+
headers: { 'Content-Type': 'application/json' },
|
|
675
|
+
body: JSON.stringify({
|
|
676
|
+
requester: params.requester,
|
|
677
|
+
provider: params.provider,
|
|
678
|
+
conversation_id: params.conversationId,
|
|
679
|
+
notary: params.notary,
|
|
680
|
+
}),
|
|
681
|
+
});
|
|
682
|
+
if (!res.ok) {
|
|
683
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
684
|
+
throw new Error(`approvePayment failed: ${err['error'] ?? res.status}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
// ── Token swap ────────────────────────────────────────────────────────────
|
|
688
|
+
/**
|
|
689
|
+
* Override the token whitelist for this agent instance.
|
|
690
|
+
* Pass an empty Set to disable whitelist enforcement (not recommended).
|
|
691
|
+
*/
|
|
692
|
+
setSwapWhitelist(whitelist) {
|
|
693
|
+
this._swapWhitelist = whitelist;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Execute a Jupiter token swap via the node's `/trade/swap` endpoint.
|
|
697
|
+
*
|
|
698
|
+
* Both `inputMint` and `outputMint` must be in the active whitelist
|
|
699
|
+
* (DEFAULT_SWAP_WHITELIST unless overridden via `setSwapWhitelist()`).
|
|
700
|
+
* This prevents agents from being deceived into swapping fraudulent tokens.
|
|
701
|
+
*
|
|
702
|
+
* @throws If either mint is not whitelisted, or the node rejects the swap.
|
|
703
|
+
*/
|
|
704
|
+
async swap(params) {
|
|
705
|
+
const whitelist = params.whitelist ?? this._swapWhitelist;
|
|
706
|
+
if (whitelist.size > 0) {
|
|
707
|
+
if (!whitelist.has(params.inputMint)) {
|
|
708
|
+
throw new Error(`swap: inputMint ${params.inputMint} is not in the token whitelist`);
|
|
709
|
+
}
|
|
710
|
+
if (!whitelist.has(params.outputMint)) {
|
|
711
|
+
throw new Error(`swap: outputMint ${params.outputMint} is not in the token whitelist`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const res = await fetch(`${this.nodeUrl}/trade/swap`, {
|
|
715
|
+
method: 'POST',
|
|
716
|
+
headers: { 'Content-Type': 'application/json' },
|
|
717
|
+
body: JSON.stringify({
|
|
718
|
+
input_mint: params.inputMint,
|
|
719
|
+
output_mint: params.outputMint,
|
|
720
|
+
amount: params.amount.toString(),
|
|
721
|
+
slippage_bps: params.slippageBps ?? 50,
|
|
722
|
+
}),
|
|
723
|
+
});
|
|
724
|
+
if (!res.ok) {
|
|
725
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
726
|
+
throw new Error(`swap failed: ${err['error'] ?? res.status}`);
|
|
727
|
+
}
|
|
728
|
+
const data = await res.json();
|
|
729
|
+
return {
|
|
730
|
+
inAmount: BigInt(data.in_amount),
|
|
731
|
+
outAmount: BigInt(data.out_amount),
|
|
732
|
+
signature: data.signature,
|
|
733
|
+
};
|
|
734
|
+
}
|
|
404
735
|
// ── Utilities ─────────────────────────────────────────────────────────────
|
|
405
736
|
/** Generate a random 16-byte conversation ID as hex. */
|
|
406
737
|
newConversationId() {
|
|
@@ -411,6 +742,7 @@ class Zerox1Agent {
|
|
|
411
742
|
/**
|
|
412
743
|
* Encode a bid value (i128 LE) into the first 16 bytes of a payload,
|
|
413
744
|
* followed by optional extra bytes (your terms).
|
|
745
|
+
* @deprecated Use `encodeProposePayload()` or `encodeCounterPayload()` instead.
|
|
414
746
|
*/
|
|
415
747
|
encodeBidValue(value, rest = Buffer.alloc(0)) {
|
|
416
748
|
const buf = Buffer.alloc(16);
|
|
@@ -607,6 +939,74 @@ class HostedAgent {
|
|
|
607
939
|
const payload = encodeFeedbackCbor(params.conversationId, params.targetAgent, params.score, outcomeMap[params.outcome], false, roleMap[params.role]);
|
|
608
940
|
return this.send({ msgType: 'FEEDBACK', conversationId: params.conversationId, payload });
|
|
609
941
|
}
|
|
942
|
+
/** Send a PROPOSE envelope via POST /hosted/negotiate/propose. */
|
|
943
|
+
async sendPropose(params) {
|
|
944
|
+
const res = await fetch(`${this.baseUrl}/hosted/negotiate/propose`, {
|
|
945
|
+
method: 'POST',
|
|
946
|
+
headers: {
|
|
947
|
+
'Content-Type': 'application/json',
|
|
948
|
+
'Authorization': `Bearer ${this.token}`,
|
|
949
|
+
},
|
|
950
|
+
body: JSON.stringify({
|
|
951
|
+
recipient: params.recipient,
|
|
952
|
+
conversation_id: params.conversationId,
|
|
953
|
+
amount_usdc_micro: params.amount !== undefined ? Number(params.amount) : undefined,
|
|
954
|
+
max_rounds: params.maxRounds,
|
|
955
|
+
message: params.message,
|
|
956
|
+
}),
|
|
957
|
+
});
|
|
958
|
+
if (!res.ok) {
|
|
959
|
+
const body = await res.text();
|
|
960
|
+
throw new Error(`hosted propose failed (${res.status}): ${body}`);
|
|
961
|
+
}
|
|
962
|
+
const json = await res.json();
|
|
963
|
+
return { conversationId: json['conversation_id'] };
|
|
964
|
+
}
|
|
965
|
+
/** Send a COUNTER envelope via POST /hosted/negotiate/counter. */
|
|
966
|
+
async sendCounter(params) {
|
|
967
|
+
if (params.round < 1 || params.round > params.maxRounds) {
|
|
968
|
+
throw new RangeError(`round ${params.round} is out of range [1, ${params.maxRounds}]`);
|
|
969
|
+
}
|
|
970
|
+
const res = await fetch(`${this.baseUrl}/hosted/negotiate/counter`, {
|
|
971
|
+
method: 'POST',
|
|
972
|
+
headers: {
|
|
973
|
+
'Content-Type': 'application/json',
|
|
974
|
+
'Authorization': `Bearer ${this.token}`,
|
|
975
|
+
},
|
|
976
|
+
body: JSON.stringify({
|
|
977
|
+
recipient: params.recipient,
|
|
978
|
+
conversation_id: params.conversationId,
|
|
979
|
+
amount_usdc_micro: Number(params.amount),
|
|
980
|
+
round: params.round,
|
|
981
|
+
max_rounds: params.maxRounds,
|
|
982
|
+
message: params.message,
|
|
983
|
+
}),
|
|
984
|
+
});
|
|
985
|
+
if (!res.ok && res.status !== 204) {
|
|
986
|
+
const body = await res.text();
|
|
987
|
+
throw new Error(`hosted counter failed (${res.status}): ${body}`);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
/** Send an ACCEPT envelope via POST /hosted/negotiate/accept. */
|
|
991
|
+
async sendAccept(params) {
|
|
992
|
+
const res = await fetch(`${this.baseUrl}/hosted/negotiate/accept`, {
|
|
993
|
+
method: 'POST',
|
|
994
|
+
headers: {
|
|
995
|
+
'Content-Type': 'application/json',
|
|
996
|
+
'Authorization': `Bearer ${this.token}`,
|
|
997
|
+
},
|
|
998
|
+
body: JSON.stringify({
|
|
999
|
+
recipient: params.recipient,
|
|
1000
|
+
conversation_id: params.conversationId,
|
|
1001
|
+
amount_usdc_micro: Number(params.amount),
|
|
1002
|
+
message: params.message,
|
|
1003
|
+
}),
|
|
1004
|
+
});
|
|
1005
|
+
if (!res.ok && res.status !== 204) {
|
|
1006
|
+
const body = await res.text();
|
|
1007
|
+
throw new Error(`hosted accept failed (${res.status}): ${body}`);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
610
1010
|
/** Generate a random 16-byte conversation ID as hex. */
|
|
611
1011
|
newConversationId() {
|
|
612
1012
|
const bytes = new Uint8Array(16);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerox1/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
4
4
|
"description": "0x01 mesh agent SDK — zero-config, binary bundled, works on every platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"ws": "^8.18.0"
|
|
15
15
|
},
|
|
16
16
|
"optionalDependencies": {
|
|
17
|
-
"@zerox1/sdk-darwin-arm64": "0.2.
|
|
18
|
-
"@zerox1/sdk-darwin-x64": "0.2.
|
|
19
|
-
"@zerox1/sdk-linux-x64": "0.2.
|
|
20
|
-
"@zerox1/sdk-win32-x64": "0.2.
|
|
17
|
+
"@zerox1/sdk-darwin-arm64": "0.2.20",
|
|
18
|
+
"@zerox1/sdk-darwin-x64": "0.2.20",
|
|
19
|
+
"@zerox1/sdk-linux-x64": "0.2.20",
|
|
20
|
+
"@zerox1/sdk-win32-x64": "0.2.20"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^22.0.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|