@keetanetwork/anchor 0.0.38 → 0.0.39
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/lib/encrypted-container.d.ts +53 -3
- package/lib/encrypted-container.d.ts.map +1 -1
- package/lib/encrypted-container.js +549 -93
- package/lib/encrypted-container.js.map +1 -1
- package/lib/http-server/index.d.ts.map +1 -1
- package/lib/http-server/index.js +58 -5
- package/lib/http-server/index.js.map +1 -1
- package/lib/queue/drivers/queue_firestore.d.ts +29 -0
- package/lib/queue/drivers/queue_firestore.d.ts.map +1 -0
- package/lib/queue/drivers/queue_firestore.js +279 -0
- package/lib/queue/drivers/queue_firestore.js.map +1 -0
- package/lib/queue/index.d.ts +56 -0
- package/lib/queue/index.d.ts.map +1 -1
- package/lib/queue/index.js +111 -21
- package/lib/queue/index.js.map +1 -1
- package/lib/resolver.d.ts +4 -15
- package/lib/resolver.d.ts.map +1 -1
- package/lib/resolver.js +468 -636
- package/lib/resolver.js.map +1 -1
- package/lib/utils/signing.d.ts +12 -3
- package/lib/utils/signing.d.ts.map +1 -1
- package/lib/utils/signing.js +7 -13
- package/lib/utils/signing.js.map +1 -1
- package/npm-shrinkwrap.json +4 -4
- package/package.json +2 -1
- package/services/asset-movement/client.d.ts +2 -2
- package/services/asset-movement/client.d.ts.map +1 -1
- package/services/asset-movement/client.js +2 -2
- package/services/asset-movement/client.js.map +1 -1
- package/services/asset-movement/common.d.ts +56 -22
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.js +295 -70
- package/services/asset-movement/common.js.map +1 -1
- package/services/fx/client.d.ts +15 -3
- package/services/fx/client.d.ts.map +1 -1
- package/services/fx/client.js +18 -0
- package/services/fx/client.js.map +1 -1
- package/services/fx/server.d.ts +22 -3
- package/services/fx/server.d.ts.map +1 -1
- package/services/fx/server.js +158 -102
- package/services/fx/server.js.map +1 -1
- package/services/fx/util.d.ts +26 -8
- package/services/fx/util.d.ts.map +1 -1
- package/services/fx/util.js +92 -4
- package/services/fx/util.js.map +1 -1
package/services/fx/server.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { __addDisposableResource, __disposeResources } from "tslib";
|
|
1
2
|
import * as __typia_transform__assertGuard from "typia/lib/internal/_assertGuard.js";
|
|
2
3
|
import * as KeetaAnchorHTTPServer from '../../lib/http-server/index.js';
|
|
3
4
|
import { KeetaNet } from '../../client/index.js';
|
|
@@ -8,7 +9,9 @@ import { KeetaAnchorQueueRunner, KeetaAnchorQueueStorageDriverMemory } from '../
|
|
|
8
9
|
import { KeetaAnchorQueuePipelineAdvanced } from '../../lib/queue/pipeline.js';
|
|
9
10
|
import { assertNever } from '../../lib/utils/never.js';
|
|
10
11
|
import * as typia from 'typia';
|
|
11
|
-
import {
|
|
12
|
+
import { assertExchangeBlockParametersAndComputeRefund, convertQuoteToExpectedSwapWithoutCost } from './util.js';
|
|
13
|
+
import { AsyncDisposableStack } from '../../lib/utils/defer.js';
|
|
14
|
+
import { asleep } from '../../lib/utils/asleep.js';
|
|
12
15
|
/**
|
|
13
16
|
* Enable additional runtime "paranoid" checks in the FX server.
|
|
14
17
|
*
|
|
@@ -50,7 +53,7 @@ async function requestToAccounts(config, request) {
|
|
|
50
53
|
let account;
|
|
51
54
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
52
55
|
if (config.account !== undefined) {
|
|
53
|
-
const rateFee = await config.fx.getConversionRateAndFee(request);
|
|
56
|
+
const rateFee = await config.fx.getConversionRateAndFee(request, { purpose: 'estimate' });
|
|
54
57
|
account = rateFee.account;
|
|
55
58
|
}
|
|
56
59
|
else {
|
|
@@ -133,7 +136,7 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
133
136
|
* on the network and marks the job as completed if so.
|
|
134
137
|
*/
|
|
135
138
|
async processor(entry) {
|
|
136
|
-
const { block,
|
|
139
|
+
const { block, request } = entry.request;
|
|
137
140
|
const config = this.serverConfig;
|
|
138
141
|
let userClient;
|
|
139
142
|
if (KeetaNet.UserClient.isInstance(config.client)) {
|
|
@@ -238,6 +241,27 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
238
241
|
}
|
|
239
242
|
/* We are clear to attempt the swap now */
|
|
240
243
|
const builder = userClient.initBuilder();
|
|
244
|
+
let expected = entry.request.expected;
|
|
245
|
+
/**
|
|
246
|
+
* We only want to refund excess for cost/paying token if it is not a fixed rate
|
|
247
|
+
* as if it is a fixed rate transfer, you can assume the client did not send unintentionally
|
|
248
|
+
*
|
|
249
|
+
* Additionally, other FX anchors are not forced to refund any, so there is no guarantee to client that refunds will occur
|
|
250
|
+
*/
|
|
251
|
+
if (expected === null) {
|
|
252
|
+
const quote = await this.serverConfig.fx.getConversionRateAndFee(request, { purpose: 'exchange', request: entry.request });
|
|
253
|
+
const { refunds } = assertExchangeBlockParametersAndComputeRefund({
|
|
254
|
+
block: block,
|
|
255
|
+
liquidityAccount: entry.request.account,
|
|
256
|
+
allowedLiquidityAccounts: null,
|
|
257
|
+
checks: { quote, request },
|
|
258
|
+
isQuoteBasedExchange: false
|
|
259
|
+
});
|
|
260
|
+
for (const refund of refunds) {
|
|
261
|
+
builder.send(block.account, refund.amount, refund.token);
|
|
262
|
+
}
|
|
263
|
+
expected = convertQuoteToExpectedSwapWithoutCost({ quote, request });
|
|
264
|
+
}
|
|
241
265
|
builder.send(block.account, expected.send.amount, expected.send.token);
|
|
242
266
|
const sendBlock = await builder.computeBlocks();
|
|
243
267
|
const swapBlocks = [...sendBlock.blocks, block];
|
|
@@ -245,9 +269,26 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
245
269
|
if (userClient.config.generateFeeBlock !== undefined) {
|
|
246
270
|
publishOptions.generateFeeBlock = userClient.config.generateFeeBlock;
|
|
247
271
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
272
|
+
try {
|
|
273
|
+
const publishResult = await userClient.client.transmit(swapBlocks, publishOptions);
|
|
274
|
+
if (!publishResult.publish) {
|
|
275
|
+
throw (new Error('Exchange Publish Failed'));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
if (KeetaNet.lib.Error.isInstance(error) &&
|
|
280
|
+
'shouldRetry' in error &&
|
|
281
|
+
// Disable this warning as there is nothing stopping this from not being a boolean
|
|
282
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare
|
|
283
|
+
error.shouldRetry === false) {
|
|
284
|
+
this.serverConfig.logger?.warn('KeetaFXAnchorQueuePipelineStage1::processor', 'Non-retryable error publishing swap blocks:', error);
|
|
285
|
+
return ({
|
|
286
|
+
status: 'failed_permanently',
|
|
287
|
+
output: null,
|
|
288
|
+
error: `${error.code} ${error.message}`
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
throw (error);
|
|
251
292
|
}
|
|
252
293
|
/* Set the output and mark the job as pending so we can run the queue again and check for completion */
|
|
253
294
|
return ({
|
|
@@ -261,12 +302,12 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
261
302
|
});
|
|
262
303
|
}
|
|
263
304
|
encodeRequest(request) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
expected
|
|
305
|
+
let expected;
|
|
306
|
+
if (request.expected === null) {
|
|
307
|
+
expected = null;
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
expected = {
|
|
270
311
|
receive: {
|
|
271
312
|
token: request.expected.receive.token.publicKeyString.get(),
|
|
272
313
|
amount: request.expected.receive.amount.toString()
|
|
@@ -275,7 +316,15 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
275
316
|
token: request.expected.send.token.publicKeyString.get(),
|
|
276
317
|
amount: request.expected.send.amount.toString()
|
|
277
318
|
}
|
|
278
|
-
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
;
|
|
322
|
+
const retval = {
|
|
323
|
+
version: 1,
|
|
324
|
+
account: request.account.publicKeyString.get(),
|
|
325
|
+
block: Buffer.from(request.block.toBytes()).toString('base64'),
|
|
326
|
+
request: request.request,
|
|
327
|
+
expected: expected
|
|
279
328
|
};
|
|
280
329
|
return (retval);
|
|
281
330
|
}
|
|
@@ -289,11 +338,12 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
289
338
|
if (reqJSON.version !== 1) {
|
|
290
339
|
throw (new Error(`Unsupported KeetaFXAnchorQueueStage1Request version ${reqJSON.version}`));
|
|
291
340
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
341
|
+
let expected;
|
|
342
|
+
if (reqJSON.expected === null) {
|
|
343
|
+
expected = null;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
expected = {
|
|
297
347
|
receive: {
|
|
298
348
|
token: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.expected.receive.token).assertKeyType(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN),
|
|
299
349
|
amount: BigInt(reqJSON.expected.receive.amount)
|
|
@@ -302,7 +352,13 @@ class KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner {
|
|
|
302
352
|
token: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.expected.send.token).assertKeyType(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN),
|
|
303
353
|
amount: BigInt(reqJSON.expected.send.amount)
|
|
304
354
|
}
|
|
305
|
-
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const retval = {
|
|
358
|
+
account: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.account),
|
|
359
|
+
block: new KeetaNet.lib.Block(reqJSON.block),
|
|
360
|
+
request: reqJSON.request,
|
|
361
|
+
expected: expected
|
|
306
362
|
};
|
|
307
363
|
return (retval);
|
|
308
364
|
}
|
|
@@ -412,7 +468,8 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
412
468
|
fx;
|
|
413
469
|
pipeline;
|
|
414
470
|
quoteConfiguration;
|
|
415
|
-
|
|
471
|
+
autoRun;
|
|
472
|
+
autoRunRunning = false;
|
|
416
473
|
constructor(config) {
|
|
417
474
|
super(config);
|
|
418
475
|
this.homepage = config.homepage ?? '';
|
|
@@ -455,9 +512,9 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
455
512
|
* If no storage driver is provided, we default to an in-memory
|
|
456
513
|
* that we auto-run
|
|
457
514
|
*/
|
|
458
|
-
|
|
515
|
+
this.autoRun = config.storage?.autoRun ?? false;
|
|
459
516
|
if (config.storage === undefined) {
|
|
460
|
-
|
|
517
|
+
this.autoRun = true;
|
|
461
518
|
}
|
|
462
519
|
/*
|
|
463
520
|
* Create the pipeline to process transactions
|
|
@@ -472,33 +529,6 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
472
529
|
logger: this.logger,
|
|
473
530
|
serverConfig: this
|
|
474
531
|
});
|
|
475
|
-
/*
|
|
476
|
-
* If auto-run is enabled, setup the interval to run the pipeline
|
|
477
|
-
*/
|
|
478
|
-
if (autorun) {
|
|
479
|
-
let running = false;
|
|
480
|
-
this.pipelineAutoRunInterval = setInterval(async () => {
|
|
481
|
-
if (running) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
running = true;
|
|
485
|
-
try {
|
|
486
|
-
await this.pipeline.maintain();
|
|
487
|
-
}
|
|
488
|
-
catch (error) {
|
|
489
|
-
this.logger.error('KeetaNetFXAnchorHTTPServer::pipelineAutoRunInterval', 'Error maintaining pipeline:', error);
|
|
490
|
-
}
|
|
491
|
-
try {
|
|
492
|
-
await this.pipeline.run({ timeoutMs: 5000 });
|
|
493
|
-
}
|
|
494
|
-
catch (error) {
|
|
495
|
-
this.logger.error('KeetaNetFXAnchorHTTPServer::pipelineAutoRunInterval', 'Error running pipeline:', error);
|
|
496
|
-
}
|
|
497
|
-
finally {
|
|
498
|
-
running = false;
|
|
499
|
-
}
|
|
500
|
-
}, 1000);
|
|
501
|
-
}
|
|
502
532
|
}
|
|
503
533
|
async initRoutes(config) {
|
|
504
534
|
const routes = {};
|
|
@@ -530,6 +560,16 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
530
560
|
});
|
|
531
561
|
};
|
|
532
562
|
}
|
|
563
|
+
async function getUnsignedQuoteData(conversion, purpose) {
|
|
564
|
+
const rateAndFee = await config.fx.getConversionRateAndFee(conversion, { purpose });
|
|
565
|
+
if (PARANOID) {
|
|
566
|
+
const quoteAccount = rateAndFee.account;
|
|
567
|
+
if (!instance.accounts.has(quoteAccount)) {
|
|
568
|
+
throw (new Error('"getConversionRateAndFee" returned an account not configured for this server'));
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return (rateAndFee);
|
|
572
|
+
}
|
|
533
573
|
/**
|
|
534
574
|
* Setup the request handler for an estimate request
|
|
535
575
|
*/
|
|
@@ -541,7 +581,7 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
541
581
|
throw (new Error('POST data missing request'));
|
|
542
582
|
}
|
|
543
583
|
const conversion = assertConversionInputCanonicalJSON(postData.request);
|
|
544
|
-
const rateAndFee = await
|
|
584
|
+
const rateAndFee = await getUnsignedQuoteData(conversion, 'estimate');
|
|
545
585
|
let requiresQuoteBody;
|
|
546
586
|
if (instance.quoteConfiguration.requiresQuote) {
|
|
547
587
|
requiresQuoteBody = { requiresQuote: true };
|
|
@@ -578,16 +618,6 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
578
618
|
output: JSON.stringify(estimateResponse)
|
|
579
619
|
});
|
|
580
620
|
};
|
|
581
|
-
async function getUnsignedQuoteData(conversion) {
|
|
582
|
-
const rateAndFee = await config.fx.getConversionRateAndFee(conversion);
|
|
583
|
-
if (PARANOID) {
|
|
584
|
-
const quoteAccount = rateAndFee.account;
|
|
585
|
-
if (!instance.accounts.has(quoteAccount)) {
|
|
586
|
-
throw (new Error('"getConversionRateAndFee" returned an account not configured for this server'));
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
return (rateAndFee);
|
|
590
|
-
}
|
|
591
621
|
routes['POST /api/getQuote'] = async function (_ignore_params, postData) {
|
|
592
622
|
if (!instance.quoteConfiguration.requiresQuote && !instance.quoteConfiguration.issueQuotes) {
|
|
593
623
|
throw (new Errors.QuoteIssuanceDisabled());
|
|
@@ -599,7 +629,7 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
599
629
|
throw (new Error('POST data missing request'));
|
|
600
630
|
}
|
|
601
631
|
const conversion = assertConversionInputCanonicalJSON(postData.request);
|
|
602
|
-
const rateAndFee = await getUnsignedQuoteData(conversion);
|
|
632
|
+
const rateAndFee = await getUnsignedQuoteData(conversion, 'quote');
|
|
603
633
|
const unsignedQuote = KeetaNet.lib.Utils.Conversion.toJSONSerializable({
|
|
604
634
|
request: conversion,
|
|
605
635
|
...rateAndFee
|
|
@@ -632,10 +662,13 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
632
662
|
let conversionInput;
|
|
633
663
|
let shouldValidateQuote;
|
|
634
664
|
let liquidityAccount;
|
|
665
|
+
let expectedConversion;
|
|
666
|
+
let isQuoteBasedExchange;
|
|
635
667
|
if ('quote' in request && 'estimate' in request && request.quote && request.estimate) {
|
|
636
668
|
throw (new Error('Request cannot contain both quote and estimate'));
|
|
637
669
|
}
|
|
638
670
|
else if ('quote' in request && request.quote) {
|
|
671
|
+
isQuoteBasedExchange = true;
|
|
639
672
|
shouldValidateQuote = true;
|
|
640
673
|
quoteInput = request.quote;
|
|
641
674
|
conversionInput = quoteInput.request;
|
|
@@ -649,13 +682,18 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
649
682
|
throw (new Errors.QuoteValidationFailed());
|
|
650
683
|
}
|
|
651
684
|
liquidityAccount = quoteInput.account;
|
|
685
|
+
expectedConversion = convertQuoteToExpectedSwapWithoutCost({
|
|
686
|
+
quote: toValidateQuoteInput(quoteInput),
|
|
687
|
+
request: conversionInput
|
|
688
|
+
});
|
|
652
689
|
}
|
|
653
690
|
else if ('request' in request && request.request) {
|
|
691
|
+
isQuoteBasedExchange = false;
|
|
654
692
|
if (instance.quoteConfiguration.requiresQuote) {
|
|
655
693
|
throw (new Errors.QuoteRequired());
|
|
656
694
|
}
|
|
657
695
|
conversionInput = request.request;
|
|
658
|
-
quoteInput = await getUnsignedQuoteData(conversionInput);
|
|
696
|
+
quoteInput = await getUnsignedQuoteData(conversionInput, 'estimate');
|
|
659
697
|
if (instance.quoteConfiguration.validateQuoteBeforeExchange !== undefined) {
|
|
660
698
|
shouldValidateQuote = instance.quoteConfiguration.validateQuoteBeforeExchange;
|
|
661
699
|
}
|
|
@@ -676,6 +714,8 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
676
714
|
if (!liquidityAccount) {
|
|
677
715
|
throw (new KeetaAnchorUserError('Could not determine liquidity account from exchange block'));
|
|
678
716
|
}
|
|
717
|
+
// No expected conversion provided when using estimate, we determine the rate when processing the exchange
|
|
718
|
+
expectedConversion = null;
|
|
679
719
|
}
|
|
680
720
|
else {
|
|
681
721
|
throw (new Error('Either quote or request must be provided (but not both) in exchange request'));
|
|
@@ -688,26 +728,7 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
688
728
|
throw (new Errors.QuoteValidationFailed());
|
|
689
729
|
}
|
|
690
730
|
}
|
|
691
|
-
let expectedSendAmount;
|
|
692
|
-
let expectedReceiveAmount;
|
|
693
|
-
if (conversionInput.affinity === 'to') {
|
|
694
|
-
expectedSendAmount = BigInt(conversionInput.amount);
|
|
695
|
-
expectedReceiveAmount = parsedQuote.convertedAmount;
|
|
696
|
-
}
|
|
697
|
-
else {
|
|
698
|
-
expectedSendAmount = parsedQuote.convertedAmount;
|
|
699
|
-
expectedReceiveAmount = BigInt(conversionInput.amount);
|
|
700
|
-
}
|
|
701
731
|
const liquidityAccountInstance = KeetaNet.lib.Account.toAccount(liquidityAccount);
|
|
702
|
-
const userSendsMinimum = { [conversionInput.from]: expectedReceiveAmount };
|
|
703
|
-
const userWillReceiveMaximum = { [conversionInput.to]: expectedSendAmount };
|
|
704
|
-
if (parsedQuote.cost.amount > 0) {
|
|
705
|
-
const feeTokenPub = parsedQuote.cost.token.publicKeyString.get();
|
|
706
|
-
if (!userSendsMinimum[feeTokenPub]) {
|
|
707
|
-
userSendsMinimum[feeTokenPub] = 0n;
|
|
708
|
-
}
|
|
709
|
-
userSendsMinimum[feeTokenPub] += parsedQuote.cost.amount;
|
|
710
|
-
}
|
|
711
732
|
let allowedLiquidityAccounts;
|
|
712
733
|
if (config.accounts) {
|
|
713
734
|
allowedLiquidityAccounts = config.accounts;
|
|
@@ -720,34 +741,73 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
720
741
|
else {
|
|
721
742
|
throw (new Error('config.account or config.accounts must be provided'));
|
|
722
743
|
}
|
|
723
|
-
|
|
744
|
+
assertExchangeBlockParametersAndComputeRefund({
|
|
724
745
|
block: block,
|
|
725
746
|
liquidityAccount: liquidityAccountInstance,
|
|
726
747
|
allowedLiquidityAccounts: allowedLiquidityAccounts,
|
|
727
|
-
|
|
728
|
-
|
|
748
|
+
checks: { quote: parsedQuote, request: conversionInput },
|
|
749
|
+
isQuoteBasedExchange: isQuoteBasedExchange
|
|
729
750
|
});
|
|
730
751
|
/* Enqueue the exchange request */
|
|
731
752
|
const exchangeID = await instance.pipeline.add({
|
|
732
753
|
account: liquidityAccountInstance,
|
|
733
754
|
block: block,
|
|
734
755
|
request: conversionInput,
|
|
735
|
-
expected:
|
|
736
|
-
receive: {
|
|
737
|
-
token: KeetaNet.lib.Account.fromPublicKeyString(conversionInput.from),
|
|
738
|
-
amount: expectedReceiveAmount
|
|
739
|
-
},
|
|
740
|
-
send: {
|
|
741
|
-
token: KeetaNet.lib.Account.fromPublicKeyString(conversionInput.to),
|
|
742
|
-
amount: expectedSendAmount
|
|
743
|
-
}
|
|
744
|
-
}
|
|
756
|
+
expected: expectedConversion
|
|
745
757
|
});
|
|
746
758
|
const exchangeResponse = {
|
|
747
759
|
ok: true,
|
|
748
760
|
exchangeID: exchangeID.toString(),
|
|
749
761
|
status: 'pending'
|
|
750
762
|
};
|
|
763
|
+
if (instance.autoRun && !instance.autoRunRunning) {
|
|
764
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
765
|
+
try {
|
|
766
|
+
/*
|
|
767
|
+
* Keep track of how many times, consecutively, the queue was empty when we
|
|
768
|
+
* went to run it
|
|
769
|
+
*/
|
|
770
|
+
let noMoreJobsCount = 0;
|
|
771
|
+
/*
|
|
772
|
+
* Create a mutex around the queue running so we don't have
|
|
773
|
+
* lock contention for the worker ID if multiple requests
|
|
774
|
+
* are being served by the same instance
|
|
775
|
+
*/
|
|
776
|
+
instance.autoRunRunning = true;
|
|
777
|
+
const cleanup = __addDisposableResource(env_1, new AsyncDisposableStack(), true);
|
|
778
|
+
cleanup.defer(async function () {
|
|
779
|
+
instance.autoRunRunning = false;
|
|
780
|
+
});
|
|
781
|
+
/*
|
|
782
|
+
* For up to 15s process the queue, stopping only when
|
|
783
|
+
* we've had 2 consecutive runs that indicate there is
|
|
784
|
+
* no more in the queue to process
|
|
785
|
+
*/
|
|
786
|
+
for (const startTime = Date.now(); Date.now() - startTime < 15000;) {
|
|
787
|
+
const more = await instance.pipeline.run({ timeoutMs: 1500 });
|
|
788
|
+
if (!more) {
|
|
789
|
+
noMoreJobsCount++;
|
|
790
|
+
if (noMoreJobsCount >= 2) {
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
noMoreJobsCount = 0;
|
|
796
|
+
}
|
|
797
|
+
await instance.pipeline.maintain();
|
|
798
|
+
await asleep(100);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
catch (e_1) {
|
|
802
|
+
env_1.error = e_1;
|
|
803
|
+
env_1.hasError = true;
|
|
804
|
+
}
|
|
805
|
+
finally {
|
|
806
|
+
const result_1 = __disposeResources(env_1);
|
|
807
|
+
if (result_1)
|
|
808
|
+
await result_1;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
751
811
|
return ({
|
|
752
812
|
output: JSON.stringify(exchangeResponse)
|
|
753
813
|
});
|
|
@@ -833,10 +893,6 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
833
893
|
});
|
|
834
894
|
}
|
|
835
895
|
async stop() {
|
|
836
|
-
if (this.pipelineAutoRunInterval !== null) {
|
|
837
|
-
clearInterval(this.pipelineAutoRunInterval);
|
|
838
|
-
this.pipelineAutoRunInterval = null;
|
|
839
|
-
}
|
|
840
896
|
await this.pipeline.destroy();
|
|
841
897
|
await super.stop();
|
|
842
898
|
}
|
|
@@ -847,7 +903,7 @@ export class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAn
|
|
|
847
903
|
* in a ".generated.ts" file but for simplicity of internal types
|
|
848
904
|
* we keep them here.
|
|
849
905
|
*/
|
|
850
|
-
const assertKeetaFXAnchorQueueStage1RequestJSON = (() => { const _io0 = input => 1 === input.version && "string" === typeof input.account && "string" === typeof input.block && ("object" === typeof input.request && null !== input.request && _io1(input.request)) && ("object" === typeof input.expected && null !== input.expected && _io2(input.expected)); const _io1 = input => "string" === typeof input.from && (RegExp(/^keeta_am(.*)/).test(input.from) || RegExp(/^keeta_an(.*)/).test(input.from) || RegExp(/^keeta_ao(.*)/).test(input.from) || RegExp(/^keeta_ap(.*)/).test(input.from) || RegExp(/^tyblocks_am(.*)/).test(input.from) || RegExp(/^tyblocks_an(.*)/).test(input.from) || RegExp(/^tyblocks_ao(.*)/).test(input.from) || RegExp(/^tyblocks_ap(.*)/).test(input.from)) && ("string" === typeof input.to && (RegExp(/^keeta_am(.*)/).test(input.to) || RegExp(/^keeta_an(.*)/).test(input.to) || RegExp(/^keeta_ao(.*)/).test(input.to) || RegExp(/^keeta_ap(.*)/).test(input.to) || RegExp(/^tyblocks_am(.*)/).test(input.to) || RegExp(/^tyblocks_an(.*)/).test(input.to) || RegExp(/^tyblocks_ao(.*)/).test(input.to) || RegExp(/^tyblocks_ap(.*)/).test(input.to))) && "string" === typeof input.amount && ("from" === input.affinity || "to" === input.affinity); const _io2 = input => "object" === typeof input.receive && null !== input.receive && _io3(input.receive) && ("object" === typeof input.send && null !== input.send && _io4(input.send)); const _io3 = input => "string" === typeof input.token && (RegExp(/^keeta_am(.*)/).test(input.token) || RegExp(/^keeta_an(.*)/).test(input.token) || RegExp(/^keeta_ao(.*)/).test(input.token) || RegExp(/^keeta_ap(.*)/).test(input.token) || RegExp(/^tyblocks_am(.*)/).test(input.token) || RegExp(/^tyblocks_an(.*)/).test(input.token) || RegExp(/^tyblocks_ao(.*)/).test(input.token) || RegExp(/^tyblocks_ap(.*)/).test(input.token)) && "string" === typeof input.amount; const _io4 = input => "string" === typeof input.token && (RegExp(/^keeta_am(.*)/).test(input.token) || RegExp(/^keeta_an(.*)/).test(input.token) || RegExp(/^keeta_ao(.*)/).test(input.token) || RegExp(/^keeta_ap(.*)/).test(input.token) || RegExp(/^tyblocks_am(.*)/).test(input.token) || RegExp(/^tyblocks_an(.*)/).test(input.token) || RegExp(/^tyblocks_ao(.*)/).test(input.token) || RegExp(/^tyblocks_ap(.*)/).test(input.token)) && "string" === typeof input.amount; const _ao0 = (input, _path, _exceptionable = true) => (1 === input.version || __typia_transform__assertGuard._assertGuard(_exceptionable, {
|
|
906
|
+
const assertKeetaFXAnchorQueueStage1RequestJSON = (() => { const _io0 = input => 1 === input.version && "string" === typeof input.account && "string" === typeof input.block && ("object" === typeof input.request && null !== input.request && _io1(input.request)) && (null === input.expected || "object" === typeof input.expected && null !== input.expected && _io2(input.expected)); const _io1 = input => "string" === typeof input.from && (RegExp(/^keeta_am(.*)/).test(input.from) || RegExp(/^keeta_an(.*)/).test(input.from) || RegExp(/^keeta_ao(.*)/).test(input.from) || RegExp(/^keeta_ap(.*)/).test(input.from) || RegExp(/^tyblocks_am(.*)/).test(input.from) || RegExp(/^tyblocks_an(.*)/).test(input.from) || RegExp(/^tyblocks_ao(.*)/).test(input.from) || RegExp(/^tyblocks_ap(.*)/).test(input.from)) && ("string" === typeof input.to && (RegExp(/^keeta_am(.*)/).test(input.to) || RegExp(/^keeta_an(.*)/).test(input.to) || RegExp(/^keeta_ao(.*)/).test(input.to) || RegExp(/^keeta_ap(.*)/).test(input.to) || RegExp(/^tyblocks_am(.*)/).test(input.to) || RegExp(/^tyblocks_an(.*)/).test(input.to) || RegExp(/^tyblocks_ao(.*)/).test(input.to) || RegExp(/^tyblocks_ap(.*)/).test(input.to))) && "string" === typeof input.amount && ("from" === input.affinity || "to" === input.affinity); const _io2 = input => "object" === typeof input.receive && null !== input.receive && _io3(input.receive) && ("object" === typeof input.send && null !== input.send && _io4(input.send)); const _io3 = input => "string" === typeof input.token && (RegExp(/^keeta_am(.*)/).test(input.token) || RegExp(/^keeta_an(.*)/).test(input.token) || RegExp(/^keeta_ao(.*)/).test(input.token) || RegExp(/^keeta_ap(.*)/).test(input.token) || RegExp(/^tyblocks_am(.*)/).test(input.token) || RegExp(/^tyblocks_an(.*)/).test(input.token) || RegExp(/^tyblocks_ao(.*)/).test(input.token) || RegExp(/^tyblocks_ap(.*)/).test(input.token)) && "string" === typeof input.amount; const _io4 = input => "string" === typeof input.token && (RegExp(/^keeta_am(.*)/).test(input.token) || RegExp(/^keeta_an(.*)/).test(input.token) || RegExp(/^keeta_ao(.*)/).test(input.token) || RegExp(/^keeta_ap(.*)/).test(input.token) || RegExp(/^tyblocks_am(.*)/).test(input.token) || RegExp(/^tyblocks_an(.*)/).test(input.token) || RegExp(/^tyblocks_ao(.*)/).test(input.token) || RegExp(/^tyblocks_ap(.*)/).test(input.token)) && "string" === typeof input.amount; const _ao0 = (input, _path, _exceptionable = true) => (1 === input.version || __typia_transform__assertGuard._assertGuard(_exceptionable, {
|
|
851
907
|
method: "typia.createAssert",
|
|
852
908
|
path: _path + ".version",
|
|
853
909
|
expected: "1",
|
|
@@ -872,15 +928,15 @@ const assertKeetaFXAnchorQueueStage1RequestJSON = (() => { const _io0 = input =>
|
|
|
872
928
|
path: _path + ".request",
|
|
873
929
|
expected: "__type",
|
|
874
930
|
value: input.request
|
|
875
|
-
}, _errorFactory)) && (("object" === typeof input.expected && null !== input.expected || __typia_transform__assertGuard._assertGuard(_exceptionable, {
|
|
931
|
+
}, _errorFactory)) && (null === input.expected || ("object" === typeof input.expected && null !== input.expected || __typia_transform__assertGuard._assertGuard(_exceptionable, {
|
|
876
932
|
method: "typia.createAssert",
|
|
877
933
|
path: _path + ".expected",
|
|
878
|
-
expected: "__type.o1",
|
|
934
|
+
expected: "(__type.o1 | null)",
|
|
879
935
|
value: input.expected
|
|
880
936
|
}, _errorFactory)) && _ao2(input.expected, _path + ".expected", true && _exceptionable) || __typia_transform__assertGuard._assertGuard(_exceptionable, {
|
|
881
937
|
method: "typia.createAssert",
|
|
882
938
|
path: _path + ".expected",
|
|
883
|
-
expected: "__type.o1",
|
|
939
|
+
expected: "(__type.o1 | null)",
|
|
884
940
|
value: input.expected
|
|
885
941
|
}, _errorFactory)); const _ao1 = (input, _path, _exceptionable = true) => ("string" === typeof input.from && (RegExp(/^keeta_am(.*)/).test(input.from) || RegExp(/^keeta_an(.*)/).test(input.from) || RegExp(/^keeta_ao(.*)/).test(input.from) || RegExp(/^keeta_ap(.*)/).test(input.from) || RegExp(/^tyblocks_am(.*)/).test(input.from) || RegExp(/^tyblocks_an(.*)/).test(input.from) || RegExp(/^tyblocks_ao(.*)/).test(input.from) || RegExp(/^tyblocks_ap(.*)/).test(input.from)) || __typia_transform__assertGuard._assertGuard(_exceptionable, {
|
|
886
942
|
method: "typia.createAssert",
|