@openzeppelin/relayer-plugin-channels 0.19.0 → 0.21.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.
@@ -20,6 +20,7 @@ const constants_1 = require("./constants");
20
20
  const stellar_sdk_1 = require("@stellar/stellar-sdk");
21
21
  const simulation_1 = require("./simulation");
22
22
  const fee_1 = require("./fee");
23
+ const fund_relayer_config_1 = require("./fund-relayer-config");
23
24
  const tx_1 = require("./tx");
24
25
  const fee_tracking_1 = require("./fee-tracking");
25
26
  const sequence_1 = require("./sequence");
@@ -56,6 +57,16 @@ function getApiKey(headers, headerName) {
56
57
  const values = headers[headerName];
57
58
  return values?.[0]?.trim() || undefined;
58
59
  }
60
+ /**
61
+ * Compute how long a channel lock should be extended based on remaining tx validity.
62
+ * The tx maxTime was set to ~(txBuildTime + maxTimeBoundOffsetSeconds) at build time.
63
+ * We add one ledger cooldown as margin for the tx to finalize after expiry.
64
+ */
65
+ function computeExtendTtlSec(txBuildTime, maxTimeBoundOffsetSeconds) {
66
+ const txExpiryMs = txBuildTime + maxTimeBoundOffsetSeconds * 1000;
67
+ const remainingMs = txExpiryMs - Date.now() + constants_1.POOL.CHANNEL_COOLDOWN_MS;
68
+ return Math.max(1, Math.ceil(remainingMs / 1000));
69
+ }
59
70
  /**
60
71
  * Extracts func and auth from an unsigned Soroban transaction.
61
72
  * Returns null if the transaction is not a single invokeHostFunction operation.
@@ -66,14 +77,17 @@ function extractFuncAuthFromUnsignedXdr(tx) {
66
77
  return null;
67
78
  }
68
79
  const envelope = tx.toEnvelope();
69
- const rawOp = envelope.v1().tx().operations()[0].body();
70
- if (rawOp.switch() !== stellar_sdk_1.xdr.OperationType.invokeHostFunction()) {
80
+ if (envelope.type !== 'envelopeTypeTx') {
81
+ return null;
82
+ }
83
+ const rawOp = envelope.v1.tx.operations[0].body;
84
+ if (rawOp.type !== 'invokeHostFunction') {
71
85
  return null;
72
86
  }
73
- const invokeHostFn = rawOp.invokeHostFunctionOp();
87
+ const invokeHostFn = rawOp.invokeHostFunctionOp;
74
88
  return {
75
- func: invokeHostFn.hostFunction(),
76
- auth: invokeHostFn.auth(),
89
+ func: invokeHostFn.hostFunction,
90
+ auth: [...invokeHostFn.auth],
77
91
  };
78
92
  }
79
93
  async function handleXdrSubmit(xdrStr, ctx, skipWait) {
@@ -97,7 +111,7 @@ async function handleXdrSubmit(xdrStr, ctx, skipWait) {
97
111
  const updatedOptions = { ...ctx.acquireOptions, contractId };
98
112
  return handleFuncAuthSubmit(extracted.func, extracted.auth, { ...ctx, acquireOptions: updatedOptions }, skipWait);
99
113
  }
100
- const validated = (0, tx_1.validateExistingTransactionForSubmitOnly)(tx);
114
+ const validated = (0, tx_1.validateExistingTransactionForSubmitOnly)(tx, ctx.config);
101
115
  const maxFee = (0, fee_1.calculateMaxFee)(validated, ctx.acquireOptions.limitedContracts, ctx.fees);
102
116
  const contractId = (0, fee_1.getContractIdFromTransaction)(validated);
103
117
  await ctx.tracker?.checkBudget(maxFee);
@@ -105,11 +119,11 @@ async function handleXdrSubmit(xdrStr, ctx, skipWait) {
105
119
  contractId,
106
120
  isLimited: contractId ? ctx.acquireOptions.limitedContracts.has(contractId) : false,
107
121
  };
108
- return (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, validated.toXDR(), ctx.network, maxFee, ctx.api, ctx.startTime, ctx.tracker, submitContext, skipWait, ctx.config);
122
+ return (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, validated.toXdr(), ctx.network, maxFee, ctx.api, ctx.startTime, ctx.tracker, submitContext, skipWait, ctx.config);
109
123
  }
110
124
  async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
111
125
  // Simulate once — used for both read-only detection and transaction assembly
112
- const simulation = await (0, simulation_1.simulateTransaction)(func, auth, ctx.fundAddress, ctx.fundRelayer, ctx.networkPassphrase);
126
+ const simulation = await (0, simulation_1.simulateTransaction)(func, auth, ctx.fundAddress, ctx.fundRelayer, ctx.networkPassphrase, ctx.config.maxTimeBoundOffsetSeconds);
113
127
  if (simulation.isReadOnly) {
114
128
  console.log(`[channels] Read-only call detected, returning simulation result`);
115
129
  return {
@@ -143,7 +157,8 @@ async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
143
157
  }
144
158
  const sequence = await (0, sequence_1.getSequence)(ctx.kv, ctx.network, channelRelayer, channelInfo.address, ctx.config.sequenceNumberCacheMaxAgeMs);
145
159
  // Assemble the transaction using the cached simulation result — no second RPC call
146
- const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence }, ctx.networkPassphrase, simulation.rawSimResult, ctx.config.minSignatureExpirationLedgerBuffer);
160
+ const txBuildTime = Date.now();
161
+ const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence }, ctx.networkPassphrase, simulation.rawSimResult, ctx.config.minSignatureExpirationLedgerBuffer, ctx.config.maxTimeBoundOffsetSeconds);
147
162
  console.debug(`[channels] After assembly: built.fee=${built.fee}, minResourceFee=${simulation.rawSimResult.minResourceFee}`);
148
163
  const signedTx = await (0, submit_1.signWithChannelAndFund)(built, channelRelayer, ctx.fundRelayer, channelInfo.address, ctx.fundAddress, ctx.networkPassphrase);
149
164
  const maxFee = (0, fee_1.calculateMaxFee)(signedTx, ctx.acquireOptions.limitedContracts, ctx.fees);
@@ -155,10 +170,11 @@ async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
155
170
  isLimited: contractId ? ctx.acquireOptions.limitedContracts.has(contractId) : false,
156
171
  };
157
172
  try {
158
- const result = await (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, signedTx.toXDR(), ctx.network, maxFee, ctx.api, ctx.startTime, ctx.tracker, submitContext, skipWait, ctx.config);
173
+ const result = await (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, signedTx.toXdr(), ctx.network, maxFee, ctx.api, ctx.startTime, ctx.tracker, submitContext, skipWait, ctx.config);
159
174
  if (result.status === 'pending' || result.status === 'sent' || result.status === 'submitted') {
160
- console.log(`[channels]: extending lock and clearing sequence`);
161
- await ctx.pool.extendLock(poolLock);
175
+ const extendSec = computeExtendTtlSec(txBuildTime, ctx.config.maxTimeBoundOffsetSeconds);
176
+ console.log(`[channels]: extending lock (${extendSec}s) and clearing sequence`);
177
+ await ctx.pool.extendLock(poolLock, extendSec);
162
178
  await (0, sequence_1.clearSequence)(ctx.kv, ctx.network, channelInfo.address);
163
179
  poolLock = undefined; // skip release in finally
164
180
  }
@@ -175,8 +191,9 @@ async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
175
191
  catch (error) {
176
192
  await (0, sequence_1.clearSequence)(ctx.kv, ctx.network, channelInfo.address);
177
193
  if (error.code === 'WAIT_TIMEOUT' && poolLock) {
178
- console.log(`[channels] Extending lock for WAIT_TIMEOUT error`);
179
- await ctx.pool.extendLock(poolLock);
194
+ const extendSec = computeExtendTtlSec(txBuildTime, ctx.config.maxTimeBoundOffsetSeconds);
195
+ console.log(`[channels] Extending lock for WAIT_TIMEOUT (${extendSec}s)`);
196
+ await ctx.pool.extendLock(poolLock, extendSec);
180
197
  poolLock = undefined; // skip release in finally
181
198
  }
182
199
  else if (error.code === 'ONCHAIN_FAILED') {
@@ -200,7 +217,7 @@ async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
200
217
  }
201
218
  async function channelAccounts(context) {
202
219
  const startTime = Date.now();
203
- const { api, kv, params, headers } = context;
220
+ const { api, kv, params, headers, config: pluginConfig } = context;
204
221
  // Management branch: handle and return immediately
205
222
  if ((0, management_1.isManagementRequest)(params)) {
206
223
  return await (0, management_1.handleManagement)(context);
@@ -255,7 +272,12 @@ async function channelAccounts(context) {
255
272
  hash: stellar.hash ?? null,
256
273
  };
257
274
  }
258
- const fundInfo = await getCachedRelayerInfo(config.network, fundRelayerId, fundRelayer);
275
+ // 3. Resolve per-fund-relayer overrides and fetch fund relayer info in parallel
276
+ const fundOverrides = (0, fund_relayer_config_1.parseFundRelayerOverrides)(pluginConfig, fundRelayerId);
277
+ const [fundInfo, fees] = await Promise.all([
278
+ getCachedRelayerInfo(config.network, fundRelayerId, fundRelayer),
279
+ (0, fund_relayer_config_1.resolveInclusionFees)(fundOverrides, config, fundRelayer, kv),
280
+ ]);
259
281
  if (!fundInfo || !fundInfo.address) {
260
282
  throw (0, relayer_sdk_1.pluginError)('Fund relayer not found', {
261
283
  code: 'RELAYER_UNAVAILABLE',
@@ -270,16 +292,21 @@ async function channelAccounts(context) {
270
292
  details: { network_type: fundInfo.network_type, relayerId: fundRelayerId },
271
293
  });
272
294
  }
273
- // 3. Build acquire options for contract capacity limits
295
+ // 4. Build acquire options and resolve remaining overrides
274
296
  const acquireOptions = {
275
297
  limitedContracts: config.limitedContracts,
276
298
  capacityRatio: config.contractCapacityRatio,
277
299
  };
278
- const fees = {
279
- inclusionFeeDefault: config.inclusionFeeDefault,
280
- inclusionFeeLimited: config.inclusionFeeLimited,
300
+ const timeouts = (0, fund_relayer_config_1.resolveTimeouts)(fundOverrides, config);
301
+ const txParams = (0, fund_relayer_config_1.resolveTransactionParams)(fundOverrides, config);
302
+ const effectiveConfig = {
303
+ ...config,
304
+ globalTimeoutMs: timeouts.globalTimeoutMs,
305
+ pollingTimeoutMs: timeouts.pollingTimeoutMs,
306
+ maxTimeBoundOffsetSeconds: txParams.maxTimeBoundOffsetSeconds,
307
+ minSignatureExpirationLedgerBuffer: txParams.minSignatureExpirationLedgerBuffer,
281
308
  };
282
- // 4. Build pipeline context
309
+ // 5. Build pipeline context
283
310
  const ctx = {
284
311
  api,
285
312
  kv,
@@ -291,10 +318,10 @@ async function channelAccounts(context) {
291
318
  acquireOptions,
292
319
  fees,
293
320
  tracker,
294
- config,
321
+ config: effectiveConfig,
295
322
  startTime,
296
323
  };
297
- // 5. Branch by request type
324
+ // 6. Branch by request type
298
325
  if (request.type === 'xdr') {
299
326
  console.log(`[channels] Flow: XDR submit-only`);
300
327
  return await handleXdrSubmit(request.xdr, ctx, request.skipWait);
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/plugin/sequence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAwBxE;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsH3F;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,2BAA2B,EAAE,MAAM,GAClC,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtG"}
1
+ {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/plugin/sequence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAwBxE;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyH3F;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,2BAA2B,EAAE,MAAM,GAClC,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtG"}
@@ -56,7 +56,7 @@ async function getAccountSequence(relayer, address) {
56
56
  id: Math.floor(Math.random() * 1e8).toString(),
57
57
  method: 'getLedgerEntries',
58
58
  params: {
59
- keys: [accountKey.toXDR('base64')],
59
+ keys: [accountKey.toXdr('base64')],
60
60
  },
61
61
  });
62
62
  }
@@ -126,8 +126,11 @@ async function getAccountSequence(relayer, address) {
126
126
  });
127
127
  }
128
128
  try {
129
- const accountEntry = stellar_sdk_1.xdr.LedgerEntryData.fromXDR(firstEntryXdr, 'base64');
130
- return accountEntry.account().seqNum().toString();
129
+ const accountEntry = stellar_sdk_1.xdr.LedgerEntryData.fromXdr(firstEntryXdr, 'base64');
130
+ if (accountEntry.type !== 'account') {
131
+ throw new Error(`Unexpected ledger entry type: ${accountEntry.type}`);
132
+ }
133
+ return accountEntry.account.seqNum.toString();
131
134
  }
132
135
  catch (error) {
133
136
  console.error('[channels] Sequence fetch failed', {
@@ -34,12 +34,22 @@ export interface SimulationResult {
34
34
  * 1. Zero auth entries — no one needs to authorize anything
35
35
  * 2. Zero read-write footprint entries — no ledger state will be modified
36
36
  */
