@openzeppelin/relayer-plugin-channels 0.11.0 → 0.12.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 +50 -2
- package/dist/plugin/config.d.ts +1 -0
- package/dist/plugin/config.d.ts.map +1 -1
- package/dist/plugin/config.js +8 -0
- package/dist/plugin/constants.d.ts +3 -0
- package/dist/plugin/constants.d.ts.map +1 -1
- package/dist/plugin/constants.js +3 -0
- package/dist/plugin/handler.d.ts.map +1 -1
- package/dist/plugin/handler.js +3 -3
- package/dist/plugin/simulation.d.ts +1 -1
- package/dist/plugin/simulation.d.ts.map +1 -1
- package/dist/plugin/simulation.js +36 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -233,6 +233,12 @@ export CONTRACT_CAPACITY_RATIO=0.8 # Max ratio of pool for limited contra
|
|
|
233
233
|
# Inclusion fee overrides (optional)
|
|
234
234
|
export INCLUSION_FEE_DEFAULT=203 # Inclusion fee in stroops for regular contracts (default: BASE_FEE * 2 + 3 = 203)
|
|
235
235
|
export INCLUSION_FEE_LIMITED=201 # Inclusion fee in stroops for limited contracts (default: BASE_FEE * 2 + 1 = 201)
|
|
236
|
+
|
|
237
|
+
# Sequence number cache (optional)
|
|
238
|
+
export SEQUENCE_NUMBER_CACHE_MAX_AGE_MS=120000 # Max age of cached sequence numbers in ms (default: 120000)
|
|
239
|
+
|
|
240
|
+
# Auth expiry validation (optional)
|
|
241
|
+
export MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER=2 # Minimum ledger margin for auth entry signatureExpirationLedger (default: 2)
|
|
236
242
|
```
|
|
237
243
|
|
|
238
244
|
Your Relayer should now contain:
|
|
@@ -940,25 +946,67 @@ Plugin error example:
|
|
|
940
946
|
- **Key**: `<network>:api-key-limit:<apiKey>`
|
|
941
947
|
- **Value**: `{ limit: number }` (custom fee limit in stroops)
|
|
942
948
|
|
|
949
|
+
### Sequence Number Cache
|
|
950
|
+
|
|
951
|
+
- **Key**: `<network>:channel:seq:<address>`
|
|
952
|
+
- **Value**: `{ sequence: string, storedAt: number }` (sequence number and cache timestamp in ms)
|
|
953
|
+
|
|
943
954
|
## Error Codes
|
|
944
955
|
|
|
956
|
+
### Configuration
|
|
957
|
+
|
|
945
958
|
- `CONFIG_MISSING`: Missing required environment variable
|
|
959
|
+
- `CONFIG_INVALID`: Invalid configuration value (e.g., invalid contract address in `LIMITED_CONTRACTS`)
|
|
946
960
|
- `UNSUPPORTED_NETWORK`: Invalid network type
|
|
961
|
+
|
|
962
|
+
### Request Validation
|
|
963
|
+
|
|
947
964
|
- `INVALID_PARAMS`: Invalid request parameters
|
|
948
965
|
- `INVALID_XDR`: Failed to parse XDR
|
|
949
966
|
- `INVALID_ENVELOPE_TYPE`: Not a regular transaction envelope
|
|
967
|
+
- `INVALID_UNSIGNED_XDR`: Unsigned XDR must contain exactly one `invokeHostFunction` operation
|
|
950
968
|
- `INVALID_TIME_BOUNDS`: TimeBounds too far in the future
|
|
969
|
+
- `TIMEBOUNDS_EXPIRED`: Transaction timebounds have expired
|
|
970
|
+
- `TIMEBOUNDS_TOO_FAR`: Transaction timebounds maxTime too far in the future
|
|
971
|
+
- `FEE_MISMATCH`: Fee mismatch in signed transaction
|
|
972
|
+
- `INVALID_OPERATION_SOURCE`: Operation source does not match transaction source
|
|
973
|
+
|
|
974
|
+
### Pool & Channel
|
|
975
|
+
|
|
951
976
|
- `NO_CHANNELS_CONFIGURED`: No channel accounts have been configured via management API
|
|
952
977
|
- `POOL_CAPACITY`: All channel accounts in use
|
|
953
978
|
- `RELAYER_UNAVAILABLE`: Relayer not found
|
|
979
|
+
- `FAILED_TO_GET_SEQUENCE`: Failed to fetch channel account sequence number
|
|
980
|
+
- `ACCOUNT_NOT_FOUND`: Channel account not found on the ledger
|
|
981
|
+
|
|
982
|
+
### Simulation & Assembly
|
|
983
|
+
|
|
954
984
|
- `SIMULATION_FAILED`: Transaction simulation failed
|
|
985
|
+
- `SIMULATION_NETWORK_ERROR`: Simulation network request failed (HTTP 502)
|
|
986
|
+
- `SIMULATION_RPC_FAILURE`: Simulation RPC provider error (HTTP 502)
|
|
987
|
+
- `SIMULATION_SIGNED_AUTH_VALIDATION_FAILED`: Signed auth entry validation failed in enforce-mode simulation
|
|
988
|
+
- `AUTH_EXPIRY_TOO_SHORT`: Auth entry `signatureExpirationLedger` too close to current ledger
|
|
989
|
+
- `ASSEMBLY_FAILED`: Transaction assembly failed
|
|
990
|
+
|
|
991
|
+
### Submission
|
|
992
|
+
|
|
993
|
+
- `INVALID_SIGNATURE`: Invalid channel signature response
|
|
955
994
|
- `ONCHAIN_FAILED`: Transaction failed on-chain
|
|
956
995
|
- `WAIT_TIMEOUT`: Transaction wait timeout
|
|
996
|
+
|
|
997
|
+
### Fee Tracking
|
|
998
|
+
|
|
999
|
+
- `API_KEY_REQUIRED`: API key header missing when `FEE_LIMIT` is configured
|
|
1000
|
+
- `FEE_LIMIT_EXCEEDED`: API key has exceeded its fee limit (HTTP 429)
|
|
1001
|
+
|
|
1002
|
+
### Management
|
|
1003
|
+
|
|
957
1004
|
- `MANAGEMENT_DISABLED`: Management API not enabled
|
|
958
1005
|
- `UNAUTHORIZED`: Invalid admin secret
|
|
1006
|
+
- `INVALID_ACTION`: Invalid management action
|
|
1007
|
+
- `INVALID_PAYLOAD`: Invalid management request payload
|
|
959
1008
|
- `LOCKED_CONFLICT`: Cannot remove locked channel accounts
|
|
960
|
-
- `
|
|
961
|
-
- `FEE_LIMIT_EXCEEDED`: API key has exceeded its fee limit (HTTP 429)
|
|
1009
|
+
- `KV_ERROR`: KV store operation failed
|
|
962
1010
|
|
|
963
1011
|
## License
|
|
964
1012
|
|
package/dist/plugin/config.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2BAA2B,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/plugin/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2BAA2B,EAAE,MAAM,CAAC;IACpC,kCAAkC,EAAE,MAAM,CAAC;CAC5C;AA0GD;;GAEG;AACH,wBAAgB,UAAU,IAAI,qBAAqB,CAwBlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAE3E"}
|
package/dist/plugin/config.js
CHANGED
|
@@ -91,6 +91,13 @@ function parseInclusionFee(envVar, defaultValue) {
|
|
|
91
91
|
return defaultValue;
|
|
92
92
|
return Math.floor(n);
|
|
93
93
|
}
|
|
94
|
+
function parseMinAuthExpiryLedgerBuffer() {
|
|
95
|
+
const raw = process.env.MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER;
|
|
96
|
+
if (!raw)
|
|
97
|
+
return constants_1.CONFIG.DEFAULT_MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER;
|
|
98
|
+
const n = Number(raw);
|
|
99
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : constants_1.CONFIG.DEFAULT_MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER;
|
|
100
|
+
}
|
|
94
101
|
function parseSequenceNumberCacheMaxAge() {
|
|
95
102
|
const raw = process.env.SEQUENCE_NUMBER_CACHE_MAX_AGE_MS;
|
|
96
103
|
if (!raw)
|
|
@@ -132,6 +139,7 @@ function loadConfig() {
|
|
|
132
139
|
inclusionFeeDefault: parseInclusionFee('INCLUSION_FEE_DEFAULT', DEFAULT_INCLUSION_FEE_DEFAULT),
|
|
133
140
|
inclusionFeeLimited: parseInclusionFee('INCLUSION_FEE_LIMITED', DEFAULT_INCLUSION_FEE_LIMITED),
|
|
134
141
|
sequenceNumberCacheMaxAgeMs: parseSequenceNumberCacheMaxAge(),
|
|
142
|
+
minSignatureExpirationLedgerBuffer: parseMinAuthExpiryLedgerBuffer(),
|
|
135
143
|
};
|
|
136
144
|
}
|
|
137
145
|
/**
|
|
@@ -20,6 +20,7 @@ export declare const CONFIG: {
|
|
|
20
20
|
readonly MAX_LOCK_TTL_SECONDS: 30;
|
|
21
21
|
readonly DEFAULT_CONTRACT_CAPACITY_RATIO: 0.8;
|
|
22
22
|
readonly DEFAULT_SEQUENCE_NUMBER_CACHE_MAX_AGE_MS: 120000;
|
|
23
|
+
readonly DEFAULT_MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER: 2;
|
|
23
24
|
};
|
|
24
25
|
export declare const POOL: {
|
|
25
26
|
readonly MUTEX_TTL_SECONDS: 1;
|
|
@@ -36,6 +37,8 @@ export declare const SIMULATION: {
|
|
|
36
37
|
readonly MAX_TIME_BOUND_OFFSET_SECONDS: 120;
|
|
37
38
|
readonly MAX_FUTURE_TIME_BOUND_SECONDS: 120;
|
|
38
39
|
readonly SIMULATION_AUTH_MODE: "enforce";
|
|
40
|
+
/** Minimum ledger margin required between latestLedger and auth signatureExpirationLedger. Must be > 1 since simulation already validates 1 ledger of validity. ~10s at ~5s/ledger. */
|
|
41
|
+
readonly MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER: 2;
|
|
39
42
|
};
|
|
40
43
|
export declare const POLLING: {
|
|
41
44
|
readonly INTERVAL_MS: 1000;
|
|
@@ -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;;;;;;;CAOT,CAAC;AAGX,eAAO,MAAM,IAAI;;;;;CAOP,CAAC;AAGX,eAAO,MAAM,IAAI;;CAEP,CAAC;AAGX,eAAO,MAAM,UAAU;;;;;;IAMrB,uLAAuL;;CAE/K,CAAC;AAGX,eAAO,MAAM,OAAO;;;CAGV,CAAC;AAEX,eAAO,MAAM,GAAG;;CAGN,CAAC"}
|
package/dist/plugin/constants.js
CHANGED
|
@@ -25,6 +25,7 @@ exports.CONFIG = {
|
|
|
25
25
|
MAX_LOCK_TTL_SECONDS: 30,
|
|
26
26
|
DEFAULT_CONTRACT_CAPACITY_RATIO: 0.8,
|
|
27
27
|
DEFAULT_SEQUENCE_NUMBER_CACHE_MAX_AGE_MS: 120000,
|
|
28
|
+
DEFAULT_MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER: 2,
|
|
28
29
|
};
|
|
29
30
|
// Pool Constants
|
|
30
31
|
exports.POOL = {
|
|
@@ -46,6 +47,8 @@ exports.SIMULATION = {
|
|
|
46
47
|
MAX_TIME_BOUND_OFFSET_SECONDS: 120,
|
|
47
48
|
MAX_FUTURE_TIME_BOUND_SECONDS: 120,
|
|
48
49
|
SIMULATION_AUTH_MODE: 'enforce',
|
|
50
|
+
/** Minimum ledger margin required between latestLedger and auth signatureExpirationLedger. Must be > 1 since simulation already validates 1 ledger of validity. ~10s at ~5s/ledger. */
|
|
51
|
+
MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER: 2,
|
|
49
52
|
};
|
|
50
53
|
// Polling for transactionWait
|
|
51
54
|
exports.POLLING = {
|
|
@@ -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;AA0BxD;;;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;
|
|
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;AA0BxD;;;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;AAsPD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
|
package/dist/plugin/handler.js
CHANGED
|
@@ -109,9 +109,9 @@ async function handleFuncAuthSubmit(func, auth, ctx) {
|
|
|
109
109
|
details: { network_type: channelInfo.network_type, relayerId: poolLock.relayerId },
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
|
-
const sequence = await (0, sequence_1.getSequence)(ctx.kv, ctx.network, channelRelayer, channelInfo.address, ctx.sequenceNumberCacheMaxAgeMs);
|
|
112
|
+
const sequence = await (0, sequence_1.getSequence)(ctx.kv, ctx.network, channelRelayer, channelInfo.address, ctx.config.sequenceNumberCacheMaxAgeMs);
|
|
113
113
|
// Assemble the transaction using the cached simulation result — no second RPC call
|
|
114
|
-
const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence }, ctx.networkPassphrase, simulation.rawSimResult);
|
|
114
|
+
const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence }, ctx.networkPassphrase, simulation.rawSimResult, ctx.config.minSignatureExpirationLedgerBuffer);
|
|
115
115
|
const signedTx = await (0, submit_1.signWithChannelAndFund)(built, channelRelayer, ctx.fundRelayer, channelInfo.address, ctx.fundAddress, ctx.networkPassphrase);
|
|
116
116
|
const maxFee = (0, fee_1.calculateMaxFee)(signedTx, ctx.acquireOptions.limitedContracts, ctx.fees);
|
|
117
117
|
const contractId = (0, fee_1.getContractIdFromFunc)(func);
|
|
@@ -212,7 +212,7 @@ async function channelAccounts(context) {
|
|
|
212
212
|
acquireOptions,
|
|
213
213
|
fees,
|
|
214
214
|
tracker,
|
|
215
|
-
|
|
215
|
+
config,
|
|
216
216
|
};
|
|
217
217
|
// 5. Branch by request type
|
|
218
218
|
if (request.type === 'xdr') {
|
|
@@ -39,7 +39,7 @@ export declare function simulateTransaction(func: xdr.HostFunction, auth: xdr.So
|
|
|
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): Transaction;
|
|
42
|
+
export declare function buildWithChannel(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, channel: ChannelAccount, networkPassphrase: string, simResult: rpc.Api.RawSimulateTransactionResponse, minSignatureExpirationLedgerBuffer?: number): Transaction;
|
|
43
43
|
/** Extract human-readable message + error type from simulation error diagnostic events */
|
|
44
44
|
export declare function parseSimulationError(error: string): string;
|
|
45
45
|
//# 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,
|
|
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,CA4Cb;AA4CD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAe1D"}
|
|
@@ -104,7 +104,12 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
|
|
|
104
104
|
* Build and assemble a transaction using a channel account and an already-
|
|
105
105
|
* obtained simulation result. No additional network calls are made.
|
|
106
106
|
*/
|
|
107
|
-
function buildWithChannel(func, auth, channel, networkPassphrase, simResult) {
|
|
107
|
+
function buildWithChannel(func, auth, channel, networkPassphrase, simResult, minSignatureExpirationLedgerBuffer = constants_1.SIMULATION.MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER) {
|
|
108
|
+
// Fail fast: reject auth entries whose signatureExpirationLedger is too close
|
|
109
|
+
// to latestLedger before doing any assembly work.
|
|
110
|
+
if (simResult.latestLedger) {
|
|
111
|
+
validateAuthExpiry(auth, simResult.latestLedger, minSignatureExpirationLedgerBuffer);
|
|
112
|
+
}
|
|
108
113
|
const now = Math.floor(Date.now() / 1000);
|
|
109
114
|
console.debug(`[channels] Building tx: channel=${channel.address}, seq=${channel.sequence}, auth_count=${auth?.length ?? 0}`);
|
|
110
115
|
// Build inner transaction (source = channel)
|
|
@@ -137,6 +142,36 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult) {
|
|
|
137
142
|
});
|
|
138
143
|
}
|
|
139
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Reject transactions where any address-credentialed auth entry has a
|
|
147
|
+
* signatureExpirationLedger too close to the current ledger. This catches
|
|
148
|
+
* tight expiries early instead of failing on-chain with "signature has expired".
|
|
149
|
+
*/
|
|
150
|
+
function validateAuthExpiry(authEntries, latestLedger, minBuffer) {
|
|
151
|
+
if (!authEntries?.length)
|
|
152
|
+
return;
|
|
153
|
+
for (const entry of authEntries) {
|
|
154
|
+
const creds = entry.credentials();
|
|
155
|
+
if (creds.switch() !== stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsAddress()) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const expiry = creds.address().signatureExpirationLedger();
|
|
159
|
+
const margin = expiry - latestLedger;
|
|
160
|
+
if (margin < minBuffer) {
|
|
161
|
+
console.error(`[channels] Auth entry signatureExpirationLedger too close to current ledger (expires in ${margin} ledgers, minimum ${minBuffer} required)`);
|
|
162
|
+
throw (0, relayer_sdk_1.pluginError)(`Auth entry signatureExpirationLedger too close to current ledger (expires in ${margin} ledgers, minimum ${minBuffer} required)`, {
|
|
163
|
+
code: 'AUTH_EXPIRY_TOO_SHORT',
|
|
164
|
+
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
165
|
+
details: {
|
|
166
|
+
signatureExpirationLedger: expiry,
|
|
167
|
+
latestLedger,
|
|
168
|
+
margin,
|
|
169
|
+
minimumRequired: minBuffer,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
140
175
|
/** Extract human-readable message + error type from simulation error diagnostic events */
|
|
141
176
|
function parseSimulationError(error) {
|
|
142
177
|
const firstLine = error.split('\n')[0]?.trim() || 'Simulation failed';
|