@upshiftfinance/sdk 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +1 -1
  2. package/lib/abis/KycRegistry.d.ts +109 -0
  3. package/lib/abis/KycRegistry.js +73 -0
  4. package/lib/abis/index.d.ts +1 -0
  5. package/lib/abis/index.js +1 -0
  6. package/lib/adapters/sui/actions.d.ts +174 -0
  7. package/lib/adapters/sui/actions.js +382 -0
  8. package/lib/adapters/sui/getters.d.ts +166 -0
  9. package/lib/adapters/sui/getters.js +391 -0
  10. package/lib/adapters/sui/index.d.ts +95 -2
  11. package/lib/adapters/sui/index.js +92 -2
  12. package/lib/adapters/sui/targets.d.ts +35 -0
  13. package/lib/adapters/sui/targets.js +35 -0
  14. package/lib/core/analytics/method-taxonomy.d.ts +1 -1
  15. package/lib/core/analytics/method-taxonomy.js +7 -0
  16. package/lib/core/analytics/version.d.ts +1 -1
  17. package/lib/core/analytics/version.js +1 -1
  18. package/lib/core/constants/core.d.ts +5 -0
  19. package/lib/core/constants/core.js +5 -0
  20. package/lib/core/constants/kyc.d.ts +9 -0
  21. package/lib/core/constants/kyc.js +12 -0
  22. package/lib/core/constants/swap-router.js +24 -0
  23. package/lib/core/constants/web3.d.ts +2 -2
  24. package/lib/core/constants/web3.js +9 -2
  25. package/lib/core/errors/index.d.ts +77 -1
  26. package/lib/core/errors/index.js +94 -1
  27. package/lib/core/fetcher.d.ts +5 -0
  28. package/lib/core/fetcher.js +1 -1
  29. package/lib/core/helpers/chain-support.d.ts +2 -2
  30. package/lib/core/helpers/chain-support.js +3 -3
  31. package/lib/core/helpers/kyc.d.ts +47 -0
  32. package/lib/core/helpers/kyc.js +111 -0
  33. package/lib/core/helpers/revert-decode.js +3 -2
  34. package/lib/core/index.d.ts +2 -0
  35. package/lib/core/index.js +2 -0
  36. package/lib/main.d.ts +31 -3
  37. package/lib/main.js +32 -0
  38. package/lib/modules/api/kyc.d.ts +4 -0
  39. package/lib/modules/api/kyc.js +148 -0
  40. package/lib/modules/api/main.d.ts +63 -1
  41. package/lib/modules/api/main.js +64 -0
  42. package/lib/modules/vaults/getters.d.ts +3 -1
  43. package/lib/modules/vaults/getters.js +53 -9
  44. package/lib/modules/vaults/main.d.ts +39 -3
  45. package/lib/modules/vaults/main.js +79 -5
  46. package/lib/modules/vaults/types.d.ts +7 -1
  47. package/lib/modules/vaults/utils.js +4 -1
  48. package/lib/sdk.d.ts +15131 -14393
  49. package/lib/types/index.d.ts +1 -0
  50. package/lib/types/index.js +1 -0
  51. package/lib/types/kyc.d.ts +61 -0
  52. package/lib/types/kyc.js +3 -0
  53. package/lib/types/vaults.d.ts +2 -0
  54. package/lib/types/webserver.d.ts +5 -0
  55. package/package.json +1 -1
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getKycStatus = getKycStatus;
4
+ exports.getKycRecord = getKycRecord;
5
+ const ethers_1 = require("ethers");
6
+ const abis_1 = require("../../abis");
7
+ const kyc_1 = require("../constants/kyc");
8
+ const errors_1 = require("../errors");
9
+ const web3_1 = require("./web3");
10
+ const KYC_STATUSES = [
11
+ 'none',
12
+ 'active',
13
+ 'expired',
14
+ 'blocked',
15
+ ];
16
+ function toKycStatus(raw, chainId) {
17
+ const status = KYC_STATUSES[Number(raw)];
18
+ if (!status) {
19
+ throw new errors_1.UpshiftSDKError('UNKNOWN', `KycRegistry on chain ${chainId} returned unknown status ${raw}`, { context: { chainId } });
20
+ }
21
+ return status;
22
+ }
23
+ function contractAt(method, chainId, address, abi, provider) {
24
+ const contract = (0, web3_1.createContract)({ address, abi, provider });
25
+ if (!contract) {
26
+ throw new errors_1.UpshiftSDKError('UNKNOWN', `${method}: could not create a contract at ${address} on chain ${chainId}`, { context: { method, chainId } });
27
+ }
28
+ return contract;
29
+ }
30
+ function connect(method, chainId, rpcUrl, wallets) {
31
+ const registryAddress = kyc_1.KYC_REGISTRY_ADDRESSES[chainId];
32
+ if (!registryAddress) {
33
+ throw new errors_1.UpshiftValidationError('INVALID_CHAIN', `${method}: no KycRegistry is deployed on chain ${chainId}`, { context: { method, chainId } });
34
+ }
35
+ for (const [field, value] of Object.entries(wallets)) {
36
+ if (!(0, ethers_1.isAddress)(value)) {
37
+ throw new errors_1.UpshiftValidationError('INVALID_ADDRESS', `${method}: ${field} is not a valid EVM address`, { context: { method, chainId, field } });
38
+ }
39
+ }
40
+ return contractAt(method, chainId, registryAddress, abis_1.ABI_KYC_REGISTRY, (0, web3_1.createProvider)(rpcUrl, chainId));
41
+ }
42
+ async function wrapRead(method, chainId, read) {
43
+ try {
44
+ return await read();
45
+ }
46
+ catch (e) {
47
+ if (e instanceof errors_1.UpshiftSDKError)
48
+ throw e;
49
+ throw new errors_1.UpshiftSDKError('UNKNOWN', `${method} failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { chainId } });
50
+ }
51
+ }
52
+ /**
53
+ * Read a wallet's KYC status from the chain's `KycRegistry` (`statusOf`).
54
+ *
55
+ * The registry decides whether a KYC vault accepts a deposit, so read it
56
+ * on-chain rather than trusting a cached backend status. `expired` covers both
57
+ * a lapsed and a revoked record; tell them apart with {@link getKycRecord}.
58
+ * Not cached: an approval lands when the registry writer sends it, and callers
59
+ * poll for it.
60
+ *
61
+ * @param options - {@link IKycWalletOptions}.
62
+ * @returns The wallet's {@link IKycStatus}.
63
+ * @throws {@link UpshiftValidationError} `INVALID_CHAIN` when no registry is
64
+ * deployed on `chainId` (see {@link KYC_REGISTRY_ADDRESSES}),
65
+ * `INVALID_ADDRESS` when `wallet` is not an EVM address.
66
+ * @throws {@link UpshiftSDKError} when the `statusOf` read fails or returns a
67
+ * status this SDK version does not know.
68
+ * @worstCaseRpcCalls 1 — one `statusOf(address)` call.
69
+ * @example
70
+ * ```ts
71
+ * const status = await getKycStatus({ chainId: 1, wallet, rpcUrl });
72
+ * if (status !== 'active') showVerifyPrompt();
73
+ * ```
74
+ */
75
+ async function getKycStatus({ chainId, wallet, rpcUrl, }) {
76
+ const registry = connect('getKycStatus', chainId, rpcUrl, { wallet });
77
+ const raw = await wrapRead('getKycStatus', chainId, () => registry.statusOf(wallet));
78
+ return toKycStatus(raw, chainId);
79
+ }
80
+ /**
81
+ * Read a wallet's raw record from the chain's `KycRegistry` (`getRecord`).
82
+ *
83
+ * Use it with {@link getKycStatus} to show when access ends (`expiresAt`) and
84
+ * to tell a lapsed record (`expiresAt` in the past) from a revoked one. Not
85
+ * cached, for the same reason as {@link getKycStatus}.
86
+ *
87
+ * @param options - {@link IKycWalletOptions}.
88
+ * @returns The wallet's {@link IKycRecord}. A never-approved wallet returns
89
+ * all-zero timestamps and `blocked: false`.
90
+ * @throws {@link UpshiftValidationError} `INVALID_CHAIN` when no registry is
91
+ * deployed on `chainId`, `INVALID_ADDRESS` when `wallet` is not an EVM
92
+ * address.
93
+ * @throws {@link UpshiftSDKError} when the `getRecord` read fails.
94
+ * @worstCaseRpcCalls 1 — one `getRecord(address)` call.
95
+ * @example
96
+ * ```ts
97
+ * const { expiresAt } = await getKycRecord({ chainId: 1, wallet, rpcUrl });
98
+ * const verifiedUntil = new Date(expiresAt * 1000);
99
+ * ```
100
+ */
101
+ async function getKycRecord({ chainId, wallet, rpcUrl, }) {
102
+ const registry = connect('getKycRecord', chainId, rpcUrl, { wallet });
103
+ const record = await wrapRead('getKycRecord', chainId, () => registry.getRecord(wallet));
104
+ return {
105
+ blocked: record.blocked,
106
+ verifiedAt: Number(record.verifiedAt),
107
+ expiresAt: Number(record.expiresAt),
108
+ revokedAt: Number(record.revokedAt),
109
+ };
110
+ }
111
+ //# sourceMappingURL=kyc.js.map
@@ -99,8 +99,8 @@ const STANDARD_ERROR_SIGNATURES = [
99
99
  * ABIs already shipped by the SDK whose `error` fragments join the corpus.
100
100
  * Covers the Upshift vault estate: tokenized vaults (plus their
101
101
  * receipt / permit / whitelist companions), the SwapRouter, lending pools,
102
- * the fee oracle, the native-deposit wrapper, Multicall3, and the RWA redeem
103
- * subaccount.
102
+ * the fee oracle, the native-deposit wrapper, Multicall3, the RWA redeem
103
+ * subaccount, and the KYC registry.
104
104
  */
105
105
  const CORPUS_ABIS = [
106
106
  STANDARD_ERROR_SIGNATURES,
@@ -112,6 +112,7 @@ const CORPUS_ABIS = [
112
112
  abis_1.ABI_TOKENIZED_VAULT_V2_SENDER_ALLOCATION_WHITELIST,
113
113
  abis_1.ABI_MULTI_ASSET_NATIVE_DEPOSIT_WRAPPER,
114
114
  abis_1.ABI_SWAP_ROUTER,
115
+ abis_1.ABI_KYC_REGISTRY,
115
116
  abis_1.ABI_LENDING_POOL_V3,
116
117
  abis_1.ABI_FEE_ORACLE,
117
118
  abis_1.ABI_MULTICALL3,
@@ -11,6 +11,7 @@ export * from './constants/core';
11
11
  export * from './constants/web3';
12
12
  export * from './constants/vaults';
13
13
  export * from './constants/swap-router';
14
+ export * from './constants/kyc';
14
15
  export * from './helpers/web3';
15
16
  export * from './helpers/multicall';
16
17
  export * from './helpers/vaults';
@@ -20,4 +21,5 @@ export * from './helpers/core';
20
21
  export * from './helpers/adapters';
21
22
  export * from './helpers/signer';
22
23
  export * from './helpers/swap-router';
24
+ export * from './helpers/kyc';
23
25
  export * from './helpers/revert-decode';
package/lib/core/index.js CHANGED
@@ -27,6 +27,7 @@ __exportStar(require("./constants/core"), exports);
27
27
  __exportStar(require("./constants/web3"), exports);
28
28
  __exportStar(require("./constants/vaults"), exports);
29
29
  __exportStar(require("./constants/swap-router"), exports);
30
+ __exportStar(require("./constants/kyc"), exports);
30
31
  __exportStar(require("./helpers/web3"), exports);
31
32
  __exportStar(require("./helpers/multicall"), exports);
32
33
  __exportStar(require("./helpers/vaults"), exports);
@@ -36,5 +37,6 @@ __exportStar(require("./helpers/core"), exports);
36
37
  __exportStar(require("./helpers/adapters"), exports);
37
38
  __exportStar(require("./helpers/signer"), exports);
38
39
  __exportStar(require("./helpers/swap-router"), exports);
40
+ __exportStar(require("./helpers/kyc"), exports);
39
41
  __exportStar(require("./helpers/revert-decode"), exports);
40
42
  //# sourceMappingURL=index.js.map
package/lib/main.d.ts CHANGED
@@ -7,7 +7,7 @@ import SolanaAdapter from './adapters/solana';
7
7
  import SuiAdapter from './adapters/sui';
8
8
  import StellarAdapter from './adapters/stellar';
9
9
  import EVMAdapter from './adapters/evm';
10
- import type { IAddress, IChainId, IVaultHistoricalParams } from './types';
10
+ import type { IAddress, IChainId, IKycRecord, IKycStatus, IKycWalletOptions, IVaultHistoricalParams } from './types';
11
11
  import { UpshiftBase, type IUpshiftBase } from './core';
12
12
  import { UpshiftVaults, type IGetVaultsOptions, type IVaultBaseOptions, type IVaultCustomOptions } from './modules/vaults';
13
13
  import type { Signer, Wallet } from 'ethers';
@@ -266,8 +266,8 @@ export declare class UpshiftSDK extends UpshiftBase {
266
266
  solanaWallet?: string;
267
267
  stellarWallet?: string;
268
268
  /**
269
- * Sui wallet address (`0x` + 64 hex chars). Validated now; Sui positions
270
- * are not read yet, so passing it does not add Sui vaults to the result.
269
+ * Sui wallet address (`0x` + 64 hex chars). Its share balance is read for
270
+ * each Sui vault; Sui positions have no redemptions in v1.
271
271
  */
272
272
  suiWallet?: string;
273
273
  options?: IVaultBaseOptions;
@@ -388,6 +388,34 @@ export declare class UpshiftSDK extends UpshiftBase {
388
388
  chainId: number;
389
389
  originCode: `0x${string}`;
390
390
  }): Promise<import("./types").IOriginInfo>;
391
+ /**
392
+ * Read a wallet's status in `chainId`'s `KycRegistry`. Delegates to
393
+ * {@link UpshiftVaults.getKycStatus}.
394
+ * @param options - `chainId` and `wallet`.
395
+ * @returns `'none' | 'active' | 'expired' | 'blocked'`.
396
+ * @throws UpshiftValidationError when no provider is configured or no
397
+ * registry is deployed for `chainId`, or `wallet` is malformed.
398
+ * @throws UpshiftSDKError when the read fails.
399
+ * @example
400
+ * ```ts
401
+ * const status = await upshiftSdk.getKycStatus({ chainId: 1, wallet });
402
+ * ```
403
+ */
404
+ getKycStatus(options: Omit<IKycWalletOptions, 'rpcUrl'>): Promise<IKycStatus>;
405
+ /**
406
+ * Read a wallet's raw `KycRegistry` record (blocked flag and Unix-second
407
+ * timestamps). Delegates to {@link UpshiftVaults.getKycRecord}.
408
+ * @param options - `chainId` and `wallet`.
409
+ * @returns {@link IKycRecord}.
410
+ * @throws UpshiftValidationError when no provider is configured or no
411
+ * registry is deployed for `chainId`, or `wallet` is malformed.
412
+ * @throws UpshiftSDKError when the read fails.
413
+ * @example
414
+ * ```ts
415
+ * const { expiresAt } = await upshiftSdk.getKycRecord({ chainId: 1, wallet });
416
+ * ```
417
+ */
418
+ getKycRecord(options: Omit<IKycWalletOptions, 'rpcUrl'>): Promise<IKycRecord>;
391
419
  /**
392
420
  * Get lifetime PnL for a user in a specific vault.
393
421
  * Calculates realized and unrealized PnL based on deposit/withdrawal history and current position.
package/lib/main.js CHANGED
@@ -463,6 +463,38 @@ class UpshiftSDK extends core_1.UpshiftBase {
463
463
  async getOriginInfo(options) {
464
464
  return await this.vaults.getOriginInfo(options);
465
465
  }
466
+ /**
467
+ * Read a wallet's status in `chainId`'s `KycRegistry`. Delegates to
468
+ * {@link UpshiftVaults.getKycStatus}.
469
+ * @param options - `chainId` and `wallet`.
470
+ * @returns `'none' | 'active' | 'expired' | 'blocked'`.
471
+ * @throws UpshiftValidationError when no provider is configured or no
472
+ * registry is deployed for `chainId`, or `wallet` is malformed.
473
+ * @throws UpshiftSDKError when the read fails.
474
+ * @example
475
+ * ```ts
476
+ * const status = await upshiftSdk.getKycStatus({ chainId: 1, wallet });
477
+ * ```
478
+ */
479
+ async getKycStatus(options) {
480
+ return await this.vaults.getKycStatus(options);
481
+ }
482
+ /**
483
+ * Read a wallet's raw `KycRegistry` record (blocked flag and Unix-second
484
+ * timestamps). Delegates to {@link UpshiftVaults.getKycRecord}.
485
+ * @param options - `chainId` and `wallet`.
486
+ * @returns {@link IKycRecord}.
487
+ * @throws UpshiftValidationError when no provider is configured or no
488
+ * registry is deployed for `chainId`, or `wallet` is malformed.
489
+ * @throws UpshiftSDKError when the read fails.
490
+ * @example
491
+ * ```ts
492
+ * const { expiresAt } = await upshiftSdk.getKycRecord({ chainId: 1, wallet });
493
+ * ```
494
+ */
495
+ async getKycRecord(options) {
496
+ return await this.vaults.getKycRecord(options);
497
+ }
466
498
  /**
467
499
  * Get lifetime PnL for a user in a specific vault.
468
500
  * Calculates realized and unrealized PnL based on deposit/withdrawal history and current position.
@@ -0,0 +1,4 @@
1
+ import type { IAddress, ICreateKycSessionOptions, IKycChallenge, IKycSession } from '../../types';
2
+ export declare function fetchKycChallenge(wallet: IAddress, chainId: number): Promise<IKycChallenge>;
3
+ export declare function postKycSession(options: ICreateKycSessionOptions): Promise<IKycSession>;
4
+ export declare function postKycSessionRefresh(sessionToken: string): Promise<string>;
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchKycChallenge = fetchKycChallenge;
4
+ exports.postKycSession = postKycSession;
5
+ exports.postKycSessionRefresh = postKycSessionRefresh;
6
+ const ethers_1 = require("ethers");
7
+ const core_1 = require("../../core/constants/core");
8
+ const errors_1 = require("../../core/errors");
9
+ const fetcher_1 = require("../../core/fetcher");
10
+ const REASONS = {
11
+ 'challenge expired': 'challenge_expired',
12
+ 'unknown or used challenge': 'challenge_used',
13
+ 'invalid signature': 'invalid_signature',
14
+ 'unknown or expired session': 'session_expired',
15
+ 'session no longer valid': 'session_expired',
16
+ 'identity blocked': 'identity_blocked',
17
+ 'wallet is bound to another identity': 'wallet_bound',
18
+ 'wallet limit reached for this identity': 'wallet_limit',
19
+ 'wallet control was proven on another chain; verify again from there': 'other_chain',
20
+ 'wallet is verified through another provider': 'other_provider',
21
+ 'wallet is not verified for this chain': 'not_verified_for_chain',
22
+ 'enrolment already in progress; retry shortly': 'enrolment_in_progress',
23
+ 'a registry write for this wallet is in progress; retry shortly': 'registry_write_in_progress',
24
+ 'enrolment timed out; retry shortly': 'enrolment_timed_out',
25
+ 'chain has no kyc registry': 'no_registry',
26
+ 'too many requests': 'rate_limited',
27
+ };
28
+ const IDENTITY_STATUSES = [
29
+ 'pending',
30
+ 'approved',
31
+ 'rejected_retry',
32
+ 'rejected_final',
33
+ 'revoked',
34
+ 'blocked',
35
+ ];
36
+ function readDetail(body) {
37
+ const detail = body?.detail;
38
+ if (typeof detail === 'string')
39
+ return detail;
40
+ if (!Array.isArray(detail))
41
+ return '';
42
+ return detail
43
+ .map((d) => d?.msg)
44
+ .filter((m) => typeof m === 'string')
45
+ .join('; ');
46
+ }
47
+ function reasonFor(status, detail) {
48
+ const known = REASONS[detail.toLowerCase()];
49
+ if (known)
50
+ return known;
51
+ if (/has no KYC registry/i.test(detail))
52
+ return 'no_registry';
53
+ if (status === 429)
54
+ return 'rate_limited';
55
+ if (status >= 500)
56
+ return 'unavailable';
57
+ if (status === 422)
58
+ return 'invalid_request';
59
+ return 'unknown';
60
+ }
61
+ async function kycRequest(method, path, data) {
62
+ const res = await (0, fetcher_1.fetchUpshiftPublic)(path, {
63
+ method: data === undefined ? 'get' : 'post',
64
+ data,
65
+ returnErrorResponse: true,
66
+ });
67
+ const body = await res.json().catch(() => null);
68
+ if (res.ok) {
69
+ if (body && typeof body === 'object')
70
+ return body;
71
+ throw new errors_1.UpshiftServerError(res.status, `${method}: empty response body`);
72
+ }
73
+ const detail = readDetail(body);
74
+ const retryAfter = Number(res.headers.get('retry-after'));
75
+ throw new errors_1.UpshiftKycError(res.status, detail, reasonFor(res.status, detail), {
76
+ correlationId: res.headers.get('x-correlation-id') ?? undefined,
77
+ context: { method, status: res.status },
78
+ retryAfterMs: retryAfter > 0 ? retryAfter * 1000 : undefined,
79
+ });
80
+ }
81
+ function assertWalletAndChain(method, wallet, chainId) {
82
+ if (!(0, ethers_1.isAddress)(wallet)) {
83
+ throw new errors_1.UpshiftValidationError('INVALID_ADDRESS', `${method}: wallet is not a valid EVM address`);
84
+ }
85
+ if (!Number.isInteger(chainId) || chainId < 1) {
86
+ throw new errors_1.UpshiftValidationError('INVALID_CHAIN', `${method}: chainId must be a positive integer, got ${chainId}`);
87
+ }
88
+ }
89
+ function field(method, body, key, check) {
90
+ const value = body[key];
91
+ if (!check(value)) {
92
+ throw new errors_1.UpshiftServerError(200, `${method}: response field ${key} is malformed`);
93
+ }
94
+ return value;
95
+ }
96
+ const isString = (v) => typeof v === 'string' && v.length > 0;
97
+ const isInteger = (v) => Number.isInteger(v);
98
+ const isIdentityStatus = (v) => IDENTITY_STATUSES.includes(v);
99
+ async function fetchKycChallenge(wallet, chainId) {
100
+ const method = 'getKycChallenge';
101
+ assertWalletAndChain(method, wallet, chainId);
102
+ const body = await kycRequest(method, core_1.WEBSERVER_ENDPOINTS.public.kyc.challenge(wallet, chainId));
103
+ return {
104
+ wallet: field(method, body, 'wallet', isString),
105
+ chainId: field(method, body, 'chain_id', isInteger),
106
+ nonce: field(method, body, 'nonce', isString),
107
+ issuedAt: field(method, body, 'issued_at', isInteger),
108
+ expiry: field(method, body, 'expiry', isInteger),
109
+ message: field(method, body, 'message', isString),
110
+ };
111
+ }
112
+ async function postKycSession(options) {
113
+ const method = 'createKycSession';
114
+ const { wallet, chainId, nonce, issuedAt, expiry, signature } = options;
115
+ assertWalletAndChain(method, wallet, chainId);
116
+ if (!/^0x[0-9a-fA-F]+$/.test(signature)) {
117
+ throw new errors_1.UpshiftValidationError('INVALID_INPUT', `${method}: signature must be 0x-prefixed hex`);
118
+ }
119
+ if (!isString(nonce) || !isInteger(issuedAt) || !isInteger(expiry)) {
120
+ throw new errors_1.UpshiftValidationError('INVALID_INPUT', `${method}: nonce, issuedAt and expiry must come from getKycChallenge`);
121
+ }
122
+ const body = await kycRequest(method, core_1.WEBSERVER_ENDPOINTS.public.kyc.session, {
123
+ wallet,
124
+ chain_id: chainId,
125
+ nonce,
126
+ issued_at: issuedAt,
127
+ expiry,
128
+ signature,
129
+ });
130
+ return {
131
+ accessToken: field(method, body, 'access_token', isString),
132
+ sessionToken: field(method, body, 'session_token', isString),
133
+ externalUserId: field(method, body, 'external_user_id', isString),
134
+ levelName: field(method, body, 'level_name', isString),
135
+ identityStatus: field(method, body, 'identity_status', isIdentityStatus),
136
+ };
137
+ }
138
+ async function postKycSessionRefresh(sessionToken) {
139
+ const method = 'refreshKycSession';
140
+ if (typeof sessionToken !== 'string' ||
141
+ sessionToken.length < 16 ||
142
+ sessionToken.length > 128) {
143
+ throw new errors_1.UpshiftValidationError('INVALID_INPUT', `${method}: sessionToken must come from createKycSession`);
144
+ }
145
+ const body = await kycRequest(method, core_1.WEBSERVER_ENDPOINTS.public.kyc.sessionRefresh, { session_token: sessionToken });
146
+ return field(method, body, 'access_token', isString);
147
+ }
148
+ //# sourceMappingURL=kyc.js.map
@@ -1,5 +1,5 @@
1
1
  import { UpshiftBase, type IUpshiftBase } from '../../core/base.class';
2
- import type { ICollateralExcessOrDeficit, ICollateralSimulationInput, ICollateralSimulationResults, ICuratorWhitelistStatus, IDiscountFactorLadder, ILoanBookInfo, IOracleClassification, IOtcMarginRequirement, IOtcPositionRead, IRevertReason, ITimelockRequest, ITransparencyApySeries, ITransparencyAuditCategory, ITransparencyAuditLog, ITransparencyFees, ITransparencyGovernancePermissions, ITransparencyGovernanceRoles, ITransparencyHistoricalAllocations, ITransparencyPositions, ITransparencyRatioPoint, ITransparencyTimelocks, ITransparencyTimelockStatus, IUnrealizedPnlSnapshot, IVaultPerformanceFees, IWSSubaccountListItem } from '../../types';
2
+ import type { IAddress, ICollateralExcessOrDeficit, ICollateralSimulationInput, ICollateralSimulationResults, ICreateKycSessionOptions, ICuratorWhitelistStatus, IDiscountFactorLadder, IKycChallenge, IKycSession, ILoanBookInfo, IOracleClassification, IOtcMarginRequirement, IOtcPositionRead, IRevertReason, ITimelockRequest, ITransparencyApySeries, ITransparencyAuditCategory, ITransparencyAuditLog, ITransparencyFees, ITransparencyGovernancePermissions, ITransparencyGovernanceRoles, ITransparencyHistoricalAllocations, ITransparencyPositions, ITransparencyRatioPoint, ITransparencyTimelocks, ITransparencyTimelockStatus, IUnrealizedPnlSnapshot, IVaultPerformanceFees, IWSSubaccountListItem } from '../../types';
3
3
  /**
4
4
  * Read-only client for Upshift backend REST endpoints that have no on-chain
5
5
  * equivalent: the unrealized-PnL series, the transparency dashboard
@@ -584,4 +584,66 @@ export declare class UpshiftApi extends UpshiftBase {
584
584
  * const losing = all.filter((s) => s.unrealizedPnl < 0);
585
585
  */
586
586
  getLatestUnrealizedPnl(): Promise<IUnrealizedPnlSnapshot[]>;
587
+ /**
588
+ * Fetch a one-time SIWE challenge that proves the wallet is the user's
589
+ * before KYC starts (`GET /kyc/challenge`).
590
+ *
591
+ * Makes one HTTPS request to the public Upshift API; no RPC calls. Never
592
+ * cached: the nonce is single use and expires after 600 s.
593
+ *
594
+ * @param params - `wallet`, the EVM wallet that will sign `message`, and
595
+ * `chainId`, the EVM chain whose `KycRegistry` the session activates.
596
+ * @returns {@link IKycChallenge}. Sign `message` verbatim with `personal_sign`.
597
+ * @throws UpshiftValidationError When `wallet` or `chainId` is malformed.
598
+ * @throws UpshiftKycError When the backend answers non-2xx: `no_registry` (400) or `unavailable` (503).
599
+ * @throws UpshiftServerError When the response body is malformed.
600
+ * @example
601
+ * ```ts
602
+ * const challenge = await sdk.apiModule.getKycChallenge({ wallet, chainId: 1 });
603
+ * const signature = await walletClient.signMessage({ message: challenge.message });
604
+ * ```
605
+ */
606
+ getKycChallenge(params: {
607
+ wallet: IAddress;
608
+ chainId: number;
609
+ }): Promise<IKycChallenge>;
610
+ /**
611
+ * Open a KYC session with a signed challenge (`POST /kyc/session`). The
612
+ * first call creates the user's Sumsub applicant; later calls resume it.
613
+ * Every call activates the identity on `chainId`.
614
+ *
615
+ * Makes one HTTPS request and never retries: the nonce is single use. On
616
+ * any failure, fetch a new challenge before trying again.
617
+ *
618
+ * @param options - The challenge fields exactly as returned, plus `signature`.
619
+ * @returns {@link IKycSession} with the Sumsub WebSDK `accessToken`.
620
+ * @throws UpshiftValidationError When an input is malformed.
621
+ * @throws UpshiftKycError When the backend answers non-2xx. `reason` names the
622
+ * case; `retryable` is true for the in-progress and timed-out answers.
623
+ * @throws UpshiftServerError When the response body is malformed.
624
+ * @example
625
+ * ```ts
626
+ * const session = await sdk.apiModule.createKycSession({ ...challenge, signature });
627
+ * openSumsubWidget(session.accessToken);
628
+ * ```
629
+ */
630
+ createKycSession(options: ICreateKycSessionOptions): Promise<IKycSession>;
631
+ /**
632
+ * Get a fresh Sumsub WebSDK access token for an open session without a new
633
+ * signature (`POST /kyc/session/refresh`). A session lasts 4 h.
634
+ *
635
+ * Makes one HTTPS request; no RPC calls.
636
+ *
637
+ * @param params - `sessionToken` from {@link UpshiftApi.createKycSession}.
638
+ * @returns The new Sumsub access token.
639
+ * @throws UpshiftValidationError When `sessionToken` is malformed.
640
+ * @throws UpshiftKycError When the backend answers non-2xx: `session_expired` (401) once the session ends or the wallet is unbound.
641
+ * @example
642
+ * ```ts
643
+ * const expirationHandler = () => sdk.apiModule.refreshKycSession({ sessionToken });
644
+ * ```
645
+ */
646
+ refreshKycSession(params: {
647
+ sessionToken: string;
648
+ }): Promise<string>;
587
649
  }
@@ -10,6 +10,7 @@ exports.UpshiftApi = void 0;
10
10
  */
11
11
  const ethers_1 = require("ethers");
12
12
  const fetcher_1 = require("./fetcher");
13
+ const kyc_1 = require("./kyc");
13
14
  const base_class_1 = require("../../core/base.class");
14
15
  const core_1 = require("../../core/constants/core");
15
16
  const errors_1 = require("../../core/errors");
@@ -906,6 +907,69 @@ class UpshiftApi extends base_class_1.UpshiftBase {
906
907
  assertSnapshotArray(data, method);
907
908
  return data.map(toUnrealizedPnlSnapshot);
908
909
  }
910
+ /**
911
+ * Fetch a one-time SIWE challenge that proves the wallet is the user's
912
+ * before KYC starts (`GET /kyc/challenge`).
913
+ *
914
+ * Makes one HTTPS request to the public Upshift API; no RPC calls. Never
915
+ * cached: the nonce is single use and expires after 600 s.
916
+ *
917
+ * @param params - `wallet`, the EVM wallet that will sign `message`, and
918
+ * `chainId`, the EVM chain whose `KycRegistry` the session activates.
919
+ * @returns {@link IKycChallenge}. Sign `message` verbatim with `personal_sign`.
920
+ * @throws UpshiftValidationError When `wallet` or `chainId` is malformed.
921
+ * @throws UpshiftKycError When the backend answers non-2xx: `no_registry` (400) or `unavailable` (503).
922
+ * @throws UpshiftServerError When the response body is malformed.
923
+ * @example
924
+ * ```ts
925
+ * const challenge = await sdk.apiModule.getKycChallenge({ wallet, chainId: 1 });
926
+ * const signature = await walletClient.signMessage({ message: challenge.message });
927
+ * ```
928
+ */
929
+ async getKycChallenge(params) {
930
+ return (0, kyc_1.fetchKycChallenge)(params.wallet, params.chainId);
931
+ }
932
+ /**
933
+ * Open a KYC session with a signed challenge (`POST /kyc/session`). The
934
+ * first call creates the user's Sumsub applicant; later calls resume it.
935
+ * Every call activates the identity on `chainId`.
936
+ *
937
+ * Makes one HTTPS request and never retries: the nonce is single use. On
938
+ * any failure, fetch a new challenge before trying again.
939
+ *
940
+ * @param options - The challenge fields exactly as returned, plus `signature`.
941
+ * @returns {@link IKycSession} with the Sumsub WebSDK `accessToken`.
942
+ * @throws UpshiftValidationError When an input is malformed.
943
+ * @throws UpshiftKycError When the backend answers non-2xx. `reason` names the
944
+ * case; `retryable` is true for the in-progress and timed-out answers.
945
+ * @throws UpshiftServerError When the response body is malformed.
946
+ * @example
947
+ * ```ts
948
+ * const session = await sdk.apiModule.createKycSession({ ...challenge, signature });
949
+ * openSumsubWidget(session.accessToken);
950
+ * ```
951
+ */
952
+ async createKycSession(options) {
953
+ return (0, kyc_1.postKycSession)(options);
954
+ }
955
+ /**
956
+ * Get a fresh Sumsub WebSDK access token for an open session without a new
957
+ * signature (`POST /kyc/session/refresh`). A session lasts 4 h.
958
+ *
959
+ * Makes one HTTPS request; no RPC calls.
960
+ *
961
+ * @param params - `sessionToken` from {@link UpshiftApi.createKycSession}.
962
+ * @returns The new Sumsub access token.
963
+ * @throws UpshiftValidationError When `sessionToken` is malformed.
964
+ * @throws UpshiftKycError When the backend answers non-2xx: `session_expired` (401) once the session ends or the wallet is unbound.
965
+ * @example
966
+ * ```ts
967
+ * const expirationHandler = () => sdk.apiModule.refreshKycSession({ sessionToken });
968
+ * ```
969
+ */
970
+ async refreshKycSession(params) {
971
+ return (0, kyc_1.postKycSessionRefresh)(params.sessionToken);
972
+ }
909
973
  }
910
974
  exports.UpshiftApi = UpshiftApi;
911
975
  //# sourceMappingURL=main.js.map
@@ -119,11 +119,13 @@ export { getSwapRouterDepositResult } from '../../core/helpers/swap-router';
119
119
  /**
120
120
  * Vault Positions
121
121
  */
122
- export declare function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, options, prefetchedReads, }: {
122
+ export declare function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, suiWallet, options, prefetchedReads, }: {
123
123
  vault: IAddress;
124
124
  wallet?: IAddress;
125
125
  solanaWallet?: string;
126
126
  stellarWallet?: string;
127
+ /** Sui wallet whose share balance is read for Sui vaults. */
128
+ suiWallet?: string;
127
129
  options: IVaultBaseOptions;
128
130
  /**
129
131
  * Per-vault values already read via a Multicall3 batch at the fan-out call