@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.
Files changed (45) hide show
  1. package/lib/encrypted-container.d.ts +53 -3
  2. package/lib/encrypted-container.d.ts.map +1 -1
  3. package/lib/encrypted-container.js +549 -93
  4. package/lib/encrypted-container.js.map +1 -1
  5. package/lib/http-server/index.d.ts.map +1 -1
  6. package/lib/http-server/index.js +58 -5
  7. package/lib/http-server/index.js.map +1 -1
  8. package/lib/queue/drivers/queue_firestore.d.ts +29 -0
  9. package/lib/queue/drivers/queue_firestore.d.ts.map +1 -0
  10. package/lib/queue/drivers/queue_firestore.js +279 -0
  11. package/lib/queue/drivers/queue_firestore.js.map +1 -0
  12. package/lib/queue/index.d.ts +56 -0
  13. package/lib/queue/index.d.ts.map +1 -1
  14. package/lib/queue/index.js +111 -21
  15. package/lib/queue/index.js.map +1 -1
  16. package/lib/resolver.d.ts +4 -15
  17. package/lib/resolver.d.ts.map +1 -1
  18. package/lib/resolver.js +468 -636
  19. package/lib/resolver.js.map +1 -1
  20. package/lib/utils/signing.d.ts +12 -3
  21. package/lib/utils/signing.d.ts.map +1 -1
  22. package/lib/utils/signing.js +7 -13
  23. package/lib/utils/signing.js.map +1 -1
  24. package/npm-shrinkwrap.json +4 -4
  25. package/package.json +2 -1
  26. package/services/asset-movement/client.d.ts +2 -2
  27. package/services/asset-movement/client.d.ts.map +1 -1
  28. package/services/asset-movement/client.js +2 -2
  29. package/services/asset-movement/client.js.map +1 -1
  30. package/services/asset-movement/common.d.ts +56 -22
  31. package/services/asset-movement/common.d.ts.map +1 -1
  32. package/services/asset-movement/common.js +295 -70
  33. package/services/asset-movement/common.js.map +1 -1
  34. package/services/fx/client.d.ts +15 -3
  35. package/services/fx/client.d.ts.map +1 -1
  36. package/services/fx/client.js +18 -0
  37. package/services/fx/client.js.map +1 -1
  38. package/services/fx/server.d.ts +22 -3
  39. package/services/fx/server.d.ts.map +1 -1
  40. package/services/fx/server.js +158 -102
  41. package/services/fx/server.js.map +1 -1
  42. package/services/fx/util.d.ts +26 -8
  43. package/services/fx/util.d.ts.map +1 -1
  44. package/services/fx/util.js +92 -4
  45. package/services/fx/util.js.map +1 -1
@@ -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 { assertExchangeBlockParameters } from './util.js';
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, expected, request } = entry.request;
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
- const publishResult = await userClient.client.transmit(swapBlocks, publishOptions);
249
- if (!publishResult.publish) {
250
- throw (new Error('Exchange Publish Failed'));
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
- const retval = {
265
- version: 1,
266
- account: request.account.publicKeyString.get(),
267
- block: Buffer.from(request.block.toBytes()).toString('base64'),
268
- request: request.request,
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
- const retval = {
293
- account: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.account),
294
- block: new KeetaNet.lib.Block(reqJSON.block),
295
- request: reqJSON.request,
296
- expected: {
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
- pipelineAutoRunInterval = null;
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
- let autorun = config.storage?.autoRun ?? false;
515
+ this.autoRun = config.storage?.autoRun ?? false;
459
516
  if (config.storage === undefined) {
460
- autorun = true;
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 config.fx.getConversionRateAndFee(conversion);
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
- assertExchangeBlockParameters({
744
+ assertExchangeBlockParametersAndComputeRefund({
724
745
  block: block,
725
746
  liquidityAccount: liquidityAccountInstance,
726
747
  allowedLiquidityAccounts: allowedLiquidityAccounts,
727
- userSendsMinimum: userSendsMinimum,
728
- userWillReceiveMaximum: userWillReceiveMaximum
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",