37
- export declare function simulateTransaction(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, sourceAddress: string, relayer: Relayer, networkPassphrase: string): Promise<SimulationResult>;
37
+ export declare function simulateTransaction(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, sourceAddress: string, relayer: Relayer, networkPassphrase: string, maxTimeBoundOffsetSeconds?: number): Promise<SimulationResult>;
38
38
  /**
39
39
  * Build and assemble a transaction using a channel account and an already-
40
40
  * obtained simulation result. No additional network calls are made.
41
41
  */
42
- export declare function buildWithChannel(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, channel: ChannelAccount, networkPassphrase: string, simResult: rpc.Api.RawSimulateTransactionResponse, minSignatureExpirationLedgerBuffer?: number): Transaction;
42
+ export declare function buildWithChannel(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, channel: ChannelAccount, networkPassphrase: string, simResult: rpc.Api.RawSimulateTransactionResponse, minSignatureExpirationLedgerBuffer?: number, maxTimeBoundOffsetSeconds?: number): Transaction;
43
+ /**
44
+ * Return the signatureExpirationLedger of an address-credentialed auth entry,
45
+ * or undefined for source-account credentials (which carry no expiry).
46
+ *
47
+ * Reads the expiry directly off the credential arm so every variant is covered
48
+ * with an exhaustive switch: legacy `sorobanCredentialsAddress`, CAP-71
49
+ * `sorobanCredentialsAddressV2` (introduced in Protocol 27, the stellar-sdk v17
50
+ * default) and `sorobanCredentialsAddressWithDelegates`.
51
+ */
52
+ export declare function getAddressCredentialExpiry(entry: xdr.SorobanAuthorizationEntry): number | undefined;
43
53
  /** Extract human-readable message + error type from simulation error diagnostic events */
