@openzeppelin/relayer-plugin-channels 0.16.0 → 0.17.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 CHANGED
@@ -16,6 +16,7 @@ A plugin for OpenZeppelin Relayer that enables parallel transaction submission o
16
16
  - [Development](#development)
17
17
  - [Overview](#overview)
18
18
  - [Architecture](#architecture)
19
+ - [x402 Fund Relayer](#x402-fund-relayer)
19
20
  - [Contract Capacity Limits](#contract-capacity-limits)
20
21
  - [Management API](#management-api)
21
22
  - [List Channel Accounts](#list-channel-accounts)
@@ -221,6 +222,8 @@ export FUND_RELAYER_ID="channels-fund"
221
222
  export PLUGIN_ADMIN_SECRET="your-secret-here" # Required for management API
222
223
 
223
224
  # Optional environment variables
225
+ # Comma-separated list of allowed alternative fund relayers (e.g., for x402 or similar flows)
226
+ export ALLOWED_FUND_RELAYER_IDS="x402-channels-fund"
224
227
  export LOCK_TTL_SECONDS=10 # default: 30, min: 3, max: 30
225
228
 
226
229
  # Fee tracking (optional)
@@ -308,6 +311,71 @@ The Channels plugin accepts Soroban operations and handles all the complexity of
308
311
  - **Channel Accounts**: Provide unique sequence numbers for parallel transaction submission
309
312
  - The channel account is the transaction source and signer; the fund account wraps it in a fee bump
310
313
 
314
+ ## Alternative Fund Relayers
315
+
316
+ The plugin supports optional secondary fund relayers for [x402](https://www.x402.org/) and similar payment flows. Pass `fundRelayerId` in the request and allowlist that ID through `ALLOWED_FUND_RELAYER_IDS`.
317
+
318
+ ### Configuration
319
+
320
+ ```bash
321
+ export ALLOWED_FUND_RELAYER_IDS="x402-fund"
322
+ ```
323
+
324
+ Every allowed alternative fund relayer must reference a relayer configured in your Relayer's `config.json`, just like the primary fund account. Add it alongside your existing relayers:
325
+
326
+ ```json
327
+ {
328
+ "id": "x402-fund",
329
+ "name": "x402 Fund Account",
330
+ "network": "testnet",
331
+ "paused": false,
332
+ "network_type": "stellar",
333
+ "signer_id": "x402-fund-signer",
334
+ "policies": {
335
+ "concurrent_transactions": true,
336
+ "fee_payment_strategy": "relayer"
337
+ }
338
+ }
339
+ ```
340
+
341
+ ### Preferred usage
342
+
343
+ Pass `fundRelayerId` in any `xdr` or `func`+`auth` request to route fee bumping through the specified fund relayer:
344
+
345
+ ```bash
346
+ curl -X POST http://localhost:8080/api/v1/plugins/channels/call \
347
+ -H "Authorization: Bearer YOUR_API_KEY" \
348
+ -H "Content-Type: application/json" \
349
+ -d '{
350
+ "params": {
351
+ "xdr": "AAAAAgAAAAB...",
352
+ "fundRelayerId": "x402-fund"
353
+ }
354
+ }'
355
+ ```
356
+
357
+ Or with `func`+`auth`:
358
+
359
+ ```bash
360
+ curl -X POST http://localhost:8080/api/v1/plugins/channels/call \
361
+ -H "Authorization: Bearer YOUR_API_KEY" \
362
+ -H "Content-Type: application/json" \
363
+ -d '{
364
+ "params": {
365
+ "func": "AAAABAAAAAEAAAAGc3ltYm9s...",
366
+ "auth": ["AAAACAAAAAEAAAA..."],
367
+ "fundRelayerId": "x402-fund"
368
+ }
369
+ }'
370
+ ```
371
+
372
+ ### Notes
373
+
374
+ - If `fundRelayerId` is provided but not listed in `ALLOWED_FUND_RELAYER_IDS`, the plugin rejects the request
375
+ - When `fundRelayerId` is omitted, the primary `FUND_RELAYER_ID` is used
376
+ - `fundRelayerId` must be a non-empty string
377
+ - `getTransaction` requests can also include `fundRelayerId`; polling should use the same relayer selection as submission
378
+
311
379
  ## Contract Capacity Limits
312
380
 
313
381
  High-volume contracts can monopolize the channel pool, starving other traffic. Contract capacity limits allow you to reserve a portion of the pool for non-limited contracts.
@@ -671,6 +739,23 @@ const result = await client.submitSorobanTransaction({
671
739
  console.log(result.hash);
672
740
  ```
673
741
 
742
+ #### Submit with Alternative Fund Relayer
743
+
744
+ ```typescript
745
+ // Submit using an alternative fund relayer for fee bumping
746
+ const result = await client.submitTransaction({
747
+ xdr: 'AAAAAgAAAAC...', // Complete transaction envelope XDR
748
+ fundRelayerId: 'x402-fund',
749
+ });
750
+
751
+ // Also works with func+auth
752
+ const result2 = await client.submitSorobanTransaction({
753
+ func: 'AAAABAAAAAEAAAAGc3ltYm9s...',
754
+ auth: ['AAAACAAAAAEAAAA...'],
755
+ fundRelayerId: 'x402-fund',
756
+ });
757
+ ```
758
+
674
759
  #### List Channel Accounts (Management)
675
760
 
676
761
  ```typescript
@@ -800,8 +885,8 @@ All request and response types are fully typed:
800
885
 
801
886
  ```typescript
802
887
  import type {
803
- ChannelsXdrRequest,
804
- ChannelsFuncAuthRequest,
888
+ ChannelsXdrRequest, // includes optional x402 field
889
+ ChannelsFuncAuthRequest, // includes optional x402 field
805
890
  ChannelsTransactionResponse,
806
891
  ListChannelAccountsResponse,
807
892
  SetChannelAccountsResponse,
@@ -867,6 +952,7 @@ curl -X POST http://localhost:8080/api/v1/plugins/channels/call \
867
952
  - `func` (string): Soroban host function XDR (base64)
868
953
  - `auth` (array): Array of Soroban authorization entry XDRs (base64)
869
954
  - `skipWait` (boolean, optional): When `true`, returns immediately after submitting the transaction without waiting for confirmation. Defaults to `false`. Must be a boolean — non-boolean values (e.g., `"false"`, `1`) are rejected.
955
+ - `fundRelayerId` (string, optional): Uses the specified alternative fund relayer for fee bumping instead of the primary fund account. Must be present in `ALLOWED_FUND_RELAYER_IDS`.
870
956
  - `getTransaction` (object, optional): Poll for a transaction's status by ID. Cannot be combined with other parameters.
871
957
 
872
958
  **Note**: Provide either `xdr` OR `func`+`auth` OR `getTransaction`, not a combination.
@@ -44,6 +44,8 @@ export interface ChannelsXdrRequest {
44
44
  xdr: string;
45
45
  /** When true, returns immediately after submission without waiting for confirmation */
46
46
  skipWait?: boolean;
47
+ /** Alternative fund relayer ID for fee bumping (must be in the allowed list) */
48
+ fundRelayerId?: string;
47
49
  }
48
50
  /**
49
51
  * Transaction submission using Soroban function and authorization
@@ -55,6 +57,8 @@ export interface ChannelsFuncAuthRequest {
55
57
  auth: string[];
56
58
  /** When true, returns immediately after submission without waiting for confirmation */
57
59
  skipWait?: boolean;
60
+ /** Alternative fund relayer ID for fee bumping (must be in the allowed list) */
61
+ fundRelayerId?: string;
58
62
  }
59
63
  /**
60
64
  * Request to get a transaction by ID
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,uFAAuF;IACvF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,sCAAsC;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gCAAgC;IAChC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,yBAAyB;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,oEAAoE;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,wBAAwB;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,6CAA6C;IAC7C,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wBAAwB;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,wBAAwB;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,CAAC;IACF,IAAI,EAAE;QACJ,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,qBAAqB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,8 @@
5
5
  */
6
6
  export interface ChannelAccountsConfig {
7
7
  fundRelayerId: string;
8
+ /** Map of allowed alternative fund relayer IDs (e.g. { "x402-channels-fund": true }) */
9
+ allowedFundRelayerIds: Set<string>;
8
10
  network: 'testnet' | 'mainnet';
9
11
  lockTtlSeconds: number;
10
12
  adminSecret?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2BAA2B,EAAE,MAAM,CAAC;IACpC,kCAAkC,EAAE,MAAM,CAAC;CAC5C;AA0GD;;GAEG;AACH,wBAAgB,UAAU,IAAI,qBAAqB,CAwBlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAE3E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,qBAAqB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2BAA2B,EAAE,MAAM,CAAC;IACpC,kCAAkC,EAAE,MAAM,CAAC;CAC5C;AAsHD;;GAEG;AACH,wBAAgB,UAAU,IAAI,qBAAqB,CA2BlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAE3E"}
@@ -105,6 +105,18 @@ function parseSequenceNumberCacheMaxAge() {
105
105
  const n = Number(raw);
106
106
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : constants_1.CONFIG.DEFAULT_SEQUENCE_NUMBER_CACHE_MAX_AGE_MS;
107
107
  }
108
+ function parseAllowedFundRelayerIds() {
109
+ const ids = new Set();
110
+ const raw = process.env.ALLOWED_FUND_RELAYER_IDS;
111
+ if (raw) {
112
+ for (const id of raw.split(',')) {
113
+ const trimmed = id.trim();
114
+ if (trimmed.length > 0)
115
+ ids.add(trimmed);
116
+ }
117
+ }
118
+ return ids;
119
+ }
108
120
  function parseContractCapacityRatio() {
109
121
  const raw = process.env.CONTRACT_CAPACITY_RATIO;
110
122
  if (!raw)
@@ -126,8 +138,10 @@ function loadConfig() {
126
138
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
127
139
  });
128
140
  }
141
+ const allowedFundRelayerIds = parseAllowedFundRelayerIds();
129
142
  return {
130
143
  fundRelayerId: requireEnv('FUND_RELAYER_ID'),
144
+ allowedFundRelayerIds,
131
145
  network: networkRaw,
132
146
  lockTtlSeconds: parseLockTtl(),
133
147
  adminSecret: parseOptionalString('PLUGIN_ADMIN_SECRET'),
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AASvE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AA2BxD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,WAAW,GACd;IAAE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,CAkB1E;AAiSD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AASvE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AA2BxD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,WAAW,GACd;IAAE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,CAkB1E;AA4SD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
@@ -186,11 +186,22 @@ async function channelAccounts(context) {
186
186
  resetPeriodMs: config.feeResetPeriodMs,
187
187
  });
188
188
  }
189
- // 1. Validate and parse request (xdr OR func+auth)
189
+ // Validate and parse request (xdr OR func+auth)
190
190
  const request = (0, validation_1.validateAndParseRequest)(params);
191
191
  console.debug(`[channels] Request type: ${request.type}, auth entries: ${request.type === 'func-auth' ? request.auth.length : 'N/A'}`);
192
- // 2. Get fund relayer
193
- const fundRelayer = api.useRelayer(config.fundRelayerId);
192
+ // Get fund relayer (use alternative fund relayer when requested)
193
+ let fundRelayerId = config.fundRelayerId;
194
+ if (request.fundRelayerId) {
195
+ if (!config.allowedFundRelayerIds.has(request.fundRelayerId)) {
196
+ throw (0, relayer_sdk_1.pluginError)(`Fund relayer '${request.fundRelayerId}' is not in the allowed list`, {
197
+ code: 'CONFIG_MISSING',
198
+ status: constants_1.HTTP_STATUS.BAD_REQUEST,
199
+ details: { fundRelayerId: request.fundRelayerId },
200
+ });
201
+ }
202
+ fundRelayerId = request.fundRelayerId;
203
+ }
204
+ const fundRelayer = api.useRelayer(fundRelayerId);
194
205
  // 2a. Handle get-transaction early — no pool, channel, or simulation needed
195
206
  if (request.type === 'get-transaction') {
196
207
  const res = await fundRelayer.getTransaction({ transactionId: request.transactionId });
@@ -206,14 +217,14 @@ async function channelAccounts(context) {
206
217
  throw (0, relayer_sdk_1.pluginError)('Fund relayer not found', {
207
218
  code: 'RELAYER_UNAVAILABLE',
208
219
  status: constants_1.HTTP_STATUS.BAD_GATEWAY,
209
- details: { relayerId: config.fundRelayerId },
220
+ details: { relayerId: fundRelayerId },
210
221
  });
211
222
  }
212
223
  if (fundInfo.network_type !== 'stellar') {
213
224
  throw (0, relayer_sdk_1.pluginError)('Fund relayer network type must be stellar', {
214
225
  code: 'UNSUPPORTED_NETWORK',
215
226
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
216
- details: { network_type: fundInfo.network_type, relayerId: config.fundRelayerId },
227
+ details: { network_type: fundInfo.network_type, relayerId: fundRelayerId },
217
228
  });
218
229
  }
219
230
  // 3. Build acquire options for contract capacity limits
@@ -13,14 +13,17 @@ export type ChannelAccountsRequest = {
13
13
  type: 'xdr';
14
14
  xdr: string;
15
15
  skipWait: boolean;
16
+ fundRelayerId?: string;
16
17
  } | {
17
18
  type: 'func-auth';
18
19
  func: xdr.HostFunction;
19
20
  auth: xdr.SorobanAuthorizationEntry[];
20
21
  skipWait: boolean;
22
+ fundRelayerId?: string;
21
23
  } | {
22
24
  type: 'get-transaction';
23
25
  transactionId: string;
26
+ fundRelayerId?: string;
24
27
  };
25
28
  /**
26
29
  * Plugin response format aligned with launchtube
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACvG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,qBAAqB,GAAG,oBAAoB,CAAC;QACrD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,qBAAqB,GAAG,oBAAoB,CAAC;QACrD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/plugin/validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEjD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,sBAAsB,CA8H3E"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/plugin/validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAqBjD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,sBAAsB,CAmJ3E"}
@@ -10,6 +10,21 @@ exports.validateAndParseRequest = validateAndParseRequest;
10
10
  const stellar_sdk_1 = require("@stellar/stellar-sdk");
11
11
  const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
12
12
  const constants_1 = require("./constants");
13
+ function validateFundRelayerId(params) {
14
+ if (params.fundRelayerId !== undefined &&
15
+ (typeof params.fundRelayerId !== 'string' || params.fundRelayerId.trim() === '')) {
16
+ throw (0, relayer_sdk_1.pluginError)('`fundRelayerId` must be a non-empty string', {
17
+ code: 'INVALID_PARAMS',
18
+ status: constants_1.HTTP_STATUS.BAD_REQUEST,
19
+ });
20
+ }
21
+ }
22
+ function parseFundRelayerId(params) {
23
+ if (params.fundRelayerId !== undefined && typeof params.fundRelayerId === 'string') {
24
+ return params.fundRelayerId.trim();
25
+ }
26
+ return undefined;
27
+ }
13
28
  function validateAndParseRequest(params) {
14
29
  if (!params || typeof params !== 'object') {
15
30
  throw (0, relayer_sdk_1.pluginError)('Invalid request: params must be an object', {
@@ -21,7 +36,7 @@ function validateAndParseRequest(params) {
21
36
  const keys = Object.keys(params);
22
37
  // Mode: getTransaction
23
38
  if ('getTransaction' in params) {
24
- const unknown = keys.filter((k) => k !== 'getTransaction');
39
+ const unknown = keys.filter((k) => !['getTransaction', 'fundRelayerId'].includes(k));
25
40
  if (unknown.length > 0) {
26
41
  throw (0, relayer_sdk_1.pluginError)('`getTransaction` request must not include other parameters', {
27
42
  code: 'INVALID_PARAMS',
@@ -29,6 +44,7 @@ function validateAndParseRequest(params) {
29
44
  details: { unknown },
30
45
  });
31
46
  }
47
+ validateFundRelayerId(params);
32
48
  const gt = params.getTransaction;
33
49
  if (!gt || typeof gt !== 'object' || typeof gt.transactionId !== 'string' || gt.transactionId.trim() === '') {
34
50
  throw (0, relayer_sdk_1.pluginError)('`getTransaction.transactionId` must be a non-empty string', {
@@ -44,7 +60,11 @@ function validateAndParseRequest(params) {
44
60
  details: { unknown: unknownInner },
45
61
  });
46
62
  }
47
- return { type: 'get-transaction', transactionId: gt.transactionId.trim() };
63
+ return {
64
+ type: 'get-transaction',
65
+ transactionId: gt.transactionId.trim(),
66
+ fundRelayerId: parseFundRelayerId(params),
67
+ };
48
68
  }
49
69
  // Mode: XDR
50
70
  if ('xdr' in params) {
@@ -55,7 +75,7 @@ function validateAndParseRequest(params) {
55
75
  });
56
76
  }
57
77
  // Strict: cannot include func/auth when using xdr
58
- const unknown = keys.filter((k) => !['xdr', 'skipWait'].includes(k));
78
+ const unknown = keys.filter((k) => !['xdr', 'skipWait', 'fundRelayerId'].includes(k));
59
79
  if (unknown.length > 0) {
60
80
  throw (0, relayer_sdk_1.pluginError)('`xdr` request must not include other parameters', {
61
81
  code: 'INVALID_PARAMS',
@@ -69,7 +89,13 @@ function validateAndParseRequest(params) {
69
89
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
70
90
  });
71
91
  }
72
- return { type: 'xdr', xdr: params.xdr.trim(), skipWait: params.skipWait === true };
92
+ validateFundRelayerId(params);
93
+ return {
94
+ type: 'xdr',
95
+ xdr: params.xdr.trim(),
96
+ skipWait: params.skipWait === true,
97
+ fundRelayerId: parseFundRelayerId(params),
98
+ };
73
99
  }
74
100
  // Mode: func+auth
75
101
  if ('func' in params || 'auth' in params) {
@@ -113,7 +139,14 @@ function validateAndParseRequest(params) {
113
139
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
114
140
  });
115
141
  }
116
- return { type: 'func-auth', func, auth, skipWait: params.skipWait === true };
142
+ validateFundRelayerId(params);
143
+ return {
144
+ type: 'func-auth',
145
+ func,
146
+ auth,
147
+ skipWait: params.skipWait === true,
148
+ fundRelayerId: parseFundRelayerId(params),
149
+ };
117
150
  }
118
151
  throw (0, relayer_sdk_1.pluginError)('Must pass either `xdr` or `func` and `auth`', {
119
152
  code: 'INVALID_PARAMS',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openzeppelin/relayer-plugin-channels",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "OpenZeppelin Relayer Plugin for Stellar Channel Accounts",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",