@keetanetwork/anchor 0.0.23 → 0.0.24

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 (37) hide show
  1. package/lib/error.d.ts.map +1 -1
  2. package/lib/error.js +2 -1
  3. package/lib/error.js.map +1 -1
  4. package/lib/http-server/common.d.ts +11 -0
  5. package/lib/http-server/common.d.ts.map +1 -1
  6. package/lib/http-server/common.js +110 -1
  7. package/lib/http-server/common.js.map +1 -1
  8. package/lib/http-server/index.js +2 -2
  9. package/lib/http-server/index.js.map +1 -1
  10. package/lib/resolver.d.ts +28 -8
  11. package/lib/resolver.d.ts.map +1 -1
  12. package/lib/resolver.js +543 -302
  13. package/lib/resolver.js.map +1 -1
  14. package/npm-shrinkwrap.json +2 -2
  15. package/package.json +1 -1
  16. package/services/asset-movement/client.d.ts +21 -11
  17. package/services/asset-movement/client.d.ts.map +1 -1
  18. package/services/asset-movement/client.js +396 -89
  19. package/services/asset-movement/client.js.map +1 -1
  20. package/services/asset-movement/common.d.ts +410 -35
  21. package/services/asset-movement/common.d.ts.map +1 -1
  22. package/services/asset-movement/common.js +10176 -1492
  23. package/services/asset-movement/common.js.map +1 -1
  24. package/services/asset-movement/server.d.ts +25 -14
  25. package/services/asset-movement/server.d.ts.map +1 -1
  26. package/services/asset-movement/server.js +247 -75
  27. package/services/asset-movement/server.js.map +1 -1
  28. package/services/fx/common.js +3 -3
  29. package/services/fx/server.d.ts +1 -1
  30. package/services/fx/server.d.ts.map +1 -1
  31. package/services/fx/server.js +1 -1
  32. package/services/fx/server.js.map +1 -1
  33. package/services/kyc/common.generated.js +2 -2
  34. package/services/kyc/server.d.ts +1 -1
  35. package/services/kyc/server.d.ts.map +1 -1
  36. package/services/kyc/server.js +1 -1
  37. package/services/kyc/server.js.map +1 -1
@@ -1,7 +1,13 @@
1
+ import * as __typia_transform__assertGuard from "typia/lib/internal/_assertGuard.js";
2
+ import * as __typia_transform__accessExpressionAsString from "typia/lib/internal/_accessExpressionAsString.js";
1
3
  import { getDefaultResolver } from '../../config.js';
2
- import { assertKeetaSupportedAssets, convertAssetLocationToString, convertAssetSearchInputToCanonical, isKeetaAssetMovementAnchorCreatePersistentForwardingResponse, isKeetaAssetMovementAnchorGetExchangeStatusResponse, isKeetaAssetMovementAnchorInitiateTransferResponse, isKeetaAssetMovementAnchorlistPersistentForwardingTransactionsResponse } from './common.js';
4
+ import { assertKeetaSupportedAssets, convertAssetLocationToString, convertAssetOrPairSearchInputToCanonical, convertAssetSearchInputToCanonical, getKeetaAssetMovementAnchorCreatePersistentForwardingAddressTemplateRequestSigningData, getKeetaAssetMovementAnchorCreatePersistentForwardingRequestSigningData, getKeetaAssetMovementAnchorGetTransferStatusRequestSigningData, getKeetaAssetMovementAnchorInitiateTransferRequestSigningData, getKeetaAssetMovementAnchorListForwardingAddressTemplateRequestSigningData, getKeetaAssetMovementAnchorlistTransactionsRequestSigningData, getKeetaAssetMovementAnchorShareKYCRequestSigningData, isKeetaAssetMovementAnchorCreatePersistentForwardingAddressTemplateResponse, isKeetaAssetMovementAnchorCreatePersistentForwardingResponse, isKeetaAssetMovementAnchorGetExchangeStatusResponse, isKeetaAssetMovementAnchorInitiateTransferResponse, isKeetaAssetMovementAnchorListForwardingAddressTemplateResponse, isKeetaAssetMovementAnchorlistPersistentForwardingTransactionsResponse, isKeetaAssetMovementAnchorShareKYCResponse } from './common.js';
3
5
  import Resolver from "../../lib/resolver.js";