44
54
  export declare function parseSimulationError(error: string): string;
45
55
  //# sourceMappingURL=simulation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/plugin/simulation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,GAAG,EAAE,WAAW,EAAsB,GAAG,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAgD,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,CAAC;CACtD;AAOD;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,gBAAgB,CAAC,CAiF3B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,OAAO,EAAE,cAAc,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,EACjD,kCAAkC,GAAE,MAA0D,GAC7F,WAAW,CA+Fb;AA4CD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAe1D"}
1
+ {"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/plugin/simulation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,GAAG,EAAE,WAAW,EAAsB,GAAG,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAgD,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,CAAC;CACtD;AAOD;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,EACzB,yBAAyB,GAAE,MAA2C,GACrE,OAAO,CAAC,gBAAgB,CAAC,CAiF3B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,OAAO,EAAE,cAAc,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,EACjD,kCAAkC,GAAE,MAA0D,EAC9F,yBAAyB,GAAE,MAA2C,GACrE,WAAW,CAiGb;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,GAAG,CAAC,yBAAyB,GAAG,MAAM,GAAG,SAAS,CAYnG;AA2CD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAe1D"}
@@ -10,6 +10,7 @@
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.simulateTransaction = simulateTransaction;
12
12
  exports.buildWithChannel = buildWithChannel;
