@rubicon-caliga/agent-sdk 0.1.1 → 0.1.2

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 CHANGED
@@ -20,7 +20,7 @@ const hasCircleCliWallet = process.env.CIRCLE_AGENT_WALLET_ADDRESS;
20
20
  const rubicon = new Rubicon({
21
21
  paymentEngine: hasCircleCliWallet
22
22
  ? new CircleCliGatewayPaymentEngine({
23
- walletAddress: process.env.CIRCLE_AGENT_WALLET_ADDRESS as `0x${string}`,
23
+ agentWalletAddress: process.env.CIRCLE_AGENT_WALLET_ADDRESS as `0x${string}`,
24
24
  })
25
25
  : new StaticPaymentEngine(),
26
26
  });
@@ -88,16 +88,32 @@ import Rubicon, { CircleCliGatewayPaymentEngine } from "@rubicon-caliga/agent-sd
88
88
  const rubicon = new Rubicon({
89
89
  baseUrl: process.env.RUBICON_GATEWAY_URL,
90
90
  paymentEngine: new CircleCliGatewayPaymentEngine({
91
- walletAddress: process.env.CIRCLE_AGENT_WALLET_ADDRESS as `0x${string}` | undefined,
91
+ agentWalletAddress: process.env.CIRCLE_AGENT_WALLET_ADDRESS as `0x${string}` | undefined,
92
92
  chain: "ARC-TESTNET",
93
93
  }),
94
94
  });
