@rubicon-caliga/agent-sdk 0.1.0 → 0.1.1

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.
Files changed (38) hide show
  1. package/README.md +51 -7
  2. package/dist/agent-client.d.ts +4 -0
  3. package/dist/agent-client.d.ts.map +1 -1
  4. package/dist/agent-client.js +6 -0
  5. package/dist/agent-client.js.map +1 -1
  6. package/dist/circle-agent-wallet.d.ts +65 -0
  7. package/dist/circle-agent-wallet.d.ts.map +1 -0
  8. package/dist/circle-agent-wallet.js +156 -0
  9. package/dist/circle-agent-wallet.js.map +1 -0
  10. package/dist/circle-agent-wallet.test.d.ts +2 -0
  11. package/dist/circle-agent-wallet.test.d.ts.map +1 -0
  12. package/dist/circle-agent-wallet.test.js +106 -0
  13. package/dist/circle-agent-wallet.test.js.map +1 -0
  14. package/dist/circle-cli-gateway-payment.d.ts +31 -0
  15. package/dist/circle-cli-gateway-payment.d.ts.map +1 -0
  16. package/dist/circle-cli-gateway-payment.js +185 -0
  17. package/dist/circle-cli-gateway-payment.js.map +1 -0
  18. package/dist/circle-cli-gateway-payment.test.d.ts +2 -0
  19. package/dist/circle-cli-gateway-payment.test.d.ts.map +1 -0
  20. package/dist/circle-cli-gateway-payment.test.js +32 -0
  21. package/dist/circle-cli-gateway-payment.test.js.map +1 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/payment-engine.d.ts +0 -14
  27. package/dist/payment-engine.d.ts.map +1 -1
  28. package/dist/payment-engine.js +0 -35
  29. package/dist/payment-engine.js.map +1 -1
  30. package/dist/payment-engine.test.d.ts.map +1 -0
  31. package/package.json +11 -11
  32. package/src/agent-client.ts +10 -0
  33. package/src/circle-agent-wallet.test.ts +118 -0
  34. package/src/circle-agent-wallet.ts +210 -0
  35. package/src/circle-cli-gateway-payment.test.ts +53 -0
  36. package/src/circle-cli-gateway-payment.ts +230 -0
  37. package/src/index.ts +2 -0
  38. package/src/payment-engine.ts +0 -38