13
+ exports.getAddressCredentialExpiry = getAddressCredentialExpiry;
13
14
  exports.parseSimulationError = parseSimulationError;
14
15
  const stellar_sdk_1 = require("@stellar/stellar-sdk");
15
16
  const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
@@ -26,12 +27,12 @@ const constants_1 = require("./constants");
26
27
  * 1. Zero auth entries — no one needs to authorize anything
27
28
  * 2. Zero read-write footprint entries — no ledger state will be modified
28
29
  */
29
- async function simulateTransaction(func, auth, sourceAddress, relayer, networkPassphrase) {
30
+ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPassphrase, maxTimeBoundOffsetSeconds = constants_1.TIME.MAX_TIME_BOUND_OFFSET_SECONDS) {
30
31
  const now = Math.floor(Date.now() / 1000);
31
32
  const transaction = new stellar_sdk_1.TransactionBuilder(new stellar_sdk_1.Account(sourceAddress, '0'), {
32
33
  fee: constants_1.SIMULATION.DEFAULT_FEE,
33
34
  networkPassphrase,
34
- timebounds: { minTime: constants_1.SIMULATION.MIN_TIME_BOUND, maxTime: now + constants_1.SIMULATION.MAX_TIME_BOUND_OFFSET_SECONDS },
35
+ timebounds: { minTime: constants_1.TIME.MIN_TIME_BOUND, maxTime: now + maxTimeBoundOffsetSeconds },
35
36
  })
36
37
  .addOperation(stellar_sdk_1.Operation.invokeHostFunction({ func, auth }))
37
38
  .build();
@@ -42,7 +43,7 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
42
43
  id: Math.floor(Math.random() * 1e8).toString(),
43
44
  method: 'simulateTransaction',
44
45
  // Enforce mode validates auth entry signatures during simulation.
45
- params: { transaction: transaction.toXDR(), authMode: constants_1.SIMULATION.SIMULATION_AUTH_MODE },
46
+ params: { transaction: transaction.toXdr(), authMode: constants_1.SIMULATION.SIMULATION_AUTH_MODE },
46
47
  });
