@openzeppelin/relayer-plugin-channels 0.9.0 → 0.10.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 +60 -0
- package/dist/client/channels-client.d.ts +15 -1
- package/dist/client/channels-client.d.ts.map +1 -1
- package/dist/client/channels-client.js +21 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/types.d.ts +27 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/plugin/config.d.ts +2 -0
- package/dist/plugin/config.d.ts.map +1 -1
- package/dist/plugin/config.js +14 -0
- package/dist/plugin/fee.d.ts +8 -5
- package/dist/plugin/fee.d.ts.map +1 -1
- package/dist/plugin/fee.js +8 -10
- package/dist/plugin/handler.d.ts +2 -0
- package/dist/plugin/handler.d.ts.map +1 -1
- package/dist/plugin/handler.js +142 -13
- package/dist/plugin/management.d.ts.map +1 -1
- package/dist/plugin/management.js +48 -0
- package/dist/plugin/pool.d.ts +1 -0
- package/dist/plugin/pool.d.ts.map +1 -1
- package/dist/plugin/pool.js +12 -4
- package/dist/plugin/submit.d.ts +10 -1
- package/dist/plugin/submit.d.ts.map +1 -1
- package/dist/plugin/submit.js +41 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -229,6 +229,10 @@ export API_KEY_HEADER="x-api-key" # Header name to extract API key (defa
|
|
|
229
229
|
# Contract capacity limits (optional)
|
|
230
230
|
export LIMITED_CONTRACTS="CDL74RF5BLYR2YBLCCI7F5FB6TPSCLKEJUBSD2RSVWZ4YHF3VMFAIGWA" # Comma-separated contract addresses
|
|
231
231
|
export CONTRACT_CAPACITY_RATIO=0.8 # Max ratio of pool for limited contracts (default: 0.8 = 80%)
|
|
232
|
+
|
|
233
|
+
# Inclusion fee overrides (optional)
|
|
234
|
+
export INCLUSION_FEE_DEFAULT=203 # Inclusion fee in stroops for regular contracts (default: BASE_FEE * 2 + 3 = 203)
|
|
235
|
+
export INCLUSION_FEE_LIMITED=201 # Inclusion fee in stroops for limited contracts (default: BASE_FEE * 2 + 1 = 201)
|
|
232
236
|
```
|
|
233
237
|
|
|
234
238
|
Your Relayer should now contain:
|
|
@@ -510,6 +514,49 @@ curl -X POST http://localhost:8080/api/v1/plugins/channels/call \
|
|
|
510
514
|
}
|
|
511
515
|
```
|
|
512
516
|
|
|
517
|
+
### Get Pool Stats
|
|
518
|
+
|
|
519
|
+
Returns pool health metrics, configuration, and fee info.
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
curl -X POST http://localhost:8080/... \
|
|
523
|
+
-H "Content-Type: application/json" \
|
|
524
|
+
-d '{
|
|
525
|
+
"params": {
|
|
526
|
+
"management": {
|
|
527
|
+
"action": "stats",
|
|
528
|
+
"adminSecret": "your-secret-here"
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}'
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Response:**
|
|
535
|
+
|
|
536
|
+
```json
|
|
537
|
+
{
|
|
538
|
+
"pool": {
|
|
539
|
+
"size": 5,
|
|
540
|
+
"locked": 2,
|
|
541
|
+
"available": 3
|
|
542
|
+
},
|
|
543
|
+
"config": {
|
|
544
|
+
"network": "testnet",
|
|
545
|
+
"lockTtlSeconds": 30,
|
|
546
|
+
"feeLimit": 10000,
|
|
547
|
+
"feeResetPeriodSeconds": 3600,
|
|
548
|
+
"contractCapacityRatio": 0.8,
|
|
549
|
+
"limitedContracts": []
|
|
550
|
+
},
|
|
551
|
+
"fees": {
|
|
552
|
+
"inclusionFeeDefault": 203,
|
|
553
|
+
"inclusionFeeLimited": 201
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
> **Note:** If lock checks fail, `locked` and `available` will be `undefined` rather than causing the request to fail. The `size` and config info are always returned.
|
|
559
|
+
|
|
513
560
|
**Important Notes:**
|
|
514
561
|
|
|
515
562
|
- You must configure at least one channel account before the plugin can process transactions
|
|
@@ -683,6 +730,19 @@ const result = await adminClient.deleteFeeLimit('client-api-key');
|
|
|
683
730
|
console.log(result.ok); // true
|
|
684
731
|
```
|
|
685
732
|
|
|
733
|
+
#### Get Pool Stats (Management)
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
// Get pool health metrics (requires adminSecret)
|
|
737
|
+
const stats = await adminClient.getStats();
|
|
738
|
+
|
|
739
|
+
console.log(stats.pool.size); // total channels
|
|
740
|
+
console.log(stats.pool.locked); // currently in-use
|
|
741
|
+
console.log(stats.pool.available); // size - locked
|
|
742
|
+
console.log(stats.config.network); // 'testnet' or 'mainnet'
|
|
743
|
+
console.log(stats.fees); // inclusion fee values
|
|
744
|
+
```
|
|
745
|
+
|
|
686
746
|
### Error Handling
|
|
687
747
|
|
|
688
748
|
The client provides three types of errors:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelsClientConfig, ChannelsXdrRequest, ChannelsFuncAuthRequest, ChannelsTransactionResponse, ListChannelAccountsResponse, SetChannelAccountsResponse, GetFeeUsageResponse, GetFeeLimitResponse, SetFeeLimitResponse, DeleteFeeLimitResponse } from './types';
|
|
1
|
+
import type { ChannelsClientConfig, ChannelsXdrRequest, ChannelsFuncAuthRequest, ChannelsTransactionResponse, ListChannelAccountsResponse, SetChannelAccountsResponse, GetFeeUsageResponse, GetFeeLimitResponse, SetFeeLimitResponse, DeleteFeeLimitResponse, GetStatsResponse } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Client for interacting with the Channels plugin
|
|
4
4
|
*
|
|
@@ -137,6 +137,20 @@ export declare class ChannelsClient {
|
|
|
137
137
|
* @throws {PluginUnexpectedError} Malformed response or client-side errors
|
|
138
138
|
*/
|
|
139
139
|
deleteFeeLimit(apiKey: string): Promise<DeleteFeeLimitResponse>;
|
|
140
|
+
/**
|
|
141
|
+
* Get pool health stats including capacity, config, and fees (requires adminSecret)
|
|
142
|
+
*
|
|
143
|
+
* @returns Pool stats with size, locked/available counts, config, and fee info
|
|
144
|
+
* @throws {Error} If adminSecret not provided in config
|
|
145
|
+
* @throws {PluginTransportError} Network/HTTP failures
|
|
146
|
+
* @throws {PluginExecutionError} Plugin rejected the request
|
|
147
|
+
* @throws {PluginUnexpectedError} Malformed response or client-side errors
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* const stats = await client.getStats();
|
|
151
|
+
* console.log(stats.pool.available);
|
|
152
|
+
*/
|
|
153
|
+
getStats(): Promise<GetStatsResponse>;
|
|
140
154
|
/**
|
|
141
155
|
* Ensures adminSecret is configured
|
|
142
156
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channels-client.d.ts","sourceRoot":"","sources":["../../src/client/channels-client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"channels-client.d.ts","sourceRoot":"","sources":["../../src/client/channels-client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAEjB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;gBAEvB,MAAM,EAAE,oBAAoB;IAiCxC;;;;;;;;;;;;;OAaG;IACG,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAI1F;;;;;;;;;;;;;;;OAeG;IACG,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAItG;;;;;;;;;;;;OAYG;IACG,mBAAmB,IAAI,OAAO,CAAC,2BAA2B,CAAC;IASjE;;;;;;;;;;;;;;;OAeG;IACG,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAUnF;;;;;;;;;;;;;OAaG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAU/D;;;;;;;;;OASG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAU/D;;;;;;;;;;OAUG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAW9E;;;;;;;;;OASG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAUrE;;;;;;;;;;;;OAYG;IACG,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAS3C;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;;;;;;OAOG;IAEH,OAAO,CAAC,eAAe;IAgBvB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAUrB;;;;;;;;OAQG;YACW,IAAI;IAwBlB;;;;;;OAMG;YACW,QAAQ;CASvB"}
|
|
@@ -221,6 +221,27 @@ class ChannelsClient {
|
|
|
221
221
|
},
|
|
222
222
|
});
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Get pool health stats including capacity, config, and fees (requires adminSecret)
|
|
226
|
+
*
|
|
227
|
+
* @returns Pool stats with size, locked/available counts, config, and fee info
|
|
228
|
+
* @throws {Error} If adminSecret not provided in config
|
|
229
|
+
* @throws {PluginTransportError} Network/HTTP failures
|
|
230
|
+
* @throws {PluginExecutionError} Plugin rejected the request
|
|
231
|
+
* @throws {PluginUnexpectedError} Malformed response or client-side errors
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* const stats = await client.getStats();
|
|
235
|
+
* console.log(stats.pool.available);
|
|
236
|
+
*/
|
|
237
|
+
async getStats() {
|
|
238
|
+
return this.call({
|
|
239
|
+
management: {
|
|
240
|
+
action: 'stats',
|
|
241
|
+
adminSecret: this.requireAdminSecret(),
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
224
245
|
/**
|
|
225
246
|
* Ensures adminSecret is configured
|
|
226
247
|
*
|
package/dist/client/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* in both direct HTTP mode and OpenZeppelin Relayer mode.
|
|
6
6
|
*/
|
|
7
7
|
export { ChannelsClient } from './channels-client';
|
|
8
|
-
export { ChannelsClientConfig, DirectHttpConfig, RelayerConfig, ChannelsXdrRequest, ChannelsFuncAuthRequest, ChannelsTransactionResponse, ListChannelAccountsResponse, SetChannelAccountsResponse, GetFeeUsageResponse, GetFeeLimitResponse, SetFeeLimitResponse, DeleteFeeLimitResponse, } from './types';
|
|
8
|
+
export { ChannelsClientConfig, DirectHttpConfig, RelayerConfig, ChannelsXdrRequest, ChannelsFuncAuthRequest, ChannelsTransactionResponse, ListChannelAccountsResponse, SetChannelAccountsResponse, GetFeeUsageResponse, GetFeeLimitResponse, SetFeeLimitResponse, DeleteFeeLimitResponse, GetStatsResponse, } from './types';
|
|
9
9
|
export { PluginClientError, PluginTransportError, PluginExecutionError, PluginUnexpectedError } from './errors';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/client/types.d.ts
CHANGED
|
@@ -156,6 +156,33 @@ export interface DeleteFeeLimitResponse {
|
|
|
156
156
|
traces?: any[];
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Response from getting pool stats
|
|
161
|
+
*/
|
|
162
|
+
export interface GetStatsResponse {
|
|
163
|
+
pool: {
|
|
164
|
+
size: number;
|
|
165
|
+
locked?: number;
|
|
166
|
+
available?: number;
|
|
167
|
+
};
|
|
168
|
+
config: {
|
|
169
|
+
network: 'testnet' | 'mainnet';
|
|
170
|
+
lockTtlSeconds: number;
|
|
171
|
+
feeLimit?: number;
|
|
172
|
+
feeResetPeriodSeconds?: number;
|
|
173
|
+
contractCapacityRatio: number;
|
|
174
|
+
limitedContracts: string[];
|
|
175
|
+
};
|
|
176
|
+
fees: {
|
|
177
|
+
inclusionFeeDefault: number;
|
|
178
|
+
inclusionFeeLimited: number;
|
|
179
|
+
};
|
|
180
|
+
/** Optional metadata (logs and traces) */
|
|
181
|
+
metadata?: {
|
|
182
|
+
logs?: LogEntry[];
|
|
183
|
+
traces?: any[];
|
|
184
|
+
};
|
|
185
|
+
}
|
|
159
186
|
/**
|
|
160
187
|
* Plugin response structure for successful operations
|
|
161
188
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin/config.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface ChannelAccountsConfig {
|
|
|
13
13
|
apiKeyHeader: string;
|
|
14
14
|
limitedContracts: Set<string>;
|
|
15
15
|
contractCapacityRatio: number;
|
|
16
|
+
inclusionFeeDefault: number;
|
|
17
|
+
inclusionFeeLimited: number;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* Load configuration from environment variables
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
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;CAC7B;AA4FD;;GAEG;AACH,wBAAgB,UAAU,IAAI,qBAAqB,CAsBlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAE3E"}
|
package/dist/plugin/config.js
CHANGED
|
@@ -10,6 +10,9 @@ exports.getNetworkPassphrase = getNetworkPassphrase;
|
|
|
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
|
+
// Default inclusion fees (matching launchtube)
|
|
14
|
+
const DEFAULT_INCLUSION_FEE_DEFAULT = Number(stellar_sdk_1.BASE_FEE) * 2 + 3; // 203
|
|
15
|
+
const DEFAULT_INCLUSION_FEE_LIMITED = Number(stellar_sdk_1.BASE_FEE) * 2 + 1; // 201
|
|
13
16
|
function requireEnv(name) {
|
|
14
17
|
const v = process.env[name];
|
|
15
18
|
if (!v || v.trim() === '') {
|
|
@@ -79,6 +82,15 @@ function parseLimitedContracts() {
|
|
|
79
82
|
}
|
|
80
83
|
return new Set(contracts);
|
|
81
84
|
}
|
|
85
|
+
function parseInclusionFee(envVar, defaultValue) {
|
|
86
|
+
const raw = process.env[envVar];
|
|
87
|
+
if (!raw)
|
|
88
|
+
return defaultValue;
|
|
89
|
+
const n = Number(raw);
|
|
90
|
+
if (!Number.isFinite(n) || n < 0)
|
|
91
|
+
return defaultValue;
|
|
92
|
+
return Math.floor(n);
|
|
93
|
+
}
|
|
82
94
|
function parseContractCapacityRatio() {
|
|
83
95
|
const raw = process.env.CONTRACT_CAPACITY_RATIO;
|
|
84
96
|
if (!raw)
|
|
@@ -110,6 +122,8 @@ function loadConfig() {
|
|
|
110
122
|
apiKeyHeader: parseApiKeyHeader(),
|
|
111
123
|
limitedContracts: parseLimitedContracts(),
|
|
112
124
|
contractCapacityRatio: parseContractCapacityRatio(),
|
|
125
|
+
inclusionFeeDefault: parseInclusionFee('INCLUSION_FEE_DEFAULT', DEFAULT_INCLUSION_FEE_DEFAULT),
|
|
126
|
+
inclusionFeeLimited: parseInclusionFee('INCLUSION_FEE_LIMITED', DEFAULT_INCLUSION_FEE_LIMITED),
|
|
113
127
|
};
|
|
114
128
|
}
|
|
115
129
|
/**
|
package/dist/plugin/fee.d.ts
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
* fee.ts
|
|
3
3
|
*
|
|
4
4
|
* Static fee calculation for fee bump submissions matching launchtube.
|
|
5
|
-
* - For Soroban transactions: use resourceFee + inclusion fee
|
|
5
|
+
* - For Soroban transactions: use resourceFee + inclusion fee
|
|
6
6
|
* - For non-Soroban: use NON_SOROBAN_FEE + inclusion fee
|
|
7
|
-
* - Limited contracts (from LIMITED_CONTRACTS env) get reduced fee
|
|
7
|
+
* - Limited contracts (from LIMITED_CONTRACTS env) get reduced fee
|
|
8
|
+
* - Inclusion fees are configurable via INCLUSION_FEE_DEFAULT and INCLUSION_FEE_LIMITED env vars
|
|
8
9
|
*/
|
|
9
10
|
import { Transaction, xdr } from '@stellar/stellar-sdk';
|
|
10
|
-
export
|
|
11
|
-
|
|
11
|
+
export interface InclusionFees {
|
|
12
|
+
inclusionFeeDefault: number;
|
|
13
|
+
inclusionFeeLimited: number;
|
|
14
|
+
}
|
|
12
15
|
/**
|
|
13
16
|
* Extract contract ID from a HostFunction (for func+auth flow)
|
|
14
17
|
*/
|
|
@@ -17,5 +20,5 @@ export declare function getContractIdFromFunc(func: xdr.HostFunction): string |
|
|
|
17
20
|
* Extract contract ID from a Transaction (for XDR flow)
|
|
18
21
|
*/
|
|
19
22
|
export declare function getContractIdFromTransaction(transaction: Transaction): string | undefined;
|
|
20
|
-
export declare function calculateMaxFee(transaction: Transaction, limitedContracts
|
|
23
|
+
export declare function calculateMaxFee(transaction: Transaction, limitedContracts: Set<string>, fees: InclusionFees): number;
|
|
21
24
|
//# sourceMappingURL=fee.d.ts.map
|
package/dist/plugin/fee.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fee.d.ts","sourceRoot":"","sources":["../../src/plugin/fee.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fee.d.ts","sourceRoot":"","sources":["../../src/plugin/fee.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,GAAG,EAAqB,MAAM,sBAAsB,CAAC;AAG3E,MAAM,WAAW,aAAa;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,GAAG,MAAM,GAAG,SAAS,CAUhF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAYzF;AASD,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAoBpH"}
|
package/dist/plugin/fee.js
CHANGED
|
@@ -3,19 +3,17 @@
|
|
|
3
3
|
* fee.ts
|
|
4
4
|
*
|
|
5
5
|
* Static fee calculation for fee bump submissions matching launchtube.
|
|
6
|
-
* - For Soroban transactions: use resourceFee + inclusion fee
|
|
6
|
+
* - For Soroban transactions: use resourceFee + inclusion fee
|
|
7
7
|
* - For non-Soroban: use NON_SOROBAN_FEE + inclusion fee
|
|
8
|
-
* - Limited contracts (from LIMITED_CONTRACTS env) get reduced fee
|
|
8
|
+
* - Limited contracts (from LIMITED_CONTRACTS env) get reduced fee
|
|
9
|
+
* - Inclusion fees are configurable via INCLUSION_FEE_DEFAULT and INCLUSION_FEE_LIMITED env vars
|
|
9
10
|
*/
|
|
10
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.INCLUSION_FEE_LIMITED = exports.INCLUSION_FEE_DEFAULT = void 0;
|
|
12
12
|
exports.getContractIdFromFunc = getContractIdFromFunc;
|
|
13
13
|
exports.getContractIdFromTransaction = getContractIdFromTransaction;
|
|
14
14
|
exports.calculateMaxFee = calculateMaxFee;
|
|
15
15
|
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
16
16
|
const constants_1 = require("./constants");
|
|
17
|
-
exports.INCLUSION_FEE_DEFAULT = Number(stellar_sdk_1.BASE_FEE) * 2 + 3;
|
|
18
|
-
exports.INCLUSION_FEE_LIMITED = Number(stellar_sdk_1.BASE_FEE) * 2 + 1;
|
|
19
17
|
/**
|
|
20
18
|
* Extract contract ID from a HostFunction (for func+auth flow)
|
|
21
19
|
*/
|
|
@@ -48,13 +46,13 @@ function getContractIdFromTransaction(transaction) {
|
|
|
48
46
|
return undefined;
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
|
-
function getInclusionFee(contractId, limitedContracts) {
|
|
49
|
+
function getInclusionFee(contractId, limitedContracts, fees) {
|
|
52
50
|
if (contractId && limitedContracts.has(contractId)) {
|
|
53
|
-
return
|
|
51
|
+
return fees.inclusionFeeLimited;
|
|
54
52
|
}
|
|
55
|
-
return
|
|
53
|
+
return fees.inclusionFeeDefault;
|
|
56
54
|
}
|
|
57
|
-
function calculateMaxFee(transaction, limitedContracts
|
|
55
|
+
function calculateMaxFee(transaction, limitedContracts, fees) {
|
|
58
56
|
const envelope = transaction.toEnvelope();
|
|
59
57
|
let resourceFee = 0n;
|
|
60
58
|
if (envelope.switch() === stellar_sdk_1.xdr.EnvelopeType.envelopeTypeTx()) {
|
|
@@ -64,7 +62,7 @@ function calculateMaxFee(transaction, limitedContracts = new Set()) {
|
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
const contractId = getContractIdFromTransaction(transaction);
|
|
67
|
-
const inclusionFee = getInclusionFee(contractId, limitedContracts);
|
|
65
|
+
const inclusionFee = getInclusionFee(contractId, limitedContracts, fees);
|
|
68
66
|
const fee = resourceFee > 0n ? resourceFee + BigInt(inclusionFee) : BigInt(constants_1.FEE.NON_SOROBAN_FEE + inclusionFee);
|
|
69
67
|
console.debug(`[channels] Calculated max_fee: ${Number(fee)} stroops (resourceFee: ${resourceFee}, inclusionFee: ${inclusionFee})`);
|
|
70
68
|
return Number(fee);
|
package/dist/plugin/handler.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Orchestrates the transaction processing pipeline using channel accounts with fee bumping.
|
|
6
6
|
*/
|
|
7
7
|
import { PluginContext } from '@openzeppelin/relayer-sdk';
|
|
8
|
+
import type { Relayer } from '@openzeppelin/relayer-sdk';
|
|
8
9
|
import { Transaction, xdr } from '@stellar/stellar-sdk';
|
|
9
10
|
/**
|
|
10
11
|
* Extracts func and auth from an unsigned Soroban transaction.
|
|
@@ -14,6 +15,7 @@ export declare function extractFuncAuthFromUnsignedXdr(tx: Transaction): {
|
|
|
14
15
|
func: xdr.HostFunction;
|
|
15
16
|
auth: xdr.SorobanAuthorizationEntry[];
|
|
16
17
|
} | null;
|
|
18
|
+
export declare function getAccountSequence(relayer: Relayer, address: string): Promise<string>;
|
|
17
19
|
/**
|
|
18
20
|
* Main plugin handler exported for OpenZeppelin Relayer
|
|
19
21
|
*/
|
|
@@ -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;
|
|
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;AACvE,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAQpE,OAAO,EAAW,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAWjE;;;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;AAKD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsH3F;AA2PD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
|
package/dist/plugin/handler.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.extractFuncAuthFromUnsignedXdr = extractFuncAuthFromUnsignedXdr;
|
|
10
|
+
exports.getAccountSequence = getAccountSequence;
|
|
10
11
|
exports.handler = handler;
|
|
11
12
|
const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
12
13
|
const pool_1 = require("./pool");
|
|
@@ -44,7 +45,121 @@ function extractFuncAuthFromUnsignedXdr(tx) {
|
|
|
44
45
|
auth: invokeHostFn.auth(),
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
|
-
async function
|
|
48
|
+
async function getAccountSequence(relayer, address) {
|
|
49
|
+
let accountKey;
|
|
50
|
+
try {
|
|
51
|
+
accountKey = stellar_sdk_1.xdr.LedgerKey.account(new stellar_sdk_1.xdr.LedgerKeyAccount({
|
|
52
|
+
accountId: stellar_sdk_1.Keypair.fromPublicKey(address).xdrPublicKey(),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error('[channels] Sequence fetch failed', {
|
|
57
|
+
event: 'invalid_channel_account_address',
|
|
58
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
59
|
+
address,
|
|
60
|
+
message: error instanceof Error ? error.message : String(error),
|
|
61
|
+
});
|
|
62
|
+
throw (0, relayer_sdk_1.pluginError)('Invalid channel account address', {
|
|
63
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
64
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
65
|
+
details: { address, message: error instanceof Error ? error.message : String(error) },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
let response;
|
|
69
|
+
try {
|
|
70
|
+
response = await relayer.rpc({
|
|
71
|
+
jsonrpc: '2.0',
|
|
72
|
+
id: Math.floor(Math.random() * 1e8).toString(),
|
|
73
|
+
method: 'getLedgerEntries',
|
|
74
|
+
params: {
|
|
75
|
+
keys: [accountKey.toXDR('base64')],
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error('[channels] Sequence fetch failed', {
|
|
81
|
+
event: 'sequence_rpc_request_failed',
|
|
82
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
83
|
+
address,
|
|
84
|
+
message: error instanceof Error ? error.message : String(error),
|
|
85
|
+
});
|
|
86
|
+
throw (0, relayer_sdk_1.pluginError)('Failed to get sequence from channel relayer', {
|
|
87
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
88
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
89
|
+
details: { message: error instanceof Error ? error.message : String(error) },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (response.error) {
|
|
93
|
+
console.error('[channels] Sequence fetch failed', {
|
|
94
|
+
event: 'sequence_rpc_error_response',
|
|
95
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
96
|
+
address,
|
|
97
|
+
message: response.error.message,
|
|
98
|
+
});
|
|
99
|
+
throw (0, relayer_sdk_1.pluginError)('Failed to get sequence from channel relayer', {
|
|
100
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
101
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
102
|
+
details: { message: response.error.message },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const result = response.result;
|
|
106
|
+
const entries = result?.entries;
|
|
107
|
+
if (!Array.isArray(entries)) {
|
|
108
|
+
console.error('[channels] Sequence fetch failed', {
|
|
109
|
+
event: 'sequence_rpc_invalid_result_shape',
|
|
110
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
111
|
+
address,
|
|
112
|
+
});
|
|
113
|
+
throw (0, relayer_sdk_1.pluginError)('Invalid RPC response for account sequence', {
|
|
114
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
115
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
116
|
+
details: { address },
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (!entries || entries.length === 0) {
|
|
120
|
+
console.warn('[channels] Sequence fetch returned no account entries', {
|
|
121
|
+
event: 'sequence_account_not_found',
|
|
122
|
+
code: 'ACCOUNT_NOT_FOUND',
|
|
123
|
+
address,
|
|
124
|
+
});
|
|
125
|
+
throw (0, relayer_sdk_1.pluginError)('Channel account not found on ledger', {
|
|
126
|
+
code: 'ACCOUNT_NOT_FOUND',
|
|
127
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
128
|
+
details: { address },
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const firstEntryXdr = entries[0]?.xdr;
|
|
132
|
+
if (typeof firstEntryXdr !== 'string') {
|
|
133
|
+
console.error('[channels] Sequence fetch failed', {
|
|
134
|
+
event: 'sequence_rpc_invalid_entry_xdr',
|
|
135
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
136
|
+
address,
|
|
137
|
+
});
|
|
138
|
+
throw (0, relayer_sdk_1.pluginError)('Invalid RPC response for account sequence', {
|
|
139
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
140
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
141
|
+
details: { address },
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const accountEntry = stellar_sdk_1.xdr.LedgerEntryData.fromXDR(firstEntryXdr, 'base64');
|
|
146
|
+
return accountEntry.account().seqNum().toString();
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error('[channels] Sequence fetch failed', {
|
|
150
|
+
event: 'sequence_xdr_decode_failed',
|
|
151
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
152
|
+
address,
|
|
153
|
+
message: error instanceof Error ? error.message : String(error),
|
|
154
|
+
});
|
|
155
|
+
throw (0, relayer_sdk_1.pluginError)('Failed to decode account sequence from ledger entry', {
|
|
156
|
+
code: 'FAILED_TO_GET_SEQUENCE',
|
|
157
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
158
|
+
details: { address, message: error instanceof Error ? error.message : String(error) },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async function handleXdrSubmit(xdrStr, fundRelayer, fundAddress, network, networkPassphrase, api, pool, acquireOptions, fees, tracker) {
|
|
48
163
|
const tx = new stellar_sdk_1.Transaction(xdrStr, networkPassphrase);
|
|
49
164
|
// Unsigned XDR: extract func+auth and route through channel path
|
|
50
165
|
if (tx.signatures.length === 0) {
|
|
@@ -63,14 +178,19 @@ async function handleXdrSubmit(xdrStr, fundRelayer, fundAddress, network, networ
|
|
|
63
178
|
// Update acquireOptions with contractId from extracted func
|
|
64
179
|
const contractId = (0, fee_1.getContractIdFromFunc)(extracted.func);
|
|
65
180
|
const updatedOptions = { ...acquireOptions, contractId };
|
|
66
|
-
return handleFuncAuthSubmit(extracted.func, extracted.auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, updatedOptions, tracker);
|
|
181
|
+
return handleFuncAuthSubmit(extracted.func, extracted.auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, updatedOptions, fees, tracker);
|
|
67
182
|
}
|
|
68
183
|
const validated = (0, tx_1.validateExistingTransactionForSubmitOnly)(tx);
|
|
69
|
-
const maxFee = (0, fee_1.calculateMaxFee)(validated, acquireOptions.limitedContracts);
|
|
184
|
+
const maxFee = (0, fee_1.calculateMaxFee)(validated, acquireOptions.limitedContracts, fees);
|
|
185
|
+
const contractId = (0, fee_1.getContractIdFromTransaction)(validated);
|
|
70
186
|
await tracker?.checkBudget(maxFee);
|
|
71
|
-
|
|
187
|
+
const submitContext = {
|
|
188
|
+
contractId,
|
|
189
|
+
isLimited: contractId ? acquireOptions.limitedContracts.has(contractId) : false,
|
|
190
|
+
};
|
|
191
|
+
return (0, submit_1.submitWithFeeBumpAndWait)(fundRelayer, validated.toXDR(), network, maxFee, api, tracker, submitContext);
|
|
72
192
|
}
|
|
73
|
-
async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, acquireOptions, tracker) {
|
|
193
|
+
async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, acquireOptions, fees, tracker) {
|
|
74
194
|
// Simulate once — used for both read-only detection and transaction assembly
|
|
75
195
|
const simulation = await (0, simulation_1.simulateTransaction)(func, auth, fundAddress, fundRelayer, networkPassphrase);
|
|
76
196
|
if (simulation.isReadOnly) {
|
|
@@ -96,20 +216,25 @@ async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddr
|
|
|
96
216
|
details: { relayerId: poolLock.relayerId },
|
|
97
217
|
});
|
|
98
218
|
}
|
|
99
|
-
|
|
100
|
-
if (channelStatus.network_type !== 'stellar') {
|
|
219
|
+
if (channelInfo.network_type !== 'stellar') {
|
|
101
220
|
throw (0, relayer_sdk_1.pluginError)('Channel relayer network type must be stellar', {
|
|
102
221
|
code: 'UNSUPPORTED_NETWORK',
|
|
103
222
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
104
|
-
details: { network_type:
|
|
223
|
+
details: { network_type: channelInfo.network_type, relayerId: poolLock.relayerId },
|
|
105
224
|
});
|
|
106
225
|
}
|
|
226
|
+
const sequence = await getAccountSequence(channelRelayer, channelInfo.address);
|
|
107
227
|
// Assemble the transaction using the cached simulation result — no second RPC call
|
|
108
|
-
const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence
|
|
228
|
+
const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence }, networkPassphrase, simulation.rawSimResult);
|
|
109
229
|
const signedTx = await (0, submit_1.signWithChannelAndFund)(built, channelRelayer, fundRelayer, channelInfo.address, fundAddress, networkPassphrase);
|
|
110
|
-
const maxFee = (0, fee_1.calculateMaxFee)(signedTx, acquireOptions.limitedContracts);
|
|
230
|
+
const maxFee = (0, fee_1.calculateMaxFee)(signedTx, acquireOptions.limitedContracts, fees);
|
|
231
|
+
const contractId = (0, fee_1.getContractIdFromFunc)(func);
|
|
111
232
|
await tracker?.checkBudget(maxFee);
|
|
112
|
-
|
|
233
|
+
const submitContext = {
|
|
234
|
+
contractId,
|
|
235
|
+
isLimited: contractId ? acquireOptions.limitedContracts.has(contractId) : false,
|
|
236
|
+
};
|
|
237
|
+
return await (0, submit_1.submitWithFeeBumpAndWait)(fundRelayer, signedTx.toXDR(), network, maxFee, api, tracker, submitContext);
|
|
113
238
|
}
|
|
114
239
|
finally {
|
|
115
240
|
if (poolLock) {
|
|
@@ -172,16 +297,20 @@ async function channelAccounts(context) {
|
|
|
172
297
|
limitedContracts: config.limitedContracts,
|
|
173
298
|
capacityRatio: config.contractCapacityRatio,
|
|
174
299
|
};
|
|
300
|
+
const fees = {
|
|
301
|
+
inclusionFeeDefault: config.inclusionFeeDefault,
|
|
302
|
+
inclusionFeeLimited: config.inclusionFeeLimited,
|
|
303
|
+
};
|
|
175
304
|
// 4. Branch by request type
|
|
176
305
|
if (request.type === 'xdr') {
|
|
177
306
|
console.log(`[channels] Flow: XDR submit-only`);
|
|
178
|
-
return await handleXdrSubmit(request.xdr, fundRelayer, fundInfo.address, config.network, networkPassphrase, api, pool, acquireOptions, tracker);
|
|
307
|
+
return await handleXdrSubmit(request.xdr, fundRelayer, fundInfo.address, config.network, networkPassphrase, api, pool, acquireOptions, fees, tracker);
|
|
179
308
|
}
|
|
180
309
|
// Extract contractId for func+auth flow
|
|
181
310
|
const contractId = (0, fee_1.getContractIdFromFunc)(request.func);
|
|
182
311
|
const funcAcquireOptions = { ...acquireOptions, contractId };
|
|
183
312
|
console.log(`[channels] Flow: func+auth with channel account`);
|
|
184
|
-
return await handleFuncAuthSubmit(request.func, request.auth, api, pool, fundRelayer, fundInfo.address, config.network, networkPassphrase, funcAcquireOptions, tracker);
|
|
313
|
+
return await handleFuncAuthSubmit(request.func, request.auth, api, pool, fundRelayer, fundInfo.address, config.network, networkPassphrase, funcAcquireOptions, fees, tracker);
|
|
185
314
|
}
|
|
186
315
|
/**
|
|
187
316
|
* Main plugin handler exported for OpenZeppelin Relayer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"management.d.ts","sourceRoot":"","sources":["../../src/plugin/management.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"management.d.ts","sourceRoot":"","sources":["../../src/plugin/management.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,2BAA2B,CAAC;AAO9E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAIxD;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAoC3E"}
|
|
@@ -48,6 +48,8 @@ async function handleManagement(context) {
|
|
|
48
48
|
return await setFeeLimit(kv, config.network, m);
|
|
49
49
|
case 'deleteFeeLimit':
|
|
50
50
|
return await deleteFeeLimit(kv, config.network, m);
|
|
51
|
+
case 'stats':
|
|
52
|
+
return await getPoolStats(config, kv);
|
|
51
53
|
default:
|
|
52
54
|
throw (0, relayer_sdk_1.pluginError)('Invalid management action', { code: 'INVALID_ACTION', status: constants_1.HTTP_STATUS.BAD_REQUEST });
|
|
53
55
|
}
|
|
@@ -194,6 +196,52 @@ async function setChannelAccounts(kv, network, payload) {
|
|
|
194
196
|
});
|
|
195
197
|
}
|
|
196
198
|
}
|
|
199
|
+
async function getPoolStats(config, kv) {
|
|
200
|
+
const { network } = config;
|
|
201
|
+
// 1. Get relayer IDs (1 KV call)
|
|
202
|
+
const key = `${network}:channel:relayer-ids`;
|
|
203
|
+
let relayerIds;
|
|
204
|
+
try {
|
|
205
|
+
const doc = await kv.get?.(key);
|
|
206
|
+
relayerIds = Array.isArray(doc?.relayerIds) ? doc.relayerIds : [];
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
throw (0, relayer_sdk_1.pluginError)('KV error while reading pool stats', {
|
|
210
|
+
code: 'KV_ERROR',
|
|
211
|
+
status: constants_1.HTTP_STATUS.INTERNAL_SERVER_ERROR,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
// 2. Check all locks in parallel (N KV calls) — best-effort
|
|
215
|
+
let locked;
|
|
216
|
+
let available;
|
|
217
|
+
try {
|
|
218
|
+
const results = await Promise.all(relayerIds.map((id) => kv.exists(`${network}:channel:in-use:${id}`)));
|
|
219
|
+
locked = results.filter(Boolean).length;
|
|
220
|
+
available = relayerIds.length - locked;
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Non-fatal: return pool size without lock info
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
pool: {
|
|
227
|
+
size: relayerIds.length,
|
|
228
|
+
locked,
|
|
229
|
+
available,
|
|
230
|
+
},
|
|
231
|
+
config: {
|
|
232
|
+
network,
|
|
233
|
+
lockTtlSeconds: config.lockTtlSeconds,
|
|
234
|
+
feeLimit: config.feeLimit,
|
|
235
|
+
feeResetPeriodSeconds: config.feeResetPeriodMs ? config.feeResetPeriodMs / 1000 : undefined,
|
|
236
|
+
contractCapacityRatio: config.contractCapacityRatio,
|
|
237
|
+
limitedContracts: Array.from(config.limitedContracts),
|
|
238
|
+
},
|
|
239
|
+
fees: {
|
|
240
|
+
inclusionFeeDefault: config.inclusionFeeDefault,
|
|
241
|
+
inclusionFeeLimited: config.inclusionFeeLimited,
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
197
245
|
function normalizeId(id) {
|
|
198
246
|
return String(id).trim().toLowerCase();
|
|
199
247
|
}
|
package/dist/plugin/pool.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/plugin/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AAIvE,MAAM,MAAM,QAAQ,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/plugin/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AAIvE,MAAM,MAAM,QAAQ,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAUF,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;gBAEvB,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,EAAE,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM;IAQrF,4CAA4C;IACtC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;YAyB3C,eAAe;YAKf,iBAAiB;IA2B/B,oCAAoC;IAC9B,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAY5C,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,OAAO;YAID,mBAAmB;YAYnB,sBAAsB;CAUrC"}
|
package/dist/plugin/pool.js
CHANGED
|
@@ -26,7 +26,6 @@ class ChannelPool {
|
|
|
26
26
|
/** Acquire a relayerId with a token lock */
|
|
27
27
|
async acquire(options) {
|
|
28
28
|
const maxSpins = constants_1.POOL.MUTEX_MAX_SPINS;
|
|
29
|
-
const isLimited = options.contractId && options.limitedContracts.has(options.contractId);
|
|
30
29
|
for (let i = 0; i < maxSpins; i++) {
|
|
31
30
|
const r = await this.withGlobalMutex(() => this.tryLockAnyRelayer(options));
|
|
32
31
|
if (r === null) {
|
|
@@ -36,12 +35,12 @@ class ChannelPool {
|
|
|
36
35
|
}
|
|
37
36
|
return r;
|
|
38
37
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
38
|
+
const diagnostics = await this.getPoolCapacityDetails(options, maxSpins);
|
|
39
|
+
console.warn('[channels] Pool capacity exhausted', diagnostics);
|
|
42
40
|
throw (0, relayer_sdk_1.pluginError)('Too many transactions queued. Please try again later', {
|
|
43
41
|
code: 'POOL_CAPACITY',
|
|
44
42
|
status: constants_1.HTTP_STATUS.SERVICE_UNAVAILABLE,
|
|
43
|
+
details: diagnostics,
|
|
45
44
|
});
|
|
46
45
|
}
|
|
47
46
|
// Run a function under the short-lived global mutex; returns null if busy
|
|
@@ -106,6 +105,15 @@ class ChannelPool {
|
|
|
106
105
|
return [];
|
|
107
106
|
}
|
|
108
107
|
}
|
|
108
|
+
async getPoolCapacityDetails(options, maxSpins) {
|
|
109
|
+
const isLimited = !!(options.contractId && options.limitedContracts.has(options.contractId));
|
|
110
|
+
return {
|
|
111
|
+
reason: isLimited ? 'limited_contract_capacity' : 'all_channels_busy_or_mutex_contention',
|
|
112
|
+
contractId: options.contractId,
|
|
113
|
+
capacityRatio: options.capacityRatio,
|
|
114
|
+
maxSpins,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
109
117
|
}
|
|
110
118
|
exports.ChannelPool = ChannelPool;
|
|
111
119
|
function shuffle(arr) {
|
package/dist/plugin/submit.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ import { Transaction } from '@stellar/stellar-sdk';
|
|
|
7
7
|
import { Relayer, PluginAPI } from '@openzeppelin/relayer-sdk';
|
|
8
8
|
import { ChannelAccountsResponse } from './types';
|
|
9
9
|
import { FeeTracker } from './fee-tracking';
|
|
10
|
+
export interface SubmitContext {
|
|
11
|
+
contractId?: string;
|
|
12
|
+
isLimited?: boolean;
|
|
13
|
+
}
|
|
10
14
|
/**
|
|
11
15
|
* Sign transaction with both channel and fund relayers
|
|
12
16
|
* - First sign with channel account
|
|
@@ -17,7 +21,12 @@ export declare function signWithChannelAndFund(transaction: Transaction, channel
|
|
|
17
21
|
/**
|
|
18
22
|
* Submit transaction with fee bump and wait for confirmation
|
|
19
23
|
*/
|
|
20
|
-
export declare function submitWithFeeBumpAndWait(fundRelayer: Relayer, signedXdr: string, network: 'testnet' | 'mainnet', maxFee: number, api: PluginAPI, tracker?: FeeTracker): Promise<ChannelAccountsResponse>;
|
|
24
|
+
export declare function submitWithFeeBumpAndWait(fundRelayer: Relayer, signedXdr: string, network: 'testnet' | 'mainnet', maxFee: number, api: PluginAPI, tracker?: FeeTracker, context?: SubmitContext): Promise<ChannelAccountsResponse>;
|
|
25
|
+
/** Try to decode a transaction result XDR from the reason string */
|
|
26
|
+
export declare function decodeTransactionResult(reason: string): {
|
|
27
|
+
feeCharged: number;
|
|
28
|
+
resultCode: string;
|
|
29
|
+
} | null;
|
|
21
30
|
/** Strip provider wrapper text, extract last segment (e.g., "TxInsufficientBalance") */
|
|
22
31
|
export declare function sanitizeReason(reason: string): string;
|
|
23
32
|
//# sourceMappingURL=submit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/plugin/submit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,
|
|
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,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;;;;;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,OAAO,CAAC,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,uBAAuB,CAAC,CA6ElC;AASD,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwBzG;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOrD"}
|
package/dist/plugin/submit.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.signWithChannelAndFund = signWithChannelAndFund;
|
|
9
9
|
exports.submitWithFeeBumpAndWait = submitWithFeeBumpAndWait;
|
|
10
|
+
exports.decodeTransactionResult = decodeTransactionResult;
|
|
10
11
|
exports.sanitizeReason = sanitizeReason;
|
|
11
12
|
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
12
13
|
const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
@@ -40,7 +41,7 @@ async function signWithChannelAndFund(transaction, channelRelayer, _fundRelayer,
|
|
|
40
41
|
/**
|
|
41
42
|
* Submit transaction with fee bump and wait for confirmation
|
|
42
43
|
*/
|
|
43
|
-
async function submitWithFeeBumpAndWait(fundRelayer, signedXdr, network, maxFee, api, tracker) {
|
|
44
|
+
async function submitWithFeeBumpAndWait(fundRelayer, signedXdr, network, maxFee, api, tracker, context) {
|
|
44
45
|
// Submit with fee bump
|
|
45
46
|
console.debug(`[channels] Sending fee bump tx: network=${network}, maxFee=${maxFee}, xdr_len=${signedXdr.length}`);
|
|
46
47
|
const payload = {
|
|
@@ -64,7 +65,18 @@ async function submitWithFeeBumpAndWait(fundRelayer, signedXdr, network, maxFee,
|
|
|
64
65
|
await tracker.recordUsage(maxFee);
|
|
65
66
|
}
|
|
66
67
|
const rawReason = final.status_reason || 'Transaction failed';
|
|
67
|
-
|
|
68
|
+
const decoded = decodeTransactionResult(rawReason);
|
|
69
|
+
const contractType = context?.isLimited ? 'limited' : 'default';
|
|
70
|
+
const base = `[channels] Transaction failed: contractId=${context?.contractId ?? 'unknown'}, contractType=${contractType}, maxFee=${maxFee}`;
|
|
71
|
+
if (decoded?.resultCode === 'txInsufficientFee') {
|
|
72
|
+
console.error(`${base}, reason=txInsufficientFee, requiredFee=${decoded.feeCharged}, shortfall=${decoded.feeCharged - maxFee}`);
|
|
73
|
+
}
|
|
74
|
+
else if (decoded) {
|
|
75
|
+
console.error(`${base}, reason=${decoded.resultCode}`);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.error(`${base}, reason=${rawReason}`);
|
|
79
|
+
}
|
|
68
80
|
const reason = sanitizeReason(rawReason);
|
|
69
81
|
throw (0, relayer_sdk_1.pluginError)(reason, {
|
|
70
82
|
code: 'ONCHAIN_FAILED',
|
|
@@ -109,6 +121,33 @@ async function submitWithFeeBumpAndWait(fundRelayer, signedXdr, network, maxFee,
|
|
|
109
121
|
function isSignTransactionResponseStellar(data) {
|
|
110
122
|
return data !== null && typeof data === 'object' && 'signature' in data && 'signedXdr' in data;
|
|
111
123
|
}
|
|
124
|
+
/** Try to decode a transaction result XDR from the reason string */
|
|
125
|
+
function decodeTransactionResult(reason) {
|
|
126
|
+
try {
|
|
127
|
+
const match = reason.match(/([A-Za-z0-9+/=]{20,})$/);
|
|
128
|
+
if (!match)
|
|
129
|
+
return null;
|
|
130
|
+
const result = stellar_sdk_1.xdr.TransactionResult.fromXDR(match[1], 'base64');
|
|
131
|
+
let resultCode = result.result().switch().name;
|
|
132
|
+
// Unwrap fee bump inner failure to get the actual result code
|
|
133
|
+
if (resultCode === 'txFeeBumpInnerFailed') {
|
|
134
|
+
try {
|
|
135
|
+
const innerResult = result.result().innerResultPair().result();
|
|
136
|
+
resultCode = innerResult.result().switch().name;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// keep outer result code if unwrap fails
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
feeCharged: Number(result.feeCharged().toBigInt()),
|
|
144
|
+
resultCode,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
112
151
|
/** Strip provider wrapper text, extract last segment (e.g., "TxInsufficientBalance") */
|
|
113
152
|
function sanitizeReason(reason) {
|
|
114
153
|
const segments = reason.split(/:\s*/);
|