4
6
  import crypto from '../../lib/utils/crypto.js';
7
+ import { createAssertEquals } from 'typia';
8
+ import { addSignatureToURL } from '../../lib/http-server/common.js';
9
+ import { SignData } from '../../lib/utils/signing.js';
10
+ import { KeetaAnchorError } from '../../lib/error.js';
5
11
  /**
6
12
  * An opaque type that represents an Asset Movement Anchor request ID
7
13
  */
@@ -11,6 +17,125 @@ function typedAssetMovementServiceEntries(obj) {
11
17
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
12
18
  return Object.entries(obj);
13
19
  }
20
+ const assertServiceMetadataEndpoint = (() => { const _io0 = (input, _exceptionable = true) => "string" === typeof input.url && (undefined === input.options || "object" === typeof input.options && null !== input.options && false === Array.isArray(input.options) && _io1(input.options, true && _exceptionable)) && (1 === Object.keys(input).length || Object.keys(input).every(key => {
21
+ if (["url", "options"].some(prop => key === prop))
22
+ return true;
23
+ const value = input[key];
24
+ if (undefined === value)
25
+ return true;
26
+ return false;
27
+ })); const _io1 = (input, _exceptionable = true) => (undefined === input.authentication || "object" === typeof input.authentication && null !== input.authentication && _io2(input.authentication, true && _exceptionable)) && (0 === Object.keys(input).length || Object.keys(input).every(key => {
28
+ if (["authentication"].some(prop => key === prop))
29
+ return true;
30
+ const value = input[key];
31
+ if (undefined === value)
32
+ return true;
33
+ return false;
34
+ })); const _io2 = (input, _exceptionable = true) => "keeta-account" === input.method && ("optional" === input.type || "required" === input.type || "none" === input.type) && (2 === Object.keys(input).length || Object.keys(input).every(key => {
35
+ if (["method", "type"].some(prop => key === prop))
36
+ return true;
37
+ const value = input[key];
38
+ if (undefined === value)
39
+ return true;
40
+ return false;
41
+ })); const _ao0 = (input, _path, _exceptionable = true) => ("string" === typeof input.url || __typia_transform__assertGuard._assertGuard(_exceptionable, {
42
+ method: "createAssertEquals",
43
+ path: _path + ".url",
44
+ expected: "string",
45
+ value: input.url
46
+ }, _errorFactory)) && (undefined === input.options || ("object" === typeof input.options && null !== input.options && false === Array.isArray(input.options) || __typia_transform__assertGuard._assertGuard(_exceptionable, {
47
+ method: "createAssertEquals",
48
+ path: _path + ".options",
49
+ expected: "(__type.o1 | undefined)",
50
+ value: input.options
51
+ }, _errorFactory)) && _ao1(input.options, _path + ".options", true && _exceptionable) || __typia_transform__assertGuard._assertGuard(_exceptionable, {
52
+ method: "createAssertEquals",
53
+ path: _path + ".options",
54
+ expected: "(__type.o1 | undefined)",
55
+ value: input.options
56
+ }, _errorFactory)) && (1 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
57
+ if (["url", "options"].some(prop => key === prop))
58
+ return true;
59
+ const value = input[key];
60
+ if (undefined === value)
61
+ return true;
62
+ return __typia_transform__assertGuard._assertGuard(_exceptionable, {
63
+ method: "createAssertEquals",
64
+ path: _path + __typia_transform__accessExpressionAsString._accessExpressionAsString(key),
65
+ expected: "undefined",
66
+ value: value
67
+ }, _errorFactory);
68
+ }))); const _ao1 = (input, _path, _exceptionable = true) => (undefined === input.authentication || ("object" === typeof input.authentication && null !== input.authentication || __typia_transform__assertGuard._assertGuard(_exceptionable, {
69
+ method: "createAssertEquals",
70
+ path: _path + ".authentication",
71
+ expected: "(ServiceMetadataAuthenticationType | undefined)",
72
+ value: input.authentication
73
+ }, _errorFactory)) && _ao2(input.authentication, _path + ".authentication", true && _exceptionable) || __typia_transform__assertGuard._assertGuard(_exceptionable, {
74
+ method: "createAssertEquals",
75
+ path: _path + ".authentication",
76
+ expected: "(ServiceMetadataAuthenticationType | undefined)",
77
+ value: input.authentication
78
+ }, _errorFactory)) && (0 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
79
+ if (["authentication"].some(prop => key === prop))
80
+ return true;
81
+ const value = input[key];
82
+ if (undefined === value)
83
+ return true;
84
+ return __typia_transform__assertGuard._assertGuard(_exceptionable, {
85
+ method: "createAssertEquals",
86
+ path: _path + __typia_transform__accessExpressionAsString._accessExpressionAsString(key),
87
+ expected: "undefined",
88
+ value: value
89
+ }, _errorFactory);
90
+ }))); const _ao2 = (input, _path, _exceptionable = true) => ("keeta-account" === input.method || __typia_transform__assertGuard._assertGuard(_exceptionable, {
91
+ method: "createAssertEquals",
92
+ path: _path + ".method",
93
+ expected: "\"keeta-account\"",
94
+ value: input.method
95
+ }, _errorFactory)) && ("optional" === input.type || "required" === input.type || "none" === input.type || __typia_transform__assertGuard._assertGuard(_exceptionable, {
96
+ method: "createAssertEquals",
97
+ path: _path + ".type",
98
+ expected: "(\"none\" | \"optional\" | \"required\")",
99
+ value: input.type
100
+ }, _errorFactory)) && (2 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
101
+ if (["method", "type"].some(prop => key === prop))
102
+ return true;
103
+ const value = input[key];
104
+ if (undefined === value)
105
+ return true;
106
+ return __typia_transform__assertGuard._assertGuard(_exceptionable, {
107
+ method: "createAssertEquals",
108
+ path: _path + __typia_transform__accessExpressionAsString._accessExpressionAsString(key),
109
+ expected: "undefined",
110
+ value: value
111
+ }, _errorFactory);
112
+ }))); const __is = (input, _exceptionable = true) => null !== input && undefined !== input && ("string" === typeof input || "object" === typeof input && null !== input && _io0(input, true)); let _errorFactory; return (input, errorFactory) => {
113
+ if (false === __is(input)) {
114
+ _errorFactory = errorFactory;
115
+ ((input, _path, _exceptionable = true) => (null !== input || __typia_transform__assertGuard._assertGuard(true, {
116
+ method: "createAssertEquals",
117
+ path: _path + "",
118
+ expected: "(__type | string)",
119
+ value: input
120
+ }, _errorFactory)) && (undefined !== input || __typia_transform__assertGuard._assertGuard(true, {
121
+ method: "createAssertEquals",
122
+ path: _path + "",
123
+ expected: "(__type | string)",
124
+ value: input
125
+ }, _errorFactory)) && ("string" === typeof input || ("object" === typeof input && null !== input || __typia_transform__assertGuard._assertGuard(true, {
126
+ method: "createAssertEquals",
127
+ path: _path + "",
128
+ expected: "(__type | string)",
129
+ value: input
130
+ }, _errorFactory)) && _ao0(input, _path + "", true) || __typia_transform__assertGuard._assertGuard(true, {
131
+ method: "createAssertEquals",
132
+ path: _path + "",
133
+ expected: "(__type | string)",
134
+ value: input
135
+ }, _errorFactory)))(input, "$input", true);
136
+ }
137
+ return input;
138
+ }; })();
14
139
  function validateURL(url) {
15
140
  if (url === undefined || url === null) {
16
141
  throw (new Error('Invalid URL: null or undefined'));
@@ -18,14 +143,16 @@ function validateURL(url) {
18
143
  const parsedURL = new URL(url);
19
144
  return (parsedURL);
20
145
  }
21
- async function getEndpoints(resolver, request, shared) {
22
- const asset = request.asset ? { asset: convertAssetSearchInputToCanonical(request.asset) } : undefined;
146
+ async function getEndpoints(resolver, request, shared, logger) {
147
+ const asset = request.asset ? { asset: convertAssetOrPairSearchInputToCanonical(request.asset) } : undefined;
23
148
  const from = request.from ? { from: convertAssetLocationToString(request.from) } : {};
24
149
  const to = request.to ? { to: convertAssetLocationToString(request.to) } : {};
150
+ const rail = request.rail ? { rail: request.rail } : {};
25
151
  const response = await resolver.lookup('assetMovement', {
26
152
  ...asset,
27
153
  ...from,
28
- ...to
154
+ ...to,
155
+ ...rail
29
156
  }, shared);
30
157
  if (response === undefined) {
31
158
  return (null);
@@ -41,13 +168,37 @@ async function getEndpoints(resolver, request, shared) {
41
168
  }
42
169
  Object.defineProperty(operationsFunctions, key, {
43
170
  get: async function () {
44
- const url = await operation('string');
45
- return (function (params) {
46
- let substitutedURL = url;
47
- for (const [paramKey, paramValue] of Object.entries(params ?? {})) {
48
- substitutedURL = substitutedURL.replace(`{${paramKey}}`, encodeURIComponent(paramValue));
171
+ const endpointInfo = assertServiceMetadataEndpoint(await Resolver.Metadata.fullyResolveValuizable(operation));
172
+ let url;
173
+ let authentication = {
174
+ type: 'none',
175
+ method: 'keeta-account'
176
+ };
177
+ if (typeof endpointInfo === 'string') {
178
+ url = endpointInfo;
179
+ }
180
+ else {
181
+ url = endpointInfo.url;
182
+ if (endpointInfo.options?.authentication) {
183
+ authentication = endpointInfo.options.authentication;
49
184
  }
50
- return (validateURL(substitutedURL));
185
+ }
186
+ return ({
187
+ url: function (params) {
188
+ let substitutedURL;
189
+ try {
190
+ substitutedURL = decodeURI(url);
191
+ }
192
+ catch (error) {
193
+ logger?.debug('getEndpoints', 'Failed to decode URI, using original URL for substitution', error, url);
194
+ substitutedURL = url;
195
+ }
196
+ for (const [paramKey, paramValue] of Object.entries(params ?? {})) {
197
+ substitutedURL = substitutedURL.replace(`{${paramKey}}`, encodeURIComponent(paramValue));
198
+ }
199
+ return (validateURL(substitutedURL));
200
+ },
201
+ options: { authentication }
51
202
  });
52
203
  },
53
204
  enumerable: true,
@@ -87,7 +238,8 @@ class KeetaAssetMovementTransfer {
87
238
  this.transfer = transfer;
88
239
  }
89
240
  async getTransferStatus() {
90
- return (await this.provider.getTransferStatus({ id: this.transfer.id }));
241
+ const account = this.request.account ? { account: this.request.account } : undefined;
242
+ return (await this.provider.getTransferStatus({ id: this.transfer.id, ...account }));
91
243
  }
92
244
  get transferId() {
93
245
  return (this.transfer.id);
@@ -107,115 +259,270 @@ class KeetaAssetMovementAnchorProvider extends KeetaAssetMovementAnchorBase {
107
259
  this.providerID = providerID;
108
260
  this.parent = parent;
109
261
  }
110
- async initiateTransfer(request) {
111
- this.logger?.debug(`Starting Asset Movement Transfer for provider ID: ${String(this.providerID)}, request: ${JSON.stringify(request)}`);
112
- const endpoints = this.serviceInfo.operations;
113
- const initiateTransfer = await endpoints.initiateTransfer;
114
- if (initiateTransfer === undefined) {
115
- throw (new Error('Asset Movement service does not support initiateTransfer operation'));
262
+ async #getOperationData(operationName, params) {
263
+ const endpoint = await this.serviceInfo.operations[operationName];
264
+ if (endpoint === undefined) {
265
+ throw (new Error(`Asset Movement service does not support ${operationName} operation`));
116
266
  }
117
- const initiateTransferURL = initiateTransfer();
118
- const requestInformation = await fetch(initiateTransferURL, {
119
- method: 'POST',
120
- headers: {
121
- 'Content-Type': 'application/json',
122
- 'Accept': 'application/json'
123
- },
124
- body: JSON.stringify({
125
- ...request
126
- })
267
+ if (endpoint.options.authentication.method !== 'keeta-account') {
268
+ throw (new Error(`Unsupported authentication method: ${endpoint.options.authentication.method}`));
269
+ }
270
+ return ({
271
+ url: endpoint.url(params),
272
+ auth: endpoint.options.authentication
273
+ });
274
+ }
275
+ async #makeRequest(input) {
276
+ const { url, auth } = await this.#getOperationData(input.endpoint, input.params);
277
+ let serializedRequest;
278
+ if (input.body && input.serializeRequest) {
279
+ serializedRequest = await input.serializeRequest(input.body);
280
+ }
281
+ else {
282
+ serializedRequest = input.body;
283
+ }
284
+ let signed;
285
+ if (auth.type === 'required' || (auth.type === 'optional' && input.account)) {
286
+ if (!input.account) {
287
+ throw (new Error('Account information is required for this operation'));
288
+ }
289
+ if (!input.getSignedData) {
290
+ throw (new Error('getSignedData function is required for signing the request'));
291
+ }
292
+ // We need this assertion because TypeScript cannot infer that the type is correct here, it is correct in the arguments.
293
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
294
+ const signable = input.getSignedData(serializedRequest);
295
+ signed = await SignData(input.account.assertAccount(), signable);
296
+ }
297
+ let usingUrl = url;
298
+ const headers = {
299
+ 'Accept': 'application/json'
300
+ };
301
+ let body = null;
302
+ if (input.method === 'POST') {
303
+ headers['Content-Type'] = 'application/json';
304
+ body = JSON.stringify({ ...serializedRequest, signed });
305
+ }
306
+ else {
307
+ if (signed) {
308
+ if (!input.account) {
309
+ throw (new Error('invariant: Account information is required for this operation, which should exist at this point'));
310
+ }
311
+ usingUrl = addSignatureToURL(usingUrl, { signedField: signed, account: input.account.assertAccount() });
312
+ }
313
+ if (input.body) {
314
+ throw (new Error('Body cannot be sent with GET requests'));
315
+ }
316
+ }
317
+ const requestInformation = await fetch(usingUrl, {
318
+ method: input.method, headers, body
127
319
  });
128
320
  const requestInformationJSON = await requestInformation.json();
129
- if (!isKeetaAssetMovementAnchorInitiateTransferResponse(requestInformationJSON)) {
321
+ if (!input.isResponse(requestInformationJSON)) {
130
322
  throw (new Error(`Invalid response from asset movement service: ${JSON.stringify(requestInformationJSON)}`));
131
323
  }
132
324
  if (!requestInformationJSON.ok) {
133
- throw (new Error(`asset movement request failed: ${requestInformationJSON.error}`));
325
+ let errorStr;
326
+ let parsedError = null;
327
+ try {
328
+ parsedError = await KeetaAnchorError.fromJSON(requestInformationJSON);
329
+ }
330
+ catch (error) {
331
+ this.logger?.debug('Failed to parse error response as KeetaAnchorError', error, requestInformationJSON);
332
+ }
333
+ if (parsedError) {
334
+ throw (parsedError);
335
+ }
336
+ else {
337
+ if ('error' in requestInformationJSON && typeof requestInformationJSON.error === 'string') {
338
+ errorStr = requestInformationJSON.error;
339
+ }
340
+ else {
341
+ errorStr = 'Unknown error';
342
+ }
343
+ throw (new Error(`asset movement ${input.endpoint} request failed: ${errorStr}`));
344
+ }
134
345
  }
346
+ // We need this assertion because TypeScript cannot infer that the type is correct here, it is correct because we checked it above.
347
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
348
+ return requestInformationJSON;
349
+ }
350
+ async initiateTransfer(request) {
351
+ this.logger?.debug(`Starting Asset Movement Transfer for provider ID: ${String(this.providerID)}`);
352
+ const requestInformationJSON = await this.#makeRequest({
353
+ method: 'POST',
354
+ endpoint: 'initiateTransfer',
355
+ account: request.account,
356
+ serializeRequest(body) {
357
+ return ({
358
+ ...body,
359
+ value: String(body.value),
360
+ from: {
361
+ location: convertAssetLocationToString(body.from.location)
362
+ },
363
+ to: {
364
+ location: convertAssetLocationToString(body.to.location),
365
+ recipient: body.to.recipient
366
+ },
367
+ asset: convertAssetOrPairSearchInputToCanonical(body.asset),
368
+ account: body.account?.assertAccount().publicKeyString.get()
369
+ });
370
+ },
371
+ body: request,
372
+ getSignedData: getKeetaAssetMovementAnchorInitiateTransferRequestSigningData,
373
+ isResponse: isKeetaAssetMovementAnchorInitiateTransferResponse
374
+ });
135
375
  this.logger?.debug(`asset movement request successful, request ID ${requestInformationJSON.id}`);
136
376
  const anchorTransfer = new KeetaAssetMovementTransfer(this, request, { id: requestInformationJSON.id, instructionChoices: requestInformationJSON.instructionChoices });
137
377
  return (anchorTransfer);
138
378
  }
139
379
  async getTransferStatus(request) {
140
- const endpoints = this.serviceInfo.operations;
141
- const getTransferStatus = await endpoints.getTransferStatus;
142
- if (getTransferStatus === undefined) {
143
- throw (new Error('Asset Movement service does not support getTransferStatus operation'));
144
- }
145
- const getTransferURL = getTransferStatus({ id: request.id });
146
- const requestInformation = await fetch(getTransferURL, {
380
+ const requestInformationJSON = await this.#makeRequest({
147
381
  method: 'GET',
148
- headers: {
149
- 'Content-Type': 'application/json',
150
- 'Accept': 'application/json'
151
- }
382
+ endpoint: 'getTransferStatus',
383
+ account: request.account,
384
+ params: { id: request.id },
385
+ getSignedData: () => getKeetaAssetMovementAnchorGetTransferStatusRequestSigningData(request),
386
+ isResponse: isKeetaAssetMovementAnchorGetExchangeStatusResponse
152
387
  });
153
- const requestInformationJSON = await requestInformation.json();
154
- if (!isKeetaAssetMovementAnchorGetExchangeStatusResponse(requestInformationJSON)) {
155
- throw (new Error(`Invalid response from asset movement service: ${JSON.stringify(requestInformationJSON)}`));
156
- }
157
- if (!requestInformationJSON.ok) {
158
- throw (new Error(`asset movement request failed: ${requestInformationJSON.error}`));
159
- }
160
388
  this.logger?.debug(`asset movement request successful, request ID ${request.id}`);
161
389
  return (requestInformationJSON);
162
390
  }
391
+ async createPersistentForwardingTemplate(request) {
392
+ this.logger?.debug(`Creating persistent forwarding for provider ID: ${String(this.providerID)}, request: ${JSON.stringify(request)}`);
393
+ const requestInformationJSON = await this.#makeRequest({
394
+ method: 'POST',
395
+ endpoint: 'createPersistentForwardingTemplate',
396
+ account: request.account,
397
+ serializeRequest(body) {
398
+ return ({
399
+ ...body,
400
+ location: convertAssetLocationToString(body.location),
401
+ asset: convertAssetOrPairSearchInputToCanonical(body.asset),
402
+ account: body.account?.assertAccount().publicKeyString.get()
403
+ });
404
+ },
405
+ body: request,
406
+ getSignedData: getKeetaAssetMovementAnchorCreatePersistentForwardingAddressTemplateRequestSigningData,
407
+ isResponse: isKeetaAssetMovementAnchorCreatePersistentForwardingAddressTemplateResponse
408
+ });
409
+ this.logger?.debug(`create persistent forwarding request successful`, requestInformationJSON.address);
410
+ return (requestInformationJSON);
411
+ }
163
412
  async createPersistentForwardingAddress(request) {
164
413
  this.logger?.debug(`Creating persistent forwarding for provider ID: ${String(this.providerID)}, request: ${JSON.stringify(request)}`);
165
- const endpoints = this.serviceInfo.operations;
166
- const createPersistentForwarding = await endpoints.createPersistentForwarding;
167
- if (createPersistentForwarding === undefined) {
168
- throw (new Error('Asset Movement service does not support createPersistentForwarding operation'));
169
- }
170
- const createPersistentForwardingURL = createPersistentForwarding();
171
- const requestInformation = await fetch(createPersistentForwardingURL, {
414
+ const requestInformationJSON = await this.#makeRequest({
172
415
  method: 'POST',
173
- headers: {
174
- 'Content-Type': 'application/json',
175
- 'Accept': 'application/json'
416
+ endpoint: 'createPersistentForwarding',
417
+ account: request.account,
418
+ serializeRequest(body) {
419
+ const base = {
420
+ sourceLocation: convertAssetLocationToString(body.sourceLocation),
421
+ asset: convertAssetOrPairSearchInputToCanonical(body.asset),
422
+ account: body.account?.assertAccount().publicKeyString.get()
423
+ };
424
+ if ('persistentAddressTemplateId' in body) {
425
+ return ({
426
+ ...base,
427
+ persistentAddressTemplateId: body.persistentAddressTemplateId
428
+ });
429
+ }
430
+ else {
431
+ return ({
432
+ ...base,
433
+ destinationAddress: body.destinationAddress,
434
+ destinationLocation: convertAssetLocationToString(body.destinationLocation)
435
+ });
436
+ }
176
437
  },
177
- body: JSON.stringify({
178
- ...request
179
- })
438
+ body: request,
439
+ getSignedData: getKeetaAssetMovementAnchorCreatePersistentForwardingRequestSigningData,
440
+ isResponse: isKeetaAssetMovementAnchorCreatePersistentForwardingResponse
180
441
  });
181
- const requestInformationJSON = await requestInformation.json();
182
- if (!isKeetaAssetMovementAnchorCreatePersistentForwardingResponse(requestInformationJSON)) {
183
- throw (new Error(`Invalid response from create persistent forwarding request: ${JSON.stringify(requestInformationJSON)}`));
184
- }
185
- if (!requestInformationJSON.ok) {
186
- throw (new Error(`create persistent forwarding request failed: ${requestInformationJSON.error}`));
187
- }
188
- this.logger?.debug(`create persistent forwarding request successful, ${requestInformationJSON.address}`);
442
+ this.logger?.debug(`create persistent forwarding request successful`, requestInformationJSON.address);
189
443
  return (requestInformationJSON);
190
444
  }
445
+ async listForwardingAddressTemplates(request) {
446
+ this.logger?.debug(`Listing persistent forwarding address templates for provider ID: ${String(this.providerID)}`);
447
+ const requestInformationJSON = await this.#makeRequest({
448
+ method: 'POST',
449
+ endpoint: 'listPersistentForwardingTemplate',
450
+ account: request.account,
451
+ body: request,
452
+ serializeRequest(body) {
453
+ return ({
454
+ account: body.account?.assertAccount().publicKeyString.get(),
455
+ asset: body.asset?.map(a => convertAssetSearchInputToCanonical(a)),
456
+ location: body.location?.map(l => convertAssetLocationToString(l))
457
+ });
458
+ },
459
+ getSignedData: getKeetaAssetMovementAnchorListForwardingAddressTemplateRequestSigningData,
460
+ isResponse: isKeetaAssetMovementAnchorListForwardingAddressTemplateResponse
461
+ });
462
+ this.logger?.debug(`list persistent forwarding address templates request successful`, requestInformationJSON.templates);
463
+ return (requestInformationJSON.templates);
464
+ }
191
465
  async listTransactions(request) {
192
466
  this.logger?.debug(`List persistent forwarding transactions provider ID: ${String(this.providerID)}, request: ${JSON.stringify(request)}`);
193
- const endpoints = this.serviceInfo.operations;
194
- const listTransactions = await endpoints.listTransactions;
195
- if (listTransactions === undefined) {
196
- throw (new Error('Asset Movement service does not support listTransactions operation'));
197
- }
198
- const listTransactionsURL = listTransactions();
199
- const requestInformation = await fetch(listTransactionsURL, {
467
+ const requestInformationJSON = await this.#makeRequest({
200
468
  method: 'POST',
201
- headers: {
202
- 'Content-Type': 'application/json',
203
- 'Accept': 'application/json'
469
+ endpoint: 'listTransactions',
470
+ account: request.account,
471
+ serializeRequest(body) {
472
+ return ({
473
+ account: body.account?.assertAccount().publicKeyString.get(),
474
+ pagination: body.pagination,
475
+ persistentAddresses: body.persistentAddresses?.map(pa => ({
476
+ location: convertAssetLocationToString(pa.location),
477
+ ...('persistentAddressTemplate' in pa ?
478
+ { persistentAddressTemplate: pa.persistentAddressTemplate } :
479
+ { persistentAddress: pa.persistentAddress })
480
+ })),
481
+ from: body.from ? {
482
+ location: convertAssetLocationToString(body.from.location),
483
+ userAddress: body.from.userAddress,
484
+ asset: body.from.asset ? convertAssetSearchInputToCanonical(body.from.asset) : undefined
485
+ } : undefined,
486
+ to: body.to ? {
487
+ location: convertAssetLocationToString(body.to.location),
488
+ userAddress: body.to.userAddress,
489
+ asset: body.to.asset ? convertAssetSearchInputToCanonical(body.to.asset) : undefined
490
+ } : undefined
491
+ });
204
492
  },
205
- body: JSON.stringify({
206
- ...request
207
- })
493
+ body: request,
494
+ getSignedData: getKeetaAssetMovementAnchorlistTransactionsRequestSigningData,
495
+ isResponse: isKeetaAssetMovementAnchorlistPersistentForwardingTransactionsResponse
208
496
  });
209
- const requestInformationJSON = await requestInformation.json();
210
- if (!isKeetaAssetMovementAnchorlistPersistentForwardingTransactionsResponse(requestInformationJSON)) {
211
- throw (new Error(`Invalid response from list persistent transactions request: ${JSON.stringify(requestInformationJSON)}`));
212
- }
213
- if (!requestInformationJSON.ok) {
214
- throw (new Error(`list persistent transactions request failed: ${requestInformationJSON.error}`));
215
- }
216
497
  this.logger?.debug(`list persistent transactions request successful, ${requestInformationJSON.transactions}`);
217
498
  return (requestInformationJSON);
218
499
  }
500
+ async shareKYCAttributes(request) {
501
+ this.logger?.debug('Sharing KYC attributes');
502
+ await this.#makeRequest({
503
+ method: 'POST',
504
+ endpoint: 'shareKYC',
505
+ account: request.account,
506
+ async serializeRequest(body) {
507
+ let attributes;
508
+ if (typeof body.attributes === 'string') {
509
+ attributes = body.attributes;
510
+ }
511
+ else {
512
+ attributes = await body.attributes.export({ format: 'string' });
513
+ }
514
+ return ({
515
+ account: body.account.assertAccount().publicKeyString.get(),
516
+ attributes: attributes,
517
+ tosAgreement: body.tosAgreement
518
+ });
519
+ },
520
+ body: request,
521
+ getSignedData: getKeetaAssetMovementAnchorShareKYCRequestSigningData,
522
+ isResponse: isKeetaAssetMovementAnchorShareKYCResponse
523
+ });
524
+ this.logger?.debug(`done sharing KYC attributes`);
525
+ }
219
526
  }
220
527
  class KeetaAssetMovementAnchorClient extends KeetaAssetMovementAnchorBase {
221
528
  resolver;
@@ -251,7 +558,7 @@ class KeetaAssetMovementAnchorClient extends KeetaAssetMovementAnchorBase {
251
558
  }
252
559
  }
253
560
  async #lookup(request, shared) {
254
- const endpoints = await getEndpoints(this.resolver, request, shared);
561
+ const endpoints = await getEndpoints(this.resolver, request, shared, this.logger);
255
562
  if (endpoints === null) {
256
563
  return (null);
257
564
  }