@openzeppelin/relayer-plugin-channels 0.6.0 → 0.8.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 +79 -43
- package/dist/client/channels-client.d.ts +1 -1
- package/dist/client/channels-client.d.ts.map +1 -1
- package/dist/client/channels-client.js +20 -21
- package/dist/client/errors.d.ts +1 -1
- package/dist/client/errors.js +12 -9
- package/dist/client/index.d.ts +3 -3
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/types.d.ts +5 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/plugin/build.d.ts +1 -1
- package/dist/plugin/build.d.ts.map +1 -1
- package/dist/plugin/build.js +11 -17
- package/dist/plugin/config.d.ts +4 -2
- package/dist/plugin/config.d.ts.map +1 -1
- package/dist/plugin/config.js +43 -13
- package/dist/plugin/constants.d.ts +1 -0
- package/dist/plugin/constants.d.ts.map +1 -1
- package/dist/plugin/constants.js +2 -1
- package/dist/plugin/fee-tracking.d.ts +2 -2
- package/dist/plugin/fee-tracking.d.ts.map +1 -1
- package/dist/plugin/fee-tracking.js +4 -9
- package/dist/plugin/fee.d.ts +12 -5
- package/dist/plugin/fee.d.ts.map +1 -1
- package/dist/plugin/fee.js +39 -23
- package/dist/plugin/handler.d.ts +2 -2
- package/dist/plugin/handler.d.ts.map +1 -1
- package/dist/plugin/handler.js +52 -34
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/management.d.ts +1 -1
- package/dist/plugin/management.d.ts.map +1 -1
- package/dist/plugin/management.js +53 -79
- package/dist/plugin/pool.d.ts +8 -3
- package/dist/plugin/pool.d.ts.map +1 -1
- package/dist/plugin/pool.js +45 -17
- package/dist/plugin/simulation.d.ts +34 -6
- package/dist/plugin/simulation.d.ts.map +1 -1
- package/dist/plugin/simulation.js +86 -49
- package/dist/plugin/submit.d.ts +5 -5
- package/dist/plugin/submit.d.ts.map +1 -1
- package/dist/plugin/submit.js +11 -14
- package/dist/plugin/tx.d.ts +1 -1
- package/dist/plugin/tx.d.ts.map +1 -1
- package/dist/plugin/tx.js +6 -8
- package/dist/plugin/types.d.ts +8 -4
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/validation.d.ts +1 -1
- package/dist/plugin/validation.d.ts.map +1 -1
- package/dist/plugin/validation.js +26 -27
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,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;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,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;CAC/B;AAoFD;;GAEG;AACH,wBAAgB,UAAU,IAAI,qBAAqB,CAoBlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAE3E"}
|
package/dist/plugin/config.js
CHANGED
|
@@ -12,9 +12,9 @@ const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
|
12
12
|
const constants_1 = require("./constants");
|
|
13
13
|
function requireEnv(name) {
|
|
14
14
|
const v = process.env[name];
|
|
15
|
-
if (!v || v.trim() ===
|
|
15
|
+
if (!v || v.trim() === '') {
|
|
16
16
|
throw (0, relayer_sdk_1.pluginError)(`Missing required environment variable: ${name}`, {
|
|
17
|
-
code:
|
|
17
|
+
code: 'CONFIG_MISSING',
|
|
18
18
|
status: constants_1.HTTP_STATUS.INTERNAL_SERVER_ERROR,
|
|
19
19
|
details: { name },
|
|
20
20
|
});
|
|
@@ -33,9 +33,7 @@ function parseLockTtl() {
|
|
|
33
33
|
if (!raw)
|
|
34
34
|
return constants_1.CONFIG.DEFAULT_LOCK_TTL_SECONDS;
|
|
35
35
|
const n = Number(raw);
|
|
36
|
-
if (!Number.isFinite(n) ||
|
|
37
|
-
n < constants_1.CONFIG.MIN_LOCK_TTL_SECONDS ||
|
|
38
|
-
n > constants_1.CONFIG.MAX_LOCK_TTL_SECONDS) {
|
|
36
|
+
if (!Number.isFinite(n) || n < constants_1.CONFIG.MIN_LOCK_TTL_SECONDS || n > constants_1.CONFIG.MAX_LOCK_TTL_SECONDS) {
|
|
39
37
|
return constants_1.CONFIG.DEFAULT_LOCK_TTL_SECONDS;
|
|
40
38
|
}
|
|
41
39
|
return Math.floor(n);
|
|
@@ -57,34 +55,66 @@ function parseFeeResetPeriod() {
|
|
|
57
55
|
function parseApiKeyHeader() {
|
|
58
56
|
const raw = process.env.API_KEY_HEADER;
|
|
59
57
|
if (!raw)
|
|
60
|
-
return
|
|
58
|
+
return 'x-api-key';
|
|
61
59
|
const trimmed = raw.trim().toLowerCase();
|
|
62
|
-
return trimmed.length > 0 ? trimmed :
|
|
60
|
+
return trimmed.length > 0 ? trimmed : 'x-api-key';
|
|
61
|
+
}
|
|
62
|
+
function parseLimitedContracts() {
|
|
63
|
+
const raw = process.env.LIMITED_CONTRACTS;
|
|
64
|
+
if (!raw)
|
|
65
|
+
return new Set();
|
|
66
|
+
const contracts = raw
|
|
67
|
+
.split(',')
|
|
68
|
+
.map((s) => s.trim().toUpperCase())
|
|
69
|
+
.filter((s) => s.length > 0);
|
|
70
|
+
// Validate each contract address
|
|
71
|
+
for (const contract of contracts) {
|
|
72
|
+
if (!stellar_sdk_1.StrKey.isValidContract(contract)) {
|
|
73
|
+
throw (0, relayer_sdk_1.pluginError)(`Invalid contract address in LIMITED_CONTRACTS: ${contract}`, {
|
|
74
|
+
code: 'CONFIG_INVALID',
|
|
75
|
+
status: constants_1.HTTP_STATUS.INTERNAL_SERVER_ERROR,
|
|
76
|
+
details: { contract },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return new Set(contracts);
|
|
81
|
+
}
|
|
82
|
+
function parseContractCapacityRatio() {
|
|
83
|
+
const raw = process.env.CONTRACT_CAPACITY_RATIO;
|
|
84
|
+
if (!raw)
|
|
85
|
+
return constants_1.CONFIG.DEFAULT_CONTRACT_CAPACITY_RATIO;
|
|
86
|
+
const n = Number(raw);
|
|
87
|
+
if (!Number.isFinite(n) || n < 0 || n > 1) {
|
|
88
|
+
return constants_1.CONFIG.DEFAULT_CONTRACT_CAPACITY_RATIO;
|
|
89
|
+
}
|
|
90
|
+
return n;
|
|
63
91
|
}
|
|
64
92
|
/**
|
|
65
93
|
* Load configuration from environment variables
|
|
66
94
|
*/
|
|
67
95
|
function loadConfig() {
|
|
68
|
-
const networkRaw = requireEnv(
|
|
69
|
-
if (networkRaw !==
|
|
96
|
+
const networkRaw = requireEnv('STELLAR_NETWORK').toLowerCase();
|
|
97
|
+
if (networkRaw !== 'testnet' && networkRaw !== 'mainnet') {
|
|
70
98
|
throw (0, relayer_sdk_1.pluginError)('STELLAR_NETWORK must be "testnet" or "mainnet"', {
|
|
71
|
-
code:
|
|
99
|
+
code: 'UNSUPPORTED_NETWORK',
|
|
72
100
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
73
101
|
});
|
|
74
102
|
}
|
|
75
103
|
return {
|
|
76
|
-
fundRelayerId: requireEnv(
|
|
104
|
+
fundRelayerId: requireEnv('FUND_RELAYER_ID'),
|
|
77
105
|
network: networkRaw,
|
|
78
106
|
lockTtlSeconds: parseLockTtl(),
|
|
79
|
-
adminSecret: parseOptionalString(
|
|
107
|
+
adminSecret: parseOptionalString('PLUGIN_ADMIN_SECRET'),
|
|
80
108
|
feeLimit: parseFeeLimit(),
|
|
81
109
|
feeResetPeriodMs: parseFeeResetPeriod(),
|
|
82
110
|
apiKeyHeader: parseApiKeyHeader(),
|
|
111
|
+
limitedContracts: parseLimitedContracts(),
|
|
112
|
+
contractCapacityRatio: parseContractCapacityRatio(),
|
|
83
113
|
};
|
|
84
114
|
}
|
|
85
115
|
/**
|
|
86
116
|
* Get the network passphrase based on the configuration
|
|
87
117
|
*/
|
|
88
118
|
function getNetworkPassphrase(network) {
|
|
89
|
-
return network ===
|
|
119
|
+
return network === 'mainnet' ? stellar_sdk_1.Networks.PUBLIC : stellar_sdk_1.Networks.TESTNET;
|
|
90
120
|
}
|
|
@@ -18,6 +18,7 @@ export declare const CONFIG: {
|
|
|
18
18
|
readonly DEFAULT_LOCK_TTL_SECONDS: 30;
|
|
19
19
|
readonly MIN_LOCK_TTL_SECONDS: 3;
|
|
20
20
|
readonly MAX_LOCK_TTL_SECONDS: 30;
|
|
21
|
+
readonly DEFAULT_CONTRACT_CAPACITY_RATIO: 0.8;
|
|
21
22
|
};
|
|
22
23
|
export declare const POOL: {
|
|
23
24
|
readonly MUTEX_TTL_SECONDS: 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/plugin/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,WAAW;;;;;;;;;;CAUd,CAAC;AAGX,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/plugin/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,WAAW;;;;;;;;;;CAUd,CAAC;AAGX,eAAO,MAAM,MAAM;;;;;CAKT,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;CAOP,CAAC;AAGX,eAAO,MAAM,IAAI;;CAEP,CAAC;AAGX,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AAGX,eAAO,MAAM,OAAO;;;CAGV,CAAC;AAEX,eAAO,MAAM,GAAG;;CAGN,CAAC"}
|
package/dist/plugin/constants.js
CHANGED
|
@@ -23,6 +23,7 @@ exports.CONFIG = {
|
|
|
23
23
|
DEFAULT_LOCK_TTL_SECONDS: 30,
|
|
24
24
|
MIN_LOCK_TTL_SECONDS: 3,
|
|
25
25
|
MAX_LOCK_TTL_SECONDS: 30,
|
|
26
|
+
DEFAULT_CONTRACT_CAPACITY_RATIO: 0.8,
|
|
26
27
|
};
|
|
27
28
|
// Pool Constants
|
|
28
29
|
exports.POOL = {
|
|
@@ -39,7 +40,7 @@ exports.TIME = {
|
|
|
39
40
|
};
|
|
40
41
|
// Simulation-related defaults
|
|
41
42
|
exports.SIMULATION = {
|
|
42
|
-
DEFAULT_FEE:
|
|
43
|
+
DEFAULT_FEE: '100',
|
|
43
44
|
MIN_TIME_BOUND: 0,
|
|
44
45
|
MAX_TIME_BOUND_OFFSET_SECONDS: 30,
|
|
45
46
|
MAX_FUTURE_TIME_BOUND_SECONDS: 30,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Supports custom per-key limits with fallback to default.
|
|
6
6
|
* Supports periodic reset of consumption.
|
|
7
7
|
*/
|
|
8
|
-
import { PluginKVStore } from
|
|
8
|
+
import { PluginKVStore } from '@openzeppelin/relayer-sdk';
|
|
9
9
|
/** KV data structure for fee consumption */
|
|
10
10
|
export interface FeeData {
|
|
11
11
|
consumed: number;
|
|
@@ -22,7 +22,7 @@ export interface UsageInfo {
|
|
|
22
22
|
/** Configuration for FeeTracker */
|
|
23
23
|
export interface FeeTrackerConfig {
|
|
24
24
|
kv: PluginKVStore;
|
|
25
|
-
network:
|
|
25
|
+
network: 'testnet' | 'mainnet';
|
|
26
26
|
apiKey: string;
|
|
27
27
|
defaultLimit?: number;
|
|
28
28
|
resetPeriodMs?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fee-tracking.d.ts","sourceRoot":"","sources":["../../src/plugin/fee-tracking.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AAGvE,4CAA4C;AAC5C,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAQD,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,aAAa,CAAC;IAClB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAS;gBAE5B,MAAM,EAAE,gBAAgB;IAUpC;;;OAGG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7C;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"fee-tracking.d.ts","sourceRoot":"","sources":["../../src/plugin/fee-tracking.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AAGvE,4CAA4C;AAC5C,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAQD,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,aAAa,CAAC;IAClB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAS;gBAE5B,MAAM,EAAE,gBAAgB;IAUpC;;;OAGG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7C;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B7C;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAexC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKnD;;OAEG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxC;;;OAGG;YACW,WAAW;IASzB;;OAEG;YACW,iBAAiB;IAK/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,OAAO,GAElB;CACF"}
|
|
@@ -31,7 +31,7 @@ class FeeTracker {
|
|
|
31
31
|
if (consumed + fee > limit) {
|
|
32
32
|
const remaining = limit - consumed;
|
|
33
33
|
throw (0, relayer_sdk_1.pluginError)(`Transaction fee (${fee} stroops) exceeds remaining budget (${remaining} stroops). Consumed: ${consumed}/${limit} stroops.`, {
|
|
34
|
-
code:
|
|
34
|
+
code: 'FEE_LIMIT_EXCEEDED',
|
|
35
35
|
status: constants_1.HTTP_STATUS.TOO_MANY_REQUESTS,
|
|
36
36
|
details: { consumed, fee, remaining, limit },
|
|
37
37
|
});
|
|
@@ -54,7 +54,7 @@ class FeeTracker {
|
|
|
54
54
|
periodStart: state.periodStart ?? now,
|
|
55
55
|
});
|
|
56
56
|
return true;
|
|
57
|
-
}, { ttlSec: 5, onBusy:
|
|
57
|
+
}, { ttlSec: 5, onBusy: 'skip' });
|
|
58
58
|
if (result !== null)
|
|
59
59
|
return;
|
|
60
60
|
// Lock busy, retry with jitter
|
|
@@ -71,17 +71,12 @@ class FeeTracker {
|
|
|
71
71
|
* Get complete usage info for management API.
|
|
72
72
|
*/
|
|
73
73
|
async getUsageInfo() {
|
|
74
|
-
const [state, limit] = await Promise.all([
|
|
75
|
-
this.getFeeState(),
|
|
76
|
-
this.getEffectiveLimit(),
|
|
77
|
-
]);
|
|
74
|
+
const [state, limit] = await Promise.all([this.getFeeState(), this.getEffectiveLimit()]);
|
|
78
75
|
return {
|
|
79
76
|
consumed: state.consumed,
|
|
80
77
|
limit,
|
|
81
78
|
remaining: limit !== undefined ? Math.max(0, limit - state.consumed) : undefined,
|
|
82
|
-
periodStartAt: state.periodStart
|
|
83
|
-
? new Date(state.periodStart).toISOString()
|
|
84
|
-
: undefined,
|
|
79
|
+
periodStartAt: state.periodStart ? new Date(state.periodStart).toISOString() : undefined,
|
|
85
80
|
periodEndsAt: state.periodStart && this.resetPeriodMs
|
|
86
81
|
? new Date(state.periodStart + this.resetPeriodMs).toISOString()
|
|
87
82
|
: undefined,
|
package/dist/plugin/fee.d.ts
CHANGED
|
@@ -4,11 +4,18 @@
|
|
|
4
4
|
* Static fee calculation for fee bump submissions matching launchtube.
|
|
5
5
|
* - For Soroban transactions: use resourceFee + inclusion fee (BASE_FEE * 2 + 3)
|
|
6
6
|
* - For non-Soroban: use NON_SOROBAN_FEE + inclusion fee
|
|
7
|
-
* -
|
|
7
|
+
* - Limited contracts (from LIMITED_CONTRACTS env) get reduced fee (BASE_FEE * 2 + 1)
|
|
8
8
|
*/
|
|
9
|
-
import { Transaction } from
|
|
10
|
-
export declare const KALE_CONTRACT = "CDL74RF5BLYR2YBLCCI7F5FB6TPSCLKEJUBSD2RSVWZ4YHF3VMFAIGWA";
|
|
9
|
+
import { Transaction, xdr } from '@stellar/stellar-sdk';
|
|
11
10
|
export declare const INCLUSION_FEE_DEFAULT: number;
|
|
12
|
-
export declare const
|
|
13
|
-
|
|
11
|
+
export declare const INCLUSION_FEE_LIMITED: number;
|
|
12
|
+
/**
|
|
13
|
+
* Extract contract ID from a HostFunction (for func+auth flow)
|
|
14
|
+
*/
|
|
15
|
+
export declare function getContractIdFromFunc(func: xdr.HostFunction): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Extract contract ID from a Transaction (for XDR flow)
|
|
18
|
+
*/
|
|
19
|
+
export declare function getContractIdFromTransaction(transaction: Transaction): string | undefined;
|
|
20
|
+
export declare function calculateMaxFee(transaction: Transaction, limitedContracts?: Set<string>): number;
|
|
14
21
|
//# 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;;;;;;;GAOG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"fee.d.ts","sourceRoot":"","sources":["../../src/plugin/fee.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,WAAW,EAAE,GAAG,EAAqB,MAAM,sBAAsB,CAAC;AAGrF,eAAO,MAAM,qBAAqB,QAA2B,CAAC;AAC9D,eAAO,MAAM,qBAAqB,QAA2B,CAAC;AAE9D;;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,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,MAAM,CAoB3G"}
|
package/dist/plugin/fee.js
CHANGED
|
@@ -5,39 +5,56 @@
|
|
|
5
5
|
* Static fee calculation for fee bump submissions matching launchtube.
|
|
6
6
|
* - For Soroban transactions: use resourceFee + inclusion fee (BASE_FEE * 2 + 3)
|
|
7
7
|
* - For non-Soroban: use NON_SOROBAN_FEE + inclusion fee
|
|
8
|
-
* -
|
|
8
|
+
* - Limited contracts (from LIMITED_CONTRACTS env) get reduced fee (BASE_FEE * 2 + 1)
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.
|
|
11
|
+
exports.INCLUSION_FEE_LIMITED = exports.INCLUSION_FEE_DEFAULT = void 0;
|
|
12
|
+
exports.getContractIdFromFunc = getContractIdFromFunc;
|
|
13
|
+
exports.getContractIdFromTransaction = getContractIdFromTransaction;
|
|
12
14
|
exports.calculateMaxFee = calculateMaxFee;
|
|
13
15
|
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
14
16
|
const constants_1 = require("./constants");
|
|
15
|
-
exports.KALE_CONTRACT = "CDL74RF5BLYR2YBLCCI7F5FB6TPSCLKEJUBSD2RSVWZ4YHF3VMFAIGWA";
|
|
16
17
|
exports.INCLUSION_FEE_DEFAULT = Number(stellar_sdk_1.BASE_FEE) * 2 + 3;
|
|
17
|
-
exports.
|
|
18
|
-
|
|
18
|
+
exports.INCLUSION_FEE_LIMITED = Number(stellar_sdk_1.BASE_FEE) * 2 + 1;
|
|
19
|
+
/**
|
|
20
|
+
* Extract contract ID from a HostFunction (for func+auth flow)
|
|
21
|
+
*/
|
|
22
|
+
function getContractIdFromFunc(func) {
|
|
23
|
+
try {
|
|
24
|
+
if (func.switch() !== stellar_sdk_1.xdr.HostFunctionType.hostFunctionTypeInvokeContract()) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const invokeContract = func.invokeContract();
|
|
28
|
+
return stellar_sdk_1.StrKey.encodeContract(invokeContract.contractAddress().contractId());
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extract contract ID from a Transaction (for XDR flow)
|
|
36
|
+
*/
|
|
37
|
+
function getContractIdFromTransaction(transaction) {
|
|
19
38
|
try {
|
|
20
39
|
if (transaction.operations.length !== 1)
|
|
21
|
-
return
|
|
40
|
+
return undefined;
|
|
22
41
|
const op = transaction.operations[0];
|
|
23
|
-
if (op.type !==
|
|
24
|
-
return
|
|
42
|
+
if (op.type !== 'invokeHostFunction')
|
|
43
|
+
return undefined;
|
|
25
44
|
const invokeOp = op;
|
|
26
|
-
|
|
27
|
-
stellar_sdk_1.xdr.HostFunctionType.hostFunctionTypeInvokeContract()) {
|
|
28
|
-
return exports.INCLUSION_FEE_DEFAULT;
|
|
29
|
-
}
|
|
30
|
-
const invokeContract = invokeOp.func.invokeContract();
|
|
31
|
-
const contract = stellar_sdk_1.StrKey.encodeContract(invokeContract.contractAddress().contractId());
|
|
32
|
-
return contract === exports.KALE_CONTRACT
|
|
33
|
-
? exports.INCLUSION_FEE_KALE
|
|
34
|
-
: exports.INCLUSION_FEE_DEFAULT;
|
|
45
|
+
return getContractIdFromFunc(invokeOp.func);
|
|
35
46
|
}
|
|
36
47
|
catch {
|
|
37
|
-
return
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function getInclusionFee(contractId, limitedContracts) {
|
|
52
|
+
if (contractId && limitedContracts.has(contractId)) {
|
|
53
|
+
return exports.INCLUSION_FEE_LIMITED;
|
|
38
54
|
}
|
|
55
|
+
return exports.INCLUSION_FEE_DEFAULT;
|
|
39
56
|
}
|
|
40
|
-
function calculateMaxFee(transaction) {
|
|
57
|
+
function calculateMaxFee(transaction, limitedContracts = new Set()) {
|
|
41
58
|
const envelope = transaction.toEnvelope();
|
|
42
59
|
let resourceFee = 0n;
|
|
43
60
|
if (envelope.switch() === stellar_sdk_1.xdr.EnvelopeType.envelopeTypeTx()) {
|
|
@@ -46,10 +63,9 @@ function calculateMaxFee(transaction) {
|
|
|
46
63
|
resourceFee = sorobanData.resourceFee().toBigInt();
|
|
47
64
|
}
|
|
48
65
|
}
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
: BigInt(constants_1.FEE.NON_SOROBAN_FEE + inclusionFee);
|
|
66
|
+
const contractId = getContractIdFromTransaction(transaction);
|
|
67
|
+
const inclusionFee = getInclusionFee(contractId, limitedContracts);
|
|
68
|
+
const fee = resourceFee > 0n ? resourceFee + BigInt(inclusionFee) : BigInt(constants_1.FEE.NON_SOROBAN_FEE + inclusionFee);
|
|
53
69
|
console.debug(`[channels] Calculated max_fee: ${Number(fee)} stroops (resourceFee: ${resourceFee}, inclusionFee: ${inclusionFee})`);
|
|
54
70
|
return Number(fee);
|
|
55
71
|
}
|
package/dist/plugin/handler.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Main handler for the channel accounts plugin.
|
|
5
5
|
* Orchestrates the transaction processing pipeline using channel accounts with fee bumping.
|
|
6
6
|
*/
|
|
7
|
-
import { PluginContext } from
|
|
8
|
-
import { Transaction, xdr } from
|
|
7
|
+
import { PluginContext } from '@openzeppelin/relayer-sdk';
|
|
8
|
+
import { Transaction, xdr } from '@stellar/stellar-sdk';
|
|
9
9
|
/**
|
|
10
10
|
* Extracts func and auth from an unsigned Soroban transaction.
|
|
11
11
|
* Returns null if the transaction is not a single invokeHostFunction operation.
|
|
@@ -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;
|
|
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;AAWxD;;;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;AAsOD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
|
package/dist/plugin/handler.js
CHANGED
|
@@ -44,14 +44,14 @@ function extractFuncAuthFromUnsignedXdr(tx) {
|
|
|
44
44
|
auth: invokeHostFn.auth(),
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
async function handleXdrSubmit(xdrStr, fundRelayer, fundAddress, network, networkPassphrase, api, pool, tracker) {
|
|
47
|
+
async function handleXdrSubmit(xdrStr, fundRelayer, fundAddress, network, networkPassphrase, api, pool, acquireOptions, tracker) {
|
|
48
48
|
const tx = new stellar_sdk_1.Transaction(xdrStr, networkPassphrase);
|
|
49
49
|
// Unsigned XDR: extract func+auth and route through channel path
|
|
50
50
|
if (tx.signatures.length === 0) {
|
|
51
51
|
const extracted = extractFuncAuthFromUnsignedXdr(tx);
|
|
52
52
|
if (!extracted) {
|
|
53
|
-
throw (0, relayer_sdk_1.pluginError)(
|
|
54
|
-
code:
|
|
53
|
+
throw (0, relayer_sdk_1.pluginError)('Unsigned XDR must contain exactly one invokeHostFunction operation', {
|
|
54
|
+
code: 'INVALID_UNSIGNED_XDR',
|
|
55
55
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
56
56
|
details: {
|
|
57
57
|
operationCount: tx.operations.length,
|
|
@@ -60,41 +60,54 @@ async function handleXdrSubmit(xdrStr, fundRelayer, fundAddress, network, networ
|
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
console.log(`[channels] Unsigned XDR detected, extracting func+auth and routing through channel path`);
|
|
63
|
-
|
|
63
|
+
// Update acquireOptions with contractId from extracted func
|
|
64
|
+
const contractId = (0, fee_1.getContractIdFromFunc)(extracted.func);
|
|
65
|
+
const updatedOptions = { ...acquireOptions, contractId };
|
|
66
|
+
return handleFuncAuthSubmit(extracted.func, extracted.auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, updatedOptions, tracker);
|
|
64
67
|
}
|
|
65
68
|
const validated = (0, tx_1.validateExistingTransactionForSubmitOnly)(tx);
|
|
66
|
-
const maxFee = (0, fee_1.calculateMaxFee)(validated);
|
|
69
|
+
const maxFee = (0, fee_1.calculateMaxFee)(validated, acquireOptions.limitedContracts);
|
|
67
70
|
await tracker?.checkBudget(maxFee);
|
|
68
71
|
return (0, submit_1.submitWithFeeBumpAndWait)(fundRelayer, validated.toXDR(), network, maxFee, api, tracker);
|
|
69
72
|
}
|
|
70
|
-
async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, tracker) {
|
|
73
|
+
async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, acquireOptions, tracker) {
|
|
74
|
+
// Simulate once — used for both read-only detection and transaction assembly
|
|
75
|
+
const simulation = await (0, simulation_1.simulateTransaction)(func, auth, fundAddress, fundRelayer, networkPassphrase);
|
|
76
|
+
if (simulation.isReadOnly) {
|
|
77
|
+
console.log(`[channels] Read-only call detected, returning simulation result`);
|
|
78
|
+
return {
|
|
79
|
+
transactionId: null,
|
|
80
|
+
status: 'readonly',
|
|
81
|
+
hash: null,
|
|
82
|
+
returnValue: simulation.returnValue,
|
|
83
|
+
latestLedger: simulation.latestLedger,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
71
86
|
let poolLock;
|
|
72
87
|
try {
|
|
73
|
-
poolLock = await pool.acquire();
|
|
88
|
+
poolLock = await pool.acquire(acquireOptions);
|
|
74
89
|
const channelRelayer = api.useRelayer(poolLock.relayerId);
|
|
75
90
|
const channelInfo = await channelRelayer.getRelayer();
|
|
76
91
|
console.log(`[channels] Acquired channel: ${poolLock.relayerId}`);
|
|
77
92
|
if (!channelInfo || !channelInfo.address) {
|
|
78
|
-
throw (0, relayer_sdk_1.pluginError)(
|
|
79
|
-
code:
|
|
93
|
+
throw (0, relayer_sdk_1.pluginError)('Channel relayer not found', {
|
|
94
|
+
code: 'RELAYER_UNAVAILABLE',
|
|
80
95
|
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
81
96
|
details: { relayerId: poolLock.relayerId },
|
|
82
97
|
});
|
|
83
98
|
}
|
|
84
99
|
const channelStatus = await channelRelayer.getRelayerStatus();
|
|
85
|
-
if (channelStatus.network_type !==
|
|
86
|
-
throw (0, relayer_sdk_1.pluginError)(
|
|
87
|
-
code:
|
|
100
|
+
if (channelStatus.network_type !== 'stellar') {
|
|
101
|
+
throw (0, relayer_sdk_1.pluginError)('Channel relayer network type must be stellar', {
|
|
102
|
+
code: 'UNSUPPORTED_NETWORK',
|
|
88
103
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
89
|
-
details: {
|
|
90
|
-
network_type: channelStatus.network_type,
|
|
91
|
-
relayerId: poolLock.relayerId,
|
|
92
|
-
},
|
|
104
|
+
details: { network_type: channelStatus.network_type, relayerId: poolLock.relayerId },
|
|
93
105
|
});
|
|
94
106
|
}
|
|
95
|
-
|
|
107
|
+
// 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: channelStatus.sequence_number }, networkPassphrase, simulation.rawSimResult);
|
|
96
109
|
const signedTx = await (0, submit_1.signWithChannelAndFund)(built, channelRelayer, fundRelayer, channelInfo.address, fundAddress, networkPassphrase);
|
|
97
|
-
const maxFee = (0, fee_1.calculateMaxFee)(signedTx);
|
|
110
|
+
const maxFee = (0, fee_1.calculateMaxFee)(signedTx, acquireOptions.limitedContracts);
|
|
98
111
|
await tracker?.checkBudget(maxFee);
|
|
99
112
|
return await (0, submit_1.submitWithFeeBumpAndWait)(fundRelayer, signedTx.toXDR(), network, maxFee, api, tracker);
|
|
100
113
|
}
|
|
@@ -119,8 +132,8 @@ async function channelAccounts(context) {
|
|
|
119
132
|
const apiKey = getApiKey(headers, config.apiKeyHeader);
|
|
120
133
|
// If default limit is set, require API key
|
|
121
134
|
if (config.feeLimit !== undefined && !apiKey) {
|
|
122
|
-
throw (0, relayer_sdk_1.pluginError)(
|
|
123
|
-
code:
|
|
135
|
+
throw (0, relayer_sdk_1.pluginError)('API key required', {
|
|
136
|
+
code: 'API_KEY_REQUIRED',
|
|
124
137
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
125
138
|
});
|
|
126
139
|
}
|
|
@@ -136,34 +149,39 @@ async function channelAccounts(context) {
|
|
|
136
149
|
}
|
|
137
150
|
// 1. Validate and parse request (xdr OR func+auth)
|
|
138
151
|
const request = (0, validation_1.validateAndParseRequest)(params);
|
|
139
|
-
console.debug(`[channels] Request type: ${request.type}, auth entries: ${request.type ===
|
|
152
|
+
console.debug(`[channels] Request type: ${request.type}, auth entries: ${request.type === 'func-auth' ? request.auth.length : 'N/A'}`);
|
|
140
153
|
// 2. Get fund relayer
|
|
141
154
|
const fundRelayer = api.useRelayer(config.fundRelayerId);
|
|
142
155
|
const fundInfo = await fundRelayer.getRelayer();
|
|
143
156
|
if (!fundInfo || !fundInfo.address) {
|
|
144
|
-
throw (0, relayer_sdk_1.pluginError)(
|
|
145
|
-
code:
|
|
157
|
+
throw (0, relayer_sdk_1.pluginError)('Fund relayer not found', {
|
|
158
|
+
code: 'RELAYER_UNAVAILABLE',
|
|
146
159
|
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
147
160
|
details: { relayerId: config.fundRelayerId },
|
|
148
161
|
});
|
|
149
162
|
}
|
|
150
|
-
if (fundInfo.network_type !==
|
|
151
|
-
throw (0, relayer_sdk_1.pluginError)(
|
|
152
|
-
code:
|
|
163
|
+
if (fundInfo.network_type !== 'stellar') {
|
|
164
|
+
throw (0, relayer_sdk_1.pluginError)('Fund relayer network type must be stellar', {
|
|
165
|
+
code: 'UNSUPPORTED_NETWORK',
|
|
153
166
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
154
|
-
details: {
|
|
155
|
-
network_type: fundInfo.network_type,
|
|
156
|
-
relayerId: config.fundRelayerId,
|
|
157
|
-
},
|
|
167
|
+
details: { network_type: fundInfo.network_type, relayerId: config.fundRelayerId },
|
|
158
168
|
});
|
|
159
169
|
}
|
|
160
|
-
// 3.
|
|
161
|
-
|
|
170
|
+
// 3. Build acquire options for contract capacity limits
|
|
171
|
+
const acquireOptions = {
|
|
172
|
+
limitedContracts: config.limitedContracts,
|
|
173
|
+
capacityRatio: config.contractCapacityRatio,
|
|
174
|
+
};
|
|
175
|
+
// 4. Branch by request type
|
|
176
|
+
if (request.type === 'xdr') {
|
|
162
177
|
console.log(`[channels] Flow: XDR submit-only`);
|
|
163
|
-
return await handleXdrSubmit(request.xdr, fundRelayer, fundInfo.address, config.network, networkPassphrase, api, pool, tracker);
|
|
178
|
+
return await handleXdrSubmit(request.xdr, fundRelayer, fundInfo.address, config.network, networkPassphrase, api, pool, acquireOptions, tracker);
|
|
164
179
|
}
|
|
180
|
+
// Extract contractId for func+auth flow
|
|
181
|
+
const contractId = (0, fee_1.getContractIdFromFunc)(request.func);
|
|
182
|
+
const funcAcquireOptions = { ...acquireOptions, contractId };
|
|
165
183
|
console.log(`[channels] Flow: func+auth with channel account`);
|
|
166
|
-
return await handleFuncAuthSubmit(request.func, request.auth, api, pool, fundRelayer, fundInfo.address, config.network, networkPassphrase, tracker);
|
|
184
|
+
return await handleFuncAuthSubmit(request.func, request.auth, api, pool, fundRelayer, fundInfo.address, config.network, networkPassphrase, funcAcquireOptions, tracker);
|
|
167
185
|
}
|
|
168
186
|
/**
|
|
169
187
|
* Main plugin handler exported for OpenZeppelin Relayer
|
package/dist/plugin/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - setFeeLimit: sets custom limit for an API key
|
|
10
10
|
* - deleteFeeLimit: removes custom limit for an API key
|
|
11
11
|
*/
|
|
12
|
-
import type { PluginContext } from
|
|
12
|
+
import type { PluginContext } from '@openzeppelin/relayer-sdk';
|
|
13
13
|
export declare function isManagementRequest(params: any): boolean;
|
|
14
14
|
export declare function handleManagement(context: PluginContext): Promise<any>;
|
|
15
15
|
//# sourceMappingURL=management.d.ts.map
|
|
@@ -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;AAM9E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,
|
|
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;AAM9E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAIxD;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAkC3E"}
|