@keetanetwork/anchor 0.0.37 → 0.0.38

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.
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/services/fx/server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as KeetaAnchorHTTPServer from '../../lib/http-server/index.js';\nimport { KeetaNet } from '../../client/index.js';\nimport {\n\tKeetaAnchorUserError\n} from '../../lib/error.js';\nimport {\n\tassertConversionInputCanonicalJSON,\n\tassertConversionQuoteJSON,\n\tErrors\n} from './common.js';\nimport type {\n\tConversionInputCanonicalJSON,\n\tKeetaFXAnchorEstimateResponse,\n\tKeetaFXAnchorExchangeResponse,\n\tKeetaFXAnchorQuote,\n\tKeetaFXAnchorQuoteJSON,\n\tKeetaFXAnchorQuoteResponse,\n\tKeetaNetAccount,\n\tKeetaNetStorageAccount\n} from './common.ts';\nimport * as Signing from '../../lib/utils/signing.js';\nimport type { AssertNever } from '../../lib/utils/never.ts';\nimport type { ServiceMetadata } from '../../lib/resolver.ts';\nimport { KeetaAnchorQueueRunner, KeetaAnchorQueueStorageDriverMemory } from '../../lib/queue/index.js';\nimport type { KeetaAnchorQueueStorageDriver, KeetaAnchorQueueRequestID } from '../../lib/queue/index.ts';\nimport { KeetaAnchorQueuePipelineAdvanced } from '../../lib/queue/pipeline.js';\nimport type { JSONSerializable } from '../../lib/utils/json.ts';\nimport { assertNever } from '../../lib/utils/never.js';\nimport * as typia from 'typia';\n\n/**\n * Enable additional runtime \"paranoid\" checks in the FX server.\n *\n * This may have a small performance impact but increases safety\n * by ensuring that the accounts used in quotes are actually\n * configured in the server.\n *\n * During the transition to multiple accounts this may help catch\n * misconfigurations so it is enabled by default for now.\n */\nconst PARANOID = true;\n\nexport interface KeetaAnchorFXServerConfig extends KeetaAnchorHTTPServer.KeetaAnchorHTTPServerConfig {\n\t/**\n\t * The data to use for the index page (optional)\n\t */\n\thomepage?: string | (() => Promise<string> | string);\n\n\t/**\n\t * All accounts that may be used by the server to perform swaps\n\t *\n\t * Temporary compatibility: If this is not provided, the single\n\t * `account` property will be used to create a set of one account.\n\t */\n\taccounts?: InstanceType<typeof KeetaNet.lib.Account.Set>;\n\n\t/**\n\t * Account to use to perform transactions\n\t *\n\t * @deprecated Use `signer` and `accounts` instead\n\t */\n\taccount?: InstanceType<typeof KeetaNet.lib.Account> | undefined;\n\n\t/**\n\t * Account which can be used to sign transactions\n\t * for the accounts above\n\t *\n\t * This may be either a function or a KeetaNet Account instance.\n\t *\n\t * Temporary compatibility: If not provided, the `account` property\n\t * will be used as the signer.\n\t */\n\tsigner?: InstanceType<typeof KeetaNet.lib.Account> | ((request: ConversionInputCanonicalJSON) => Promise<InstanceType<typeof KeetaNet.lib.Account>> | InstanceType<typeof KeetaNet.lib.Account>);\n\n\t/**\n\t * Account which performs the signing and validation of quotes\n\t */\n\tquoteSigner: Signing.SignableAccount;\n\n\t/**\n\t * Configuration for FX handling\n\t */\n\tfx: {\n\t\t/**\n\t\t * Supported conversions\n\t\t */\n\t\tfrom?: NonNullable<ServiceMetadata['services']['fx']>[string]['from'];\n\t\t/**\n\t\t * Handle the conversion request of one token to another\n\t\t *\n\t\t * This is used to handle quotes and estimates\n\t\t */\n\t\tgetConversionRateAndFee: (request: ConversionInputCanonicalJSON) => Promise<Omit<KeetaFXAnchorQuote, 'request' | 'signed' >>;\n\n\t\t/**\n\t\t * Optional callback to validate a quote before completing an exchange\n\t\t *\n\t\t * This allows the FX Server operator to reject quotes that are no longer\n\t\t * acceptable (e.g., due to price changes, expiry, or other business logic)\n\t\t *\n\t\t * @param quote The quote to validate\n\t\t * @returns true to accept the quote and proceed with the exchange, false to reject it\n\t\t */\n\t\tvalidateQuote?: (quote: KeetaFXAnchorQuoteJSON) => Promise<boolean> | boolean;\n\n\t};\n\n\t/**\n\t * Storage driver to use for stateful operation and managing queues\n\t *\n\t * You are responsible for running and maintaining the queue processor unless\n\t * you enable auto-run below.\n\t */\n\tstorage?: {\n\t\t/**\n\t\t * The storage driver or queue runner to use to serialize\n\t\t * and batch requests\n\t\t */\n\t\tqueue: KeetaAnchorQueueStorageDriver<JSONSerializable, JSONSerializable>;\n\t\t/**\n\t\t * If enabled the server will automatically run the queue processor\n\t\t */\n\t\tautoRun?: boolean;\n\t};\n\n\t/**\n\t * The network client to use for submitting blocks\n\t */\n\tclient: { client: KeetaNet.Client; network: bigint; networkAlias: typeof KeetaNet.Client.Config.networksArray[number] } | KeetaNet.UserClient;\n};\n\nasync function formatQuoteSignable(unsignedQuote: Omit<KeetaFXAnchorQuoteJSON, 'signed'>): Promise<Signing.Signable> {\n\tconst retval: Signing.Signable = [\n\t\tunsignedQuote.request.from,\n\t\tunsignedQuote.request.to,\n\t\tunsignedQuote.request.amount,\n\t\tunsignedQuote.request.affinity,\n\t\tunsignedQuote.account,\n\t\tunsignedQuote.convertedAmount,\n\t\tunsignedQuote.cost.token,\n\t\tunsignedQuote.cost.amount\n\t];\n\n\treturn(retval);\n\n\t/**\n\t * This is a static assertion to ensure that this function is updated\n\t * if new fields are added to the KeetaFXAnchorQuote type to ensure\n\t * that we are always signing all the fields.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\ttype _ignore_static_assert = AssertNever<\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n\t\tAssertNever<keyof Omit<typeof unsignedQuote['request'], 'from' | 'to' | 'amount' | 'affinity'>> &\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents,@typescript-eslint/no-duplicate-type-constituents\n\t\tAssertNever<keyof Omit<typeof unsignedQuote['cost'], 'token' | 'amount'>> &\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents,@typescript-eslint/no-duplicate-type-constituents\n\t\tAssertNever<keyof Omit<typeof unsignedQuote, 'request' | 'convertedAmount' | 'cost' | 'account'>>\n\t>;\n}\n\nasync function generateSignedQuote(signer: Signing.SignableAccount, unsignedQuote: Omit<KeetaFXAnchorQuoteJSON, 'signed'>): Promise<KeetaFXAnchorQuoteJSON> {\n\tconst signableQuote = await formatQuoteSignable(unsignedQuote);\n\tconst signed = await Signing.SignData(signer, signableQuote);\n\n\treturn({\n\t\t...unsignedQuote,\n\t\tsigned: signed\n\t});\n}\n\nasync function verifySignedData(signedBy: Signing.VerifableAccount, quote: KeetaFXAnchorQuoteJSON): Promise<boolean> {\n\tconst signableQuote = await formatQuoteSignable(quote);\n\n\treturn(await Signing.VerifySignedData(signedBy, signableQuote, quote.signed));\n}\n\nasync function requestToAccounts(config: KeetaAnchorFXServerConfig, request: ConversionInputCanonicalJSON): Promise<{ signer: Signing.SignableAccount; account: KeetaNetAccount | KeetaNetStorageAccount | null; }> {\n\tlet account: KeetaNetAccount | KeetaNetStorageAccount | null;\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tif (config.account !== undefined) {\n\t\tconst rateFee = await config.fx.getConversionRateAndFee(request);\n\t\taccount = rateFee.account;\n\t} else {\n\t\taccount = null;\n\t}\n\n\tlet signer: Signing.SignableAccount | null = null;\n\tif (config.signer !== undefined) {\n\t\tsigner = (KeetaNet.lib.Account.isInstance(config.signer) ? config.signer : await config.signer(request)).assertAccount();\n\t}\n\n\tif (account !== null) {\n\t\tif (signer === null) {\n\t\t\tsigner = account.assertAccount();\n\t\t}\n\n\t\tif (!account.isAccount() && !account.isStorage()) {\n\t\t\tthrow(new Error('FX Account should be an Account or Storage Account'));\n\t\t}\n\t} else if (signer === null) {\n\t\tthrow(new Error('Either account or signer must be provided'));\n\t}\n\n\treturn({\n\t\taccount: account,\n\t\tsigner: signer\n\t});\n}\n\n/* QUEUE PROCESSOR PIPELINE */\ntype KeetaFXAnchorQueueStage1Request = {\n\taccount: KeetaNetAccount;\n\tblock: Parameters<typeof KeetaNet.UserClient['acceptSwapRequest']>[0]['block'];\n\trequest: ConversionInputCanonicalJSON;\n\texpected: Required<NonNullable<Parameters<typeof KeetaNet.UserClient['acceptSwapRequest']>[0]['expected']>>;\n};\ntype KeetaFXAnchorQueueStage1RequestJSON = {\n\t/** Version of the request format */\n\tversion: 1;\n\t/** FX Anchor Account performing swap */\n\taccount: string;\n\t/** Base64 encoded block from the user */\n\tblock: string;\n\t/** Original request */\n\trequest: ConversionInputCanonicalJSON;\n\t/** Expected exchange details for verification */\n\texpected: {\n\t\ttoken: string;\n\t\tamount: string;\n\t};\n};\ntype KeetaFXAnchorQueueStage1Response = {\n\t/**\n\t * All the blocks for the given swap request\n\t */\n\tblocks: string[];\n\t/**\n\t * The hash of one of the blocks submitted\n\t */\n\tblockhash: string;\n};\n\nclass KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response> {\n\tprotected readonly serverConfig: KeetaAnchorFXServerConfig;\n\tprotected sequential = true;\n\n\t/**\n\t * Timeout for processing a single job -- if exceeded the job is marked as aborted\n\t */\n\tprotected processTimeout: number = 60 * 1000;\n\n\tconstructor(config: ConstructorParameters<typeof KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>>[0] & { serverConfig: KeetaAnchorFXServerConfig; }) {\n\t\tsuper(config);\n\n\t\tthis.serverConfig = config.serverConfig;\n\t\tthis.processorAborted = this.processorStuck.bind(this);\n\t}\n\n\t/**\n\t * Handles both stuck (no status update after a long period) and\n\t * aborted (timeout while processing an entry) states.\n\t *\n\t * We just put the job back into pending because the processor\n\t * will check the network state again.\n\t */\n\tprotected async processorStuck(entry: Parameters<NonNullable<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processorStuck']>>[0]): ReturnType<NonNullable<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processorStuck']>> {\n\t\treturn({\n\t\t\tstatus: 'pending',\n\t\t\toutput: entry.output\n\t\t});\n\t}\n\n\t/**\n\t * Process the entry, attempting to submit the swap block(s)\n\t * to the network. Verifies the block can be submitted before\n\t * attempting submission. Also verifies if the block is already\n\t * on the network and marks the job as completed if so.\n\t */\n\tprotected async processor(entry: Parameters<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processor']>[0]): ReturnType<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processor']> {\n\t\tconst { block, expected, request } = entry.request;\n\t\tconst expectedToken = expected.token;\n\t\tconst expectedAmount = expected.amount;\n\t\tconst config = this.serverConfig;\n\n\t\tlet userClient: KeetaNet.UserClient;\n\n\t\tif (KeetaNet.UserClient.isInstance(config.client)) {\n\t\t\tuserClient = config.client;\n\t\t} else {\n\t\t\tconst { signer, account: checkAccount } = await requestToAccounts(config, request);\n\n\t\t\tif (checkAccount === null) {\n\t\t\t\tif (this.serverConfig.accounts === undefined) {\n\t\t\t\t\tthrow(new Error('No accounts configured for FX server'));\n\t\t\t\t}\n\n\t\t\t\tif (!this.serverConfig.accounts.has(entry.request.account)) {\n\t\t\t\t\treturn({\n\t\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\t\toutput: null,\n\t\t\t\t\t\terror: `Mismatched account for FX request and configured account (no matching account found)`\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (!checkAccount.comparePublicKey(entry.request.account)) {\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Mismatched account for FX request and configured account (single account not matched)`\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tuserClient = new KeetaNet.UserClient({\n\t\t\t\tclient: config.client.client,\n\t\t\t\tnetwork: config.client.network,\n\t\t\t\tnetworkAlias: config.client.networkAlias,\n\t\t\t\taccount: entry.request.account,\n\t\t\t\tsigner: signer\n\t\t\t});\n\t\t}\n\n\t\t/* Check for the block already being on the network, if so we can mark this job as completed */\n\t\tconst blockExists = await userClient.block(block.hash);\n\t\tif (blockExists !== null) {\n\t\t\tconst existingOutput = entry.output;\n\t\t\tconst blocks = existingOutput?.blocks ?? [Buffer.from(block.toBytes()).toString('base64')];\n\n\t\t\treturn({\n\t\t\t\tstatus: 'completed',\n\t\t\t\toutput: {\n\t\t\t\t\tblockhash: block.hash.toString(),\n\t\t\t\t\tblocks: blocks\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* Get the current head block of the account in the block */\n\t\tconst accountHead = await userClient.head({ account: block.account });\n\t\tlet isHeadBlock = false;\n\t\tif (accountHead !== null) {\n\t\t\tisHeadBlock = accountHead.compare(block.previous);\n\t\t} else {\n\t\t\tisHeadBlock = block['$opening'];\n\t\t}\n\n\t\t/* If the account's head block is not the block's previous, see if the block's previous exists on the network */\n\t\tif (!isHeadBlock) {\n\t\t\tlet previousBlockOnNetwork = false;\n\t\t\tif (block['$opening']) {\n\t\t\t\t/* Opening block means that there is no previous block, so we are free to proceed */\n\t\t\t\tpreviousBlockOnNetwork = true;\n\t\t\t} else {\n\t\t\t\tconst previousBlock = await userClient.block(block.previous);\n\t\t\t\tif (previousBlock !== null) {\n\t\t\t\t\tpreviousBlockOnNetwork = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet blockPreviousString: string;\n\t\t\tif (block['$opening']) {\n\t\t\t\tblockPreviousString = '<opening>';\n\t\t\t} else {\n\t\t\t\tblockPreviousString = block.previous.toString();\n\t\t\t}\n\n\t\t\t/* If block.previous exists on the network, and it's not the account head block we can mark this job as failed_permanently */\n\t\t\tif (previousBlockOnNetwork) {\n\t\t\t\t/* Block's previous exists on the network, but is not the account head -- mark as failed_permanently */\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Block previous (${blockPreviousString}) exists on the network but is not the account head`\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t/* If block.previous does not exist on the network we can mark this job as failed_temporarily -- it can't process until the missing block is added */\n\t\t\t\t/* Block's previous does not exist on the network -- mark as failed_temporarily */\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_temporarily',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Block previous (${blockPreviousString}) does not exist on the network`\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t/* We are clear to attempt the swap now */\n\t\tconst swapBlocks = await userClient.acceptSwapRequest({ block, expected: { token: expectedToken, amount: BigInt(expectedAmount) }});\n\t\tconst publishOptions: Parameters<typeof userClient.client.transmit>[1] = {};\n\t\tif (userClient.config.generateFeeBlock !== undefined) {\n\t\t\tpublishOptions.generateFeeBlock = userClient.config.generateFeeBlock;\n\t\t}\n\t\tconst publishResult = await userClient.client.transmit(swapBlocks, publishOptions);\n\t\tif (!publishResult.publish) {\n\t\t\tthrow(new Error('Exchange Publish Failed'));\n\t\t}\n\n\t\t/* Set the output and mark the job as pending so we can run the queue again and check for completion */\n\t\treturn({\n\t\t\tstatus: 'pending',\n\t\t\toutput: {\n\t\t\t\tblockhash: block.hash.toString(),\n\t\t\t\tblocks: swapBlocks.map(function(block) {\n\t\t\t\t\treturn(Buffer.from(block.toBytes()).toString('base64'));\n\t\t\t\t})\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected encodeRequest(request: KeetaFXAnchorQueueStage1Request): JSONSerializable {\n\t\tconst retval: KeetaFXAnchorQueueStage1RequestJSON = {\n\t\t\tversion: 1,\n\t\t\taccount: request.account.publicKeyString.get(),\n\t\t\tblock: Buffer.from(request.block.toBytes()).toString('base64'),\n\t\t\trequest: request.request,\n\t\t\texpected: {\n\t\t\t\ttoken: request.expected.token.publicKeyString.get(),\n\t\t\t\tamount: request.expected.amount.toString()\n\t\t\t}\n\t\t};\n\n\t\treturn(retval);\n\t}\n\n\tprotected encodeResponse(response: KeetaFXAnchorQueueStage1Response | null): JSONSerializable | null {\n\t\treturn(response);\n\t}\n\n\tprotected decodeRequest(request: JSONSerializable): KeetaFXAnchorQueueStage1Request {\n\t\t/* See note at bottom of file */\n\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\tconst reqJSON = assertKeetaFXAnchorQueueStage1RequestJSON(request);\n\n\t\tif (reqJSON.version !== 1) {\n\t\t\tthrow(new Error(`Unsupported KeetaFXAnchorQueueStage1Request version ${reqJSON.version}`));\n\t\t}\n\n\t\tconst retval: KeetaFXAnchorQueueStage1Request = {\n\t\t\taccount: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.account),\n\t\t\tblock: new KeetaNet.lib.Block(reqJSON.block),\n\t\t\trequest: reqJSON.request,\n\t\t\texpected: {\n\t\t\t\ttoken: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.expected.token).assertKeyType(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN),\n\t\t\t\tamount: BigInt(reqJSON.expected.amount)\n\t\t\t}\n\t\t};\n\n\t\treturn(retval);\n\t}\n\n\tprotected decodeResponse(response: JSONSerializable | null): KeetaFXAnchorQueueStage1Response | null {\n\t\t/* See note at bottom of file */\n\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\treturn(assertKeetaFXAnchorQueueStage1ResponseOrNull(response));\n\t}\n}\n\nclass KeetaFXAnchorQueuePipeline extends KeetaAnchorQueuePipelineAdvanced<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response> {\n\tprivate readonly serverConfig: KeetaAnchorFXServerConfig;\n\tprivate readonly accounts: InstanceType<typeof KeetaNet.lib.Account.Set>;\n\tprivate runners: { [account: string]: KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>; } = {};\n\n\tconstructor(options: ConstructorParameters<typeof KeetaAnchorQueuePipelineAdvanced<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>>[0] & { serverConfig: KeetaAnchorFXServerConfig; accounts: InstanceType<typeof KeetaNet.lib.Account.Set>; }) {\n\t\tsuper(options);\n\n\t\tthis.serverConfig = options.serverConfig;\n\t\tthis.accounts = options.accounts;\n\t}\n\n\tprotected async createPipeline(): Promise<void> {\n\t\tfor (const account of this.accounts) {\n\t\t\tconst queue = await this.baseQueue.partition(account.publicKeyAndTypeString);\n\t\t\tthis.queues.push(queue);\n\n\t\t\tconst runner = new KeetaFXAnchorQueuePipelineStage1({\n\t\t\t\tid: `keeta-fx-anchor-runner-${account.publicKeyAndTypeString}`,\n\t\t\t\tqueue: queue,\n\t\t\t\tlogger: this.logger,\n\t\t\t\tserverConfig: this.serverConfig\n\t\t\t});\n\t\t\tthis.runners[account.publicKeyAndTypeString] = runner;\n\t\t}\n\t}\n\n\tprotected getStage(stageID: typeof KeetaAnchorQueuePipelineAdvanced.StageID.first | typeof KeetaAnchorQueuePipelineAdvanced.StageID.last): KeetaFXAnchorQueuePipelineStage1;\n\tprotected getStage(_ignore_stageID: typeof KeetaAnchorQueuePipelineAdvanced.StageID.first | typeof KeetaAnchorQueuePipelineAdvanced.StageID.last | string): KeetaFXAnchorQueuePipelineStage1 | null {\n\t\tthrow(new Error('method not supported'));\n\t}\n\n\tasync add(request: KeetaFXAnchorQueueStage1Request): ReturnType<KeetaFXAnchorQueuePipelineStage1['add']> {\n\t\tawait super.init();\n\n\t\tconst account = request.account.publicKeyAndTypeString;\n\n\t\tconst runner = this.runners[account];\n\t\tif (runner === undefined) {\n\t\t\tthrow(new Error(`No queue runner for account ${account}`));\n\t\t}\n\n\t\treturn(await runner.add(request));\n\t}\n\n\tasync get(id: KeetaAnchorQueueRequestID): ReturnType<KeetaFXAnchorQueuePipelineStage1['get']> {\n\t\tawait super.init();\n\n\t\tfor (const account of this.accounts) {\n\t\t\tconst runner = this.runners[account.publicKeyAndTypeString];\n\t\t\tif (runner === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst entry = await runner.get(id);\n\t\t\tif (entry !== null) {\n\t\t\t\treturn(entry);\n\t\t\t}\n\t\t}\n\n\t\treturn(null);\n\t}\n\n\tasync run(options?: Parameters<KeetaFXAnchorQueuePipelineStage1['run']>[0]): ReturnType<KeetaFXAnchorQueuePipelineStage1['run']> {\n\t\tawait super.init();\n\n\t\tlet retval = false;\n\t\tfor (const account of this.accounts) {\n\t\t\tconst runner = this.runners[account.publicKeyAndTypeString];\n\t\t\tif (runner === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst more = await runner.run(options);\n\t\t\tif (more) {\n\t\t\t\tretval = true;\n\t\t\t}\n\t\t}\n\n\t\treturn(retval);\n\t}\n\n\tasync maintain(): Promise<void> {\n\t\tawait super.init();\n\n\t\tfor (const account of this.accounts) {\n\t\t\tconst runner = this.runners[account.publicKeyAndTypeString];\n\t\t\tif (runner === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tawait runner.maintain();\n\t\t}\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tconst logger = this.methodLogger('destroy');\n\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.destroyed = true;\n\n\t\tawait super.destroy();\n\n\t\tfor (const runner of Object.values(this.runners)) {\n\t\t\ttry {\n\t\t\t\tawait runner.destroy();\n\t\t\t} catch (error) {\n\t\t\t\tlogger?.error('Error destroying runner:', error);\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nexport class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAnchorHTTPServer<KeetaAnchorFXServerConfig> implements Omit<Required<KeetaAnchorFXServerConfig>, 'storage'> {\n\treadonly homepage: NonNullable<KeetaAnchorFXServerConfig['homepage']>;\n\treadonly client: KeetaAnchorFXServerConfig['client'];\n\treadonly accounts: NonNullable<KeetaAnchorFXServerConfig['accounts']>;\n\treadonly account: KeetaAnchorFXServerConfig['account'] = undefined;\n\treadonly signer: NonNullable<KeetaAnchorFXServerConfig['signer']>;\n\treadonly quoteSigner: KeetaAnchorFXServerConfig['quoteSigner'];\n\treadonly fx: KeetaAnchorFXServerConfig['fx'];\n\treadonly pipeline: KeetaFXAnchorQueuePipeline;\n\tprotected pipelineAutoRunInterval: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(config: KeetaAnchorFXServerConfig) {\n\t\tsuper(config);\n\n\t\tthis.homepage = config.homepage ?? '';\n\t\tthis.client = config.client;\n\t\tthis.fx = config.fx;\n\t\tthis.quoteSigner = config.quoteSigner;\n\n\t\t/*\n\t\t * Setup the accounts\n\t\t */\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif (config.account !== undefined && config.accounts === undefined) {\n\t\t\t/*\n\t\t\t * Deprecated: If a single account is provided, use that\n\t\t\t * along with the signer to create the accounts set\n\t\t\t */\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tthis.accounts = new KeetaNet.lib.Account.Set([config.account]);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tthis.signer = config.signer ?? config.account;\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t} else if (config.accounts !== undefined && config.account === undefined) {\n\t\t\t/*\n\t\t\t * Only allow either \"account\" or \"accounts\"+\"signer\" to be provided\n\t\t\t */\n\t\t\tif (config.signer === undefined) {\n\t\t\t\tthrow(new Error('If \"accounts\" is provided, \"signer\" must also be provided'));\n\t\t\t}\n\n\t\t\tthis.accounts = config.accounts;\n\t\t\tthis.signer = config.signer;\n\t\t} else {\n\t\t\tthrow(new Error('Either \"account\" (and optional \"signer\") or \"accounts\" and \"signer\" must be provided, but not both \"account\" and \"accounts\"'));\n\t\t}\n\n\t\tif (this.accounts.size === 0) {\n\t\t\tthrow(new Error('No FX accounts provided'));\n\t\t}\n\n\t\t/*\n\t\t * If no storage driver is provided, we default to an in-memory\n\t\t * that we auto-run\n\t\t */\n\t\tlet autorun = config.storage?.autoRun ?? false;\n\t\tif (config.storage === undefined) {\n\t\t\tautorun = true;\n\t\t}\n\n\t\t/*\n\t\t * Create the pipeline to process transactions\n\t\t */\n\t\tthis.pipeline = new KeetaFXAnchorQueuePipeline({\n\t\t\tid: 'keeta-fx-anchor-queue-pipeline',\n\t\t\tbaseQueue: config.storage?.queue ?? new KeetaAnchorQueueStorageDriverMemory({\n\t\t\t\tid: 'keeta-fx-anchor-queue-pipeline-memory-driver',\n\t\t\t\tlogger: this.logger\n\t\t\t}),\n\t\t\taccounts: this.accounts,\n\t\t\tlogger: this.logger,\n\t\t\tserverConfig: this\n\t\t});\n\n\t\t/*\n\t\t * If auto-run is enabled, setup the interval to run the pipeline\n\t\t */\n\t\tif (autorun) {\n\t\t\tlet running = false;\n\t\t\tthis.pipelineAutoRunInterval = setInterval(async () => {\n\t\t\t\tif (running) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\trunning = true;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.pipeline.maintain();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error('KeetaNetFXAnchorHTTPServer::pipelineAutoRunInterval', 'Error maintaining pipeline:', error);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait this.pipeline.run({ timeoutMs: 5000 });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error('KeetaNetFXAnchorHTTPServer::pipelineAutoRunInterval', 'Error running pipeline:', error);\n\t\t\t\t} finally {\n\t\t\t\t\trunning = false;\n\t\t\t\t}\n\t\t\t}, 1000);\n\t\t}\n\t}\n\n\tprotected async initRoutes(config: KeetaAnchorFXServerConfig): Promise<KeetaAnchorHTTPServer.Routes> {\n\t\tconst routes: KeetaAnchorHTTPServer.Routes = {};\n\t\tconst logger = this.logger;\n\n\t\t/*\n\t\t * To use the instance within the route handlers, we need to\n\t\t * make a local reference to it.\n\t\t */\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tconst instance = this;\n\n\t\t/**\n\t\t * If a homepage is provided, setup the route for it\n\t\t */\n\t\tif ('homepage' in config) {\n\t\t\troutes['GET /'] = async function() {\n\t\t\t\tlet homepageData: string;\n\t\t\t\tif (typeof config.homepage === 'string') {\n\t\t\t\t\thomepageData = config.homepage;\n\t\t\t\t} else {\n\t\t\t\t\tif (!config.homepage) {\n\t\t\t\t\t\tthrow(new Error('internal error: No homepage function provided'));\n\t\t\t\t\t}\n\n\t\t\t\t\thomepageData = await config.homepage();\n\t\t\t\t}\n\n\t\t\t\treturn({\n\t\t\t\t\toutput: homepageData,\n\t\t\t\t\tcontentType: 'text/html'\n\t\t\t\t});\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Setup the request handler for an estimate request\n\t\t */\n\t\troutes['POST /api/getEstimate'] = async function(_ignore_params, postData) {\n\t\t\tif (!postData || typeof postData !== 'object') {\n\t\t\t\tthrow(new Error('No POST data provided'));\n\t\t\t}\n\t\t\tif (!('request' in postData)) {\n\t\t\t\tthrow(new Error('POST data missing request'));\n\t\t\t}\n\n\t\t\tconst conversion = assertConversionInputCanonicalJSON(postData.request);\n\t\t\tconst rateAndFee = await config.fx.getConversionRateAndFee(conversion);\n\t\t\tconst estimateResponse: KeetaFXAnchorEstimateResponse = {\n\t\t\t\tok: true,\n\t\t\t\testimate: KeetaNet.lib.Utils.Conversion.toJSONSerializable({\n\t\t\t\t\trequest: conversion,\n\t\t\t\t\tconvertedAmount: rateAndFee.convertedAmount,\n\t\t\t\t\texpectedCost: {\n\t\t\t\t\t\tmin: rateAndFee.cost.amount,\n\t\t\t\t\t\tmax: rateAndFee.cost.amount,\n\t\t\t\t\t\ttoken: rateAndFee.cost.token\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t};\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(estimateResponse)\n\t\t\t});\n\t\t}\n\n\t\troutes['POST /api/getQuote'] = async function(_ignore_params, postData) {\n\t\t\tif (!postData || typeof postData !== 'object') {\n\t\t\t\tthrow(new Error('No POST data provided'));\n\t\t\t}\n\t\t\tif (!('request' in postData)) {\n\t\t\t\tthrow(new Error('POST data missing request'));\n\t\t\t}\n\n\t\t\tconst conversion = assertConversionInputCanonicalJSON(postData.request);\n\t\t\tconst rateAndFee = await config.fx.getConversionRateAndFee(conversion);\n\n\t\t\tif (PARANOID) {\n\t\t\t\tconst quoteAccount = rateAndFee.account;\n\t\t\t\tif (!instance.accounts.has(quoteAccount)) {\n\t\t\t\t\tthrow(new Error('\"getConversionRateAndFee\" returned an account not configured for this server'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst unsignedQuote: Omit<KeetaFXAnchorQuoteJSON, 'signed'> = KeetaNet.lib.Utils.Conversion.toJSONSerializable({\n\t\t\t\trequest: conversion,\n\t\t\t\t...rateAndFee\n\t\t\t});\n\n\t\t\tconst signedQuote = await generateSignedQuote(config.quoteSigner, unsignedQuote);\n\t\t\tconst quoteResponse: KeetaFXAnchorQuoteResponse = {\n\t\t\t\tok: true,\n\t\t\t\tquote: signedQuote\n\t\t\t};\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(quoteResponse)\n\t\t\t});\n\t\t}\n\n\t\troutes['POST /api/createExchange'] = async function(_ignore_params, postData) {\n\t\t\tif (!postData || typeof postData !== 'object') {\n\t\t\t\tthrow(new Error('No POST data provided'));\n\t\t\t}\n\n\t\t\tif (!('request' in postData)) {\n\t\t\t\tthrow(new Error('POST data missing request'));\n\t\t\t}\n\t\t\tconst request = postData.request;\n\t\t\tif (!request || typeof request !== 'object') {\n\t\t\t\tthrow(new Error('Request is not an object'));\n\t\t\t}\n\n\t\t\tif (!('quote' in request)) {\n\t\t\t\tthrow(new Error('Quote is missing from request'));\n\t\t\t}\n\t\t\tif (!('block' in request) || typeof request.block !== 'string') {\n\t\t\t\tthrow(new Error('Block was not provided in exchange request'));\n\t\t\t}\n\n\t\t\tconst quote = assertConversionQuoteJSON(request.quote);\n\t\t\tconst isValidQuote = await verifySignedData(config.quoteSigner, quote);\n\t\t\tif (!isValidQuote) {\n\t\t\t\tthrow(new Error('Invalid quote signature'));\n\t\t\t}\n\n\t\t\t/* Validate the quote using the optional callback */\n\t\t\tif (config.fx.validateQuote !== undefined) {\n\t\t\t\tconst isAcceptable = await config.fx.validateQuote(quote);\n\t\t\t\tif (!isAcceptable) {\n\t\t\t\t\tthrow(new Errors.QuoteValidationFailed());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst block = new KeetaNet.lib.Block(request.block);\n\n\t\t\t/* Get Expected Amount and Token to Verify Swap */\n\t\t\tconst expectedToken = KeetaNet.lib.Account.fromPublicKeyString(quote.request.from);\n\t\t\tlet expectedAmount = quote.request.affinity === 'from' ? BigInt(quote.request.amount) : BigInt(quote.convertedAmount);\n\t\t\t/* If cost is required verify the amounts and token. */\n\t\t\tif (BigInt(quote.cost.amount) > 0) {\n\t\t\t\t/* If swap token matches the cost token the add the amount since they should be combined in one block and will be checked in `acceptSwapRequest` */\n\t\t\t\tif (expectedToken.comparePublicKey(quote.cost.token)) {\n\t\t\t\t\texpectedAmount += BigInt(quote.cost.amount);\n\t\t\t\t/* If token is different then check block operations for matching amount and token */\n\t\t\t\t} else {\n\t\t\t\t\tlet requestIncludesCost = false;\n\t\t\t\t\tfor (const operation of block.operations) {\n\t\t\t\t\t\tif (operation.type === KeetaNet.lib.Block.OperationType.SEND) {\n\t\t\t\t\t\t\tconst recipientMatches = operation.to.comparePublicKey(quote.account);\n\t\t\t\t\t\t\tconst tokenMatches = operation.token.comparePublicKey(quote.cost.token);\n\t\t\t\t\t\t\tconst amountMatches = operation.amount === BigInt(quote.cost.amount);\n\t\t\t\t\t\t\tif (recipientMatches && tokenMatches && amountMatches) {\n\t\t\t\t\t\t\t\trequestIncludesCost = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!requestIncludesCost) {\n\t\t\t\t\t\tthrow(new Error('Exchange missing required cost'));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Enqueue the exchange request */\n\t\t\tconst exchangeID = await instance.pipeline.add({\n\t\t\t\taccount: KeetaNet.lib.Account.fromPublicKeyString(quote.account),\n\t\t\t\tblock: block,\n\t\t\t\trequest: quote.request,\n\t\t\t\texpected: {\n\t\t\t\t\ttoken: expectedToken,\n\t\t\t\t\tamount: BigInt(expectedAmount)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst exchangeResponse: KeetaFXAnchorExchangeResponse = {\n\t\t\t\tok: true,\n\t\t\t\texchangeID: exchangeID.toString(),\n\t\t\t\tstatus: 'pending'\n\t\t\t};\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(exchangeResponse)\n\t\t\t});\n\t\t}\n\n\t\troutes['GET /api/getExchangeStatus/:id'] = async function(params) {\n\t\t\tif (params === undefined || params === null) {\n\t\t\t\tthrow(new KeetaAnchorUserError('Expected params'));\n\t\t\t}\n\t\t\tconst exchangeID = params.get('id');\n\t\t\tif (typeof exchangeID !== 'string') {\n\t\t\t\tthrow(new Error('Missing exchangeID in params'));\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\tconst queueEntryInfo = await instance.pipeline.get(exchangeID as unknown as KeetaAnchorQueueRequestID);\n\t\t\tconst exchangeResponse = (function(): KeetaFXAnchorExchangeResponse {\n\t\t\t\tconst inputStatus = queueEntryInfo?.status;\n\t\t\t\tswitch (inputStatus) {\n\t\t\t\t\tcase undefined:\n\t\t\t\t\t\tthrow(new KeetaAnchorUserError('Exchange ID not found'));\n\t\t\t\t\tcase 'pending':\n\t\t\t\t\tcase 'processing':\n\t\t\t\t\tcase 'stuck':\n\t\t\t\t\tcase 'aborted':\n\t\t\t\t\tcase 'failed_temporarily':\n\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\tstatus: 'pending',\n\t\t\t\t\t\t\texchangeID: exchangeID\n\t\t\t\t\t\t});\n\t\t\t\t\tcase 'completed': {\n\t\t\t\t\t\tconst blockhash = queueEntryInfo?.output?.blockhash;\n\t\t\t\t\t\tif (blockhash === undefined) {\n\t\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\t\tstatus: 'pending',\n\t\t\t\t\t\t\t\texchangeID: exchangeID\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t\t\texchangeID: exchangeID,\n\t\t\t\t\t\t\t\tblockhash: blockhash\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'failed_permanently':\n\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\texchangeID: exchangeID,\n\t\t\t\t\t\t\tstatus: 'failed',\n\t\t\t\t\t\t\terror: 'Exchange failed'\n\t\t\t\t\t\t});\n\t\t\t\t\tcase 'moved':\n\t\t\t\t\t\tthrow(new Error('Exchange ID has been moved'));\n\t\t\t\t\tcase '@internal':\n\t\t\t\t\t\tthrow(new Error('Invalid exchange status @internal'));\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tassertNever(inputStatus);\n\t\t\t\t}\n\t\t\t})();\n\n\t\t\tlogger.debug('GET /api/getExchangeStatus/:id', 'Exchange Status for ID', exchangeID, 'is', exchangeResponse, 'based on jobInfo', queueEntryInfo);\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(exchangeResponse)\n\t\t\t});\n\t\t}\n\n\t\treturn(routes);\n\t}\n\n\t/**\n\t * Return the servers endpoints and possible currency conversions metadata\n\t */\n\tasync serviceMetadata(): Promise<NonNullable<ServiceMetadata['services']['fx']>[string]> {\n\t\tconst operations: NonNullable<ServiceMetadata['services']['fx']>[string]['operations'] = {\n\t\t\tgetEstimate: (new URL('/api/getEstimate', this.url)).toString(),\n\t\t\tgetQuote: (new URL('/api/getQuote', this.url)).toString(),\n\t\t\tcreateExchange: (new URL('/api/createExchange', this.url)).toString(),\n\t\t\tgetExchangeStatus: (new URL('/api/getExchangeStatus', this.url)).toString() + '/{id}'\n\t\t};\n\n\t\treturn({\n\t\t\tfrom: this.fx.from ?? [],\n\t\t\toperations: operations\n\t\t});\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tif (this.pipelineAutoRunInterval !== null) {\n\t\t\tclearInterval(this.pipelineAutoRunInterval);\n\t\t\tthis.pipelineAutoRunInterval = null;\n\t\t}\n\n\t\tawait this.pipeline.destroy();\n\n\t\tawait super.stop();\n\t}\n}\n\n/*\n * These are placed at the bottom of the file because the generation\n * breaks the code coverage computation; Normally, we'd place these\n * in a \".generated.ts\" file but for simplicity of internal types\n * we keep them here.\n */\nconst assertKeetaFXAnchorQueueStage1RequestJSON = typia.createAssert<KeetaFXAnchorQueueStage1RequestJSON>();\nconst assertKeetaFXAnchorQueueStage1ResponseOrNull = typia.createAssert<KeetaFXAnchorQueueStage1Response | null>();\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/services/fx/server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as KeetaAnchorHTTPServer from '../../lib/http-server/index.js';\nimport { KeetaNet } from '../../client/index.js';\nimport {\n\tKeetaAnchorError,\n\tKeetaAnchorUserError\n} from '../../lib/error.js';\nimport {\n\tassertConversionInputCanonicalJSON,\n\tassertKeetaFXAnchorClientCreateExchangeRequestJSON,\n\tErrors\n} from './common.js';\nimport type {\n\tConversionInputCanonicalJSON,\n\tKeetaFXAnchorEstimate,\n\tKeetaFXAnchorEstimateResponse,\n\tKeetaFXAnchorExchangeResponse,\n\tKeetaFXAnchorQuote,\n\tKeetaFXAnchorQuoteJSON,\n\tKeetaFXAnchorQuoteResponse,\n\tKeetaNetAccount,\n\tKeetaNetStorageAccount\n} from './common.ts';\nimport * as Signing from '../../lib/utils/signing.js';\nimport type { AssertNever } from '../../lib/utils/never.ts';\nimport type { ServiceMetadata } from '../../lib/resolver.ts';\nimport { KeetaAnchorQueueRunner, KeetaAnchorQueueStorageDriverMemory } from '../../lib/queue/index.js';\nimport type { KeetaAnchorQueueStorageDriver, KeetaAnchorQueueRequestID } from '../../lib/queue/index.ts';\nimport { KeetaAnchorQueuePipelineAdvanced } from '../../lib/queue/pipeline.js';\nimport type { JSONSerializable, ToJSONSerializable } from '../../lib/utils/json.ts';\nimport { assertNever } from '../../lib/utils/never.js';\nimport type { DeepRequired } from '../../lib/utils/types.ts';\nimport * as typia from 'typia';\nimport { assertExchangeBlockParameters } from './util.js';\n\n/**\n * Enable additional runtime \"paranoid\" checks in the FX server.\n *\n * This may have a small performance impact but increases safety\n * by ensuring that the accounts used in quotes are actually\n * configured in the server.\n *\n * During the transition to multiple accounts this may help catch\n * misconfigurations so it is enabled by default for now.\n */\nconst PARANOID = true;\n\nexport interface KeetaAnchorFXServerConfig extends KeetaAnchorHTTPServer.KeetaAnchorHTTPServerConfig {\n\t/**\n\t * The data to use for the index page (optional)\n\t */\n\thomepage?: string | (() => Promise<string> | string);\n\n\t/**\n\t * All accounts that may be used by the server to perform swaps\n\t *\n\t * Temporary compatibility: If this is not provided, the single\n\t * `account` property will be used to create a set of one account.\n\t */\n\taccounts?: InstanceType<typeof KeetaNet.lib.Account.Set>;\n\n\t/**\n\t * Account to use to perform transactions\n\t *\n\t * @deprecated Use `signer` and `accounts` instead\n\t */\n\taccount?: InstanceType<typeof KeetaNet.lib.Account> | undefined;\n\n\t/**\n\t * Account which can be used to sign transactions\n\t * for the accounts above\n\t *\n\t * This may be either a function or a KeetaNet Account instance.\n\t *\n\t * Temporary compatibility: If not provided, the `account` property\n\t * will be used as the signer.\n\t */\n\tsigner?: InstanceType<typeof KeetaNet.lib.Account> | ((request: ConversionInputCanonicalJSON) => Promise<InstanceType<typeof KeetaNet.lib.Account>> | InstanceType<typeof KeetaNet.lib.Account>);\n\n\t/**\n\t * Account which performs the signing and validation of quotes,\n\t * This can be null but only if `quoteConfiguration.issueQuotes` is false.\n\t */\n\tquoteSigner: Signing.SignableAccount | null;\n\n\t/**\n\t * Indicates whether the liquidity provider requires a quote before performing an exchange\n\t * defaults to requiresQuote: true\n\t */\n\tquoteConfiguration?: {\n\t\trequiresQuote: true;\n\t} | {\n\t\trequiresQuote: false;\n\n\t\t/**\n\t\t * Indicates whether to call validateQuote before performing the exchange, defaults to true if validateQuote is provided\n\t\t */\n\t\tvalidateQuoteBeforeExchange: boolean;\n\n\t\t/**\n\t\t * Indicates if the server should issue quotes when requested, if not it will throw a\n\t\t */\n\t\tissueQuotes: boolean;\n\t};\n\n\t/**\n\t * Configuration for FX handling\n\t */\n\tfx: {\n\t\t/**\n\t\t * Supported conversions\n\t\t */\n\t\tfrom?: NonNullable<ServiceMetadata['services']['fx']>[string]['from'];\n\t\t/**\n\t\t * Handle the conversion request of one token to another\n\t\t *\n\t\t * This is used to handle quotes and estimates\n\t\t */\n\t\tgetConversionRateAndFee: (request: ConversionInputCanonicalJSON) => Promise<KeetaFXInternalPriceQuote>;\n\n\t\t/**\n\t\t * Optional callback to validate a quote before completing an exchange\n\t\t *\n\t\t * This allows the FX Server operator to reject quotes that are no longer\n\t\t * acceptable (e.g., due to price changes, expiry, or other business logic)\n\t\t *\n\t\t * @param quote The quote to validate\n\t\t * @returns true to accept the quote and proceed with the exchange, false to reject it\n\t\t */\n\t\tvalidateQuote?: (quote: ValidateQuoteArguments) => Promise<boolean> | boolean;\n\t};\n\n\t/**\n\t * Storage driver to use for stateful operation and managing queues\n\t *\n\t * You are responsible for running and maintaining the queue processor unless\n\t * you enable auto-run below.\n\t */\n\tstorage?: {\n\t\t/**\n\t\t * The storage driver or queue runner to use to serialize\n\t\t * and batch requests\n\t\t */\n\t\tqueue: KeetaAnchorQueueStorageDriver<JSONSerializable, JSONSerializable>;\n\t\t/**\n\t\t * If enabled the server will automatically run the queue processor\n\t\t */\n\t\tautoRun?: boolean;\n\t};\n\n\t/**\n\t * The network client to use for submitting blocks\n\t */\n\tclient: { client: KeetaNet.Client; network: bigint; networkAlias: typeof KeetaNet.Client.Config.networksArray[number] } | KeetaNet.UserClient;\n};\n\nasync function formatQuoteSignable(unsignedQuote: Omit<KeetaFXAnchorQuoteJSON, 'signed'>): Promise<Signing.Signable> {\n\tconst retval: Signing.Signable = [\n\t\tunsignedQuote.request.from,\n\t\tunsignedQuote.request.to,\n\t\tunsignedQuote.request.amount,\n\t\tunsignedQuote.request.affinity,\n\t\tunsignedQuote.account,\n\t\tunsignedQuote.convertedAmount,\n\t\tunsignedQuote.cost.token,\n\t\tunsignedQuote.cost.amount\n\t];\n\n\treturn(retval);\n\n\t/**\n\t * This is a static assertion to ensure that this function is updated\n\t * if new fields are added to the KeetaFXAnchorQuote type to ensure\n\t * that we are always signing all the fields.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\ttype _ignore_static_assert = AssertNever<\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n\t\tAssertNever<keyof Omit<typeof unsignedQuote['request'], 'from' | 'to' | 'amount' | 'affinity'>> &\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents,@typescript-eslint/no-duplicate-type-constituents\n\t\tAssertNever<keyof Omit<typeof unsignedQuote['cost'], 'token' | 'amount'>> &\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents,@typescript-eslint/no-duplicate-type-constituents\n\t\tAssertNever<keyof Omit<typeof unsignedQuote, 'request' | 'convertedAmount' | 'cost' | 'account'>>\n\t>;\n}\n\nasync function generateSignedQuote(signer: Signing.SignableAccount, unsignedQuote: Omit<KeetaFXAnchorQuoteJSON, 'signed'>): Promise<KeetaFXAnchorQuoteJSON> {\n\tconst signableQuote = await formatQuoteSignable(unsignedQuote);\n\tconst signed = await Signing.SignData(signer, signableQuote);\n\n\treturn({\n\t\t...unsignedQuote,\n\t\tsigned: signed\n\t});\n}\n\nasync function verifySignedData(signedBy: Signing.VerifableAccount, quote: KeetaFXAnchorQuoteJSON): Promise<boolean> {\n\tconst signableQuote = await formatQuoteSignable(quote);\n\n\treturn(await Signing.VerifySignedData(signedBy, signableQuote, quote.signed));\n}\n\nasync function requestToAccounts(config: KeetaAnchorFXServerConfig, request: ConversionInputCanonicalJSON): Promise<{ signer: Signing.SignableAccount; account: KeetaNetAccount | KeetaNetStorageAccount | null; }> {\n\tlet account: KeetaNetAccount | KeetaNetStorageAccount | null;\n\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\tif (config.account !== undefined) {\n\t\tconst rateFee = await config.fx.getConversionRateAndFee(request);\n\t\taccount = rateFee.account;\n\t} else {\n\t\taccount = null;\n\t}\n\n\tlet signer: Signing.SignableAccount | null = null;\n\tif (config.signer !== undefined) {\n\t\tsigner = (KeetaNet.lib.Account.isInstance(config.signer) ? config.signer : await config.signer(request)).assertAccount();\n\t}\n\n\tif (account !== null) {\n\t\tif (signer === null) {\n\t\t\tsigner = account.assertAccount();\n\t\t}\n\n\t\tif (!account.isAccount() && !account.isStorage()) {\n\t\t\tthrow(new Error('FX Account should be an Account or Storage Account'));\n\t\t}\n\t} else if (signer === null) {\n\t\tthrow(new Error('Either account or signer must be provided'));\n\t}\n\n\treturn({\n\t\taccount: account,\n\t\tsigner: signer\n\t});\n}\n\nexport type KeetaFXInternalPriceQuote = Omit<KeetaFXAnchorQuote, 'signed' | 'request'> & Pick<KeetaFXAnchorEstimate, 'convertedAmountBound'>;\nexport type ValidateQuoteArguments = KeetaFXInternalPriceQuote & Partial<Omit<KeetaFXAnchorQuote, keyof KeetaFXInternalPriceQuote>>;\n\nexport function toValidateQuoteInput(input: KeetaFXAnchorQuoteJSON | KeetaFXInternalPriceQuote | KeetaFXAnchorQuote): ValidateQuoteArguments {\n\tconst ret: ValidateQuoteArguments = {\n\t\taccount: KeetaNet.lib.Account.toAccount(input.account),\n\t\tconvertedAmount: BigInt(input.convertedAmount),\n\t\tcost: {\n\t\t\tamount: BigInt(input.cost.amount),\n\t\t\ttoken: KeetaNet.lib.Account.toAccount(input.cost.token)\n\t\t}\n\t};\n\n\tif ('convertedAmountBound' in input && input.convertedAmountBound !== undefined) {\n\t\tret.convertedAmountBound = BigInt(input.convertedAmountBound);\n\t}\n\n\tif ('signed' in input && input.signed !== undefined) {\n\t\tret.signed = input.signed;\n\t}\n\n\tif ('request' in input && input.request !== undefined) {\n\t\tret.request = {\n\t\t\tfrom: KeetaNet.lib.Account.toAccount(input.request.from),\n\t\t\tto: KeetaNet.lib.Account.toAccount(input.request.to),\n\t\t\tamount: BigInt(input.request.amount),\n\t\t\taffinity: input.request.affinity\n\t\t};\n\t}\n\n\treturn(ret);\n}\n\n\n/* QUEUE PROCESSOR PIPELINE */\ntype KeetaFXAnchorQueueStage1Request = {\n\taccount: KeetaNetAccount;\n\tblock: Parameters<typeof KeetaNet.UserClient['acceptSwapRequest']>[0]['block'];\n\trequest: ConversionInputCanonicalJSON;\n\texpected: Extract<DeepRequired<NonNullable<Parameters<typeof KeetaNet.UserClient['acceptSwapRequest']>[0]['expected']>>, { receive: unknown; }>;\n};\ntype KeetaFXAnchorQueueStage1RequestJSON = {\n\t/** Version of the request format */\n\tversion: 1;\n\t/** FX Anchor Account performing swap */\n\taccount: string;\n\t/** Base64 encoded block from the user */\n\tblock: string;\n\t/** Original request */\n\trequest: ConversionInputCanonicalJSON;\n\t/** Expected exchange details for verification */\n\texpected: ToJSONSerializable<KeetaFXAnchorQueueStage1Request['expected']>;\n};\ntype KeetaFXAnchorQueueStage1Response = {\n\t/**\n\t * All the blocks for the given swap request\n\t */\n\tblocks: string[];\n\t/**\n\t * The hash of one of the blocks submitted\n\t */\n\tblockhash: string;\n};\n\nclass KeetaFXAnchorQueuePipelineStage1 extends KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response> {\n\tprotected readonly serverConfig: KeetaAnchorFXServerConfig;\n\tprotected sequential = true;\n\n\t/**\n\t * Timeout for processing a single job -- if exceeded the job is marked as aborted\n\t */\n\tprotected processTimeout: number = 60 * 1000;\n\n\tconstructor(config: ConstructorParameters<typeof KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>>[0] & { serverConfig: KeetaAnchorFXServerConfig; }) {\n\t\tsuper(config);\n\n\t\tthis.serverConfig = config.serverConfig;\n\t\tthis.processorAborted = this.processorStuck.bind(this);\n\t}\n\n\t/**\n\t * Handles both stuck (no status update after a long period) and\n\t * aborted (timeout while processing an entry) states.\n\t *\n\t * We just put the job back into pending because the processor\n\t * will check the network state again.\n\t */\n\tprotected async processorStuck(entry: Parameters<NonNullable<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processorStuck']>>[0]): ReturnType<NonNullable<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processorStuck']>> {\n\t\treturn({\n\t\t\tstatus: 'pending',\n\t\t\toutput: entry.output\n\t\t});\n\t}\n\n\t/**\n\t * Process the entry, attempting to submit the swap block(s)\n\t * to the network. Verifies the block can be submitted before\n\t * attempting submission. Also verifies if the block is already\n\t * on the network and marks the job as completed if so.\n\t */\n\tprotected async processor(entry: Parameters<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processor']>[0]): ReturnType<KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>['processor']> {\n\t\tconst { block, expected, request } = entry.request;\n\t\tconst config = this.serverConfig;\n\n\t\tlet userClient: KeetaNet.UserClient;\n\n\t\tif (KeetaNet.UserClient.isInstance(config.client)) {\n\t\t\tuserClient = config.client;\n\n\t\t\tif (!(userClient.account.comparePublicKey(entry.request.account))) {\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Mismatched account for FX request with configured UserClient account`\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tconst { signer, account: checkAccount } = await requestToAccounts(config, request);\n\n\t\t\tif (checkAccount === null) {\n\t\t\t\tif (this.serverConfig.accounts === undefined) {\n\t\t\t\t\tthrow(new Error('No accounts configured for FX server'));\n\t\t\t\t}\n\n\t\t\t\tif (!this.serverConfig.accounts.has(entry.request.account)) {\n\t\t\t\t\treturn({\n\t\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\t\toutput: null,\n\t\t\t\t\t\terror: `Mismatched account for FX request and configured account (no matching account found)`\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (!checkAccount.comparePublicKey(entry.request.account)) {\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Mismatched account for FX request and configured account (single account not matched)`\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tuserClient = new KeetaNet.UserClient({\n\t\t\t\tclient: config.client.client,\n\t\t\t\tnetwork: config.client.network,\n\t\t\t\tnetworkAlias: config.client.networkAlias,\n\t\t\t\taccount: entry.request.account,\n\t\t\t\tsigner: signer\n\t\t\t});\n\t\t}\n\n\t\t/* Check for the block already being on the network, if so we can mark this job as completed */\n\t\tconst blockExists = await userClient.block(block.hash);\n\t\tif (blockExists !== null) {\n\t\t\tconst existingOutput = entry.output;\n\t\t\tconst blocks = existingOutput?.blocks ?? [Buffer.from(block.toBytes()).toString('base64')];\n\n\t\t\treturn({\n\t\t\t\tstatus: 'completed',\n\t\t\t\toutput: {\n\t\t\t\t\tblockhash: block.hash.toString(),\n\t\t\t\t\tblocks: blocks\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* Get the current head block of the account in the block */\n\t\tconst accountHead = await userClient.head({ account: block.account });\n\t\tlet isHeadBlock = false;\n\t\tif (accountHead !== null) {\n\t\t\tisHeadBlock = accountHead.compare(block.previous);\n\t\t} else {\n\t\t\tisHeadBlock = block['$opening'];\n\t\t}\n\n\t\t/* If the account's head block is not the block's previous, see if the block's previous exists on the network */\n\t\tif (!isHeadBlock) {\n\t\t\tlet previousBlockOnNetwork = false;\n\t\t\tif (block['$opening']) {\n\t\t\t\t/* Opening block means that there is no previous block, so we are free to proceed */\n\t\t\t\tpreviousBlockOnNetwork = true;\n\t\t\t} else {\n\t\t\t\tconst previousBlock = await userClient.block(block.previous);\n\t\t\t\tif (previousBlock !== null) {\n\t\t\t\t\tpreviousBlockOnNetwork = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet blockPreviousString: string;\n\t\t\tif (block['$opening']) {\n\t\t\t\tblockPreviousString = '<opening>';\n\t\t\t} else {\n\t\t\t\tblockPreviousString = block.previous.toString();\n\t\t\t}\n\n\t\t\t/* If block.previous exists on the network, and it's not the account head block we can mark this job as failed_permanently */\n\t\t\tif (previousBlockOnNetwork) {\n\t\t\t\t/* Block's previous exists on the network, but is not the account head -- mark as failed_permanently */\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_permanently',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Block previous (${blockPreviousString}) exists on the network but is not the account head`\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t/* If block.previous does not exist on the network we can mark this job as failed_temporarily -- it can't process until the missing block is added */\n\t\t\t\t/* Block's previous does not exist on the network -- mark as failed_temporarily */\n\t\t\t\treturn({\n\t\t\t\t\tstatus: 'failed_temporarily',\n\t\t\t\t\toutput: null,\n\t\t\t\t\terror: `Block previous (${blockPreviousString}) does not exist on the network`\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t/* We are clear to attempt the swap now */\n\n\t\tconst builder = userClient.initBuilder();\n\t\tbuilder.send(block.account, expected.send.amount, expected.send.token);\n\n\t\tconst sendBlock = await builder.computeBlocks();\n\n\t\tconst swapBlocks = [ ...sendBlock.blocks, block ];\n\n\t\tconst publishOptions: Parameters<typeof userClient.client.transmit>[1] = {};\n\t\tif (userClient.config.generateFeeBlock !== undefined) {\n\t\t\tpublishOptions.generateFeeBlock = userClient.config.generateFeeBlock;\n\t\t}\n\t\tconst publishResult = await userClient.client.transmit(swapBlocks, publishOptions);\n\t\tif (!publishResult.publish) {\n\t\t\tthrow(new Error('Exchange Publish Failed'));\n\t\t}\n\n\t\t/* Set the output and mark the job as pending so we can run the queue again and check for completion */\n\t\treturn({\n\t\t\tstatus: 'pending',\n\t\t\toutput: {\n\t\t\t\tblockhash: block.hash.toString(),\n\t\t\t\tblocks: swapBlocks.map(function(block) {\n\t\t\t\t\treturn(Buffer.from(block.toBytes()).toString('base64'));\n\t\t\t\t})\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected encodeRequest(request: KeetaFXAnchorQueueStage1Request): JSONSerializable {\n\t\tconst retval: KeetaFXAnchorQueueStage1RequestJSON = {\n\t\t\tversion: 1,\n\t\t\taccount: request.account.publicKeyString.get(),\n\t\t\tblock: Buffer.from(request.block.toBytes()).toString('base64'),\n\t\t\trequest: request.request,\n\t\t\texpected: {\n\t\t\t\treceive: {\n\t\t\t\t\ttoken: request.expected.receive.token.publicKeyString.get(),\n\t\t\t\t\tamount: request.expected.receive.amount.toString()\n\t\t\t\t},\n\t\t\t\tsend: {\n\t\t\t\t\ttoken: request.expected.send.token.publicKeyString.get(),\n\t\t\t\t\tamount: request.expected.send.amount.toString()\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\treturn(retval);\n\t}\n\n\tprotected encodeResponse(response: KeetaFXAnchorQueueStage1Response | null): JSONSerializable | null {\n\t\treturn(response);\n\t}\n\n\tprotected decodeRequest(request: JSONSerializable): KeetaFXAnchorQueueStage1Request {\n\t\t/* See note at bottom of file */\n\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\tconst reqJSON = assertKeetaFXAnchorQueueStage1RequestJSON(request);\n\n\t\tif (reqJSON.version !== 1) {\n\t\t\tthrow(new Error(`Unsupported KeetaFXAnchorQueueStage1Request version ${reqJSON.version}`));\n\t\t}\n\n\t\tconst retval: KeetaFXAnchorQueueStage1Request = {\n\t\t\taccount: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.account),\n\t\t\tblock: new KeetaNet.lib.Block(reqJSON.block),\n\t\t\trequest: reqJSON.request,\n\t\t\texpected: {\n\t\t\t\treceive: {\n\t\t\t\t\ttoken: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.expected.receive.token).assertKeyType(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN),\n\t\t\t\t\tamount: BigInt(reqJSON.expected.receive.amount)\n\t\t\t\t},\n\t\t\t\tsend: {\n\t\t\t\t\ttoken: KeetaNet.lib.Account.fromPublicKeyString(reqJSON.expected.send.token).assertKeyType(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN),\n\t\t\t\t\tamount: BigInt(reqJSON.expected.send.amount)\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\treturn(retval);\n\t}\n\n\tprotected decodeResponse(response: JSONSerializable | null): KeetaFXAnchorQueueStage1Response | null {\n\t\t/* See note at bottom of file */\n\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\treturn(assertKeetaFXAnchorQueueStage1ResponseOrNull(response));\n\t}\n}\n\nclass KeetaFXAnchorQueuePipeline extends KeetaAnchorQueuePipelineAdvanced<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response> {\n\tprivate readonly serverConfig: KeetaAnchorFXServerConfig;\n\tprivate readonly accounts: InstanceType<typeof KeetaNet.lib.Account.Set>;\n\tprivate runners: { [account: string]: KeetaAnchorQueueRunner<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>; } = {};\n\n\tconstructor(options: ConstructorParameters<typeof KeetaAnchorQueuePipelineAdvanced<KeetaFXAnchorQueueStage1Request, KeetaFXAnchorQueueStage1Response>>[0] & { serverConfig: KeetaAnchorFXServerConfig; accounts: InstanceType<typeof KeetaNet.lib.Account.Set>; }) {\n\t\tsuper(options);\n\n\t\tthis.serverConfig = options.serverConfig;\n\t\tthis.accounts = options.accounts;\n\t}\n\n\tprotected async createPipeline(): Promise<void> {\n\t\tfor (const account of this.accounts) {\n\t\t\tconst queue = await this.baseQueue.partition(account.publicKeyAndTypeString);\n\t\t\tthis.queues.push(queue);\n\n\t\t\tconst runner = new KeetaFXAnchorQueuePipelineStage1({\n\t\t\t\tid: `keeta-fx-anchor-runner-${account.publicKeyAndTypeString}`,\n\t\t\t\tqueue: queue,\n\t\t\t\tlogger: this.logger,\n\t\t\t\tserverConfig: this.serverConfig\n\t\t\t});\n\t\t\tthis.runners[account.publicKeyAndTypeString] = runner;\n\t\t}\n\t}\n\n\tprotected getStage(stageID: typeof KeetaAnchorQueuePipelineAdvanced.StageID.first | typeof KeetaAnchorQueuePipelineAdvanced.StageID.last): KeetaFXAnchorQueuePipelineStage1;\n\tprotected getStage(_ignore_stageID: typeof KeetaAnchorQueuePipelineAdvanced.StageID.first | typeof KeetaAnchorQueuePipelineAdvanced.StageID.last | string): KeetaFXAnchorQueuePipelineStage1 | null {\n\t\tthrow(new Error('method not supported'));\n\t}\n\n\tasync add(request: KeetaFXAnchorQueueStage1Request): ReturnType<KeetaFXAnchorQueuePipelineStage1['add']> {\n\t\tawait super.init();\n\n\t\tconst account = request.account.publicKeyAndTypeString;\n\n\t\tconst runner = this.runners[account];\n\t\tif (runner === undefined) {\n\t\t\tthrow(new Error(`No queue runner for account ${account}`));\n\t\t}\n\n\t\treturn(await runner.add(request));\n\t}\n\n\tasync get(id: KeetaAnchorQueueRequestID): ReturnType<KeetaFXAnchorQueuePipelineStage1['get']> {\n\t\tawait super.init();\n\n\t\tfor (const account of this.accounts) {\n\t\t\tconst runner = this.runners[account.publicKeyAndTypeString];\n\t\t\tif (runner === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst entry = await runner.get(id);\n\t\t\tif (entry !== null) {\n\t\t\t\treturn(entry);\n\t\t\t}\n\t\t}\n\n\t\treturn(null);\n\t}\n\n\tasync run(options?: Parameters<KeetaFXAnchorQueuePipelineStage1['run']>[0]): ReturnType<KeetaFXAnchorQueuePipelineStage1['run']> {\n\t\tawait super.init();\n\n\t\tlet retval = false;\n\t\tfor (const account of this.accounts) {\n\t\t\tconst runner = this.runners[account.publicKeyAndTypeString];\n\t\t\tif (runner === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst more = await runner.run(options);\n\t\t\tif (more) {\n\t\t\t\tretval = true;\n\t\t\t}\n\t\t}\n\n\t\treturn(retval);\n\t}\n\n\tasync maintain(): Promise<void> {\n\t\tawait super.init();\n\n\t\tfor (const account of this.accounts) {\n\t\t\tconst runner = this.runners[account.publicKeyAndTypeString];\n\t\t\tif (runner === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tawait runner.maintain();\n\t\t}\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tconst logger = this.methodLogger('destroy');\n\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.destroyed = true;\n\n\t\tawait super.destroy();\n\n\t\tfor (const runner of Object.values(this.runners)) {\n\t\t\ttry {\n\t\t\t\tawait runner.destroy();\n\t\t\t} catch (error) {\n\t\t\t\tlogger?.error('Error destroying runner:', error);\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nexport class KeetaNetFXAnchorHTTPServer extends KeetaAnchorHTTPServer.KeetaNetAnchorHTTPServer<KeetaAnchorFXServerConfig> implements Omit<Required<KeetaAnchorFXServerConfig>, 'storage'> {\n\treadonly homepage: NonNullable<KeetaAnchorFXServerConfig['homepage']>;\n\treadonly client: KeetaAnchorFXServerConfig['client'];\n\treadonly accounts: NonNullable<KeetaAnchorFXServerConfig['accounts']>;\n\treadonly account: KeetaAnchorFXServerConfig['account'] = undefined;\n\treadonly signer: NonNullable<KeetaAnchorFXServerConfig['signer']>;\n\treadonly quoteSigner: KeetaAnchorFXServerConfig['quoteSigner'];\n\treadonly fx: KeetaAnchorFXServerConfig['fx'];\n\treadonly pipeline: KeetaFXAnchorQueuePipeline;\n\treadonly quoteConfiguration: Exclude<KeetaAnchorFXServerConfig['quoteConfiguration'], undefined>;\n\n\tprotected pipelineAutoRunInterval: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(config: KeetaAnchorFXServerConfig) {\n\t\tsuper(config);\n\n\t\tthis.homepage = config.homepage ?? '';\n\t\tthis.client = config.client;\n\t\tthis.fx = config.fx;\n\t\tthis.quoteSigner = config.quoteSigner;\n\t\tthis.quoteConfiguration = config.quoteConfiguration ?? { requiresQuote: true };\n\n\t\t/*\n\t\t * Setup the accounts\n\t\t */\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif (config.account !== undefined && config.accounts === undefined) {\n\t\t\t/*\n\t\t\t * Deprecated: If a single account is provided, use that\n\t\t\t * along with the signer to create the accounts set\n\t\t\t */\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tthis.accounts = new KeetaNet.lib.Account.Set([config.account]);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tthis.signer = config.signer ?? config.account;\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t} else if (config.accounts !== undefined && config.account === undefined) {\n\t\t\t/*\n\t\t\t * Only allow either \"account\" or \"accounts\"+\"signer\" to be provided\n\t\t\t */\n\t\t\tif (config.signer === undefined) {\n\t\t\t\tthrow(new Error('If \"accounts\" is provided, \"signer\" must also be provided'));\n\t\t\t}\n\n\t\t\tthis.accounts = config.accounts;\n\t\t\tthis.signer = config.signer;\n\t\t} else {\n\t\t\tthrow(new Error('Either \"account\" (and optional \"signer\") or \"accounts\" and \"signer\" must be provided, but not both \"account\" and \"accounts\"'));\n\t\t}\n\n\t\tif (this.accounts.size === 0) {\n\t\t\tthrow(new Error('No FX accounts provided'));\n\t\t}\n\n\t\t/*\n\t\t * If no storage driver is provided, we default to an in-memory\n\t\t * that we auto-run\n\t\t */\n\t\tlet autorun = config.storage?.autoRun ?? false;\n\t\tif (config.storage === undefined) {\n\t\t\tautorun = true;\n\t\t}\n\n\t\t/*\n\t\t * Create the pipeline to process transactions\n\t\t */\n\t\tthis.pipeline = new KeetaFXAnchorQueuePipeline({\n\t\t\tid: 'keeta-fx-anchor-queue-pipeline',\n\t\t\tbaseQueue: config.storage?.queue ?? new KeetaAnchorQueueStorageDriverMemory({\n\t\t\t\tid: 'keeta-fx-anchor-queue-pipeline-memory-driver',\n\t\t\t\tlogger: this.logger\n\t\t\t}),\n\t\t\taccounts: this.accounts,\n\t\t\tlogger: this.logger,\n\t\t\tserverConfig: this\n\t\t});\n\n\t\t/*\n\t\t * If auto-run is enabled, setup the interval to run the pipeline\n\t\t */\n\t\tif (autorun) {\n\t\t\tlet running = false;\n\t\t\tthis.pipelineAutoRunInterval = setInterval(async () => {\n\t\t\t\tif (running) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\trunning = true;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.pipeline.maintain();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error('KeetaNetFXAnchorHTTPServer::pipelineAutoRunInterval', 'Error maintaining pipeline:', error);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait this.pipeline.run({ timeoutMs: 5000 });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error('KeetaNetFXAnchorHTTPServer::pipelineAutoRunInterval', 'Error running pipeline:', error);\n\t\t\t\t} finally {\n\t\t\t\t\trunning = false;\n\t\t\t\t}\n\t\t\t}, 1000);\n\t\t}\n\t}\n\n\tprotected async initRoutes(config: KeetaAnchorFXServerConfig): Promise<KeetaAnchorHTTPServer.Routes> {\n\t\tconst routes: KeetaAnchorHTTPServer.Routes = {};\n\t\tconst logger = this.logger;\n\n\t\t/*\n\t\t * To use the instance within the route handlers, we need to\n\t\t * make a local reference to it.\n\t\t */\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tconst instance = this;\n\n\t\t/**\n\t\t * If a homepage is provided, setup the route for it\n\t\t */\n\t\tif ('homepage' in config) {\n\t\t\troutes['GET /'] = async function() {\n\t\t\t\tlet homepageData: string;\n\t\t\t\tif (typeof config.homepage === 'string') {\n\t\t\t\t\thomepageData = config.homepage;\n\t\t\t\t} else {\n\t\t\t\t\tif (!config.homepage) {\n\t\t\t\t\t\tthrow(new Error('internal error: No homepage function provided'));\n\t\t\t\t\t}\n\n\t\t\t\t\thomepageData = await config.homepage();\n\t\t\t\t}\n\n\t\t\t\treturn({\n\t\t\t\t\toutput: homepageData,\n\t\t\t\t\tcontentType: 'text/html'\n\t\t\t\t});\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Setup the request handler for an estimate request\n\t\t */\n\t\troutes['POST /api/getEstimate'] = async function(_ignore_params, postData) {\n\t\t\tif (!postData || typeof postData !== 'object') {\n\t\t\t\tthrow(new Error('No POST data provided'));\n\t\t\t}\n\t\t\tif (!('request' in postData)) {\n\t\t\t\tthrow(new Error('POST data missing request'));\n\t\t\t}\n\n\t\t\tconst conversion = assertConversionInputCanonicalJSON(postData.request);\n\t\t\tconst rateAndFee = await config.fx.getConversionRateAndFee(conversion);\n\n\t\t\tlet requiresQuoteBody: { requiresQuote: true } | { requiresQuote: false; account: KeetaNetAccount | KeetaNetStorageAccount; };\n\t\t\tif (instance.quoteConfiguration.requiresQuote) {\n\t\t\t\trequiresQuoteBody = { requiresQuote: true };\n\t\t\t} else {\n\t\t\t\tif (rateAndFee.convertedAmountBound === undefined) {\n\t\t\t\t\tinstance.logger.warn('POST /api/getEstimate', 'FX configuration indicates quotes are not required, but \"convertedAmountBound\" was not provided in the rate and fee response');\n\t\t\t\t} else {\n\t\t\t\t\tif (conversion.affinity === 'to' && (BigInt(conversion.amount) > rateAndFee.convertedAmountBound)) {\n\t\t\t\t\t\tthrow(new KeetaAnchorError('Affinity is to, but bound is less than estimated sent amount'));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (conversion.affinity === 'from' && (BigInt(conversion.amount) < rateAndFee.convertedAmountBound)) {\n\t\t\t\t\t\tthrow(new KeetaAnchorError('Affinity is from, but bound is greater than estimated received amount'));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trequiresQuoteBody = { requiresQuote: false, account: rateAndFee.account };\n\t\t\t}\n\n\t\t\tconst estimateResponse: KeetaFXAnchorEstimateResponse = {\n\t\t\t\tok: true,\n\t\t\t\testimate: KeetaNet.lib.Utils.Conversion.toJSONSerializable({\n\t\t\t\t\trequest: conversion,\n\t\t\t\t\tconvertedAmount: rateAndFee.convertedAmount,\n\t\t\t\t\tconvertedAmountBound: rateAndFee.convertedAmountBound,\n\t\t\t\t\texpectedCost: {\n\t\t\t\t\t\tmin: rateAndFee.cost.amount,\n\t\t\t\t\t\tmax: rateAndFee.cost.amount,\n\t\t\t\t\t\ttoken: rateAndFee.cost.token\n\t\t\t\t\t},\n\t\t\t\t\t...requiresQuoteBody\n\t\t\t\t})\n\t\t\t};\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(estimateResponse)\n\t\t\t});\n\t\t}\n\n\t\tasync function getUnsignedQuoteData(conversion: ConversionInputCanonicalJSON) {\n\t\t\tconst rateAndFee = await config.fx.getConversionRateAndFee(conversion);\n\n\t\t\tif (PARANOID) {\n\t\t\t\tconst quoteAccount = rateAndFee.account;\n\t\t\t\tif (!instance.accounts.has(quoteAccount)) {\n\t\t\t\t\tthrow(new Error('\"getConversionRateAndFee\" returned an account not configured for this server'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn(rateAndFee);\n\t\t}\n\n\t\troutes['POST /api/getQuote'] = async function(_ignore_params, postData) {\n\t\t\tif (!instance.quoteConfiguration.requiresQuote && !instance.quoteConfiguration.issueQuotes) {\n\t\t\t\tthrow(new Errors.QuoteIssuanceDisabled());\n\t\t\t}\n\n\t\t\tif (!postData || typeof postData !== 'object') {\n\t\t\t\tthrow(new Error('No POST data provided'));\n\t\t\t}\n\n\t\t\tif (!('request' in postData)) {\n\t\t\t\tthrow(new Error('POST data missing request'));\n\t\t\t}\n\n\t\t\tconst conversion = assertConversionInputCanonicalJSON(postData.request);\n\t\t\tconst rateAndFee = await getUnsignedQuoteData(conversion);\n\n\t\t\tconst unsignedQuote: Omit<KeetaFXAnchorQuoteJSON, 'signed'> = KeetaNet.lib.Utils.Conversion.toJSONSerializable({\n\t\t\t\trequest: conversion,\n\t\t\t\t...rateAndFee\n\t\t\t});\n\n\t\t\tif (config.quoteSigner === null) {\n\t\t\t\tthrow(new Error('Quote signer not configured, this is required when issuing quotes'));\n\t\t\t}\n\n\t\t\tconst signedQuote = await generateSignedQuote(config.quoteSigner, unsignedQuote);\n\t\t\tconst quoteResponse: KeetaFXAnchorQuoteResponse = {\n\t\t\t\tok: true,\n\t\t\t\tquote: signedQuote\n\t\t\t};\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(quoteResponse)\n\t\t\t});\n\t\t}\n\n\t\troutes['POST /api/createExchange'] = async function(_ignore_params, postData) {\n\t\t\tif (!postData || typeof postData !== 'object') {\n\t\t\t\tthrow(new Error('No POST data provided'));\n\t\t\t}\n\n\t\t\tif (!('request' in postData)) {\n\t\t\t\tthrow(new Error('POST data missing request'));\n\t\t\t}\n\n\t\t\tconst request = assertKeetaFXAnchorClientCreateExchangeRequestJSON(postData.request);\n\n\t\t\tif (!('block' in request) || typeof request.block !== 'string') {\n\t\t\t\tthrow(new Error('Block was not provided in exchange request'));\n\t\t\t}\n\n\t\t\tconst block = new KeetaNet.lib.Block(request.block);\n\n\t\t\tlet quoteInput;\n\t\t\tlet conversionInput;\n\t\t\tlet shouldValidateQuote;\n\t\t\tlet liquidityAccount;\n\t\t\tif ('quote' in request && 'estimate' in request && request.quote && request.estimate) {\n\t\t\t\tthrow(new Error('Request cannot contain both quote and estimate'));\n\t\t\t} else if ('quote' in request && request.quote) {\n\t\t\t\tshouldValidateQuote = true;\n\t\t\t\tquoteInput = request.quote;\n\t\t\t\tconversionInput = quoteInput.request;\n\n\t\t\t\tconst isValidQuote = await (async () => {\n\t\t\t\t\tif (config.quoteSigner === null) {\n\t\t\t\t\t\treturn(false);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn(await verifySignedData(config.quoteSigner, quoteInput));\n\t\t\t\t})();\n\n\t\t\t\tif (!isValidQuote) {\n\t\t\t\t\tthrow(new Errors.QuoteValidationFailed());\n\t\t\t\t}\n\n\t\t\t\tliquidityAccount = quoteInput.account;\n\t\t\t} else if ('request' in request && request.request) {\n\t\t\t\tif (instance.quoteConfiguration.requiresQuote) {\n\t\t\t\t\tthrow(new Errors.QuoteRequired());\n\t\t\t\t}\n\n\t\t\t\tconversionInput = request.request;\n\t\t\t\tquoteInput = await getUnsignedQuoteData(conversionInput);\n\n\t\t\t\tif (instance.quoteConfiguration.validateQuoteBeforeExchange !== undefined) {\n\t\t\t\t\tshouldValidateQuote = instance.quoteConfiguration.validateQuoteBeforeExchange;\n\t\t\t\t} else {\n\t\t\t\t\tshouldValidateQuote = config.fx.validateQuote !== undefined;\n\t\t\t\t}\n\n\t\t\t\tfor (const operation of block.operations) {\n\t\t\t\t\tif (operation.type === KeetaNet.lib.Block.OperationType.SEND) {\n\t\t\t\t\t\tif (!config.accounts) {\n\t\t\t\t\t\t\tthrow(new Error('No accounts configured for FX server, cannot infer liquidity account from block'));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (config.accounts.has(operation.to)) {\n\t\t\t\t\t\t\tliquidityAccount = operation.to;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!liquidityAccount) {\n\t\t\t\t\tthrow(new KeetaAnchorUserError('Could not determine liquidity account from exchange block'));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow(new Error('Either quote or request must be provided (but not both) in exchange request'));\n\t\t\t}\n\n\t\t\tconst parsedQuote = toValidateQuoteInput(quoteInput);\n\n\t\t\t/* Validate the quote using the optional callback */\n\t\t\tif (config.fx.validateQuote !== undefined && shouldValidateQuote) {\n\t\t\t\tconst isAcceptable = await config.fx.validateQuote(parsedQuote);\n\t\t\t\tif (!isAcceptable) {\n\t\t\t\t\tthrow(new Errors.QuoteValidationFailed());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet expectedSendAmount: bigint;\n\t\t\tlet expectedReceiveAmount: bigint;\n\n\t\t\tif (conversionInput.affinity === 'to') {\n\t\t\t\texpectedSendAmount = BigInt(conversionInput.amount);\n\t\t\t\texpectedReceiveAmount = parsedQuote.convertedAmount;\n\t\t\t} else {\n\t\t\t\texpectedSendAmount = parsedQuote.convertedAmount;\n\t\t\t\texpectedReceiveAmount = BigInt(conversionInput.amount);\n\t\t\t}\n\t\t\tconst liquidityAccountInstance = KeetaNet.lib.Account.toAccount(liquidityAccount);\n\n\t\t\tconst userSendsMinimum = { [conversionInput.from]: expectedReceiveAmount };\n\t\t\tconst userWillReceiveMaximum = { [conversionInput.to]: expectedSendAmount };\n\n\t\t\tif (parsedQuote.cost.amount > 0) {\n\t\t\t\tconst feeTokenPub = parsedQuote.cost.token.publicKeyString.get();\n\n\t\t\t\tif (!userSendsMinimum[feeTokenPub]) {\n\t\t\t\t\tuserSendsMinimum[feeTokenPub] = 0n;\n\t\t\t\t}\n\n\t\t\t\tuserSendsMinimum[feeTokenPub] += parsedQuote.cost.amount;\n\t\t\t}\n\n\t\t\tlet allowedLiquidityAccounts;\n\t\t\tif (config.accounts) {\n\t\t\t\tallowedLiquidityAccounts = config.accounts;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t} else if (config.account) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\tallowedLiquidityAccounts = new KeetaNet.lib.Account.Set([ config.account ]);\n\t\t\t} else {\n\t\t\t\tthrow(new Error('config.account or config.accounts must be provided'));\n\t\t\t}\n\n\t\t\tassertExchangeBlockParameters({\n\t\t\t\tblock: block,\n\t\t\t\tliquidityAccount: liquidityAccountInstance,\n\t\t\t\tallowedLiquidityAccounts: allowedLiquidityAccounts,\n\t\t\t\tuserSendsMinimum: userSendsMinimum,\n\t\t\t\tuserWillReceiveMaximum: userWillReceiveMaximum\n\t\t\t});\n\n\t\t\t/* Enqueue the exchange request */\n\t\t\tconst exchangeID = await instance.pipeline.add({\n\t\t\t\taccount: liquidityAccountInstance,\n\t\t\t\tblock: block,\n\t\t\t\trequest: conversionInput,\n\t\t\t\texpected: {\n\t\t\t\t\treceive: {\n\t\t\t\t\t\ttoken: KeetaNet.lib.Account.fromPublicKeyString(conversionInput.from),\n\t\t\t\t\t\tamount: expectedReceiveAmount\n\t\t\t\t\t},\n\t\t\t\t\tsend: {\n\t\t\t\t\t\ttoken: KeetaNet.lib.Account.fromPublicKeyString(conversionInput.to),\n\t\t\t\t\t\tamount: expectedSendAmount\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst exchangeResponse: KeetaFXAnchorExchangeResponse = {\n\t\t\t\tok: true,\n\t\t\t\texchangeID: exchangeID.toString(),\n\t\t\t\tstatus: 'pending'\n\t\t\t};\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(exchangeResponse)\n\t\t\t});\n\t\t}\n\n\t\troutes['GET /api/getExchangeStatus/:id'] = async function(params) {\n\t\t\tif (params === undefined || params === null) {\n\t\t\t\tthrow(new KeetaAnchorUserError('Expected params'));\n\t\t\t}\n\t\t\tconst exchangeID = params.get('id');\n\t\t\tif (typeof exchangeID !== 'string') {\n\t\t\t\tthrow(new Error('Missing exchangeID in params'));\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\tconst queueEntryInfo = await instance.pipeline.get(exchangeID as unknown as KeetaAnchorQueueRequestID);\n\t\t\tconst exchangeResponse = (function(): KeetaFXAnchorExchangeResponse {\n\t\t\t\tconst inputStatus = queueEntryInfo?.status;\n\t\t\t\tswitch (inputStatus) {\n\t\t\t\t\tcase undefined:\n\t\t\t\t\t\tthrow(new KeetaAnchorUserError('Exchange ID not found'));\n\t\t\t\t\tcase 'pending':\n\t\t\t\t\tcase 'processing':\n\t\t\t\t\tcase 'stuck':\n\t\t\t\t\tcase 'aborted':\n\t\t\t\t\tcase 'failed_temporarily':\n\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\tstatus: 'pending',\n\t\t\t\t\t\t\texchangeID: exchangeID\n\t\t\t\t\t\t});\n\t\t\t\t\tcase 'completed': {\n\t\t\t\t\t\tconst blockhash = queueEntryInfo?.output?.blockhash;\n\t\t\t\t\t\tif (blockhash === undefined) {\n\t\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\t\tstatus: 'pending',\n\t\t\t\t\t\t\t\texchangeID: exchangeID\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t\t\texchangeID: exchangeID,\n\t\t\t\t\t\t\t\tblockhash: blockhash\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'failed_permanently':\n\t\t\t\t\t\treturn({\n\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\texchangeID: exchangeID,\n\t\t\t\t\t\t\tstatus: 'failed',\n\t\t\t\t\t\t\terror: 'Exchange failed'\n\t\t\t\t\t\t});\n\t\t\t\t\tcase 'moved':\n\t\t\t\t\t\tthrow(new Error('Exchange ID has been moved'));\n\t\t\t\t\tcase '@internal':\n\t\t\t\t\t\tthrow(new Error('Invalid exchange status @internal'));\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tassertNever(inputStatus);\n\t\t\t\t}\n\t\t\t})();\n\n\t\t\tlogger.debug('GET /api/getExchangeStatus/:id', 'Exchange Status for ID', exchangeID, 'is', exchangeResponse, 'based on jobInfo', queueEntryInfo);\n\n\t\t\treturn({\n\t\t\t\toutput: JSON.stringify(exchangeResponse)\n\t\t\t});\n\t\t}\n\n\t\treturn(routes);\n\t}\n\n\t/**\n\t * Return the servers endpoints and possible currency conversions metadata\n\t */\n\tasync serviceMetadata(): Promise<NonNullable<ServiceMetadata['services']['fx']>[string]> {\n\t\tconst operations: NonNullable<ServiceMetadata['services']['fx']>[string]['operations'] = {\n\t\t\tgetEstimate: (new URL('/api/getEstimate', this.url)).toString(),\n\t\t\tgetQuote: (new URL('/api/getQuote', this.url)).toString(),\n\t\t\tcreateExchange: (new URL('/api/createExchange', this.url)).toString(),\n\t\t\tgetExchangeStatus: (new URL('/api/getExchangeStatus', this.url)).toString() + '/{id}'\n\t\t};\n\n\t\treturn({\n\t\t\tfrom: this.fx.from ?? [],\n\t\t\toperations: operations\n\t\t});\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tif (this.pipelineAutoRunInterval !== null) {\n\t\t\tclearInterval(this.pipelineAutoRunInterval);\n\t\t\tthis.pipelineAutoRunInterval = null;\n\t\t}\n\n\t\tawait this.pipeline.destroy();\n\n\t\tawait super.stop();\n\t}\n}\n\n/*\n * These are placed at the bottom of the file because the generation\n * breaks the code coverage computation; Normally, we'd place these\n * in a \".generated.ts\" file but for simplicity of internal types\n * we keep them here.\n */\nconst assertKeetaFXAnchorQueueStage1RequestJSON = typia.createAssert<KeetaFXAnchorQueueStage1RequestJSON>();\nconst assertKeetaFXAnchorQueueStage1ResponseOrNull = typia.createAssert<KeetaFXAnchorQueueStage1Response | null>();\n"]}
@@ -0,0 +1,13 @@
1
+ import { KeetaNet } from "../../client/index.js";
2
+ export declare function assertExchangeBlockParameters(args: {
3
+ block: InstanceType<typeof KeetaNet['lib']['Block']>;
4
+ liquidityAccount: InstanceType<typeof KeetaNet['lib']['Account']>;
5
+ allowedLiquidityAccounts: null | InstanceType<typeof KeetaNet['lib']['Account']['Set']>;
6
+ userSendsMinimum: {
7
+ [tokenPublicKey: string]: bigint;
8
+ };
9
+ userWillReceiveMaximum: {
10
+ [tokenPublicKey: string]: bigint;
11
+ };
12
+ }): void;
13
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/services/fx/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IACnD,KAAK,EAAE,YAAY,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,gBAAgB,EAAE,YAAY,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAElE,wBAAwB,EAAE,IAAI,GAAG,YAAY,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAExF,gBAAgB,EAAE;QACjB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;KACjC,CAAC;IAEF,sBAAsB,EAAE;QACvB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;KACjC,CAAC;CACF,GAAG,IAAI,CAkDP"}
@@ -0,0 +1,44 @@
1
+ import { KeetaNet } from "../../client/index.js";
2
+ import { KeetaAnchorUserError } from "../../lib/error.js";
3
+ export function assertExchangeBlockParameters(args) {
4
+ if (args.allowedLiquidityAccounts !== null && !(args.allowedLiquidityAccounts.has(args.liquidityAccount))) {
5
+ throw (new KeetaAnchorUserError(`Invalid liquidity account provided ${args.liquidityAccount.publicKeyString.get()}`));
6
+ }
7
+ const userSent = {};
8
+ const userExpectsReceive = {};
9
+ for (const operation of args.block.operations) {
10
+ if (operation.type === KeetaNet.lib.Block.OperationType.SEND) {
11
+ if (!(operation.to.comparePublicKey(args.liquidityAccount))) {
12
+ continue;
13
+ }
14
+ const tokenPub = operation.token.publicKeyString.get();
15
+ if (!(userSent[tokenPub])) {
16
+ userSent[tokenPub] = 0n;
17
+ }
18
+ userSent[tokenPub] += operation.amount;
19
+ }
20
+ else if (operation.type === KeetaNet.lib.Block.OperationType.RECEIVE) {
21
+ if (!(operation.from.comparePublicKey(args.liquidityAccount))) {
22
+ throw (new KeetaAnchorUserError('Receive operations in exchange block must be made requesting from liquidity account'));
23
+ }
24
+ const tokenPub = operation.token.publicKeyString.get();
25
+ if (!(userExpectsReceive[tokenPub])) {
26
+ userExpectsReceive[tokenPub] = 0n;
27
+ }
28
+ userExpectsReceive[tokenPub] += operation.amount;
29
+ }
30
+ }
31
+ for (const [tokenPub, amount] of Object.entries(args.userSendsMinimum)) {
32
+ const userDidSend = userSent[tokenPub] ?? 0n;
33
+ if (userDidSend < amount) {
34
+ throw (new KeetaAnchorUserError(`Expected send of ${amount}, only saw ${userDidSend} for token ${tokenPub}`));
35
+ }
36
+ }
37
+ for (const [tokenPub, amount] of Object.entries(args.userWillReceiveMaximum)) {
38
+ const userAskedReceive = userExpectsReceive[tokenPub] ?? 0n;
39
+ if (userAskedReceive > amount) {
40
+ throw (new KeetaAnchorUserError(`Expected to receive maximum of ${amount}, user asked for ${userAskedReceive} for token ${tokenPub}`));
41
+ }
42
+ }
43
+ }
44
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/services/fx/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeetaNet } from \"../../client/index.js\";\nimport { KeetaAnchorUserError } from \"../../lib/error.js\";\n\nexport function assertExchangeBlockParameters(args: {\n\tblock: InstanceType<typeof KeetaNet['lib']['Block']>;\n\tliquidityAccount: InstanceType<typeof KeetaNet['lib']['Account']>;\n\n\tallowedLiquidityAccounts: null | InstanceType<typeof KeetaNet['lib']['Account']['Set']>;\n\n\tuserSendsMinimum: {\n\t\t[tokenPublicKey: string]: bigint;\n\t};\n\n\tuserWillReceiveMaximum: {\n\t\t[tokenPublicKey: string]: bigint;\n\t};\n}): void {\n\tif (args.allowedLiquidityAccounts !== null && !(args.allowedLiquidityAccounts.has(args.liquidityAccount))) {\n\t\tthrow(new KeetaAnchorUserError(`Invalid liquidity account provided ${args.liquidityAccount.publicKeyString.get()}`));\n\t}\n\n\tconst userSent: { [tokenPublicKey: string]: bigint; } = {};\n\tconst userExpectsReceive: { [tokenPublicKey: string]: bigint; } = {};\n\tfor (const operation of args.block.operations) {\n\t\tif (operation.type === KeetaNet.lib.Block.OperationType.SEND) {\n\t\t\tif (!(operation.to.comparePublicKey(args.liquidityAccount))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst tokenPub = operation.token.publicKeyString.get();\n\n\t\t\tif (!(userSent[tokenPub])) {\n\t\t\t\tuserSent[tokenPub] = 0n;\n\t\t\t}\n\n\t\t\tuserSent[tokenPub] += operation.amount;\n\t\t} else if (operation.type === KeetaNet.lib.Block.OperationType.RECEIVE) {\n\t\t\tif (!(operation.from.comparePublicKey(args.liquidityAccount))) {\n\t\t\t\tthrow(new KeetaAnchorUserError('Receive operations in exchange block must be made requesting from liquidity account'));\n\t\t\t}\n\n\t\t\tconst tokenPub = operation.token.publicKeyString.get();\n\n\t\t\tif (!(userExpectsReceive[tokenPub])) {\n\t\t\t\tuserExpectsReceive[tokenPub] = 0n;\n\t\t\t}\n\n\t\t\tuserExpectsReceive[tokenPub] += operation.amount;\n\t\t}\n\t}\n\n\tfor (const [ tokenPub, amount ] of Object.entries(args.userSendsMinimum)) {\n\t\tconst userDidSend = userSent[tokenPub] ?? 0n;\n\n\t\tif (userDidSend < amount) {\n\t\t\tthrow(new KeetaAnchorUserError(`Expected send of ${amount}, only saw ${userDidSend} for token ${tokenPub}`));\n\t\t}\n\t}\n\n\tfor (const [ tokenPub, amount ] of Object.entries(args.userWillReceiveMaximum)) {\n\t\tconst userAskedReceive = userExpectsReceive[tokenPub] ?? 0n;\n\n\t\tif (userAskedReceive > amount) {\n\t\t\tthrow(new KeetaAnchorUserError(`Expected to receive maximum of ${amount}, user asked for ${userAskedReceive} for token ${tokenPub}`));\n\t\t}\n\t}\n}\n"]}