@@ -0,0 +1,185 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { registerBatchScheme } from "@circle-fin/x402-batching/client";
4
+ import { x402Client } from "@x402/core/client";
5
+ import { ExactEvmScheme } from "@x402/evm/exact/client";
6
+ import { serializeTypedData, toEip712Payload } from "./circle-agent-wallet.js";
7
+ const execFileAsync = promisify(execFile);
8
+ /**
9
+ * Circle CLI / Agent Wallet payment engine. It creates the one-word x402
10
+ * payment payload for Rubicon's session-first flow and delegates EIP-712
11
+ * signing to `circle wallet sign typed-data`, so agents never need raw private
12
+ * keys or hand-built x402 payloads.
13
+ */
14
+ export class CircleCliGatewayPaymentEngine {
15
+ x402 = new x402Client();
16
+ signer;
17
+ constructor(options = {}) {
18
+ this.signer = new CircleCliGatewaySigner({
19
+ walletAddress: options.walletAddress,
20
+ chain: options.chain ?? "ARC-TESTNET",
21
+ command: options.command ?? "circle",
22
+ runner: options.runner ?? runCircleCli,
23
+ });
24
+ registerBatchScheme(this.x402, {
25
+ signer: this.signer,
26
+ fallbackScheme: new ExactEvmScheme(this.signer),
27
+ });
28
+ }
29
+ async createWordPayment(session) {
30
+ if (!session.paymentRequired) {
31
+ throw new Error("Session did not include an x402 one-word payment requirement");
32
+ }
33
+ await this.signer.ensureAddress();
34
+ return {
35
+ paymentPayload: await this.x402.createPaymentPayload(session.paymentRequired),
36
+ };
37
+ }
38
+ }
39
+ class CircleCliGatewaySigner {
40
+ options;
41
+ address = "0x0000000000000000000000000000000000000000";
42
+ resolved = false;
43
+ resolving;
44
+ constructor(options) {
45
+ this.options = options;
46
+ if (options.walletAddress) {
47
+ this.address = options.walletAddress;
48
+ this.resolved = true;
49
+ }
50
+ }
51
+ async ensureAddress() {
52
+ if (this.resolved)
53
+ return;
54
+ if (!this.resolving) {
55
+ this.resolving = this.resolveAddress();
56
+ }
57
+ return this.resolving;
58
+ }
59
+ async signTypedData(typed) {
60
+ await this.ensureAddress();
61
+ const signature = await this.options.runner(this.options.command, [
62
+ "wallet",
63
+ "sign",
64
+ "typed-data",
65
+ serializeTypedData(toEip712Payload(typed)),
66
+ "--address",
67
+ this.address,
68
+ "--chain",
69
+ this.options.chain,
70
+ "--quiet",
71
+ ]);
72
+ return parseCircleCliSignature(signature);
73
+ }
74
+ async resolveAddress() {
75
+ const output = await this.options.runner(this.options.command, [
76
+ "wallet",
77
+ "list",
78
+ "--chain",
79
+ this.options.chain,
80
+ "--type",
81
+ "agent",
82
+ "--output",
83
+ "json",
84
+ ]);
85
+ const address = parseCircleCliWalletAddress(output);
86
+ this.address = address;
87
+ this.resolved = true;
88
+ }
89
+ }
90
+ async function runCircleCli(command, args) {
91
+ try {
92
+ const { stdout } = await execFileAsync(command, args, {
93
+ maxBuffer: 1024 * 1024,
94
+ });
95
+ return stdout;
96
+ }
97
+ catch (error) {
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ throw new Error(`Circle CLI command failed. Ensure Circle CLI is installed, logged in, and has an Agent Wallet on the selected chain. ${message}`);
100
+ }
101
+ }
102
+ export function parseCircleCliSignature(output) {
103
+ const trimmed = output.trim();
104
+ if (isHexSignature(trimmed)) {
105
+ return trimmed;
106
+ }
107
+ let parsed;
108
+ try {
109
+ parsed = parseJson(trimmed);
110
+ }
111
+ catch {
112
+ throw new Error("Circle CLI did not return a hex EIP-712 signature");
113
+ }
114
+ const signature = findString(parsed, ["signature", "signedData", "data.signature"]);
115
+ if (signature && isHexSignature(signature)) {
116
+ return signature;
117
+ }
118
+ throw new Error("Circle CLI did not return a hex EIP-712 signature");
119
+ }
120
+ export function parseCircleCliWalletAddress(output) {
121
+ const parsed = parseJson(output);
122
+ const wallets = collectWalletCandidates(parsed);
123
+ const addresses = wallets
124
+ .map((wallet) => findString(wallet, ["address", "walletAddress", "blockchainAddress"]))
125
+ .filter((address) => Boolean(address && isAddress(address)));
126
+ const unique = [...new Set(addresses.map((address) => address.toLowerCase()))];
127
+ if (unique.length === 1) {
128
+ return addresses.find((address) => address.toLowerCase() === unique[0]);
129
+ }
130
+ if (unique.length === 0) {
131
+ throw new Error("Circle CLI did not return an Agent Wallet address");
132
+ }
133
+ throw new Error("Multiple Circle Agent Wallets found; pass walletAddress explicitly");
134
+ }
135
+ function collectWalletCandidates(value) {
136
+ if (Array.isArray(value)) {
137
+ return value.filter(isRecord);
138
+ }
139
+ if (!isRecord(value)) {
140
+ return [];
141
+ }
142
+ for (const key of ["wallets", "items", "data"]) {
143
+ const nested = value[key];
144
+ if (Array.isArray(nested)) {
145
+ return nested.filter(isRecord);
146
+ }
147
+ if (isRecord(nested)) {
148
+ const deeper = collectWalletCandidates(nested);
149
+ if (deeper.length > 0)
150
+ return deeper;
151
+ }
152
+ }
153
+ return [value];
154
+ }
155
+ function findString(value, keys) {
156
+ for (const key of keys) {
157
+ const found = key.split(".").reduce((current, part) => {
158
+ if (!isRecord(current))
159
+ return undefined;
160
+ return current[part];
161
+ }, value);
162
+ if (typeof found === "string") {
163
+ return found;
164
+ }
165
+ }
166
+ return undefined;
167
+ }
168
+ function parseJson(value) {
169
+ try {
170
+ return JSON.parse(value);
171
+ }
172
+ catch {
173
+ throw new Error("Circle CLI returned non-JSON output");
174
+ }
175
+ }
176
+ function isHexSignature(value) {
177
+ return /^0x[0-9a-fA-F]+$/.test(value);
178
+ }
179
+ function isAddress(value) {
180
+ return /^0x[0-9a-fA-F]{40}$/.test(value);
181
+ }
182
+ function isRecord(value) {
183
+ return typeof value === "object" && value !== null;
184
+ }
185
+ //# sourceMappingURL=circle-cli-gateway-payment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circle-cli-gateway-payment.js","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=circle-cli-gateway-payment.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circle-cli-gateway-payment.test.d.ts","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { parseCircleCliSignature, parseCircleCliWalletAddress, } from "./circle-cli-gateway-payment.js";
4
+ test("parses quiet Circle CLI signatures", () => {
5
+ assert.equal(parseCircleCliSignature("0xabc123\n"), "0xabc123");
6
+ });
7
+ test("parses JSON Circle CLI signatures", () => {
8
+ assert.equal(parseCircleCliSignature(JSON.stringify({ data: { signature: "0xdef456" } })), "0xdef456");
9
+ });
10
+ test("rejects non-signature Circle CLI output", () => {
11
+ assert.throws(() => parseCircleCliSignature("signed"), /did not return a hex EIP-712 signature/);
12
+ });
13
+ test("parses a sole wallet address from Circle CLI list output", () => {
14
+ assert.equal(parseCircleCliWalletAddress(JSON.stringify({
15
+ data: {
16
+ wallets: [
17
+ {
18
+ address: "0x1111111111111111111111111111111111111111",
19
+ },
20
+ ],
21
+ },
22
+ })), "0x1111111111111111111111111111111111111111");
23
+ });
24
+ test("requires explicit wallet address when multiple Agent Wallets are present", () => {
25
+ assert.throws(() => parseCircleCliWalletAddress(JSON.stringify({
26
+ data: [
27
+ { address: "0x1111111111111111111111111111111111111111" },
28
+ { address: "0x2222222222222222222222222222222222222222" },
29
+ ],
30
+ })), /Multiple Circle Agent Wallets found/);
31
+ });
32
+ //# sourceMappingURL=circle-cli-gateway-payment.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circle-cli-gateway-payment.test.js","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EACL,uBAAuB,EACvB,2BAA2B,GAC5B,MAAM,iCAAiC,CAAC;AAEzC,IAAI,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAC9C,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;IAC7C,MAAM,CAAC,KAAK,CACV,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,EAC5E,UAAU,CACX,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACnD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,wCAAwC,CAAC,CAAC;AACnG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,MAAM,CAAC,KAAK,CACV,2BAA2B,CACzB,IAAI,CAAC,SAAS,CAAC;QACb,IAAI,EAAE;YACJ,OAAO,EAAE;gBACP;oBACE,OAAO,EAAE,4CAA4C;iBACtD;aACF;SACF;KACF,CAAC,CACH,EACD,4CAA4C,CAC7C,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0EAA0E,EAAE,GAAG,EAAE;IACpF,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CACH,2BAA2B,CACzB,IAAI,CAAC,SAAS,CAAC;QACb,IAAI,EAAE;YACJ,EAAE,OAAO,EAAE,4CAA4C,EAAE;YACzD,EAAE,OAAO,EAAE,4CAA4C,EAAE;SAC1D;KACF,CAAC,CACH,EACH,qCAAqC,CACtC,CAAC;AACJ,CAAC,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./agent-client.js";
2
2
  export * from "./payment-engine.js";