47
48
  }
48
49
  catch (err) {
@@ -81,8 +82,8 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
81
82
  let hasReadWrite = false;
82
83
  if (simResult.transactionData) {
83
84
  try {
84
- const sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXDR(simResult.transactionData, 'base64');
85
- hasReadWrite = sorobanData.resources().footprint().readWrite().length > 0;
85
+ const sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXdr(simResult.transactionData, 'base64');
86
+ hasReadWrite = sorobanData.resources.footprint.readWrite.length > 0;
86
87
  }
87
88
  catch {
88
89
  // If we can't parse transactionData, treat as not read-only (safe fallback)
@@ -104,7 +105,7 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
104
105
  * Build and assemble a transaction using a channel account and an already-
105
106
  * obtained simulation result. No additional network calls are made.
106
107
  */
107
- function buildWithChannel(func, auth, channel, networkPassphrase, simResult, minSignatureExpirationLedgerBuffer = constants_1.SIMULATION.MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER) {
108
+ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, minSignatureExpirationLedgerBuffer = constants_1.SIMULATION.MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER, maxTimeBoundOffsetSeconds = constants_1.TIME.MAX_TIME_BOUND_OFFSET_SECONDS) {
108
109
  if (!simResult.transactionData) {
109
110
  throw (0, relayer_sdk_1.pluginError)('Simulation response missing transactionData', {
110
111
  code: 'SIMULATION_INVALID_RESPONSE',
@@ -114,7 +115,7 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
114
115
  // Parse sorobanData from the simulation result
115
116
  let sorobanData;
116
117
  try {
117
- sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXDR(simResult.transactionData, 'base64');
118
+ sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXdr(simResult.transactionData, 'base64');
118
119
  }
119
120
  catch (err) {
120
121
  throw (0, relayer_sdk_1.pluginError)('Failed to parse simulation transactionData', {
@@ -130,7 +131,7 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
130
131
  }
131
132
  else {
132
133
  try {
133
- resolvedAuth = (simResult.results?.[0]?.auth ?? []).map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64'));
134
+ resolvedAuth = (simResult.results?.[0]?.auth ?? []).map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXdr(a, 'base64'));
134
135
  }
135
136
  catch (err) {
136
137
  throw (0, relayer_sdk_1.pluginError)('Failed to parse simulation auth entries', {
@@ -168,7 +169,7 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
168
169
  const transaction = new stellar_sdk_1.TransactionBuilder(new stellar_sdk_1.Account(channel.address, channel.sequence), {
169
170
  fee: constants_1.SIMULATION.DEFAULT_FEE,
170
171
  networkPassphrase,
171
- timebounds: { minTime: constants_1.SIMULATION.MIN_TIME_BOUND, maxTime: now + constants_1.SIMULATION.MAX_TIME_BOUND_OFFSET_SECONDS },
172
+ timebounds: { minTime: constants_1.TIME.MIN_TIME_BOUND, maxTime: now + maxTimeBoundOffsetSeconds },
172
173
  sorobanData,
173
174
  })
174
175
  .addOperation(stellar_sdk_1.Operation.invokeHostFunction({
@@ -177,7 +178,9 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
177
178
  }))
178
179
  .build();
179
180
  try {
180
- const resourceFee = transaction.toEnvelope().v1().tx().ext().sorobanData()?.resourceFee();
181
+ const envelope = transaction.toEnvelope();
182
+ const ext = envelope.type === 'envelopeTypeTx' ? envelope.v1.tx.ext : undefined;
183
+ const resourceFee = ext?.type === 'sorobanData' ? ext.sorobanData.resourceFee : undefined;
181
184
  console.debug(`[channels] Assembly complete: fee=${transaction.fee}, resourceFee=${resourceFee}`);
182
185
  return transaction;
183
186
  }
@@ -192,6 +195,28 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
192
195
  });
193
196
  }
194
197
  }
198
+ /**
199
+ * Return the signatureExpirationLedger of an address-credentialed auth entry,
200
+ * or undefined for source-account credentials (which carry no expiry).
201
+ *
202
+ * Reads the expiry directly off the credential arm so every variant is covered
203
+ * with an exhaustive switch: legacy `sorobanCredentialsAddress`, CAP-71
204
+ * `sorobanCredentialsAddressV2` (introduced in Protocol 27, the stellar-sdk v17
205
+ * default) and `sorobanCredentialsAddressWithDelegates`.
206
+ */
207
+ function getAddressCredentialExpiry(entry) {
208
+ const creds = entry.credentials;
209
+ switch (creds.type) {
210
+ case 'sorobanCredentialsSourceAccount':
211
+ return undefined;
212
+ case 'sorobanCredentialsAddress':
213
+ return creds.address.signatureExpirationLedger;
214
+ case 'sorobanCredentialsAddressV2':
215
+ return creds.addressV2.signatureExpirationLedger;
216
+ case 'sorobanCredentialsAddressWithDelegates':
217
+ return creds.addressWithDelegates.addressCredentials.signatureExpirationLedger;
218
+ }
219
+ }
195
220
  /**
196
221
  * Reject transactions where any address-credentialed auth entry has a
197
222
  * signatureExpirationLedger too close to the current ledger. This catches
@@ -201,11 +226,10 @@ function validateAuthExpiry(authEntries, latestLedger, minBuffer) {
201
226
  if (!authEntries?.length)
202
227
  return;
203
228
  for (const entry of authEntries) {
204
- const creds = entry.credentials();
205
- if (creds.switch() !== stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsAddress()) {
229
+ const expiry = getAddressCredentialExpiry(entry);
230
+ if (expiry === undefined) {
206
231
  continue;
207
232
  }
208
- const expiry = creds.address().signatureExpirationLedger();
209
233
  const margin = expiry - latestLedger;
210
234
  if (margin < minBuffer) {
211
235
  console.error(`[channels] Auth entry signatureExpirationLedger too close to current ledger (expires in ${margin} ledgers, minimum ${minBuffer} required)`);
@@ -1 +1 @@
1
- {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/plugin/submit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAO,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAEL,OAAO,EAGP,SAAS,EACV,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,wBAAwB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,WAAW,CAAC,CAuBtB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,OAAO,EAClB,MAAM,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,GAC3E,OAAO,CAAC,uBAAuB,CAAC,CAmHlC;AASD,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAkCvF;AAeD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAepG;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOrD"}
1
+ {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/plugin/submit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAO,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAEL,OAAO,EAGP,SAAS,EACV,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,wBAAwB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,WAAW,CAAC,CAuBtB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,OAAO,EAClB,MAAM,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,GAC3E,OAAO,CAAC,uBAAuB,CAAC,CAmHlC;AASD,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAmCvF;AAeD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAepG;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOrD"}
@@ -20,7 +20,7 @@ const constants_1 = require("./constants");
20
20
  * - Both signatures are added to the transaction
21
21
  */
22
22
  async function signWithChannelAndFund(transaction, channelRelayer, _fundRelayer, channelAddress, _fundAddress, networkPassphrase) {
23
- const txXdr = transaction.toXDR();
23
+ const txXdr = transaction.toXdr();
24
24
  console.debug(`[channels] Signing transaction with channel (${channelAddress})`);
25
25
  // Get signatures from both accounts sequentially
26
26
  // Channel signs first
@@ -172,14 +172,16 @@ function decodeTransactionResult(reason) {
172
172
  const match = reason.match(/([A-Za-z0-9+/=]{20,})$/);
173
173
  if (!match)
174
174
  return null;
175
- const result = stellar_sdk_1.xdr.TransactionResult.fromXDR(match[1], 'base64');
176
- const outerResultCode = String(result.result().switch().name);
175
+ const result = stellar_sdk_1.xdr.TransactionResult.fromXdr(match[1], 'base64');
176
+ const outerResultCode = result.result.type;
177
177
  let resultCode = outerResultCode;
178
178
  // Unwrap fee bump inner failure to get the actual result code
179
179
  if (outerResultCode === 'txFeeBumpInnerFailed') {
180
180
  try {
181
- const innerResult = result.result().innerResultPair().result();
182
- const innerResultCode = String(innerResult.result().switch().name);
181
+ const outer = result.result;
182
+ if (outer.type !== 'txFeeBumpInnerFailed')
183
+ throw new Error('unreachable');
184
+ const innerResultCode = outer.innerResultPair.result.result.type;
183
185
  resultCode = `${outerResultCode}:${innerResultCode}`;
184
186
  }
185
187
  catch {
@@ -187,7 +189,7 @@ function decodeTransactionResult(reason) {
187
189
  }
188
190
  }
189
191
  return {
190
- feeCharged: Number(result.feeCharged().toBigInt()),
192
+ feeCharged: Number(result.feeCharged),
191
193
  resultCode,
192
194
  };
193
195
  }
@@ -4,5 +4,13 @@
4
4
  * Transaction validation helpers for the XDR submit-only path.
5
5
  */
6
6
  import { Transaction } from '@stellar/stellar-sdk';
7
- export declare function validateExistingTransactionForSubmitOnly(tx: Transaction): Transaction;
7
+ import type { ChannelAccountsConfig } from './config';
8
+ /**
9
+ * Validate a client-built transaction for the XDR submit-only path.
10
+ *
11
+ * Rejects fee-bump envelopes, Soroban transactions whose fee exceeds the
12
+ * declared resource fee plus the base inclusion fee, and a `timeBounds.maxTime`
13
+ * that is already in the past or further out than the configured maximum offset.
14
+ */
15
+ export declare function validateExistingTransactionForSubmitOnly(tx: Transaction, config: Pick<ChannelAccountsConfig, 'maxTimeBoundOffsetSeconds'>): Transaction;
8
16
  //# sourceMappingURL=tx.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tx.d.ts","sourceRoot":"","sources":["../../src/plugin/tx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAO,MAAM,sBAAsB,CAAC;AAIxD,wBAAgB,wCAAwC,CAAC,EAAE,EAAE,WAAW,GAAG,WAAW,CAkDrF"}
1
+ {"version":3,"file":"tx.d.ts","sourceRoot":"","sources":["../../src/plugin/tx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGtD;;;;;;GAMG;AACH,wBAAgB,wCAAwC,CACtD,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,2BAA2B,CAAC,GAC/D,WAAW,CAkDb"}
package/dist/plugin/tx.js CHANGED
@@ -6,24 +6,30 @@
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.validateExistingTransactionForSubmitOnly = validateExistingTransactionForSubmitOnly;
9
- const stellar_sdk_1 = require("@stellar/stellar-sdk");
10
9
  const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
11
10
  const constants_1 = require("./constants");
12
- function validateExistingTransactionForSubmitOnly(tx) {
11
+ /**
12
+ * Validate a client-built transaction for the XDR submit-only path.
13
+ *
14
+ * Rejects fee-bump envelopes, Soroban transactions whose fee exceeds the
15
+ * declared resource fee plus the base inclusion fee, and a `timeBounds.maxTime`
16
+ * that is already in the past or further out than the configured maximum offset.
17
+ */
18
+ function validateExistingTransactionForSubmitOnly(tx, config) {
19
+ const { maxTimeBoundOffsetSeconds } = config;
13
20
  const now = Math.floor(Date.now() / 1000);
14
21
  // Reject fee-bump envelopes
15
22
  const envelope = tx.toEnvelope();
16
- const kind = envelope.switch();
17
- if (kind !== stellar_sdk_1.xdr.EnvelopeType.envelopeTypeTx()) {
23
+ if (envelope.type !== 'envelopeTypeTx') {
18
24
  throw (0, relayer_sdk_1.pluginError)('Input must be a regular transaction envelope (fee-bump not allowed)', {
19
25
  code: 'INVALID_ENVELOPE_TYPE',
20
26
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
21
27
  });
22
28
  }
23
29
  // Soroban sanity checks
24
- const sorobanData = envelope.v1().tx().ext().sorobanData();
25
- if (sorobanData) {
26
- const resourceFee = sorobanData.resourceFee().toBigInt();
30
+ const ext = envelope.v1.tx.ext;
31
+ if (ext.type === 'sorobanData') {
32
+ const resourceFee = ext.sorobanData.resourceFee;
27
33
  if (BigInt(tx.fee) > resourceFee + 201n) {
28
34
  throw (0, relayer_sdk_1.pluginError)('Transaction fee must be equal to the resource fee', {
29
35
  code: 'FEE_MISMATCH',
@@ -42,8 +48,8 @@ function validateExistingTransactionForSubmitOnly(tx) {
42
48
  details: { maxTime, now },
43
49
  });
44
50
  }
45
- if (maxTime - now > constants_1.SIMULATION.MAX_FUTURE_TIME_BOUND_SECONDS) {
46
- throw (0, relayer_sdk_1.pluginError)(`Transaction \`timeBounds.maxTime\` too far into the future. Must be no greater than ${constants_1.SIMULATION.MAX_FUTURE_TIME_BOUND_SECONDS} seconds`, {
51
+ if (maxTime - now > maxTimeBoundOffsetSeconds) {
52
+ throw (0, relayer_sdk_1.pluginError)(`Transaction \`timeBounds.maxTime\` too far into the future. Must be no greater than ${maxTimeBoundOffsetSeconds} seconds`, {
47
53
  code: 'TIMEBOUNDS_TOO_FAR',
48
54
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
49
55
  });
@@ -5,5 +5,12 @@
5
5
  * Supports either a signed XDR or func+auth.
6
6
  */
7
7
  import { ChannelAccountsRequest } from './types';
8
+ /**
9
+ * Validate and normalize an incoming plugin request into one of the two
10
+ * supported shapes: a signed transaction `xdr` (submit-only) or a `func` +
11
+ * `auth` pair (channel flow). Base64 XDR fields are decoded here; malformed
12
+ * encodings and source-account auth credentials are rejected with
13
+ * `INVALID_PARAMS`.
14
+ */
8
15
  export declare function validateAndParseRequest(params: any): ChannelAccountsRequest;
9
16
  //# sourceMappingURL=validation.d.ts.map
@@ -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;AAqBjD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,sBAAsB,CAmJ3E"}
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;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,sBAAsB,CAkJ3E"}
@@ -25,6 +25,13 @@ function parseFundRelayerId(params) {
25
25
  }
26
26
  return undefined;
27
27
  }
28
+ /**
29
+ * Validate and normalize an incoming plugin request into one of the two
30
+ * supported shapes: a signed transaction `xdr` (submit-only) or a `func` +
31
+ * `auth` pair (channel flow). Base64 XDR fields are decoded here; malformed
32
+ * encodings and source-account auth credentials are rejected with
33
+ * `INVALID_PARAMS`.
34
+ */
28
35
  function validateAndParseRequest(params) {
29
36
  if (!params || typeof params !== 'object') {
30
37
  throw (0, relayer_sdk_1.pluginError)('Invalid request: params must be an object', {
@@ -109,11 +116,11 @@ function validateAndParseRequest(params) {
109
116
  let func;
110
117
  let auth = [];
111
118
  try {
112
- func = stellar_sdk_1.xdr.HostFunction.fromXDR(params.func, 'base64');
119
+ func = stellar_sdk_1.xdr.HostFunction.fromXdr(params.func, 'base64');
113
120
  if (!Array.isArray(params.auth)) {
114
121
  throw new Error('auth must be an array of base64 strings');
115
122
  }
116
- auth = params.auth.map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64'));
123
+ auth = params.auth.map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXdr(a, 'base64'));
117
124
  }
118
125
  catch (e) {
119
126
  throw (0, relayer_sdk_1.pluginError)('Invalid `func` or `auth` encoding', {
@@ -124,8 +131,7 @@ function validateAndParseRequest(params) {
124
131
  }
125
132
  // Reject SourceAccount credentials: incompatible with relayer-managed channel source
126
133
  for (const entry of auth) {
127
- const credType = entry.credentials().switch();
128
- if (credType === stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsSourceAccount()) {
134
+ if (entry.credentials.type === 'sorobanCredentialsSourceAccount') {
129
135
  throw (0, relayer_sdk_1.pluginError)('Detached address credentials required: source-account credentials are incompatible with relayer-managed channel accounts', {
130
136
  code: 'INVALID_PARAMS',
131
137
  status: constants_1.HTTP_STATUS.BAD_REQUEST,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openzeppelin/relayer-plugin-channels",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "OpenZeppelin Relayer Plugin for Stellar Channel Accounts",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "@actions/exec": "^1.1.1",
23
23
  "@openzeppelin/relayer-sdk": "^1.10.0",
24
- "@stellar/stellar-sdk": "^14.6.0",
24
+ "@stellar/stellar-sdk": "^17.0.1",
25
25
  "axios": "^1.13.5"
26
26
  },
27
27
  "devDependencies": {
@@ -1,21 +0,0 @@
1
- /**
2
- * build.ts
3
- *
4
- * Transaction rebuild logic to use channel account as source.
5
- */
6
- import { Transaction } from '@stellar/stellar-sdk';
7
- export interface RebuildParams {
8
- inputXdr: string;
9
- channelAddress: string;
10
- channelSequence: string;
11
- fundAddress: string;
12
- networkPassphrase: string;
13
- }
14
- /**
15
- * Rebuild transaction with channel account as source
16
- * - Set transaction source to channel account with current sequence
17
- * - Preserve memo, timeBounds, etc.
18
- * - Copy operations ensuring their source equals the fund address
19
- */
20
- export declare function rebuildWithChannel(params: RebuildParams): Transaction;
21
- //# sourceMappingURL=build.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/plugin/build.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAe,MAAM,sBAAsB,CAAC;AAIhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAmGrE"}