95
95
  ```
96
96
 
97
- When `walletAddress` is omitted, the engine runs
97
+ `CircleCliGatewayPaymentEngine` keeps two addresses distinct:
98
+
99
+ - `agentWalletAddress` is the Circle Agent Wallet passed to
100
+ `circle wallet sign typed-data --address`.
101
+ - `buyerWalletAddress` / `backingEOA` is the Gateway backing EOA used as the
102
+ x402 `TransferWithAuthorization.from` address.
103
+
104
+ When only `agentWalletAddress` is provided, the engine discovers the backing EOA
105
+ with `circle gateway balance --address <agentWalletAddress> --chain ARC-TESTNET --output json`.
106
+ When no address is provided, the engine first runs
98
107
  `circle wallet list --chain ARC-TESTNET --type agent --output json` and uses the
99
- sole Agent Wallet it finds. If multiple wallets are present, pass the address
100
- explicitly.
108
+ sole Agent Wallet it finds, then discovers its backing EOA with Gateway balance.
109
+ The older `walletAddress` option remains as an alias for `agentWalletAddress`.
110
+ If multiple Agent Wallets are present, pass the agent wallet explicitly.
111
+
112
+ Gateway/Nanopayments receipts may have empty `transactionHashes`. Treat
113
+ `settlementIds` as the primary proof of payment; scanner visibility is not
114
+ guaranteed because a successful nanopayment may not appear as a direct ERC-20
115
+ transfer to the seller. Seller dashboards should count Rubicon backend payment
116
+ receipts and Circle Gateway settlement IDs, not direct on-chain transfers.
101
117
 
102
118
  The lower-level API-backed custody path is also available:
103
119
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agent-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-client.test.d.ts","sourceRoot":"","sources":["../src/agent-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { RubiconClient } from "./agent-client.js";
4
+ const paymentEngine = {
5
+ async createWordPayment() {
6
+ return { paymentPayload: { ok: true } };
7
+ },
8
+ };
9
+ test("run receipt preserves Gateway settlement receipt fields", async () => {
10
+ const fetcher = (async (input) => {
11
+ const url = String(input);
12
+ if (url.endsWith("/v1/sessions")) {
13
+ return jsonResponse({
14
+ sessionId: "session_1",
15
+ state: "active",
16
+ article: article(),
17
+ navigation: navigation(),
18
+ pricePerWordAtomic: "1",
19
+ maxArticlePriceAtomic: "10",
20
+ conversationId: "conversation_1",
21
+ wordPaymentAtomic: "1",
22
+ gatewayFeeBps: 0,
23
+ paymentRequired: { scheme: "exact" },
24
+ expiresAt: "2026-06-18T12:00:00.000Z",
25
+ wordsPaid: 0,
26
+ wordsDelivered: 0,
27
+ paidAtomic: "0",
28
+ });
29
+ }
30
+ if (url.endsWith("/v1/sessions/session_1/payments")) {
31
+ return jsonResponse({
32
+ accepted: true,
33
+ sequence: 0,
34
+ word: "Rubicon",
35
+ priceAtomic: "1",
36
+ wordsPaid: 1,
37
+ wordsDelivered: 1,
38
+ paidAtomic: "1",
39
+ completed: true,
40
+ transactionHashes: [],
41
+ settlementIds: ["settlement_1"],
42
+ payment: {
43
+ paymentId: "payment_1",
44
+ sessionId: "session_1",
45
+ articleId: "article_1",
46
+ sequence: 0,
47
+ meteringUnit: "word",
48
+ amountAtomic: "1",
49
+ currency: "USDC",
50
+ network: "eip155:5042002",
51
+ payTo: "0x3333333333333333333333333333333333333333",
52
+ transactionHashes: [],
53
+ settlementIds: ["settlement_1"],
54
+ buyerWalletAddress: "0x2222222222222222222222222222222222222222",
55
+ settledAt: "2026-06-18T12:00:00.000Z",
56
+ },
57
+ });
58
+ }
59
+ throw new Error(`Unexpected fetch: ${url}`);
60
+ });
61
+ const client = new RubiconClient({
62
+ baseUrl: "http://rubicon.test",
63
+ paymentEngine,
64
+ fetch: fetcher,
65
+ });
66
+ const receipt = await client.run({
67
+ articleId: "article_1",
68
+ maxSpendAtomic: "10",
69
+ });
70
+ assert.deepEqual(receipt.transactionHashes, []);
71
+ assert.deepEqual(receipt.settlementIds, ["settlement_1"]);
72
+ assert.equal(receipt.buyerWalletAddress, "0x2222222222222222222222222222222222222222");
73
+ assert.equal(receipt.sellerPayTo, "0x3333333333333333333333333333333333333333");
74
+ assert.equal(receipt.network, "eip155:5042002");
75
+ });
76
+ function jsonResponse(body) {
77
+ return new Response(JSON.stringify(body), {
78
+ status: 200,
79
+ headers: { "content-type": "application/json" },
80
+ });
81
+ }
82
+ function article() {
83
+ return {
84
+ articleId: "article_1",
85
+ creatorId: "creator_1",
86
+ creatorUsername: "creator",
87
+ title: "Title",
88
+ author: "Author",
89
+ state: "published",
90
+ totalWords: 1,
91
+ pricePerWordAtomic: "1",
92
+ maxArticlePriceAtomic: "1",
93
+ sections: [],
94
+ };
95
+ }
96
+ function navigation() {
97
+ return {
98
+ articleId: "article_1",
99
+ sections: [],
100
+ sellerAgent: {
101
+ recommendedSectionId: "intro",
102
+ alternativeSectionIds: [],
103
+ rationale: "",
104
+ safeHints: [],
105
+ withheld: [],
106
+ },
107
+ stopConditions: [],
108
+ };
109
+ }
110
+ //# sourceMappingURL=agent-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-client.test.js","sourceRoot":"","sources":["../src/agent-client.test.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,24 @@ export interface CircleCliGatewayPaymentEngineOptions {
5
5
  /**
6
6
  * Agent Wallet address controlled by Circle CLI. When omitted, the engine
7
7
  * resolves the sole agent wallet returned by `circle wallet list`.
8
+ *
9
+ * @deprecated Use `agentWalletAddress`. This alias is kept for existing SDK
10
+ * callers and is treated as the Circle CLI signing wallet, not the x402
11
+ * authorization `from` address.
8
12
  */
9
13
  walletAddress?: `0x${string}`;
14
+ /**
15
+ * Agent Wallet address controlled by Circle CLI. This is passed to
16
+ * `circle wallet sign typed-data --address`.
17
+ */
18
+ agentWalletAddress?: `0x${string}`;
19
+ /**
20
+ * Gateway backing EOA used as the x402 authorization `from` address. When
21
+ * omitted, the engine resolves it from `circle gateway balance`.
22
+ */
23
+ buyerWalletAddress?: `0x${string}`;
24
+ /** Alias for `buyerWalletAddress`. */
25
+ backingEOA?: `0x${string}`;
10
26
  /** Circle CLI chain name. Rubicon real reads settle on Arc Testnet by default. */
11
27
  chain?: string;
12
28
  /** Circle CLI binary name or path. */
@@ -14,6 +30,12 @@ export interface CircleCliGatewayPaymentEngineOptions {
14
30
  /** Command runner injection point for tests or hosted agent sandboxes. */
15
31
  runner?: CircleCliRunner;
16
32
  }
33
+ interface TypedDataRequest {
34
+ domain: Record<string, unknown>;
35
+ types: Record<string, unknown>;
36
+ primaryType: string;
37
+ message: Record<string, unknown>;
38
+ }
17
39
  /**
18
40
  * Circle CLI / Agent Wallet payment engine. It creates the one-word x402
19
41
  * payment payload for Rubicon's session-first flow and delegates EIP-712
@@ -26,6 +48,27 @@ export declare class CircleCliGatewayPaymentEngine implements AgentPaymentEngine
26
48
  constructor(options?: CircleCliGatewayPaymentEngineOptions);
27
49
  createWordPayment(session: StartSessionResponse): Promise<StreamPaymentRequest>;
28
50
  }
51
+ export declare class CircleCliGatewaySigner {
52
+ private readonly options;
53
+ agentWalletAddress: `0x${string}`;
54
+ address: `0x${string}`;
55
+ private resolved;
56
+ private resolving?;
57
+ constructor(options: {
58
+ agentWalletAddress?: `0x${string}`;
59
+ buyerWalletAddress?: `0x${string}`;
60
+ chain: string;
61
+ command: string;
62
+ runner: CircleCliRunner;
63
+ });
64
+ ensureAddress(): Promise<void>;
65
+ signTypedData(typed: TypedDataRequest): Promise<`0x${string}`>;
66
+ private resolveAddress;
67
+ private resolveAgentWalletAddress;
68
+ private resolveBackingEOA;
69
+ }
29
70
  export declare function parseCircleCliSignature(output: string): `0x${string}`;
30
71
  export declare function parseCircleCliWalletAddress(output: string): `0x${string}`;
72
+ export declare function parseCircleGatewayBackingEOA(output: string): `0x${string}`;
73
+ export {};
31
74
  //# sourceMappingURL=circle-cli-gateway-payment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"circle-cli-gateway-payment.d.ts","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIvF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAK9D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEnF,MAAM,WAAW,oCAAoC;IACnD;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC9B,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AASD;;;;;GAKG;AACH,qBAAa,6BAA8B,YAAW,kBAAkB;IACtE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAEpC,OAAO,GAAE,oCAAyC;IAaxD,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAStF;AA4ED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAiBrE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAezE"}
1
+ {"version":3,"file":"circle-cli-gateway-payment.d.ts","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIvF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAK9D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEnF,MAAM,WAAW,oCAAoC;IACnD;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACnC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACnC,sCAAsC;IACtC,UAAU,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,6BAA8B,YAAW,kBAAkB;IACtE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAEpC,OAAO,GAAE,oCAAyC;IAcxD,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAStF;AAED,qBAAa,sBAAsB;IAO/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,kBAAkB,EAAE,KAAK,MAAM,EAAE,CAAgD;IACjF,OAAO,EAAE,KAAK,MAAM,EAAE,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAC,CAAgB;gBAGf,OAAO,EAAE;QACxB,kBAAkB,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;QACnC,kBAAkB,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;QACnC,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,eAAe,CAAC;KACzB;IAaG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,MAAM,EAAE,CAAC;YAgBtD,cAAc;YASd,yBAAyB;YAczB,iBAAiB;CAahC;AAgBD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAiBrE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAezE;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAO1E"}
@@ -16,7 +16,8 @@ export class CircleCliGatewayPaymentEngine {
16
16
  signer;
17
17
  constructor(options = {}) {
18
18
  this.signer = new CircleCliGatewaySigner({
19
- walletAddress: options.walletAddress,
19
+ agentWalletAddress: options.agentWalletAddress ?? options.walletAddress,
20
+ buyerWalletAddress: options.buyerWalletAddress ?? options.backingEOA,
20
21
  chain: options.chain ?? "ARC-TESTNET",
21
22
  command: options.command ?? "circle",
22
23
  runner: options.runner ?? runCircleCli,
@@ -36,15 +37,21 @@ export class CircleCliGatewayPaymentEngine {
36
37
  };
37
38
  }
38
39
  }
39
- class CircleCliGatewaySigner {
40
+ export class CircleCliGatewaySigner {
40
41
  options;
42
+ agentWalletAddress = "0x0000000000000000000000000000000000000000";
41
43
  address = "0x0000000000000000000000000000000000000000";
42
44
  resolved = false;
43
45
  resolving;
44
46
  constructor(options) {
45
47
  this.options = options;
46
- if (options.walletAddress) {
47
- this.address = options.walletAddress;
48
+ if (options.agentWalletAddress) {
49
+ this.agentWalletAddress = options.agentWalletAddress;
50
+ }
51
+ if (options.buyerWalletAddress) {
52
+ this.address = options.buyerWalletAddress;
53
+ }
54
+ if (options.agentWalletAddress && options.buyerWalletAddress) {
48
55
  this.resolved = true;
49
56
  }
50
57
  }
@@ -64,7 +71,7 @@ class CircleCliGatewaySigner {
64
71
  "typed-data",
65
72
  serializeTypedData(toEip712Payload(typed)),
66
73
  "--address",
67
- this.address,
74
+ this.agentWalletAddress,
68
75
  "--chain",
69
76
  this.options.chain,
70
77
  "--quiet",
@@ -72,6 +79,13 @@ class CircleCliGatewaySigner {
72
79
  return parseCircleCliSignature(signature);
73
80
  }
74
81
  async resolveAddress() {
82
+ const agentWalletAddress = this.options.agentWalletAddress ?? (await this.resolveAgentWalletAddress());
83
+ this.agentWalletAddress = agentWalletAddress;
84
+ this.address =
85
+ this.options.buyerWalletAddress ?? (await this.resolveBackingEOA(agentWalletAddress));
86
+ this.resolved = true;
87
+ }
88
+ async resolveAgentWalletAddress() {
75
89
  const output = await this.options.runner(this.options.command, [
76
90
  "wallet",
77
91
  "list",
@@ -82,9 +96,20 @@ class CircleCliGatewaySigner {
82
96
  "--output",
83
97
  "json",
84
98
  ]);
85
- const address = parseCircleCliWalletAddress(output);
86
- this.address = address;
87
- this.resolved = true;
99
+ return parseCircleCliWalletAddress(output);
100
+ }
101
+ async resolveBackingEOA(agentWalletAddress) {
102
+ const output = await this.options.runner(this.options.command, [
103
+ "gateway",
104
+ "balance",
105
+ "--address",
106
+ agentWalletAddress,
107
+ "--chain",
108
+ this.options.chain,
109
+ "--output",
110
+ "json",
111
+ ]);
112
+ return parseCircleGatewayBackingEOA(output);
88
113
  }
89
114
  }
90
115
  async function runCircleCli(command, args) {
@@ -130,7 +155,15 @@ export function parseCircleCliWalletAddress(output) {
130
155
  if (unique.length === 0) {
131
156
  throw new Error("Circle CLI did not return an Agent Wallet address");
132
157
  }
133
- throw new Error("Multiple Circle Agent Wallets found; pass walletAddress explicitly");
158
+ throw new Error("Multiple Circle Agent Wallets found; pass agentWalletAddress explicitly");
159
+ }
160
+ export function parseCircleGatewayBackingEOA(output) {
161
+ const parsed = parseJson(output);
162
+ const backingEOA = findString(parsed, ["data.backingEOA", "backingEOA"]);
163
+ if (backingEOA && isAddress(backingEOA)) {
164
+ return backingEOA;
165
+ }
166
+ throw new Error("Circle Gateway balance did not return a backingEOA address");
134
167
  }
135
168
  function collectWalletCandidates(value) {
136
169
  if (Array.isArray(value)) {
@@ -1 +1 @@
1
- {"version":3,"file":"circle-cli-gateway-payment.js","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"circle-cli-gateway-payment.js","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE/E,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAyC1C;;;;;GAKG;AACH,MAAM,OAAO,6BAA6B;IACvB,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;IACxB,MAAM,CAAyB;IAEhD,YAAY,UAAgD,EAAE;QAC5D,IAAI,CAAC,MAAM,GAAG,IAAI,sBAAsB,CAAC;YACvC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,aAAa;YACvE,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,UAAU;YACpE,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,aAAa;YACrC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ;YACpC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,YAAY;SACvC,CAAC,CAAC;QACH,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE;YAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,cAAc,EAAE,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;SAChD,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,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAClC,OAAO;YACL,cAAc,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,eAAwB,CAAC;SACvF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,sBAAsB;IAOd;IANnB,kBAAkB,GAAkB,4CAA4C,CAAC;IACjF,OAAO,GAAkB,4CAA4C,CAAC;IAC9D,QAAQ,GAAG,KAAK,CAAC;IACjB,SAAS,CAAiB;IAElC,YACmB,OAMhB;QANgB,YAAO,GAAP,OAAO,CAMvB;QAED,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC/B,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;QACvD,CAAC;QACD,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAC5C,CAAC;QACD,IAAI,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC7D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAuB;QACzC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YAChE,QAAQ;YACR,MAAM;YACN,YAAY;YACZ,kBAAkB,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC1C,WAAW;YACX,IAAI,CAAC,kBAAkB;YACvB,SAAS;YACT,IAAI,CAAC,OAAO,CAAC,KAAK;YAClB,SAAS;SACV,CAAC,CAAC;QACH,OAAO,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,MAAM,kBAAkB,GACtB,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAC7C,IAAI,CAAC,OAAO;YACV,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC;QACxF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,yBAAyB;QACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YAC7D,QAAQ;YACR,MAAM;YACN,SAAS;YACT,IAAI,CAAC,OAAO,CAAC,KAAK;YAClB,QAAQ;YACR,OAAO;YACP,UAAU;YACV,MAAM;SACP,CAAC,CAAC;QACH,OAAO,2BAA2B,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,kBAAiC;QAC/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YAC7D,SAAS;YACT,SAAS;YACT,WAAW;YACX,kBAAkB;YAClB,SAAS;YACT,IAAI,CAAC,OAAO,CAAC,KAAK;YAClB,UAAU;YACV,MAAM;SACP,CAAC,CAAC;QACH,OAAO,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;CACF;AAED,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,IAAc;IACzD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE;YACpD,SAAS,EAAE,IAAI,GAAG,IAAI;SACvB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CACb,wHAAwH,OAAO,EAAE,CAClI,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAc;IACpD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACpF,IAAI,SAAS,IAAI,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3C,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAAc;IACxD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,OAAO;SACtB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,mBAAmB,CAAC,CAAC,CAAC;SACtF,MAAM,CAAC,CAAC,OAAO,EAA4B,EAAE,CAAC,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAE,CAAC;IAC3E,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,MAAc;IACzD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC,CAAC;IACzE,IAAI,UAAU,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QACxC,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,MAAM,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,IAAc;IAChD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAU,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE;YAC7D,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,OAAO,SAAS,CAAC;YACzC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { parseCircleCliSignature, parseCircleCliWalletAddress, } from "./circle-cli-gateway-payment.js";
3
+ import { CircleCliGatewaySigner, parseCircleGatewayBackingEOA, parseCircleCliSignature, parseCircleCliWalletAddress, } from "./circle-cli-gateway-payment.js";
4
4
  test("parses quiet Circle CLI signatures", () => {
5
5
  assert.equal(parseCircleCliSignature("0xabc123\n"), "0xabc123");
6
6
  });
@@ -21,6 +21,115 @@ test("parses a sole wallet address from Circle CLI list output", () => {
21
21
  },
22
22
  })), "0x1111111111111111111111111111111111111111");
23
23
  });
24
+ test("parses backing EOA from Circle Gateway balance output", () => {
25
+ assert.equal(parseCircleGatewayBackingEOA(JSON.stringify({
26
+ data: {
27
+ backingEOA: "0x2222222222222222222222222222222222222222",
28
+ },
29
+ })), "0x2222222222222222222222222222222222222222");
30
+ });
31
+ test("separates Circle CLI Agent Wallet address from x402 backing EOA", async () => {
32
+ const calls = [];
33
+ const signer = new CircleCliGatewaySigner({
34
+ agentWalletAddress: "0x1111111111111111111111111111111111111111",
35
+ chain: "ARC-TESTNET",
36
+ command: "circle",
37
+ runner: async (_command, args) => {
38
+ calls.push(args);
39
+ assert.deepEqual(args, [
40
+ "gateway",
41
+ "balance",
42
+ "--address",
43
+ "0x1111111111111111111111111111111111111111",
44
+ "--chain",
45
+ "ARC-TESTNET",
46
+ "--output",
47
+ "json",
48
+ ]);
49
+ return JSON.stringify({
50
+ data: {
51
+ backingEOA: "0x2222222222222222222222222222222222222222",
52
+ },
53
+ });
54
+ },
55
+ });
56
+ await signer.ensureAddress();
57
+ assert.equal(signer.agentWalletAddress, "0x1111111111111111111111111111111111111111");
58
+ assert.equal(signer.address, "0x2222222222222222222222222222222222222222");
59
+ assert.equal(calls.length, 1);
60
+ });
61
+ test("discovers sole Agent Wallet and then its Gateway backing EOA", async () => {
62
+ const calls = [];
63
+ const signer = new CircleCliGatewaySigner({
64
+ chain: "ARC-TESTNET",
65
+ command: "circle",
66
+ runner: async (_command, args) => {
67
+ calls.push(args);
68
+ if (args[0] === "wallet") {
69
+ return JSON.stringify({
70
+ data: {
71
+ wallets: [{ address: "0x1111111111111111111111111111111111111111" }],
72
+ },
73
+ });
74
+ }
75
+ return JSON.stringify({
76
+ data: {
77
+ backingEOA: "0x2222222222222222222222222222222222222222",
78
+ },
79
+ });
80
+ },
81
+ });
82
+ await signer.ensureAddress();
83
+ assert.equal(signer.agentWalletAddress, "0x1111111111111111111111111111111111111111");
84
+ assert.equal(signer.address, "0x2222222222222222222222222222222222222222");
85
+ assert.deepEqual(calls, [
86
+ ["wallet", "list", "--chain", "ARC-TESTNET", "--type", "agent", "--output", "json"],
87
+ [
88
+ "gateway",
89
+ "balance",
90
+ "--address",
91
+ "0x1111111111111111111111111111111111111111",
92
+ "--chain",
93
+ "ARC-TESTNET",
94
+ "--output",
95
+ "json",
96
+ ],
97
+ ]);
98
+ });
99
+ test("typed data message.from uses backing EOA while CLI signs with Agent Wallet", async () => {
100
+ let signedPayload;
101
+ const signer = new CircleCliGatewaySigner({
102
+ agentWalletAddress: "0x1111111111111111111111111111111111111111",
103
+ buyerWalletAddress: "0x2222222222222222222222222222222222222222",
104
+ chain: "ARC-TESTNET",
105
+ command: "circle",
106
+ runner: async (_command, args) => {
107
+ const addressFlag = args.indexOf("--address");
108
+ assert.equal(args[addressFlag + 1], "0x1111111111111111111111111111111111111111");
109
+ signedPayload = JSON.parse(args[3] ?? "{}");
110
+ return "0xabc123";
111
+ },
112
+ });
113
+ await signer.ensureAddress();
114
+ assert.equal(signer.address, "0x2222222222222222222222222222222222222222");
115
+ await signer.signTypedData({
116
+ domain: { name: "USD Coin", version: "2", chainId: 5042002 },
117
+ types: {
118
+ TransferWithAuthorization: [
119
+ { name: "from", type: "address" },
120
+ { name: "to", type: "address" },
121
+ { name: "value", type: "uint256" },
122
+ ],
123
+ },
124
+ primaryType: "TransferWithAuthorization",
125
+ message: {
126
+ from: signer.address,
127
+ to: "0x3333333333333333333333333333333333333333",
128
+ value: 1n,
129
+ },
130
+ });
131
+ assert.equal((signedPayload?.message).from, "0x2222222222222222222222222222222222222222");
132
+ });
24
133
  test("requires explicit wallet address when multiple Agent Wallets are present", () => {
25
134
  assert.throws(() => parseCircleCliWalletAddress(JSON.stringify({
26
135
  data: [
@@ -1 +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"}
1
+ {"version":3,"file":"circle-cli-gateway-payment.test.js","sourceRoot":"","sources":["../src/circle-cli-gateway-payment.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubicon-caliga/agent-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Client SDK for autonomous agents consuming per-word article streams via Rubicon x402.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,118 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { RubiconClient } from "./agent-client.js";
4
+ import type { AgentPaymentEngine } from "./payment-engine.js";
5
+
6
+ const paymentEngine: AgentPaymentEngine = {
7
+ async createWordPayment() {
8
+ return { paymentPayload: { ok: true } };
9
+ },
10
+ };
11
+
12
+ test("run receipt preserves Gateway settlement receipt fields", async () => {
13
+ const fetcher = (async (input: Parameters<typeof fetch>[0]) => {
14
+ const url = String(input);
15
+ if (url.endsWith("/v1/sessions")) {
16
+ return jsonResponse({
17
+ sessionId: "session_1",
18
+ state: "active",
19
+ article: article(),
20
+ navigation: navigation(),
21
+ pricePerWordAtomic: "1",
22
+ maxArticlePriceAtomic: "10",
23
+ conversationId: "conversation_1",
24
+ wordPaymentAtomic: "1",
25
+ gatewayFeeBps: 0,
26
+ paymentRequired: { scheme: "exact" },
27
+ expiresAt: "2026-06-18T12:00:00.000Z",
28
+ wordsPaid: 0,
29
+ wordsDelivered: 0,
30
+ paidAtomic: "0",
31
+ });
32
+ }
33
+ if (url.endsWith("/v1/sessions/session_1/payments")) {
34
+ return jsonResponse({
35
+ accepted: true,
36
+ sequence: 0,
37
+ word: "Rubicon",
38
+ priceAtomic: "1",
39
+ wordsPaid: 1,
40
+ wordsDelivered: 1,
41
+ paidAtomic: "1",
42
+ completed: true,
43
+ transactionHashes: [],
44
+ settlementIds: ["settlement_1"],
45
+ payment: {
46
+ paymentId: "payment_1",
47
+ sessionId: "session_1",
48
+ articleId: "article_1",
49
+ sequence: 0,
50
+ meteringUnit: "word",
51
+ amountAtomic: "1",
52
+ currency: "USDC",
53
+ network: "eip155:5042002",
54
+ payTo: "0x3333333333333333333333333333333333333333",
55
+ transactionHashes: [],
56
+ settlementIds: ["settlement_1"],
57
+ buyerWalletAddress: "0x2222222222222222222222222222222222222222",
58
+ settledAt: "2026-06-18T12:00:00.000Z",
59
+ },
60
+ });
61
+ }
62
+ throw new Error(`Unexpected fetch: ${url}`);
63
+ }) as typeof fetch;
64
+
65
+ const client = new RubiconClient({
66
+ baseUrl: "http://rubicon.test",
67
+ paymentEngine,
68
+ fetch: fetcher,
69
+ });
70
+
71
+ const receipt = await client.run({
72
+ articleId: "article_1",
73
+ maxSpendAtomic: "10",
74
+ });
75
+
76
+ assert.deepEqual(receipt.transactionHashes, []);
77
+ assert.deepEqual(receipt.settlementIds, ["settlement_1"]);
78
+ assert.equal(receipt.buyerWalletAddress, "0x2222222222222222222222222222222222222222");
79
+ assert.equal(receipt.sellerPayTo, "0x3333333333333333333333333333333333333333");
80
+ assert.equal(receipt.network, "eip155:5042002");
81
+ });
82
+
83
+ function jsonResponse(body: unknown): Response {
84
+ return new Response(JSON.stringify(body), {
85
+ status: 200,
86
+ headers: { "content-type": "application/json" },
87
+ });
88
+ }
89
+
90
+ function article() {
91
+ return {
92
+ articleId: "article_1",
93
+ creatorId: "creator_1",
94
+ creatorUsername: "creator",
95
+ title: "Title",
96
+ author: "Author",
97
+ state: "published",
98
+ totalWords: 1,
99
+ pricePerWordAtomic: "1",
100
+ maxArticlePriceAtomic: "1",
101
+ sections: [],
102
+ };
103
+ }
104
+
105
+ function navigation() {
106
+ return {
107
+ articleId: "article_1",
108
+ sections: [],
109
+ sellerAgent: {
110
+ recommendedSectionId: "intro",
111
+ alternativeSectionIds: [],
112
+ rationale: "",
113
+ safeHints: [],
114
+ withheld: [],
115
+ },
116
+ stopConditions: [],
117
+ };
118
+ }
@@ -1,6 +1,8 @@
1
1
  import { test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import {
4
+ CircleCliGatewaySigner,
5
+ parseCircleGatewayBackingEOA,
4
6
  parseCircleCliSignature,
5
7
  parseCircleCliWalletAddress,
6
8
  } from "./circle-cli-gateway-payment.js";
@@ -37,6 +39,133 @@ test("parses a sole wallet address from Circle CLI list output", () => {
37
39
  );
38
40
  });
39
41
 
42
+ test("parses backing EOA from Circle Gateway balance output", () => {
43
+ assert.equal(
44
+ parseCircleGatewayBackingEOA(
45
+ JSON.stringify({
46
+ data: {
47
+ backingEOA: "0x2222222222222222222222222222222222222222",
48
+ },
49
+ }),
50
+ ),
51
+ "0x2222222222222222222222222222222222222222",
52
+ );
53
+ });
54
+
55
+ test("separates Circle CLI Agent Wallet address from x402 backing EOA", async () => {
56
+ const calls: string[][] = [];
57
+ const signer = new CircleCliGatewaySigner({
58
+ agentWalletAddress: "0x1111111111111111111111111111111111111111",
59
+ chain: "ARC-TESTNET",
60
+ command: "circle",
61
+ runner: async (_command, args) => {
62
+ calls.push(args);
63
+ assert.deepEqual(args, [
64
+ "gateway",
65
+ "balance",
66
+ "--address",
67
+ "0x1111111111111111111111111111111111111111",
68
+ "--chain",
69
+ "ARC-TESTNET",
70
+ "--output",
71
+ "json",
72
+ ]);
73
+ return JSON.stringify({
74
+ data: {
75
+ backingEOA: "0x2222222222222222222222222222222222222222",
76
+ },
77
+ });
78
+ },
79
+ });
80
+
81
+ await signer.ensureAddress();
82
+
83
+ assert.equal(signer.agentWalletAddress, "0x1111111111111111111111111111111111111111");
84
+ assert.equal(signer.address, "0x2222222222222222222222222222222222222222");
85
+ assert.equal(calls.length, 1);
86
+ });
87
+
88
+ test("discovers sole Agent Wallet and then its Gateway backing EOA", async () => {
89
+ const calls: string[][] = [];
90
+ const signer = new CircleCliGatewaySigner({
91
+ chain: "ARC-TESTNET",
92
+ command: "circle",
93
+ runner: async (_command, args) => {
94
+ calls.push(args);
95
+ if (args[0] === "wallet") {
96
+ return JSON.stringify({
97
+ data: {
98
+ wallets: [{ address: "0x1111111111111111111111111111111111111111" }],
99
+ },
100
+ });
101
+ }
102
+ return JSON.stringify({
103
+ data: {
104
+ backingEOA: "0x2222222222222222222222222222222222222222",
105
+ },
106
+ });
107
+ },
108
+ });
109
+
110
+ await signer.ensureAddress();
111
+
112
+ assert.equal(signer.agentWalletAddress, "0x1111111111111111111111111111111111111111");
113
+ assert.equal(signer.address, "0x2222222222222222222222222222222222222222");
114
+ assert.deepEqual(calls, [
115
+ ["wallet", "list", "--chain", "ARC-TESTNET", "--type", "agent", "--output", "json"],
116
+ [
117
+ "gateway",
118
+ "balance",
119
+ "--address",
120
+ "0x1111111111111111111111111111111111111111",
121
+ "--chain",
122
+ "ARC-TESTNET",
123
+ "--output",
124
+ "json",
125
+ ],
126
+ ]);
127
+ });
128
+
129
+ test("typed data message.from uses backing EOA while CLI signs with Agent Wallet", async () => {
130
+ let signedPayload: Record<string, unknown> | undefined;
131
+ const signer = new CircleCliGatewaySigner({
132
+ agentWalletAddress: "0x1111111111111111111111111111111111111111",
133
+ buyerWalletAddress: "0x2222222222222222222222222222222222222222",
134
+ chain: "ARC-TESTNET",
135
+ command: "circle",
136
+ runner: async (_command, args) => {
137
+ const addressFlag = args.indexOf("--address");
138
+ assert.equal(args[addressFlag + 1], "0x1111111111111111111111111111111111111111");
139
+ signedPayload = JSON.parse(args[3] ?? "{}") as Record<string, unknown>;
140
+ return "0xabc123";
141
+ },
142
+ });
143
+ await signer.ensureAddress();
144
+ assert.equal(signer.address, "0x2222222222222222222222222222222222222222");
145
+
146
+ await signer.signTypedData({
147
+ domain: { name: "USD Coin", version: "2", chainId: 5042002 },
148
+ types: {
149
+ TransferWithAuthorization: [
150
+ { name: "from", type: "address" },
151
+ { name: "to", type: "address" },
152
+ { name: "value", type: "uint256" },
153
+ ],
154
+ },
155
+ primaryType: "TransferWithAuthorization",
156
+ message: {
157
+ from: signer.address,
158
+ to: "0x3333333333333333333333333333333333333333",
159
+ value: 1n,
160
+ },
161
+ });
162
+
163
+ assert.equal(
164
+ (signedPayload?.message as Record<string, unknown>).from,
165
+ "0x2222222222222222222222222222222222222222",
166
+ );
167
+ });
168
+
40
169
  test("requires explicit wallet address when multiple Agent Wallets are present", () => {
41
170
  assert.throws(
42
171
  () =>
@@ -15,8 +15,24 @@ export interface CircleCliGatewayPaymentEngineOptions {
15
15
  /**
16
16
  * Agent Wallet address controlled by Circle CLI. When omitted, the engine
17
17
  * resolves the sole agent wallet returned by `circle wallet list`.
18
+ *
19
+ * @deprecated Use `agentWalletAddress`. This alias is kept for existing SDK
20
+ * callers and is treated as the Circle CLI signing wallet, not the x402
21
+ * authorization `from` address.
18
22
  */
19
23
  walletAddress?: `0x${string}`;
24
+ /**
25
+ * Agent Wallet address controlled by Circle CLI. This is passed to
26
+ * `circle wallet sign typed-data --address`.
27
+ */
28
+ agentWalletAddress?: `0x${string}`;
29
+ /**
30
+ * Gateway backing EOA used as the x402 authorization `from` address. When
31
+ * omitted, the engine resolves it from `circle gateway balance`.
32
+ */
33
+ buyerWalletAddress?: `0x${string}`;
34
+ /** Alias for `buyerWalletAddress`. */
35
+ backingEOA?: `0x${string}`;
20
36
  /** Circle CLI chain name. Rubicon real reads settle on Arc Testnet by default. */
21
37
  chain?: string;
22
38
  /** Circle CLI binary name or path. */
@@ -44,7 +60,8 @@ export class CircleCliGatewayPaymentEngine implements AgentPaymentEngine {
44
60
 
45
61
  constructor(options: CircleCliGatewayPaymentEngineOptions = {}) {
46
62
  this.signer = new CircleCliGatewaySigner({
47
- walletAddress: options.walletAddress,
63
+ agentWalletAddress: options.agentWalletAddress ?? options.walletAddress,
64
+ buyerWalletAddress: options.buyerWalletAddress ?? options.backingEOA,
48
65
  chain: options.chain ?? "ARC-TESTNET",
49
66
  command: options.command ?? "circle",
50
67
  runner: options.runner ?? runCircleCli,
@@ -66,21 +83,28 @@ export class CircleCliGatewayPaymentEngine implements AgentPaymentEngine {
66
83
  }
67
84
  }
68
85
 
69
- class CircleCliGatewaySigner {
86
+ export class CircleCliGatewaySigner {
87
+ agentWalletAddress: `0x${string}` = "0x0000000000000000000000000000000000000000";
70
88
  address: `0x${string}` = "0x0000000000000000000000000000000000000000";
71
89
  private resolved = false;
72
90
  private resolving?: Promise<void>;
73
91
 
74
92
  constructor(
75
93
  private readonly options: {
76
- walletAddress?: `0x${string}`;
94
+ agentWalletAddress?: `0x${string}`;
95
+ buyerWalletAddress?: `0x${string}`;
77
96
  chain: string;
78
97
  command: string;
79
98
  runner: CircleCliRunner;
80
99
  },
81
100
  ) {
82
- if (options.walletAddress) {
83
- this.address = options.walletAddress;
101
+ if (options.agentWalletAddress) {
102
+ this.agentWalletAddress = options.agentWalletAddress;
103
+ }
104
+ if (options.buyerWalletAddress) {
105
+ this.address = options.buyerWalletAddress;
106
+ }
107
+ if (options.agentWalletAddress && options.buyerWalletAddress) {
84
108
  this.resolved = true;
85
109
  }
86
110
  }
@@ -101,7 +125,7 @@ class CircleCliGatewaySigner {
101
125
  "typed-data",
102
126
  serializeTypedData(toEip712Payload(typed)),
103
127
  "--address",
104
- this.address,
128
+ this.agentWalletAddress,
105
129
  "--chain",
106
130
  this.options.chain,
107
131
  "--quiet",
@@ -110,6 +134,15 @@ class CircleCliGatewaySigner {
110
134
  }
111
135
 
112
136
  private async resolveAddress(): Promise<void> {
137
+ const agentWalletAddress =
138
+ this.options.agentWalletAddress ?? (await this.resolveAgentWalletAddress());
139
+ this.agentWalletAddress = agentWalletAddress;
140
+ this.address =
141
+ this.options.buyerWalletAddress ?? (await this.resolveBackingEOA(agentWalletAddress));
142
+ this.resolved = true;
143
+ }
144
+
145
+ private async resolveAgentWalletAddress(): Promise<`0x${string}`> {
113
146
  const output = await this.options.runner(this.options.command, [
114
147
  "wallet",
115
148
  "list",
@@ -120,9 +153,21 @@ class CircleCliGatewaySigner {
120
153
  "--output",
121
154
  "json",
122
155
  ]);
123
- const address = parseCircleCliWalletAddress(output);
124
- this.address = address;
125
- this.resolved = true;
156
+ return parseCircleCliWalletAddress(output);
157
+ }
158
+
159
+ private async resolveBackingEOA(agentWalletAddress: `0x${string}`): Promise<`0x${string}`> {
160
+ const output = await this.options.runner(this.options.command, [
161
+ "gateway",
162
+ "balance",
163
+ "--address",
164
+ agentWalletAddress,
165
+ "--chain",
166
+ this.options.chain,
167
+ "--output",
168
+ "json",
169
+ ]);
170
+ return parseCircleGatewayBackingEOA(output);
126
171
  }
127
172
  }
128
173
 
@@ -173,7 +218,16 @@ export function parseCircleCliWalletAddress(output: string): `0x${string}` {
173
218
  if (unique.length === 0) {
174
219
  throw new Error("Circle CLI did not return an Agent Wallet address");
175
220
  }
176
- throw new Error("Multiple Circle Agent Wallets found; pass walletAddress explicitly");
221
+ throw new Error("Multiple Circle Agent Wallets found; pass agentWalletAddress explicitly");
222
+ }
223
+
224
+ export function parseCircleGatewayBackingEOA(output: string): `0x${string}` {
225
+ const parsed = parseJson(output);
226
+ const backingEOA = findString(parsed, ["data.backingEOA", "backingEOA"]);
227
+ if (backingEOA && isAddress(backingEOA)) {
228
+ return backingEOA;
229
+ }
230
+ throw new Error("Circle Gateway balance did not return a backingEOA address");
177
231
  }
178
232
 
179
233
  function collectWalletCandidates(value: unknown): Record<string, unknown>[] {