3
+ export * from "./circle-agent-wallet.js";
4
+ export * from "./circle-cli-gateway-payment.js";
3
5
  export { RubiconClient as Rubicon, RubiconClient as default } from "./agent-client.js";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./agent-client.js";
2
2
  export * from "./payment-engine.js";
3
+ export * from "./circle-agent-wallet.js";
4
+ export * from "./circle-cli-gateway-payment.js";
3
5
  export { RubiconClient as Rubicon, RubiconClient as default } from "./agent-client.js";
4
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,5 +1,4 @@
1
1
  import type { StartSessionResponse, StreamPaymentRequest } from "@rubicon-caliga/core";
2
- import { type GatewayClientConfig } from "@circle-fin/x402-batching/client";
3
2
  /**
4
3
  * Produces the payment payload for exactly one word. Called once per word by the
5
4
  * SDK's read loop — application developers never assemble payments themselves.
@@ -16,17 +15,4 @@ export declare class StaticPaymentEngine implements AgentPaymentEngine {
16
15
  constructor(network?: string);
17
16
  createWordPayment(session: StartSessionResponse): Promise<StreamPaymentRequest>;
18
17
  }
19
- export type CircleGatewayPaymentEngineOptions = GatewayClientConfig;
20
- /**
21
- * Circle/x402 engine. Signs the gateway's one-word `paymentRequired` terms.
22
- * Circle may batch settlement internally, but each signed payload corresponds to
23
- * exactly one word.
24
- */
25
- export declare class CircleGatewayPaymentEngine implements AgentPaymentEngine {
26
- private readonly options;
27
- private readonly client;
28
- private readonly account;
29
- constructor(options: CircleGatewayPaymentEngineOptions);
30
- createWordPayment(session: StartSessionResponse): Promise<StreamPaymentRequest>;
31
- }
32
18
  //# sourceMappingURL=payment-engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"payment-engine.d.ts","sourceRoot":"","sources":["../src/payment-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEvF,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAIjG;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACjF;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,kBAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,SAAmB;IAEjD,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAWtF;AAED,MAAM,MAAM,iCAAiC,GAAG,mBAAmB,CAAC;AAEpE;;;;GAIG;AACH,qBAAa,0BAA2B,YAAW,kBAAkB;IAIvD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;gBAEpC,OAAO,EAAE,iCAAiC;IAajE,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAQtF"}
