@taquito/taquito 25.0.0-beta.1 → 25.0.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 +1 -1
- package/dist/lib/estimate/errors.js +11 -1
- package/dist/lib/estimate/rpc-estimate-provider.js +171 -10
- package/dist/lib/version.js +2 -2
- package/dist/taquito.es6.js +183 -13
- package/dist/taquito.es6.js.map +1 -1
- package/dist/taquito.min.js +1 -1
- package/dist/taquito.min.js.LICENSE.txt +0 -2
- package/dist/taquito.umd.js +183 -12
- package/dist/taquito.umd.js.map +1 -1
- package/dist/types/estimate/errors.d.ts +5 -0
- package/dist/types/estimate/rpc-estimate-provider.d.ts +9 -0
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ The `@taquito/taquito` package contains higher-level functionality that builds u
|
|
|
7
7
|
## CDN Bundle
|
|
8
8
|
|
|
9
9
|
```html
|
|
10
|
-
<script src="https://unpkg.com/@taquito/taquito@25.0.0
|
|
10
|
+
<script src="https://unpkg.com/@taquito/taquito@25.0.0/dist/taquito.min.js"
|
|
11
11
|
crossorigin="anonymous" integrity="sha384-IxvP0ECHi5oqLyz94wF85pU9+ktcsL1HHtA42MITxZsGbsUMEu/g+0Vkjj5vqiMR"></script>
|
|
12
12
|
```
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RevealEstimateError = void 0;
|
|
3
|
+
exports.BatchGasLimitExceededError = exports.RevealEstimateError = void 0;
|
|
4
4
|
const core_1 = require("@taquito/core");
|
|
5
5
|
/**
|
|
6
6
|
* @category Error
|
|
@@ -14,3 +14,13 @@ class RevealEstimateError extends core_1.TaquitoError {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
exports.RevealEstimateError = RevealEstimateError;
|
|
17
|
+
class BatchGasLimitExceededError extends core_1.TaquitoError {
|
|
18
|
+
constructor(requiredGasLimit, hardGasLimitPerBlock) {
|
|
19
|
+
super();
|
|
20
|
+
this.requiredGasLimit = requiredGasLimit;
|
|
21
|
+
this.hardGasLimitPerBlock = hardGasLimitPerBlock;
|
|
22
|
+
this.name = 'BatchGasLimitExceededError';
|
|
23
|
+
this.message = `Batch gas estimation requires at least ${requiredGasLimit} gas, which exceeds the per-block limit of ${hardGasLimitPerBlock}. Split the batch into smaller operations.`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.BatchGasLimitExceededError = BatchGasLimitExceededError;
|
|
@@ -28,6 +28,7 @@ class RPCEstimateProvider extends provider_1.Provider {
|
|
|
28
28
|
this.REVEAL_LENGTH_TZ4 = 622; // injecting size tz4=620
|
|
29
29
|
this.MILLIGAS_BUFFER = 100 * 1000; // 100 buffer depends on operation kind
|
|
30
30
|
this.STORAGE_BUFFER = 20; // according to octez-client
|
|
31
|
+
this.UNKNOWN_GAS_LIMIT_PER_OPERATION = 1000;
|
|
31
32
|
this.prepare = new prepare_provider_1.PrepareProvider(this.context);
|
|
32
33
|
}
|
|
33
34
|
async getKeys() {
|
|
@@ -85,6 +86,129 @@ class RPCEstimateProvider extends provider_1.Provider {
|
|
|
85
86
|
};
|
|
86
87
|
}
|
|
87
88
|
}
|
|
89
|
+
hasOperationGasExhausted(errors) {
|
|
90
|
+
return errors.some((error) => error.id.endsWith('gas_exhausted.operation'));
|
|
91
|
+
}
|
|
92
|
+
getOperationResult(content) {
|
|
93
|
+
return content?.metadata?.operation_result;
|
|
94
|
+
}
|
|
95
|
+
getInternalOperationResults(content) {
|
|
96
|
+
const internalResults = content?.metadata?.internal_operation_results;
|
|
97
|
+
return Array.isArray(internalResults) ? internalResults : [];
|
|
98
|
+
}
|
|
99
|
+
operationResultHasGasExhausted(result) {
|
|
100
|
+
return Array.isArray(result?.errors)
|
|
101
|
+
? result.errors.some((error) => error.id?.endsWith('gas_exhausted.operation'))
|
|
102
|
+
: false;
|
|
103
|
+
}
|
|
104
|
+
findGasExhaustedContentIndex(contents) {
|
|
105
|
+
const directFailureIndex = contents.findIndex((content) => this.operationResultHasGasExhausted(this.getOperationResult(content)));
|
|
106
|
+
if (directFailureIndex !== -1) {
|
|
107
|
+
return directFailureIndex;
|
|
108
|
+
}
|
|
109
|
+
const internalFailureIndex = contents.findIndex((content) => this.getInternalOperationResults(content).some((internalResult) => this.operationResultHasGasExhausted(internalResult.result)));
|
|
110
|
+
if (internalFailureIndex !== -1) {
|
|
111
|
+
return internalFailureIndex;
|
|
112
|
+
}
|
|
113
|
+
const firstSkippedIndex = contents.findIndex((content) => this.getOperationResult(content)?.status === 'skipped');
|
|
114
|
+
return firstSkippedIndex > 0 ? firstSkippedIndex - 1 : -1;
|
|
115
|
+
}
|
|
116
|
+
getContentGasLimit(content) {
|
|
117
|
+
const gasLimit = Number(content?.gas_limit);
|
|
118
|
+
return Number.isFinite(gasLimit) && gasLimit >= 0 ? gasLimit : 0;
|
|
119
|
+
}
|
|
120
|
+
getMeasuredGasLimit(content, hardGasLimitPerOperation) {
|
|
121
|
+
const operationResults = (0, errors_1.flattenOperationResult)({ contents: [content] });
|
|
122
|
+
const consumedMilligas = operationResults.reduce((total, result) => total + (Number(result.consumed_milligas) || 0), 0);
|
|
123
|
+
if (consumedMilligas <= 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const safetyGas = (0, types_1.isOpWithGasBuffer)(content) ? this.MILLIGAS_BUFFER / 1000 : 0;
|
|
127
|
+
return Math.min(Math.ceil(consumedMilligas / 1000) + safetyGas, hardGasLimitPerOperation);
|
|
128
|
+
}
|
|
129
|
+
rebalanceGasLimits(op, opResponse, preparedOperation, constants) {
|
|
130
|
+
const hardGasLimitPerOperation = Number(constants.hard_gas_limit_per_operation);
|
|
131
|
+
const hardGasLimitPerBlock = Number(constants.hard_gas_limit_per_block);
|
|
132
|
+
const patchableIndexes = preparedOperation.simulation?.gasLimitPatchableIndexes?.filter((index) => index >= 0 && index < opResponse.contents.length);
|
|
133
|
+
if (!Array.isArray(op.operation.contents) ||
|
|
134
|
+
!patchableIndexes?.length ||
|
|
135
|
+
!Number.isFinite(hardGasLimitPerOperation) ||
|
|
136
|
+
!Number.isFinite(hardGasLimitPerBlock)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const responseContents = opResponse.contents;
|
|
140
|
+
const starvedIndex = this.findGasExhaustedContentIndex(responseContents);
|
|
141
|
+
if (starvedIndex === -1 || !patchableIndexes.includes(starvedIndex)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const patchableIndexSet = new Set(patchableIndexes);
|
|
145
|
+
const contents = op.operation.contents.map((content) => ({
|
|
146
|
+
...content,
|
|
147
|
+
}));
|
|
148
|
+
const patchedGasLimits = new Map();
|
|
149
|
+
let fixedGasTotal = 0;
|
|
150
|
+
let measuredGasTotal = 0;
|
|
151
|
+
const unknownPatchableIndexes = [];
|
|
152
|
+
for (const [index, content] of responseContents.entries()) {
|
|
153
|
+
if (!patchableIndexSet.has(index)) {
|
|
154
|
+
fixedGasTotal += this.getContentGasLimit(contents[index]);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (index === starvedIndex) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const status = this.getOperationResult(content)?.status;
|
|
161
|
+
const measuredGasLimit = status === 'applied' || status === 'backtracked'
|
|
162
|
+
? this.getMeasuredGasLimit(content, hardGasLimitPerOperation)
|
|
163
|
+
: undefined;
|
|
164
|
+
if (typeof measuredGasLimit === 'number') {
|
|
165
|
+
patchedGasLimits.set(index, measuredGasLimit);
|
|
166
|
+
measuredGasTotal += measuredGasLimit;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
unknownPatchableIndexes.push(index);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const requiredKnownGas = fixedGasTotal + measuredGasTotal;
|
|
173
|
+
if (requiredKnownGas > hardGasLimitPerBlock) {
|
|
174
|
+
throw new errors_2.BatchGasLimitExceededError(requiredKnownGas, hardGasLimitPerBlock);
|
|
175
|
+
}
|
|
176
|
+
const gasAvailableAfterKnown = hardGasLimitPerBlock - requiredKnownGas;
|
|
177
|
+
const minimumUnknownGas = unknownPatchableIndexes.length + 1;
|
|
178
|
+
if (gasAvailableAfterKnown < minimumUnknownGas) {
|
|
179
|
+
throw new errors_2.BatchGasLimitExceededError(requiredKnownGas + minimumUnknownGas, hardGasLimitPerBlock);
|
|
180
|
+
}
|
|
181
|
+
const unknownGasLimit = unknownPatchableIndexes.length > 0
|
|
182
|
+
? Math.min(this.UNKNOWN_GAS_LIMIT_PER_OPERATION, Math.floor((gasAvailableAfterKnown - 1) / unknownPatchableIndexes.length))
|
|
183
|
+
: 0;
|
|
184
|
+
const gasReservedForUnknown = unknownGasLimit * unknownPatchableIndexes.length;
|
|
185
|
+
const starvedGasLimit = Math.min(hardGasLimitPerOperation, gasAvailableAfterKnown - gasReservedForUnknown);
|
|
186
|
+
if (starvedGasLimit <= 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
patchedGasLimits.set(starvedIndex, starvedGasLimit);
|
|
190
|
+
for (const index of unknownPatchableIndexes) {
|
|
191
|
+
patchedGasLimits.set(index, unknownGasLimit);
|
|
192
|
+
}
|
|
193
|
+
let patched = false;
|
|
194
|
+
for (const [index, gasLimit] of patchedGasLimits.entries()) {
|
|
195
|
+
if (this.getContentGasLimit(contents[index]) === gasLimit) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
contents[index].gas_limit = gasLimit.toString();
|
|
199
|
+
patched = true;
|
|
200
|
+
}
|
|
201
|
+
if (!patched) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
...op,
|
|
206
|
+
operation: {
|
|
207
|
+
...op.operation,
|
|
208
|
+
contents: contents,
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
|
88
212
|
async calculateEstimates(op, constants) {
|
|
89
213
|
let feeParams = estimate_1.DEFAULT_FEE_PARAMS;
|
|
90
214
|
try {
|
|
@@ -97,24 +221,61 @@ class RPCEstimateProvider extends provider_1.Provider {
|
|
|
97
221
|
catch {
|
|
98
222
|
// Fall back to L1 defaults when the endpoint is missing or unavailable.
|
|
99
223
|
}
|
|
100
|
-
const
|
|
224
|
+
const forgedOperation = await this.forge(op);
|
|
225
|
+
const { opbytes: initialOpBytes, opOb: { branch, contents }, } = forgedOperation;
|
|
101
226
|
const operation = {
|
|
102
227
|
operation: { branch, contents, signature: STUB_SIGNATURE },
|
|
103
228
|
chain_id: await this.context.readProvider.getChainId(),
|
|
104
229
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
230
|
+
let currentOperation = operation;
|
|
231
|
+
let opResponse;
|
|
232
|
+
let simulatedOperation;
|
|
233
|
+
let opbytes = initialOpBytes;
|
|
234
|
+
let lastError;
|
|
235
|
+
const maxRebalanceAttempts = (op.simulation?.gasLimitPatchableIndexes?.length ?? 0) + 1;
|
|
236
|
+
for (let attempt = 0; attempt <= maxRebalanceAttempts; attempt++) {
|
|
237
|
+
// Keep PreparedOperation on attempt 0 for provider-level block/counter recovery. Rebalance
|
|
238
|
+
// retries intentionally omit it so patchSimulationGasLimits cannot restore the even split.
|
|
239
|
+
const simulated = await this.simulate(currentOperation, attempt === 0 ? op : undefined);
|
|
240
|
+
opResponse = simulated.opResponse;
|
|
241
|
+
simulatedOperation = simulated.op;
|
|
242
|
+
currentOperation = simulated.op;
|
|
243
|
+
const errors = [...(0, errors_1.flattenErrors)(opResponse, 'backtracked'), ...(0, errors_1.flattenErrors)(opResponse)];
|
|
244
|
+
if (errors.length === 0) {
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
lastError = new errors_1.TezosOperationError(errors, 'Error occurred during estimation', opResponse.contents);
|
|
248
|
+
if (!this.hasOperationGasExhausted(errors)) {
|
|
249
|
+
throw lastError;
|
|
250
|
+
}
|
|
251
|
+
const rebalancedOperation = this.rebalanceGasLimits(currentOperation, opResponse, op, constants);
|
|
252
|
+
if (!rebalancedOperation || attempt === maxRebalanceAttempts) {
|
|
253
|
+
throw lastError;
|
|
254
|
+
}
|
|
255
|
+
currentOperation = rebalancedOperation;
|
|
256
|
+
opResponse = undefined;
|
|
257
|
+
simulatedOperation = undefined;
|
|
258
|
+
}
|
|
259
|
+
if (!opResponse || !simulatedOperation) {
|
|
260
|
+
throw lastError ?? new Error('Unable to simulate operation for estimation');
|
|
111
261
|
}
|
|
262
|
+
if (simulatedOperation !== operation) {
|
|
263
|
+
if (!simulatedOperation.operation.branch) {
|
|
264
|
+
throw new Error('Unable to reforge simulated operation without a branch');
|
|
265
|
+
}
|
|
266
|
+
opbytes = await this.context.forger.forge({
|
|
267
|
+
branch: simulatedOperation.operation.branch,
|
|
268
|
+
contents: simulatedOperation.operation.contents,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
const { cost_per_byte, origination_size } = constants;
|
|
112
272
|
let numberOfOps = 1;
|
|
113
|
-
if (Array.isArray(
|
|
273
|
+
if (Array.isArray(simulatedOperation.operation.contents) &&
|
|
274
|
+
simulatedOperation.operation.contents.length > 1) {
|
|
114
275
|
numberOfOps =
|
|
115
276
|
opResponse.contents[0].kind === 'reveal'
|
|
116
|
-
?
|
|
117
|
-
:
|
|
277
|
+
? simulatedOperation.operation.contents.length - 1
|
|
278
|
+
: simulatedOperation.operation.contents.length;
|
|
118
279
|
}
|
|
119
280
|
return opResponse.contents.map((x) => {
|
|
120
281
|
const content = x;
|
package/dist/lib/version.js
CHANGED
|
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.VERSION = void 0;
|
|
4
4
|
// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT!
|
|
5
5
|
exports.VERSION = {
|
|
6
|
-
"commitHash": "
|
|
7
|
-
"version": "25.0.0
|
|
6
|
+
"commitHash": "13f62cd47ea018312f100b660d0225604c757afa",
|
|
7
|
+
"version": "25.0.0"
|
|
8
8
|
};
|
package/dist/taquito.es6.js
CHANGED
|
@@ -3889,6 +3889,15 @@ class RevealEstimateError extends TaquitoError {
|
|
|
3889
3889
|
this.message = 'Public key is unknown, unable to estimate the reveal operation in Wallet API.';
|
|
3890
3890
|
}
|
|
3891
3891
|
}
|
|
3892
|
+
class BatchGasLimitExceededError extends TaquitoError {
|
|
3893
|
+
constructor(requiredGasLimit, hardGasLimitPerBlock) {
|
|
3894
|
+
super();
|
|
3895
|
+
this.requiredGasLimit = requiredGasLimit;
|
|
3896
|
+
this.hardGasLimitPerBlock = hardGasLimitPerBlock;
|
|
3897
|
+
this.name = 'BatchGasLimitExceededError';
|
|
3898
|
+
this.message = `Batch gas estimation requires at least ${requiredGasLimit} gas, which exceeds the per-block limit of ${hardGasLimitPerBlock}. Split the batch into smaller operations.`;
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3892
3901
|
|
|
3893
3902
|
// stub signature that won't be verified by tezos rpc simulate_operation
|
|
3894
3903
|
const STUB_SIGNATURE = 'edsigtkpiSSschcaCt9pUVrpNPf7TTcgvgDEDD6NCEHMy8NNQJCGnMfLZzYoQj74yLjo9wx6MPVV29CvVzgi7qEcEUok3k7AuMg';
|
|
@@ -3907,6 +3916,7 @@ class RPCEstimateProvider extends Provider {
|
|
|
3907
3916
|
this.REVEAL_LENGTH_TZ4 = 622; // injecting size tz4=620
|
|
3908
3917
|
this.MILLIGAS_BUFFER = 100 * 1000; // 100 buffer depends on operation kind
|
|
3909
3918
|
this.STORAGE_BUFFER = 20; // according to octez-client
|
|
3919
|
+
this.UNKNOWN_GAS_LIMIT_PER_OPERATION = 1000;
|
|
3910
3920
|
this.prepare = new PrepareProvider(this.context);
|
|
3911
3921
|
}
|
|
3912
3922
|
async getKeys() {
|
|
@@ -3964,6 +3974,129 @@ class RPCEstimateProvider extends Provider {
|
|
|
3964
3974
|
};
|
|
3965
3975
|
}
|
|
3966
3976
|
}
|
|
3977
|
+
hasOperationGasExhausted(errors) {
|
|
3978
|
+
return errors.some((error) => error.id.endsWith('gas_exhausted.operation'));
|
|
3979
|
+
}
|
|
3980
|
+
getOperationResult(content) {
|
|
3981
|
+
return content?.metadata?.operation_result;
|
|
3982
|
+
}
|
|
3983
|
+
getInternalOperationResults(content) {
|
|
3984
|
+
const internalResults = content?.metadata?.internal_operation_results;
|
|
3985
|
+
return Array.isArray(internalResults) ? internalResults : [];
|
|
3986
|
+
}
|
|
3987
|
+
operationResultHasGasExhausted(result) {
|
|
3988
|
+
return Array.isArray(result?.errors)
|
|
3989
|
+
? result.errors.some((error) => error.id?.endsWith('gas_exhausted.operation'))
|
|
3990
|
+
: false;
|
|
3991
|
+
}
|
|
3992
|
+
findGasExhaustedContentIndex(contents) {
|
|
3993
|
+
const directFailureIndex = contents.findIndex((content) => this.operationResultHasGasExhausted(this.getOperationResult(content)));
|
|
3994
|
+
if (directFailureIndex !== -1) {
|
|
3995
|
+
return directFailureIndex;
|
|
3996
|
+
}
|
|
3997
|
+
const internalFailureIndex = contents.findIndex((content) => this.getInternalOperationResults(content).some((internalResult) => this.operationResultHasGasExhausted(internalResult.result)));
|
|
3998
|
+
if (internalFailureIndex !== -1) {
|
|
3999
|
+
return internalFailureIndex;
|
|
4000
|
+
}
|
|
4001
|
+
const firstSkippedIndex = contents.findIndex((content) => this.getOperationResult(content)?.status === 'skipped');
|
|
4002
|
+
return firstSkippedIndex > 0 ? firstSkippedIndex - 1 : -1;
|
|
4003
|
+
}
|
|
4004
|
+
getContentGasLimit(content) {
|
|
4005
|
+
const gasLimit = Number(content?.gas_limit);
|
|
4006
|
+
return Number.isFinite(gasLimit) && gasLimit >= 0 ? gasLimit : 0;
|
|
4007
|
+
}
|
|
4008
|
+
getMeasuredGasLimit(content, hardGasLimitPerOperation) {
|
|
4009
|
+
const operationResults = flattenOperationResult({ contents: [content] });
|
|
4010
|
+
const consumedMilligas = operationResults.reduce((total, result) => total + (Number(result.consumed_milligas) || 0), 0);
|
|
4011
|
+
if (consumedMilligas <= 0) {
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
const safetyGas = isOpWithGasBuffer(content) ? this.MILLIGAS_BUFFER / 1000 : 0;
|
|
4015
|
+
return Math.min(Math.ceil(consumedMilligas / 1000) + safetyGas, hardGasLimitPerOperation);
|
|
4016
|
+
}
|
|
4017
|
+
rebalanceGasLimits(op, opResponse, preparedOperation, constants) {
|
|
4018
|
+
const hardGasLimitPerOperation = Number(constants.hard_gas_limit_per_operation);
|
|
4019
|
+
const hardGasLimitPerBlock = Number(constants.hard_gas_limit_per_block);
|
|
4020
|
+
const patchableIndexes = preparedOperation.simulation?.gasLimitPatchableIndexes?.filter((index) => index >= 0 && index < opResponse.contents.length);
|
|
4021
|
+
if (!Array.isArray(op.operation.contents) ||
|
|
4022
|
+
!patchableIndexes?.length ||
|
|
4023
|
+
!Number.isFinite(hardGasLimitPerOperation) ||
|
|
4024
|
+
!Number.isFinite(hardGasLimitPerBlock)) {
|
|
4025
|
+
return;
|
|
4026
|
+
}
|
|
4027
|
+
const responseContents = opResponse.contents;
|
|
4028
|
+
const starvedIndex = this.findGasExhaustedContentIndex(responseContents);
|
|
4029
|
+
if (starvedIndex === -1 || !patchableIndexes.includes(starvedIndex)) {
|
|
4030
|
+
return;
|
|
4031
|
+
}
|
|
4032
|
+
const patchableIndexSet = new Set(patchableIndexes);
|
|
4033
|
+
const contents = op.operation.contents.map((content) => ({
|
|
4034
|
+
...content,
|
|
4035
|
+
}));
|
|
4036
|
+
const patchedGasLimits = new Map();
|
|
4037
|
+
let fixedGasTotal = 0;
|
|
4038
|
+
let measuredGasTotal = 0;
|
|
4039
|
+
const unknownPatchableIndexes = [];
|
|
4040
|
+
for (const [index, content] of responseContents.entries()) {
|
|
4041
|
+
if (!patchableIndexSet.has(index)) {
|
|
4042
|
+
fixedGasTotal += this.getContentGasLimit(contents[index]);
|
|
4043
|
+
continue;
|
|
4044
|
+
}
|
|
4045
|
+
if (index === starvedIndex) {
|
|
4046
|
+
continue;
|
|
4047
|
+
}
|
|
4048
|
+
const status = this.getOperationResult(content)?.status;
|
|
4049
|
+
const measuredGasLimit = status === 'applied' || status === 'backtracked'
|
|
4050
|
+
? this.getMeasuredGasLimit(content, hardGasLimitPerOperation)
|
|
4051
|
+
: undefined;
|
|
4052
|
+
if (typeof measuredGasLimit === 'number') {
|
|
4053
|
+
patchedGasLimits.set(index, measuredGasLimit);
|
|
4054
|
+
measuredGasTotal += measuredGasLimit;
|
|
4055
|
+
}
|
|
4056
|
+
else {
|
|
4057
|
+
unknownPatchableIndexes.push(index);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
const requiredKnownGas = fixedGasTotal + measuredGasTotal;
|
|
4061
|
+
if (requiredKnownGas > hardGasLimitPerBlock) {
|
|
4062
|
+
throw new BatchGasLimitExceededError(requiredKnownGas, hardGasLimitPerBlock);
|
|
4063
|
+
}
|
|
4064
|
+
const gasAvailableAfterKnown = hardGasLimitPerBlock - requiredKnownGas;
|
|
4065
|
+
const minimumUnknownGas = unknownPatchableIndexes.length + 1;
|
|
4066
|
+
if (gasAvailableAfterKnown < minimumUnknownGas) {
|
|
4067
|
+
throw new BatchGasLimitExceededError(requiredKnownGas + minimumUnknownGas, hardGasLimitPerBlock);
|
|
4068
|
+
}
|
|
4069
|
+
const unknownGasLimit = unknownPatchableIndexes.length > 0
|
|
4070
|
+
? Math.min(this.UNKNOWN_GAS_LIMIT_PER_OPERATION, Math.floor((gasAvailableAfterKnown - 1) / unknownPatchableIndexes.length))
|
|
4071
|
+
: 0;
|
|
4072
|
+
const gasReservedForUnknown = unknownGasLimit * unknownPatchableIndexes.length;
|
|
4073
|
+
const starvedGasLimit = Math.min(hardGasLimitPerOperation, gasAvailableAfterKnown - gasReservedForUnknown);
|
|
4074
|
+
if (starvedGasLimit <= 0) {
|
|
4075
|
+
return;
|
|
4076
|
+
}
|
|
4077
|
+
patchedGasLimits.set(starvedIndex, starvedGasLimit);
|
|
4078
|
+
for (const index of unknownPatchableIndexes) {
|
|
4079
|
+
patchedGasLimits.set(index, unknownGasLimit);
|
|
4080
|
+
}
|
|
4081
|
+
let patched = false;
|
|
4082
|
+
for (const [index, gasLimit] of patchedGasLimits.entries()) {
|
|
4083
|
+
if (this.getContentGasLimit(contents[index]) === gasLimit) {
|
|
4084
|
+
continue;
|
|
4085
|
+
}
|
|
4086
|
+
contents[index].gas_limit = gasLimit.toString();
|
|
4087
|
+
patched = true;
|
|
4088
|
+
}
|
|
4089
|
+
if (!patched) {
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
4092
|
+
return {
|
|
4093
|
+
...op,
|
|
4094
|
+
operation: {
|
|
4095
|
+
...op.operation,
|
|
4096
|
+
contents: contents,
|
|
4097
|
+
},
|
|
4098
|
+
};
|
|
4099
|
+
}
|
|
3967
4100
|
async calculateEstimates(op, constants) {
|
|
3968
4101
|
let feeParams = DEFAULT_FEE_PARAMS;
|
|
3969
4102
|
try {
|
|
@@ -3976,24 +4109,61 @@ class RPCEstimateProvider extends Provider {
|
|
|
3976
4109
|
catch {
|
|
3977
4110
|
// Fall back to L1 defaults when the endpoint is missing or unavailable.
|
|
3978
4111
|
}
|
|
3979
|
-
const
|
|
4112
|
+
const forgedOperation = await this.forge(op);
|
|
4113
|
+
const { opbytes: initialOpBytes, opOb: { branch, contents }, } = forgedOperation;
|
|
3980
4114
|
const operation = {
|
|
3981
4115
|
operation: { branch, contents, signature: STUB_SIGNATURE },
|
|
3982
4116
|
chain_id: await this.context.readProvider.getChainId(),
|
|
3983
4117
|
};
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4118
|
+
let currentOperation = operation;
|
|
4119
|
+
let opResponse;
|
|
4120
|
+
let simulatedOperation;
|
|
4121
|
+
let opbytes = initialOpBytes;
|
|
4122
|
+
let lastError;
|
|
4123
|
+
const maxRebalanceAttempts = (op.simulation?.gasLimitPatchableIndexes?.length ?? 0) + 1;
|
|
4124
|
+
for (let attempt = 0; attempt <= maxRebalanceAttempts; attempt++) {
|
|
4125
|
+
// Keep PreparedOperation on attempt 0 for provider-level block/counter recovery. Rebalance
|
|
4126
|
+
// retries intentionally omit it so patchSimulationGasLimits cannot restore the even split.
|
|
4127
|
+
const simulated = await this.simulate(currentOperation, attempt === 0 ? op : undefined);
|
|
4128
|
+
opResponse = simulated.opResponse;
|
|
4129
|
+
simulatedOperation = simulated.op;
|
|
4130
|
+
currentOperation = simulated.op;
|
|
4131
|
+
const errors = [...flattenErrors(opResponse, 'backtracked'), ...flattenErrors(opResponse)];
|
|
4132
|
+
if (errors.length === 0) {
|
|
4133
|
+
break;
|
|
4134
|
+
}
|
|
4135
|
+
lastError = new TezosOperationError(errors, 'Error occurred during estimation', opResponse.contents);
|
|
4136
|
+
if (!this.hasOperationGasExhausted(errors)) {
|
|
4137
|
+
throw lastError;
|
|
4138
|
+
}
|
|
4139
|
+
const rebalancedOperation = this.rebalanceGasLimits(currentOperation, opResponse, op, constants);
|
|
4140
|
+
if (!rebalancedOperation || attempt === maxRebalanceAttempts) {
|
|
4141
|
+
throw lastError;
|
|
4142
|
+
}
|
|
4143
|
+
currentOperation = rebalancedOperation;
|
|
4144
|
+
opResponse = undefined;
|
|
4145
|
+
simulatedOperation = undefined;
|
|
3990
4146
|
}
|
|
4147
|
+
if (!opResponse || !simulatedOperation) {
|
|
4148
|
+
throw lastError ?? new Error('Unable to simulate operation for estimation');
|
|
4149
|
+
}
|
|
4150
|
+
if (simulatedOperation !== operation) {
|
|
4151
|
+
if (!simulatedOperation.operation.branch) {
|
|
4152
|
+
throw new Error('Unable to reforge simulated operation without a branch');
|
|
4153
|
+
}
|
|
4154
|
+
opbytes = await this.context.forger.forge({
|
|
4155
|
+
branch: simulatedOperation.operation.branch,
|
|
4156
|
+
contents: simulatedOperation.operation.contents,
|
|
4157
|
+
});
|
|
4158
|
+
}
|
|
4159
|
+
const { cost_per_byte, origination_size } = constants;
|
|
3991
4160
|
let numberOfOps = 1;
|
|
3992
|
-
if (Array.isArray(
|
|
4161
|
+
if (Array.isArray(simulatedOperation.operation.contents) &&
|
|
4162
|
+
simulatedOperation.operation.contents.length > 1) {
|
|
3993
4163
|
numberOfOps =
|
|
3994
4164
|
opResponse.contents[0].kind === 'reveal'
|
|
3995
|
-
?
|
|
3996
|
-
:
|
|
4165
|
+
? simulatedOperation.operation.contents.length - 1
|
|
4166
|
+
: simulatedOperation.operation.contents.length;
|
|
3997
4167
|
}
|
|
3998
4168
|
return opResponse.contents.map((x) => {
|
|
3999
4169
|
const content = x;
|
|
@@ -7578,8 +7748,8 @@ class Context {
|
|
|
7578
7748
|
|
|
7579
7749
|
// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT!
|
|
7580
7750
|
const VERSION = {
|
|
7581
|
-
"commitHash": "
|
|
7582
|
-
"version": "25.0.0
|
|
7751
|
+
"commitHash": "13f62cd47ea018312f100b660d0225604c757afa",
|
|
7752
|
+
"version": "25.0.0"
|
|
7583
7753
|
};
|
|
7584
7754
|
|
|
7585
7755
|
/**
|
|
@@ -8055,5 +8225,5 @@ class TezosToolkit {
|
|
|
8055
8225
|
}
|
|
8056
8226
|
}
|
|
8057
8227
|
|
|
8058
|
-
export { BallotOperation, BatchOperation, BigMapAbstraction, COST_PER_BYTE, ChainIds, CompositeForger, Context, ContractAbstraction, ContractMethodObject, ContractView, DEFAULT_FEE_PARAMS, DEFAULT_SMART_CONTRACT_METHOD_NAME, DefaultGlobalConstantsProvider, DelegateOperation, DelegationWalletOperation, DrainDelegateOperation, Estimate, GlobalConstantNotFound, IncreasePaidStorageOperation, InvalidBalanceError, InvalidCodeParameter, InvalidDelegationSource, InvalidEstimateValueError, InvalidInitParameter, InvalidParameterError, InvalidViewSimulationContext, LegacyWalletProvider, MANAGER_LAMBDA, MichelCodecPacker, MichelCodecParser, NoopParser, ORIGINATION_SIZE, ObservableSubscription, Operation, OperationBatch, OriginationOperation, OriginationParameterError, OriginationWalletOperation, PollingSubscribeProvider, PrepareProvider, ProposalsOperation, Protocols, REVEAL_STORAGE_LIMIT, RPCEstimateProvider, RegisterGlobalConstantOperation, RegisterGlobalConstantWalletOperation, RevealEstimateError, RevealOperation, RevealOperationError, RpcForger, RpcInjector, RpcPacker, RpcReadAdapter, SaplingStateAbstraction, SmartRollupAddMessagesOperation, SmartRollupOriginateOperation, TaquitoLocalForger, TezosOperationError, TezosPreapplyFailureError, TezosToolkit, TransactionOperation, TransactionWalletOperation, TransferTicketOperation, TransferTicketWalletOperation, UnconfiguredGlobalConstantsProviderError, UpdateCompanionKeyOperation, UpdateConsensusKeyOperation, VIEW_LAMBDA, ViewSimulationError, Wallet, WalletOperation, WalletOperationBatch, attachKind, compose, createActivationOperation, createBallotOperation, createDrainDelegateOperation, createIncreasePaidStorageOperation, createOriginationOperation, createProposalsOperation, createRegisterDelegateOperation, createRegisterGlobalConstantOperation, createRevealOperation, createSetDelegateOperation, createSmartRollupAddMessagesOperation, createSmartRollupExecuteOutboxMessageOperation, createSmartRollupOriginateOperation, createTransferOperation, createTransferTicketOperation, createUpdateCompanionKeyOperation, createUpdateConsensusKeyOperation, defaultConfigConfirmation, feeParamsFromMempoolFilter, findWithKind, getRevealFee, getRevealFeeInternal, getRevealGasLimit, hasMetadata, hasMetadataWithInternalOperationResult, hasMetadataWithResult, importKey, isKind, isOpRequireReveal, isOpWithFee, isOpWithGasBuffer, isSourceOp, protocols, smartContractAbstractionSemantic, validateAndExtractFailwith };
|
|
8228
|
+
export { BallotOperation, BatchGasLimitExceededError, BatchOperation, BigMapAbstraction, COST_PER_BYTE, ChainIds, CompositeForger, Context, ContractAbstraction, ContractMethodObject, ContractView, DEFAULT_FEE_PARAMS, DEFAULT_SMART_CONTRACT_METHOD_NAME, DefaultGlobalConstantsProvider, DelegateOperation, DelegationWalletOperation, DrainDelegateOperation, Estimate, GlobalConstantNotFound, IncreasePaidStorageOperation, InvalidBalanceError, InvalidCodeParameter, InvalidDelegationSource, InvalidEstimateValueError, InvalidInitParameter, InvalidParameterError, InvalidViewSimulationContext, LegacyWalletProvider, MANAGER_LAMBDA, MichelCodecPacker, MichelCodecParser, NoopParser, ORIGINATION_SIZE, ObservableSubscription, Operation, OperationBatch, OriginationOperation, OriginationParameterError, OriginationWalletOperation, PollingSubscribeProvider, PrepareProvider, ProposalsOperation, Protocols, REVEAL_STORAGE_LIMIT, RPCEstimateProvider, RegisterGlobalConstantOperation, RegisterGlobalConstantWalletOperation, RevealEstimateError, RevealOperation, RevealOperationError, RpcForger, RpcInjector, RpcPacker, RpcReadAdapter, SaplingStateAbstraction, SmartRollupAddMessagesOperation, SmartRollupOriginateOperation, TaquitoLocalForger, TezosOperationError, TezosPreapplyFailureError, TezosToolkit, TransactionOperation, TransactionWalletOperation, TransferTicketOperation, TransferTicketWalletOperation, UnconfiguredGlobalConstantsProviderError, UpdateCompanionKeyOperation, UpdateConsensusKeyOperation, VIEW_LAMBDA, ViewSimulationError, Wallet, WalletOperation, WalletOperationBatch, attachKind, compose, createActivationOperation, createBallotOperation, createDrainDelegateOperation, createIncreasePaidStorageOperation, createOriginationOperation, createProposalsOperation, createRegisterDelegateOperation, createRegisterGlobalConstantOperation, createRevealOperation, createSetDelegateOperation, createSmartRollupAddMessagesOperation, createSmartRollupExecuteOutboxMessageOperation, createSmartRollupOriginateOperation, createTransferOperation, createTransferTicketOperation, createUpdateCompanionKeyOperation, createUpdateConsensusKeyOperation, defaultConfigConfirmation, feeParamsFromMempoolFilter, findWithKind, getRevealFee, getRevealFeeInternal, getRevealGasLimit, hasMetadata, hasMetadataWithInternalOperationResult, hasMetadataWithResult, importKey, isKind, isOpRequireReveal, isOpWithFee, isOpWithGasBuffer, isSourceOp, protocols, smartContractAbstractionSemantic, validateAndExtractFailwith };
|
|
8059
8229
|
//# sourceMappingURL=taquito.es6.js.map
|
package/dist/taquito.es6.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taquito.es6.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"taquito.es6.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|