1
+ {"version":3,"file":"payment-engine.d.ts","sourceRoot":"","sources":["../src/payment-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEvF;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACjF;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,kBAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,SAAmB;IAEjD,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAWtF"}
@@ -1,7 +1,3 @@
1
- import { x402Client } from "@x402/core/client";
2
- import { registerBatchScheme } from "@circle-fin/x402-batching/client";
3
- import { ExactEvmScheme } from "@x402/evm/exact/client";
4
- import { privateKeyToAccount } from "viem/accounts";
5
1
  /**
6
2
  * Development engine. Declares the one-word amount without settling real funds,
7
3
  * for use against a dev-mode gateway. NOT for production.
@@ -23,35 +19,4 @@ export class StaticPaymentEngine {
23
19
  };
24
20
  }
25
21
  }
26
- /**
27
- * Circle/x402 engine. Signs the gateway's one-word `paymentRequired` terms.
28
- * Circle may batch settlement internally, but each signed payload corresponds to
29
- * exactly one word.
30
- */
31
- export class CircleGatewayPaymentEngine {
32
- options;
33
- client = new x402Client();
34
- account;
35
- constructor(options) {
36
- this.options = options;
37
- this.account = privateKeyToAccount(this.options.privateKey);
38
- // Recommended buyer integration (Circle x402 buyer how-to): register the
39
- // gasless batched scheme with an `exact` fallback. `registerBatchScheme`
40
- // wires a CompositeEvmScheme that uses Gateway batching when the seller
41
- // supports it and falls back to a standard EIP-3009 `exact` payment
42
- // otherwise — no per-request routing logic needed.
43
- registerBatchScheme(this.client, {
44
- signer: this.account,
45
- fallbackScheme: new ExactEvmScheme(this.account),
46
- });
47
- }
48
- async createWordPayment(session) {
49
- if (!session.paymentRequired) {
50
- throw new Error("Session did not include an x402 one-word payment requirement");
51
- }
52
- return {
53
- paymentPayload: await this.client.createPaymentPayload(session.paymentRequired),
54
- };
55
- }
56
- }
57
22
  //# sourceMappingURL=payment-engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"payment-engine.js","sourceRoot":"","sources":["../src/payment-engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAA4B,MAAM,kCAAkC,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAUpD;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,UAAU,gBAAgB;QAA1B,YAAO,GAAP,OAAO,CAAmB;IAAG,CAAC;IAE3D,KAAK,CAAC,iBAAiB,CAAC,OAA6B;QACnD,OAAO;YACL,cAAc,EAAE;gBACd,MAAM,EAAE,oBAAoB;gBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,YAAY,EAAE,OAAO,CAAC,iBAAiB;gBACvC,YAAY,EAAE,MAAM;aACrB;SACF,CAAC;IACJ,CAAC;CACF;AAID;;;;GAIG;AACH,MAAM,OAAO,0BAA0B;IAIR;IAHZ,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IAC1B,OAAO,CAAyC;IAEjE,YAA6B,OAA0C;QAA1C,YAAO,GAAP,OAAO,CAAmC;QACrE,IAAI,CAAC,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC5D,yEAAyE;QACzE,yEAAyE;QACzE,wEAAwE;QACxE,oEAAoE;QACpE,mDAAmD;QACnD,mBAAmB,CAAC,IAAI,CAAC,MAAM,EAAE;YAC/B,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,cAAc,EAAE,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;SACjD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,OAA6B;QACnD,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAClF,CAAC;QACD,OAAO;YACL,cAAc,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,eAAwB,CAAC;SACzF,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"payment-engine.js","sourceRoot":"","sources":["../src/payment-engine.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,UAAU,gBAAgB;QAA1B,YAAO,GAAP,OAAO,CAAmB;IAAG,CAAC;IAE3D,KAAK,CAAC,iBAAiB,CAAC,OAA6B;QACnD,OAAO;YACL,cAAc,EAAE;gBACd,MAAM,EAAE,oBAAoB;gBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,YAAY,EAAE,OAAO,CAAC,iBAAiB;gBACvC,YAAY,EAAE,MAAM;aACrB;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment-engine.test.d.ts","sourceRoot":"","sources":["../src/payment-engine.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubicon-caliga/agent-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Client SDK for autonomous agents consuming per-word article streams via Rubicon x402.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,19 +24,19 @@
24
24
  "publishConfig": {
25
25
  "access": "public"
26
26
  },
27
- "scripts": {
28
- "build": "tsc -p tsconfig.json",
29
- "lint": "tsc -p tsconfig.json --noEmit",
30
- "typecheck": "tsc -p tsconfig.json --noEmit",
31
- "test": "node --test dist/**/*.test.js",
32
- "prepublishOnly": "pnpm run build"
33
- },
34
27
  "dependencies": {
35
- "@rubicon-caliga/core": "^0.1.0",
28
+ "@circle-fin/developer-controlled-wallets": "^10.6.0",
36
29
  "@circle-fin/x402-batching": "^3.1.2",
37
30
  "@x402/core": "^2.15.0",
38
31
  "@x402/evm": "^2.15.0",
39
32
  "eventsource": "^4.0.0",
40
- "viem": "^2.52.2"
33
+ "viem": "^2.52.2",
34
+ "@rubicon-caliga/core": "0.1.0"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.json",
38
+ "lint": "tsc -p tsconfig.json --noEmit",
39
+ "typecheck": "tsc -p tsconfig.json --noEmit",
40
+ "test": "node --test dist/**/*.test.js"
41
41
  }
42
- }
42
+ }
@@ -39,6 +39,10 @@ export interface ReadReceipt {
39
39
  amountPaidAtomic: `${bigint}`;
40
40
  payments: WordPaymentReceipt[];
41
41
  transactionHashes: string[];
42
+ settlementIds: string[];
43
+ buyerWalletAddress?: `0x${string}`;
44
+ sellerPayTo?: `0x${string}`;
45
+ network?: string;
42
46
  text: string;
43
47
  completed: boolean;
44
48
  stopReason: "article_completed" | "stop_condition" | "budget_reached" | "max_words" | "aborted";
@@ -268,6 +272,7 @@ export class RubiconClient {
268
272
  let wordsRead = 0;
269
273
  let amountPaid = 0n;
270
274
  const transactionHashes: string[] = [];
275
+ const settlementIds: string[] = [];
271
276
  const payments: WordPaymentReceipt[] = [];
272
277
  let stopReason: ReadReceipt["stopReason"] = "article_completed";
273
278
  let completed = false;
@@ -280,6 +285,10 @@ export class RubiconClient {
280
285
  amountPaidAtomic: `${amountPaid}`,
281
286
  payments: [...payments],
282
287
  transactionHashes: [...transactionHashes],
288
+ settlementIds: [...settlementIds],
289
+ buyerWalletAddress: [...payments].reverse().find((payment) => payment.buyerWalletAddress)?.buyerWalletAddress,
290
+ sellerPayTo: [...payments].reverse().find((payment) => payment.payTo)?.payTo,
291
+ network: [...payments].reverse().find((payment) => payment.network)?.network,
283
292
  text,
284
293
  completed,
285
294
  stopReason,
@@ -326,6 +335,7 @@ export class RubiconClient {
326
335
  payments.push(result.payment);
327
336
  }
328
337
  transactionHashes.push(...(result.transactionHashes ?? (result.transactionHash ? [result.transactionHash] : [])));
338
+ settlementIds.push(...(result.settlementIds ?? (result.settlementId ? [result.settlementId] : [])));
329
339
  text = text ? `${text} ${result.word}` : result.word;
330
340
 
331
341
  yield {
@@ -0,0 +1,118 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { serializeTypedData, toEip712Payload } from "./circle-agent-wallet.js";
4
+
5
+ // The x402 schemes hand the signer viem-style typed data with no EIP712Domain
6
+ // entry; Circle's API needs the complete document. These pin the bridging.
7
+
8
+ const TRANSFER_TYPES = {
9
+ TransferWithAuthorization: [
10
+ { name: "from", type: "address" },
11
+ { name: "to", type: "address" },
12
+ { name: "value", type: "uint256" },
13
+ ],
14
+ };
15
+
16
+ const EIP3009_TRANSFER_TYPES = {
17
+ TransferWithAuthorization: [
18
+ { name: "from", type: "address" },
19
+ { name: "to", type: "address" },
20
+ { name: "value", type: "uint256" },
21
+ { name: "validAfter", type: "uint256" },
22
+ { name: "validBefore", type: "uint256" },
23
+ { name: "nonce", type: "bytes32" },
24
+ ],
25
+ };
26
+
27
+ test("injects EIP712Domain derived from the domain fields present", () => {
28
+ const payload = toEip712Payload({
29
+ domain: {
30
+ name: "USD Coin",
31
+ version: "2",
32
+ chainId: 5042002,
33
+ verifyingContract: "0xabc",
34
+ },
35
+ types: TRANSFER_TYPES,
36
+ primaryType: "TransferWithAuthorization",
37
+ message: { from: "0x1", to: "0x2", value: "5" },
38
+ });
39
+
40
+ assert.deepEqual(payload.types.EIP712Domain, [
41
+ { name: "name", type: "string" },
42
+ { name: "version", type: "string" },
43
+ { name: "chainId", type: "uint256" },
44
+ { name: "verifyingContract", type: "address" },
45
+ ]);
46
+ // Original typed-data entries are preserved alongside the injected domain.
47
+ assert.deepEqual(payload.types.TransferWithAuthorization, TRANSFER_TYPES.TransferWithAuthorization);
48
+ assert.equal(payload.primaryType, "TransferWithAuthorization");
49
+ });
50
+
51
+ test("only includes domain fields that are actually present", () => {
52
+ const payload = toEip712Payload({
53
+ domain: { name: "Test", chainId: 1337 },
54
+ types: TRANSFER_TYPES,
55
+ primaryType: "TransferWithAuthorization",
56
+ message: {},
57
+ });
58
+
59
+ assert.deepEqual(payload.types.EIP712Domain, [
60
+ { name: "name", type: "string" },
61
+ { name: "chainId", type: "uint256" },
62
+ ]);
63
+ });
64
+
65
+ test("does not overwrite an EIP712Domain the caller already supplied", () => {
66
+ const provided = [{ name: "name", type: "string" }];
67
+ const payload = toEip712Payload({
68
+ domain: { name: "Test", chainId: 1337 },
69
+ types: { ...TRANSFER_TYPES, EIP712Domain: provided },
70
+ primaryType: "TransferWithAuthorization",
71
+ message: {},
72
+ });
73
+
74
+ assert.deepEqual(payload.types.EIP712Domain, provided);
75
+ });
76
+
77
+ test("serializes bigint authorization fields (exact fallback) as decimal strings", () => {
78
+ // The `exact` scheme hands the signer bigint value/validAfter/validBefore;
79
+ // plain JSON.stringify would throw, so they must be coerced to strings.
80
+ const payload = toEip712Payload({
81
+ domain: { name: "USD Coin", chainId: 5042002 },
82
+ types: EIP3009_TRANSFER_TYPES,
83
+ primaryType: "TransferWithAuthorization",
84
+ message: {
85
+ from: "0x1",
86
+ to: "0x2",
87
+ value: 5n,
88
+ validAfter: 0n,
89
+ validBefore: 1893456000n,
90
+ nonce: "0xabc",
91
+ },
92
+ });
93
+
94
+ const json = serializeTypedData(payload);
95
+ const parsed = JSON.parse(json);
96
+ assert.equal(parsed.message.value, "5");
97
+ assert.equal(parsed.message.validAfter, "0");
98
+ assert.equal(parsed.message.validBefore, "1893456000");
99
+ });
100
+
101
+ test("removes message fields that are not declared by the primary type", () => {
102
+ const payload = toEip712Payload({
103
+ domain: { name: "USD Coin", chainId: 5042002 },
104
+ types: TRANSFER_TYPES,
105
+ primaryType: "TransferWithAuthorization",
106
+ message: {
107
+ from: "0x1",
108
+ to: "0x2",
109
+ value: "5",
110
+ validAfter: "0",
111
+ validBefore: "1893456000",
112
+ nonce: "0xabc",
113
+ authorization: { unexpected: true },
114
+ },
115
+ });
116
+
117
+ assert.deepEqual(payload.message, { from: "0x1", to: "0x2", value: "5" });
118
+ });