@coinlist-co/react 0.10.1 → 0.11.1-rc.22d81d4

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 (38) hide show
  1. package/README.md +32 -0
  2. package/dist/chunk-AQIHCFW4.js +279 -0
  3. package/dist/chunk-AQIHCFW4.js.map +1 -0
  4. package/dist/{chunk-AQVCOWOV.js → chunk-PRG3EDQJ.js} +216 -317
  5. package/dist/chunk-PRG3EDQJ.js.map +1 -0
  6. package/dist/chunk-ZVB6KWZ2.js +2206 -0
  7. package/dist/chunk-ZVB6KWZ2.js.map +1 -0
  8. package/dist/client/index.cjs +11285 -3319
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +4243 -881
  11. package/dist/client/index.d.ts +4243 -881
  12. package/dist/client/index.js +9103 -2389
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/collections-DrJFEDHl.d.cts +116 -0
  15. package/dist/collections-pLtrj6fw.d.ts +116 -0
  16. package/dist/config-C6vlghJY.d.cts +2617 -0
  17. package/dist/config-C6vlghJY.d.ts +2617 -0
  18. package/dist/server/index.cjs +1588 -514
  19. package/dist/server/index.cjs.map +1 -1
  20. package/dist/server/index.d.cts +266 -162
  21. package/dist/server/index.d.ts +266 -162
  22. package/dist/server/index.js +235 -169
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/shared/index.cjs +2203 -937
  25. package/dist/shared/index.cjs.map +1 -1
  26. package/dist/shared/index.d.cts +256 -132
  27. package/dist/shared/index.d.ts +256 -132
  28. package/dist/shared/index.js +102 -28
  29. package/package.json +12 -8
  30. package/dist/chunk-AQVCOWOV.js.map +0 -1
  31. package/dist/chunk-TBU3EBNM.js +0 -442
  32. package/dist/chunk-TBU3EBNM.js.map +0 -1
  33. package/dist/chunk-UOHD7US2.js +0 -855
  34. package/dist/chunk-UOHD7US2.js.map +0 -1
  35. package/dist/collections-Bv1Oxzu_.d.ts +0 -28
  36. package/dist/collections-DDyxbOPZ.d.cts +0 -28
  37. package/dist/requirement-oVZA1INj.d.cts +0 -1040
  38. package/dist/requirement-oVZA1INj.d.ts +0 -1040
@@ -32,20 +32,26 @@ __export(shared_exports, {
32
32
  Blockchain: () => Blockchain,
33
33
  BlockchainAmount: () => BlockchainAmount,
34
34
  Bps: () => Bps,
35
+ Chain: () => Chain,
35
36
  ClientCredentialsOAuth: () => ClientCredentialsOAuth,
36
37
  ClientId: () => ClientId,
37
38
  ClientSecret: () => ClientSecret,
38
39
  CodeChallenge: () => CodeChallenge,
39
40
  CodeVerifier: () => CodeVerifier,
41
+ CoinListTokenSaleNamespaceImpl: () => CoinListTokenSaleNamespaceImpl,
40
42
  ConnectExternalWalletParams: () => ConnectExternalWalletParams,
41
43
  CreateParticipationParams: () => CreateParticipationParams,
42
44
  CreateWalletOwnershipChallengeParams: () => CreateWalletOwnershipChallengeParams,
43
45
  Cursor: () => Cursor,
44
46
  DEFAULT_AMOUNT_TO_COMPUTE_PRICE: () => DEFAULT_AMOUNT_TO_COMPUTE_PRICE,
47
+ DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE: () => DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE,
45
48
  DEFAULT_SLIPPAGE_BPS: () => DEFAULT_SLIPPAGE_BPS,
49
+ DecimalString: () => DecimalString,
46
50
  DocumentSubmission: () => DocumentSubmission,
47
51
  ERC20_ABI: () => ERC20_ABI,
52
+ ETHEREUM_CHAINS: () => ETHEREUM_CHAINS,
48
53
  Erc20NamespaceImpl: () => Erc20NamespaceImpl,
54
+ EthereumChain: () => EthereumChain,
49
55
  EvmContractAddress: () => EvmContractAddress,
50
56
  EvmWalletAddress: () => EvmWalletAddress,
51
57
  FaqItem: () => FaqItem,
@@ -53,10 +59,13 @@ __export(shared_exports, {
53
59
  FormattedAmountUi: () => FormattedAmountUi,
54
60
  FormattedPercentUi: () => FormattedPercentUi,
55
61
  HexEncodedTransactionData: () => HexEncodedTransactionData,
62
+ HttpError: () => HttpError,
63
+ InvariantError: () => InvariantError,
56
64
  Iso2CountryCode: () => Iso2CountryCode,
57
65
  KnownAssetSymbol: () => KnownAssetSymbol,
58
66
  KycToken: () => KycToken,
59
67
  Link: () => Link,
68
+ MAX_ASSET_DECIMALS: () => MAX_ASSET_DECIMALS,
60
69
  MAX_UINT_256: () => MAX_UINT_256,
61
70
  Milestone: () => Milestone,
62
71
  NA_AMOUNT_ASSET_UI: () => NA_AMOUNT_ASSET_UI,
@@ -64,6 +73,9 @@ __export(shared_exports, {
64
73
  NotImplementedError: () => NotImplementedError,
65
74
  OAuthRefreshToken: () => OAuthRefreshToken,
66
75
  OAuthSession: () => OAuthSession,
76
+ ONDO_POLL_INTERVAL_MS: () => ONDO_POLL_INTERVAL_MS,
77
+ ONDO_QUOTE_EXPIRY_THRESHOLD_MS: () => ONDO_QUOTE_EXPIRY_THRESHOLD_MS,
78
+ ONDO_SUPPORTED_INPUT_ASSETS: () => ONDO_SUPPORTED_INPUT_ASSETS,
67
79
  Offer: () => Offer,
68
80
  OfferDetail: () => OfferDetail,
69
81
  OfferId: () => OfferId,
@@ -73,6 +85,12 @@ __export(shared_exports, {
73
85
  OfferOptionId: () => OfferOptionId,
74
86
  OfferOptionSlug: () => OfferOptionSlug,
75
87
  OfferSlug: () => OfferSlug,
88
+ OfferToken: () => OfferToken,
89
+ OffersNamespaceImpl: () => OffersNamespaceImpl,
90
+ OndoNamespaceImpl: () => OndoNamespaceImpl,
91
+ OndoQuote: () => OndoQuote,
92
+ OndoSwapTransaction: () => OndoSwapTransaction,
93
+ OndoTradingStatus: () => OndoTradingStatus,
76
94
  PKCEState: () => PKCEState,
77
95
  PaginatedResponse: () => PaginatedResponse,
78
96
  PaginationParams: () => PaginationParams,
@@ -82,27 +100,37 @@ __export(shared_exports, {
82
100
  Pii: () => Pii,
83
101
  PiiAddress: () => PiiAddress,
84
102
  PiiJurisdiction: () => PiiJurisdiction,
103
+ RedactedWalletError: () => RedactedWalletError,
85
104
  RedirectUri: () => RedirectUri,
86
105
  Requirement: () => Requirement,
87
106
  RequirementId: () => RequirementId,
88
107
  RequirementStatusInfo: () => RequirementStatusInfo,
108
+ RequirementsNamespaceImpl: () => RequirementsNamespaceImpl,
89
109
  SLIPPAGE_OPTIONS_BPS: () => SLIPPAGE_OPTIONS_BPS,
110
+ SOLANA_CHAINS: () => SOLANA_CHAINS,
111
+ STABLE_DECIMALS: () => STABLE_DECIMALS,
112
+ SUPERSTATE_ISSUER_NAME: () => SUPERSTATE_ISSUER_NAME,
113
+ SUPERSTATE_SUPPORTED_INPUT_ASSETS: () => SUPERSTATE_SUPPORTED_INPUT_ASSETS,
90
114
  SUPERSTATE_SWAP_ABI: () => SUPERSTATE_SWAP_ABI,
91
115
  SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA: () => SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA,
92
- SUPERSTATE_TOS_URL: () => SUPERSTATE_TOS_URL,
93
116
  SWAP_POLL_INTERVAL_MS: () => SWAP_POLL_INTERVAL_MS,
94
117
  ShortenedWalletAddress: () => ShortenedWalletAddress,
118
+ SolanaChain: () => SolanaChain,
95
119
  StablecoinSymbol: () => StablecoinSymbol,
120
+ SuperstateSwapNamespaceImpl: () => SuperstateSwapNamespaceImpl,
96
121
  SwapAuthorization: () => SwapAuthorization,
97
- SwapNamespaceImpl: () => SwapNamespaceImpl,
98
122
  SwapPreview: () => SwapPreview,
99
123
  SwapQuote: () => SwapQuote,
100
124
  SwapStatus: () => SwapStatus,
101
125
  TOKEN_REGISTRY: () => TOKEN_REGISTRY,
102
126
  TermItem: () => TermItem,
127
+ Ticker: () => Ticker,
103
128
  TokenAllowance: () => TokenAllowance,
104
129
  TokenBalance: () => TokenBalance,
105
- TokenSaleNamespaceImpl: () => TokenSaleNamespaceImpl,
130
+ TokenLogo: () => TokenLogo,
131
+ TokenLogoUrl: () => TokenLogoUrl,
132
+ TokenMetadata: () => TokenMetadata,
133
+ TokensNamespaceImpl: () => TokensNamespaceImpl,
106
134
  TxExplorerUrl: () => TxExplorerUrl,
107
135
  USDC: () => USDC,
108
136
  USDC_SYMBOL: () => USDC_SYMBOL,
@@ -111,11 +139,17 @@ __export(shared_exports, {
111
139
  User: () => User,
112
140
  UserEmail: () => UserEmail,
113
141
  UserId: () => UserId,
142
+ ValidationError: () => ValidationError,
114
143
  WalletAddress: () => WalletAddress,
115
144
  WalletOwnershipChallenge: () => WalletOwnershipChallenge,
145
+ WalletsNamespaceImpl: () => WalletsNamespaceImpl,
146
+ apiErrorCode: () => apiErrorCode,
116
147
  applyBps: () => applyBps,
117
148
  assertUint256: () => assertUint256,
118
149
  assetAmount: () => assetAmount,
150
+ blockchainAmountFromRawOrThrow: () => blockchainAmountFromRawOrThrow,
151
+ chainFromId: () => chainFromId,
152
+ computeOndoPrice: () => computeOndoPrice,
119
153
  computePrice: () => computePrice,
120
154
  computeSlip: () => computeSlip,
121
155
  decodeSwappedOutputAmount: () => decodeSwappedOutputAmount,
@@ -130,15 +164,182 @@ __export(shared_exports, {
130
164
  getChainId: () => getChainId,
131
165
  getNetworkName: () => getNetworkName,
132
166
  isStopped: () => isStopped,
167
+ ondoSwapContractAddress: () => ondoSwapContractAddress,
133
168
  parseBlockchainAmount: () => parseBlockchainAmount,
169
+ parseUint256: () => parseUint256,
134
170
  shortenAddress: () => shortenAddress,
171
+ superstateSwapContractAddress: () => superstateSwapContractAddress,
135
172
  txExplorerUrl: () => txExplorerUrl,
136
173
  usdAmount: () => usdAmount
137
174
  });
138
175
  module.exports = __toCommonJS(shared_exports);
139
176
 
177
+ // src/shared/api/http-attributes.ts
178
+ var empty = {};
179
+ var concat = (left, right) => ({
180
+ ...left,
181
+ ...right
182
+ });
183
+ var concatAll = (...items) => {
184
+ let result = empty;
185
+ for (const item of items) {
186
+ result = concat(result, item);
187
+ }
188
+ return result;
189
+ };
190
+ var protectedRequest = () => ({ protected: true });
191
+ var userAgent = () => ({ userAgent: true });
192
+ var idempotencyKey = () => ({
193
+ idempotencyKey: true
194
+ });
195
+ var clientCredentials = (credentials) => ({
196
+ clientCredentials: credentials
197
+ });
198
+ var retryAttempt = (attempt) => ({
199
+ retryAttempt: attempt
200
+ });
201
+ var renewAttempted = (value) => ({
202
+ renewAttempted: value
203
+ });
204
+ var requestId = (id) => ({ requestId: id });
205
+ var getRequestId = (attrs) => attrs?.requestId ?? null;
206
+ var isProtected = (attrs) => attrs?.protected === true;
207
+ var needUserAgent = (attrs) => attrs?.userAgent === true;
208
+ var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
209
+ var getRetryAttempt = (attrs) => attrs?.retryAttempt ?? 0;
210
+ var wasRenewAttempted = (attrs) => attrs?.renewAttempted === true;
211
+ var getClientCredentials = (attrs) => attrs?.clientCredentials;
212
+ var Attributes = {
213
+ empty,
214
+ concat,
215
+ concatAll,
216
+ protected: protectedRequest,
217
+ isProtected,
218
+ userAgent,
219
+ needUserAgent,
220
+ idempotencyKey,
221
+ isIdempotent,
222
+ retryAttempt,
223
+ getRetryAttempt,
224
+ renewAttempted,
225
+ wasRenewAttempted,
226
+ clientCredentials,
227
+ getClientCredentials,
228
+ requestId,
229
+ getRequestId
230
+ };
231
+
232
+ // src/shared/api/http.ts
233
+ var HttpError = class extends Error {
234
+ constructor(response) {
235
+ super(`Request failed with ${response.status} status`);
236
+ this.name = "HttpError";
237
+ this.response = response;
238
+ }
239
+ /**
240
+ * Correlates this failure with the `[HTTP]` log lines for the same request,
241
+ * which carry the method, the URL, the duration and every retry. `null` when
242
+ * the response did not come from an {@link HttpClient}.
243
+ *
244
+ * Worth quoting in a bug report: it is what makes a log excerpt readable.
245
+ */
246
+ get requestId() {
247
+ return this.response.requestId ?? null;
248
+ }
249
+ };
250
+ function apiErrorCode(error) {
251
+ if (!(error instanceof HttpError)) return null;
252
+ const body = error.response.body;
253
+ if (typeof body !== "object" || body === null) return null;
254
+ const code = body.code;
255
+ return typeof code === "string" ? code : null;
256
+ }
257
+ async function makeRequest(request) {
258
+ const headers = {
259
+ Accept: "application/json",
260
+ ...request.method === "POST" && request.body !== void 0 ? { "Content-Type": "application/json" } : {},
261
+ ...request.headers ?? {}
262
+ };
263
+ const init = {
264
+ method: request.method,
265
+ headers,
266
+ ...request.redirect !== void 0 ? { redirect: request.redirect } : {}
267
+ };
268
+ if (request.method === "POST" && request.body !== void 0) {
269
+ init.body = JSON.stringify(request.body);
270
+ }
271
+ const response = await fetch(
272
+ buildUrlWithQueryParams(request.url, request.queryParams),
273
+ init
274
+ );
275
+ const responseHeaders = headersToRecord(response.headers);
276
+ if (response.status === 204 || response.status === 205) {
277
+ return {
278
+ status: response.status,
279
+ body: null,
280
+ headers: responseHeaders
281
+ };
282
+ }
283
+ if (response.status >= 300 && response.status < 400) {
284
+ await response.text();
285
+ return {
286
+ status: response.status,
287
+ body: null,
288
+ headers: responseHeaders
289
+ };
290
+ }
291
+ const text = await response.text();
292
+ let body;
293
+ try {
294
+ body = text ? JSON.parse(text) : null;
295
+ } catch (_) {
296
+ throw new HttpError({
297
+ status: response.status,
298
+ headers: responseHeaders,
299
+ body: text
300
+ });
301
+ }
302
+ return {
303
+ status: response.status,
304
+ body,
305
+ headers: responseHeaders
306
+ };
307
+ }
308
+ function buildUrlWithQueryParams(url, queryParams) {
309
+ if (!queryParams) {
310
+ return url;
311
+ }
312
+ const searchParams = new URLSearchParams();
313
+ for (const [key, value] of Object.entries(queryParams)) {
314
+ if (value === void 0 || value === null) {
315
+ continue;
316
+ }
317
+ if (Array.isArray(value)) {
318
+ for (const item of value) {
319
+ if (item === void 0 || item === null) {
320
+ continue;
321
+ }
322
+ searchParams.append(key, String(item));
323
+ }
324
+ continue;
325
+ }
326
+ searchParams.append(key, String(value));
327
+ }
328
+ const queryString = searchParams.toString();
329
+ if (!queryString) {
330
+ return url;
331
+ }
332
+ return url.includes("?") ? `${url}&${queryString}` : `${url}?${queryString}`;
333
+ }
334
+ function headersToRecord(headers) {
335
+ const record = {};
336
+ headers.forEach((value, key) => {
337
+ record[key.toLowerCase()] = value;
338
+ });
339
+ return record;
340
+ }
341
+
140
342
  // src/shared/api/pagination.ts
141
- var Cursor = (value) => value;
142
343
  async function fetchAllPages(fetchPage, baseParams) {
143
344
  const items = [];
144
345
  let cursor = null;
@@ -153,82 +354,284 @@ async function fetchAllPages(fetchPage, baseParams) {
153
354
  } while (cursor);
154
355
  return items;
155
356
  }
156
- var PaginatedResponse = {
157
- fromDto: (dto, itemMapper) => ({
158
- data: dto.data.map(itemMapper),
159
- startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
160
- startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
161
- })
357
+
358
+ // src/shared/core/utils/crypto.ts
359
+ async function sha256(data) {
360
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
361
+ const buffer = bytes.buffer.slice(
362
+ bytes.byteOffset,
363
+ bytes.byteOffset + bytes.byteLength
364
+ );
365
+ return crypto.subtle.digest("SHA-256", buffer);
366
+ }
367
+ function arrayBufferToBase64Url(buffer, padding = true) {
368
+ const bytes = new Uint8Array(buffer);
369
+ let binary = "";
370
+ for (let i = 0; i < bytes.length; i++) {
371
+ binary += String.fromCharCode(bytes[i]);
372
+ }
373
+ let base64 = btoa(binary);
374
+ base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
375
+ if (!padding) {
376
+ base64 = base64.replace(/=+$/, "");
377
+ }
378
+ return base64;
379
+ }
380
+ function generateSecureRandomBase64Url(byteLength) {
381
+ const bytes = new Uint8Array(byteLength);
382
+ crypto.getRandomValues(bytes);
383
+ const buffer = bytes.buffer;
384
+ return arrayBufferToBase64Url(buffer, false);
385
+ }
386
+ function notBlankStringOrNull(value) {
387
+ if (value?.trim()) {
388
+ return value;
389
+ } else {
390
+ return null;
391
+ }
392
+ }
393
+
394
+ // src/shared/types/oauth.ts
395
+ var AuthorizationCode = (value) => value;
396
+ var CodeVerifier = (value) => value;
397
+ var CodeChallenge = (value) => value;
398
+ var PKCEState = (value) => value;
399
+ var RedirectUri = (value) => value;
400
+ var ClientId = (value) => value;
401
+ var ClientSecret = (value) => value;
402
+
403
+ // src/shared/core/auth/pkce.ts
404
+ async function generatePKCEParams(config) {
405
+ const state = generateSecureRandomBase64Url(32);
406
+ const codeVerifier = generateSecureRandomBase64Url(32);
407
+ const codeChallengeRaw = await sha256(codeVerifier);
408
+ const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);
409
+ return {
410
+ clientId: config.clientId,
411
+ responseType: "code",
412
+ redirectUri: config.redirectUri,
413
+ codeChallenge: CodeChallenge(codeChallenge),
414
+ codeChallengeMethod: "S256",
415
+ state: PKCEState(state),
416
+ codeVerifier: CodeVerifier(codeVerifier)
417
+ };
418
+ }
419
+
420
+ // src/shared/types/errors.ts
421
+ var NotImplementedError = class extends Error {
422
+ constructor(message = "Not implemented yet") {
423
+ super(message);
424
+ this.name = "NotImplementedError";
425
+ }
162
426
  };
163
- var PaginationParams = {
164
- toQueryParams: (params) => {
165
- const queryParams = {};
166
- if (params.after) {
167
- queryParams.starting_after = params.after;
168
- }
169
- if (params.before) {
170
- queryParams.starting_before = params.before;
171
- }
172
- if (params.limit) {
173
- queryParams.limit = params.limit;
174
- }
175
- return queryParams;
427
+ var NotAuthenticatedError = class extends Error {
428
+ constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
429
+ super(message);
430
+ this.name = "NotAuthenticatedError";
431
+ }
432
+ };
433
+ var ValidationError = class extends Error {
434
+ constructor(message) {
435
+ super(message);
436
+ this.name = "ValidationError";
437
+ }
438
+ };
439
+ var InvariantError = class extends Error {
440
+ constructor(message) {
441
+ super(message);
442
+ this.name = "InvariantError";
176
443
  }
177
444
  };
178
445
 
179
- // src/shared/core/blockchain/abis/erc20.ts
180
- var ERC20_ABI = [
181
- {
182
- type: "function",
183
- name: "allowance",
184
- inputs: [
185
- { name: "owner", type: "address" },
186
- { name: "spender", type: "address" }
187
- ],
188
- outputs: [{ name: "", type: "uint256" }],
189
- stateMutability: "view"
190
- },
191
- {
192
- type: "function",
193
- name: "approve",
194
- inputs: [
195
- { name: "spender", type: "address" },
196
- { name: "amount", type: "uint256" }
197
- ],
198
- outputs: [{ name: "", type: "bool" }],
199
- stateMutability: "nonpayable"
200
- },
201
- {
202
- type: "function",
203
- name: "balanceOf",
204
- inputs: [{ name: "account", type: "address" }],
205
- outputs: [{ name: "", type: "uint256" }],
206
- stateMutability: "view"
207
- },
208
- {
209
- type: "function",
210
- name: "decimals",
211
- inputs: [],
212
- outputs: [{ name: "", type: "uint8" }],
213
- stateMutability: "view"
214
- },
215
- {
216
- type: "function",
217
- name: "name",
218
- inputs: [],
219
- outputs: [{ name: "", type: "string" }],
220
- stateMutability: "view"
221
- },
222
- {
223
- type: "function",
224
- name: "symbol",
225
- inputs: [],
226
- outputs: [{ name: "", type: "string" }],
227
- stateMutability: "view"
228
- },
446
+ // src/shared/types/blockchain/core.ts
447
+ var ETHEREUM_CHAINS = {
448
+ ethereum_mainnet: true,
449
+ ethereum_sepolia: true
450
+ };
451
+ var EthereumChain = (value) => {
452
+ if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {
453
+ throw new ValidationError(`Unsupported Ethereum chain: "${value}"`);
454
+ }
455
+ return value;
456
+ };
457
+ var SOLANA_CHAINS = {
458
+ solana_mainnet: true,
459
+ solana_devnet: true
460
+ };
461
+ var SolanaChain = (value) => {
462
+ if (!Object.keys(SOLANA_CHAINS).includes(value)) {
463
+ throw new ValidationError(`Unsupported Solana chain: "${value}"`);
464
+ }
465
+ return value;
466
+ };
467
+ var Chain = (value) => {
468
+ if (!Object.keys(ETHEREUM_CHAINS).includes(value) && !Object.keys(SOLANA_CHAINS).includes(value)) {
469
+ throw new ValidationError(`Unsupported chain: "${value}"`);
470
+ }
471
+ return value;
472
+ };
473
+ var EvmWalletAddress = (value) => value;
474
+ var EvmContractAddress = (value) => value;
475
+ var HexEncodedTransactionData = (value) => value;
476
+ var MAX_ASSET_DECIMALS = 77;
477
+ var AssetDecimals = (value) => {
478
+ if (!Number.isInteger(value)) {
479
+ throw new ValidationError(`Asset decimals must be an integer: ${value}`);
480
+ }
481
+ if (value < 0 || value > MAX_ASSET_DECIMALS) {
482
+ throw new ValidationError(
483
+ `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`
484
+ );
485
+ }
486
+ return value;
487
+ };
488
+ var STABLE_DECIMALS = AssetDecimals(6);
489
+ var DecimalString = (value) => value;
490
+ var MAX_UINT_256 = 2n ** 256n - 1n;
491
+ var assertUint256 = (value) => {
492
+ if (isUint256(value)) return value;
493
+ throw new InvariantError(`Value out of uint256 bounds: ${value}`);
494
+ };
495
+ var parseUint256 = (value, label) => {
496
+ if (isUint256(value)) return value;
497
+ throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
498
+ };
499
+ var isUint256 = (value) => value >= 0n && value <= MAX_UINT_256;
500
+ var BlockchainAmount = Object.assign(
501
+ (value) => value,
229
502
  {
230
- type: "function",
231
- name: "totalSupply",
503
+ add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
504
+ sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
505
+ }
506
+ );
507
+ function combineAmounts(a, b, op) {
508
+ if (a.decimals !== b.decimals) {
509
+ throw new InvariantError(
510
+ `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
511
+ );
512
+ }
513
+ const raw = op(a.raw, b.raw);
514
+ if (raw < 0n || raw > MAX_UINT_256) {
515
+ throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);
516
+ }
517
+ return BlockchainAmount({ raw, decimals: a.decimals });
518
+ }
519
+ var AssetSymbol = (value) => value;
520
+ var StablecoinSymbol = (value) => value;
521
+ var KnownAssetSymbol = StablecoinSymbol;
522
+ var Bps = (value) => value;
523
+
524
+ // src/shared/core/blockchain/bps.ts
525
+ var BPS_DENOM = Bps(10000n);
526
+ function applyBps(amount, bps) {
527
+ return assertUint256(amount * bps / BPS_DENOM);
528
+ }
529
+
530
+ // src/shared/types/blockchain/ui.ts
531
+ var FormattedAmountUi = (value) => value;
532
+ var FormattedPercentUi = (value) => value;
533
+ var TxExplorerUrl = (value) => value;
534
+ var ShortenedWalletAddress = (value) => value;
535
+ var FormattedAmountAssetUi = (value) => value;
536
+ var AssetIconUrl = (value) => value;
537
+
538
+ // src/shared/core/blockchain/chain.ts
539
+ var CHAIN_IDS = {
540
+ ethereum_mainnet: 1,
541
+ ethereum_sepolia: 11155111
542
+ };
543
+ function getChainId(chain) {
544
+ return CHAIN_IDS[chain];
545
+ }
546
+ function chainFromId(chainId) {
547
+ const chains = Object.keys(CHAIN_IDS);
548
+ const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);
549
+ if (!chain) {
550
+ throw new ValidationError(`Unsupported EIP-155 chain id: "${chainId}"`);
551
+ }
552
+ return chain;
553
+ }
554
+ function getNetworkName(chain) {
555
+ switch (chain) {
556
+ case "ethereum_mainnet":
557
+ return "Ethereum";
558
+ case "ethereum_sepolia":
559
+ return "Ethereum Sepolia";
560
+ default: {
561
+ const _exhaustive = chain;
562
+ return _exhaustive;
563
+ }
564
+ }
565
+ }
566
+ function txExplorerUrl(chain, txHash) {
567
+ return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);
568
+ }
569
+ function explorerBaseUrl(chain) {
570
+ switch (chain) {
571
+ case "ethereum_mainnet":
572
+ return "https://etherscan.io";
573
+ case "ethereum_sepolia":
574
+ return "https://sepolia.etherscan.io";
575
+ default: {
576
+ const _exhaustive = chain;
577
+ return _exhaustive;
578
+ }
579
+ }
580
+ }
581
+
582
+ // src/shared/core/blockchain/erc20/abi.ts
583
+ var ERC20_ABI = [
584
+ {
585
+ type: "function",
586
+ name: "allowance",
587
+ inputs: [
588
+ { name: "owner", type: "address" },
589
+ { name: "spender", type: "address" }
590
+ ],
591
+ outputs: [{ name: "", type: "uint256" }],
592
+ stateMutability: "view"
593
+ },
594
+ {
595
+ type: "function",
596
+ name: "approve",
597
+ inputs: [
598
+ { name: "spender", type: "address" },
599
+ { name: "amount", type: "uint256" }
600
+ ],
601
+ outputs: [{ name: "", type: "bool" }],
602
+ stateMutability: "nonpayable"
603
+ },
604
+ {
605
+ type: "function",
606
+ name: "balanceOf",
607
+ inputs: [{ name: "account", type: "address" }],
608
+ outputs: [{ name: "", type: "uint256" }],
609
+ stateMutability: "view"
610
+ },
611
+ {
612
+ type: "function",
613
+ name: "decimals",
614
+ inputs: [],
615
+ outputs: [{ name: "", type: "uint8" }],
616
+ stateMutability: "view"
617
+ },
618
+ {
619
+ type: "function",
620
+ name: "name",
621
+ inputs: [],
622
+ outputs: [{ name: "", type: "string" }],
623
+ stateMutability: "view"
624
+ },
625
+ {
626
+ type: "function",
627
+ name: "symbol",
628
+ inputs: [],
629
+ outputs: [{ name: "", type: "string" }],
630
+ stateMutability: "view"
631
+ },
632
+ {
633
+ type: "function",
634
+ name: "totalSupply",
232
635
  inputs: [],
233
636
  outputs: [{ name: "", type: "uint256" }],
234
637
  stateMutability: "view"
@@ -274,9 +677,1041 @@ var ERC20_ABI = [
274
677
  ],
275
678
  anonymous: false
276
679
  }
277
- ];
680
+ ];
681
+
682
+ // src/shared/types/providers/superstate/swap.ts
683
+ var SwapAuthorization = {
684
+ fromDto: (dto) => ({
685
+ authorized: dto.authorized
686
+ })
687
+ };
688
+ var SwapPreview = {
689
+ fromDto: (dto) => ({
690
+ inputAmount: parseUint256(
691
+ BigInt(dto.pay_input_amount),
692
+ "SwapPreview.pay_input_amount"
693
+ ),
694
+ fee: parseUint256(BigInt(dto.fee), "SwapPreview.fee"),
695
+ outputAmount: parseUint256(
696
+ BigInt(dto.receive_output_amount),
697
+ "SwapPreview.receive_output_amount"
698
+ )
699
+ })
700
+ };
701
+ var SwapStatus = {
702
+ fromDto: (dto) => ({
703
+ stopped: parseUint256(BigInt(dto.stopped), "SwapStatus.stopped"),
704
+ swapLevel: parseUint256(BigInt(dto.swap_level), "SwapStatus.swap_level")
705
+ })
706
+ };
707
+ var TokenAllowance = {
708
+ fromDto: (dto) => ({
709
+ allowance: parseUint256(BigInt(dto.allowance), "TokenAllowance.allowance")
710
+ })
711
+ };
712
+ var TokenBalance = {
713
+ fromDto: (dto) => ({
714
+ balance: parseUint256(BigInt(dto.balance), "TokenBalance.balance")
715
+ })
716
+ };
717
+ var AllowWalletResponse = {
718
+ fromDto: (dto) => {
719
+ switch (dto.action) {
720
+ case "broadcast_transaction":
721
+ return {
722
+ action: "broadcast_transaction",
723
+ to: EvmContractAddress(dto.to),
724
+ data: HexEncodedTransactionData(dto.data)
725
+ };
726
+ case "none":
727
+ return {
728
+ action: "none",
729
+ alreadyAllowed: dto.already_allowed
730
+ };
731
+ default: {
732
+ const _exhaustive = dto;
733
+ return _exhaustive;
734
+ }
735
+ }
736
+ }
737
+ };
738
+
739
+ // src/shared/api/frontline/providers/superstate/swap.ts
740
+ async function getSwapAuthorization(api, params) {
741
+ const dto = await api.send({
742
+ method: "GET",
743
+ url: "/v1/wallet/authorized",
744
+ queryParams: {
745
+ chain: params.chain,
746
+ contract_address: params.contractAddress,
747
+ wallet_address: params.walletAddress
748
+ },
749
+ attributes: Attributes.protected()
750
+ });
751
+ return SwapAuthorization.fromDto(dto);
752
+ }
753
+ async function getSwapOutputToken(api, params) {
754
+ const dto = await api.send({
755
+ method: "GET",
756
+ url: "/v1/swap/output-token",
757
+ queryParams: {
758
+ chain: params.chain,
759
+ contract_address: params.contractAddress
760
+ },
761
+ attributes: Attributes.protected()
762
+ });
763
+ return toErc20Asset(dto);
764
+ }
765
+ async function getSwapPreview(api, params) {
766
+ const dto = await api.send({
767
+ method: "GET",
768
+ url: "/v1/swap/preview",
769
+ queryParams: {
770
+ chain: params.chain,
771
+ contract_address: params.contractAddress,
772
+ input_token: params.inputToken,
773
+ amount: params.amount.toString()
774
+ },
775
+ attributes: Attributes.protected()
776
+ });
777
+ return SwapPreview.fromDto(dto);
778
+ }
779
+ async function getSwapStatus(api, params) {
780
+ const dto = await api.send({
781
+ method: "GET",
782
+ url: "/v1/swap/status",
783
+ queryParams: {
784
+ chain: params.chain,
785
+ contract_address: params.contractAddress
786
+ },
787
+ attributes: Attributes.protected()
788
+ });
789
+ return SwapStatus.fromDto(dto);
790
+ }
791
+ async function getTokenAllowance(api, params) {
792
+ const dto = await api.send({
793
+ method: "GET",
794
+ url: "/v1/token/allowance",
795
+ queryParams: {
796
+ chain: params.chain,
797
+ token_address: params.tokenAddress,
798
+ owner: params.owner,
799
+ spender: params.spender
800
+ },
801
+ attributes: Attributes.protected()
802
+ });
803
+ return TokenAllowance.fromDto(dto);
804
+ }
805
+ async function getTokenBalance(api, params) {
806
+ const dto = await api.send({
807
+ method: "GET",
808
+ url: "/v1/token/balance",
809
+ queryParams: {
810
+ chain: params.chain,
811
+ token_address: params.tokenAddress,
812
+ owner: params.owner
813
+ },
814
+ attributes: Attributes.protected()
815
+ });
816
+ return TokenBalance.fromDto(dto);
817
+ }
818
+ async function allowWallet(api, params) {
819
+ const dto = await api.send({
820
+ method: "POST",
821
+ url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,
822
+ body: {
823
+ wallet_address: params.walletAddress,
824
+ chain: params.chain,
825
+ signature: params.signature
826
+ },
827
+ attributes: Attributes.protected()
828
+ });
829
+ return AllowWalletResponse.fromDto(dto);
830
+ }
831
+ function toErc20Asset(dto) {
832
+ return {
833
+ name: dto.name,
834
+ symbol: AssetSymbol(dto.symbol),
835
+ decimals: AssetDecimals(dto.decimals)
836
+ };
837
+ }
838
+
839
+ // src/shared/core/observability/log-cause.ts
840
+ function classifyLogCause(error) {
841
+ if (error instanceof HttpError) {
842
+ return httpCause(error);
843
+ }
844
+ if (error instanceof ValidationError) {
845
+ return { type: "validation", message: error.message };
846
+ }
847
+ if (error instanceof InvariantError) {
848
+ return { type: "invariant", message: error.message };
849
+ }
850
+ if (error instanceof NotAuthenticatedError) {
851
+ return { type: "not-authenticated" };
852
+ }
853
+ if (error instanceof NotImplementedError) {
854
+ return { type: "not-implemented" };
855
+ }
856
+ return { type: "generic-error", name: errorName(error) };
857
+ }
858
+ function describeErrorUnredacted(error) {
859
+ if (error instanceof HttpError) {
860
+ return describeHttpErrorRedacted(error);
861
+ }
862
+ if (error instanceof Error) {
863
+ return `${error.name}: ${error.message}`;
864
+ }
865
+ return `thrown non-error: ${stringifyUnredacted(error)}`;
866
+ }
867
+ function stringifyUnredacted(value) {
868
+ if (value === void 0) return "";
869
+ try {
870
+ return JSON.stringify(
871
+ value,
872
+ (_key, item) => typeof item === "bigint" ? `${item}` : item
873
+ ) ?? String(value);
874
+ } catch (_) {
875
+ return "<unserializable>";
876
+ }
877
+ }
878
+ function describeHttpErrorRedacted(error) {
879
+ const code = apiErrorCode(error);
880
+ const status = error.response.status;
881
+ return code === null ? `HttpError ${status}` : `HttpError ${status} (${code})`;
882
+ }
883
+ function errorName(error) {
884
+ return error instanceof Error ? error.name : `non-error ${typeof error}`;
885
+ }
886
+ function httpCause(error) {
887
+ return {
888
+ type: "http",
889
+ requestId: error.requestId,
890
+ status: error.response.status,
891
+ code: apiErrorCode(error),
892
+ eventId: apiErrorEventId(error)
893
+ };
894
+ }
895
+ function apiErrorEventId(error) {
896
+ const body = error.response.body;
897
+ if (typeof body !== "object" || body === null) return null;
898
+ const eventId = body.event_id;
899
+ return typeof eventId === "string" ? eventId : null;
900
+ }
901
+
902
+ // src/shared/core/observability/internal-logger.ts
903
+ function internalLogger(logger, scope) {
904
+ return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;
905
+ }
906
+ var LEVEL_RANK = {
907
+ none: 0,
908
+ error: 1,
909
+ warn: 2,
910
+ info: 3,
911
+ debug: 4
912
+ };
913
+ function scopedLogger(logger, scope, bindings) {
914
+ const admits = (level) => LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];
915
+ const safe = (event) => ({
916
+ msg: event.msg,
917
+ scope,
918
+ bindings,
919
+ fields: event.fields ?? {},
920
+ ...event.cause === void 0 ? {} : { cause: event.cause }
921
+ });
922
+ const unredacted = (event) => ({
923
+ msg: event.msg,
924
+ scope,
925
+ bindings,
926
+ fields: event.fields ?? {}
927
+ });
928
+ const self = {
929
+ child: (binding) => scopedLogger(logger, scope, { ...bindings, ...binding }),
930
+ debug: (event) => {
931
+ if (admits("debug")) logger.debug(() => unredacted(event()));
932
+ },
933
+ info: (event) => {
934
+ if (admits("info")) logger.info(() => safe(event()));
935
+ },
936
+ warn: (event) => {
937
+ if (admits("warn")) logger.warn(() => safe(event()));
938
+ },
939
+ error: (event) => {
940
+ if (admits("error")) logger.error(() => safe(event()));
941
+ },
942
+ failure: (event, error) => {
943
+ if (admits("debug"))
944
+ logger.debug(() => unredacted(verbatim(event(), error)));
945
+ if (admits("error")) logger.error(() => safe(classified(event(), error)));
946
+ },
947
+ warning: (event, error) => {
948
+ if (admits("debug"))
949
+ logger.debug(() => unredacted(verbatim(event(), error)));
950
+ if (admits("warn")) logger.warn(() => safe(classified(event(), error)));
951
+ },
952
+ wrap: async (op, params, run) => {
953
+ const opLog = self.child({ op });
954
+ opLog.debug(() => ({ msg: "call", fields: { params } }));
955
+ try {
956
+ return await run();
957
+ } catch (error) {
958
+ opLog.failure(() => ({ msg: "call failed" }), error);
959
+ throw error;
960
+ }
961
+ }
962
+ };
963
+ return self;
964
+ }
965
+ function verbatim(event, error) {
966
+ return {
967
+ msg: event.msg,
968
+ fields: { ...event.fields, error: describeErrorUnredacted(error) }
969
+ };
970
+ }
971
+ function classified(event, error) {
972
+ return { ...event, cause: event.cause ?? classifyLogCause(error) };
973
+ }
974
+ var noopInternalLogger = {
975
+ child: () => noopInternalLogger,
976
+ debug: () => void 0,
977
+ info: () => void 0,
978
+ warn: () => void 0,
979
+ error: () => void 0,
980
+ failure: () => void 0,
981
+ warning: () => void 0,
982
+ wrap: (_op, _params, run) => run()
983
+ };
984
+
985
+ // src/shared/core/blockchain/erc20/erc20-namespace.ts
986
+ var Erc20NamespaceImpl = class {
987
+ constructor(ctx) {
988
+ this.ctx = ctx;
989
+ this.log = internalLogger(ctx.logger, "ERC20");
990
+ }
991
+ async getAllowance(params) {
992
+ return this.log.wrap("getAllowance", params, async () => {
993
+ await this.ctx.ensureUserAuthenticated();
994
+ return getTokenAllowance(this.ctx.api, params);
995
+ });
996
+ }
997
+ async getBalance(params) {
998
+ return this.log.wrap("getBalance", params, async () => {
999
+ await this.ctx.ensureUserAuthenticated();
1000
+ return getTokenBalance(this.ctx.api, params);
1001
+ });
1002
+ }
1003
+ };
1004
+
1005
+ // src/shared/core/blockchain/formatters.ts
1006
+ var import_viem = require("viem");
1007
+ function shortenAddress(address) {
1008
+ const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
1009
+ return ShortenedWalletAddress(short);
1010
+ }
1011
+ function formatAmount(amount, locale, options) {
1012
+ const decimal = formatRawAmount(amount);
1013
+ let [integerPart, fractionPart = ""] = decimal.split(".");
1014
+ const maxFractionDigits = options?.maxFractionDigits;
1015
+ const minFractionDigits = maxFractionDigits !== void 0 ? Math.min(maxFractionDigits, amount.decimals) : Math.min(2, amount.decimals);
1016
+ if (maxFractionDigits !== void 0 && fractionPart.length > maxFractionDigits) {
1017
+ ({ integerPart, fractionPart } = roundFractionHalfUp(
1018
+ integerPart,
1019
+ fractionPart,
1020
+ maxFractionDigits
1021
+ ));
1022
+ }
1023
+ const fraction = minFractionDigits === 0 ? "" : fractionPart.padEnd(minFractionDigits, "0");
1024
+ const integerFormatted = BigInt(integerPart).toLocaleString(locale);
1025
+ if (minFractionDigits === 0 && fraction === "") {
1026
+ return FormattedAmountUi(integerFormatted);
1027
+ }
1028
+ const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
1029
+ return FormattedAmountUi(`${integerFormatted}${decimalSeparator}${fraction}`);
1030
+ }
1031
+ function roundFractionHalfUp(integerPart, fractionPart, maxFractionDigits) {
1032
+ if (fractionPart.length <= maxFractionDigits) {
1033
+ return { integerPart, fractionPart };
1034
+ }
1035
+ if (maxFractionDigits === 0) {
1036
+ const roundUp = fractionPart[0] >= "5";
1037
+ const integer = BigInt(integerPart) + (roundUp ? 1n : 0n);
1038
+ return { integerPart: integer.toString(), fractionPart: "" };
1039
+ }
1040
+ const trimmed = fractionPart.slice(0, maxFractionDigits);
1041
+ if (fractionPart[maxFractionDigits] < "5") {
1042
+ return { integerPart, fractionPart: trimmed };
1043
+ }
1044
+ const digits = trimmed.split("").map((digit) => Number.parseInt(digit, 10));
1045
+ let carry = 1;
1046
+ for (let i = digits.length - 1; i >= 0 && carry > 0; i -= 1) {
1047
+ const sum = digits[i] + carry;
1048
+ if (sum === 10) {
1049
+ digits[i] = 0;
1050
+ carry = 1;
1051
+ } else {
1052
+ digits[i] = sum;
1053
+ carry = 0;
1054
+ }
1055
+ }
1056
+ return {
1057
+ integerPart: carry > 0 ? (BigInt(integerPart) + 1n).toString() : integerPart,
1058
+ fractionPart: digits.join("")
1059
+ };
1060
+ }
1061
+ function formatRawAmount(amount) {
1062
+ return (0, import_viem.formatUnits)(amount.raw, amount.decimals);
1063
+ }
1064
+ function formatCompactAmount(amount, locale) {
1065
+ const value = Number(formatRawAmount(amount));
1066
+ const formatted = new Intl.NumberFormat(locale, {
1067
+ notation: "compact",
1068
+ maximumFractionDigits: 2
1069
+ }).format(value);
1070
+ return FormattedAmountUi(formatted);
1071
+ }
1072
+ function formatBpsAsPercent(bps, locale) {
1073
+ const whole = bps / 100n;
1074
+ const fraction = bps % 100n;
1075
+ const wholeFormatted = whole.toLocaleString(locale);
1076
+ const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
1077
+ if (fraction === 0n) {
1078
+ return FormattedPercentUi(`${wholeFormatted}%`);
1079
+ }
1080
+ const fractionFormatted = fraction.toString().padStart(2, "0").replace(/0+$/, "");
1081
+ return FormattedPercentUi(
1082
+ `${wholeFormatted}${decimalSeparator}${fractionFormatted}%`
1083
+ );
1084
+ }
1085
+ function usdAmount(amount) {
1086
+ return FormattedAmountAssetUi(`$${amount}`);
1087
+ }
1088
+ function assetAmount(amount, symbol) {
1089
+ return FormattedAmountAssetUi(`${amount} ${symbol}`);
1090
+ }
1091
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
1092
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
1093
+ function formattedUsdPrice(amount, locale) {
1094
+ if (!amount) return NA_AMOUNT_ASSET_UI;
1095
+ return usdAmount(
1096
+ formatAmount(amount, locale, { maxFractionDigits: USD_FRACTION_DIGITS })
1097
+ );
1098
+ }
1099
+
1100
+ // src/shared/core/blockchain/math.ts
1101
+ var import_viem2 = require("viem");
1102
+ function blockchainAmountFromRawOrThrow({
1103
+ label,
1104
+ raw,
1105
+ decimals
1106
+ }) {
1107
+ const trimmed = raw.trim();
1108
+ if (trimmed === "") {
1109
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1110
+ }
1111
+ let value;
1112
+ try {
1113
+ value = BigInt(trimmed);
1114
+ } catch {
1115
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1116
+ }
1117
+ try {
1118
+ return BlockchainAmount({ raw: assertUint256(value), decimals });
1119
+ } catch {
1120
+ throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
1121
+ }
1122
+ }
1123
+ function parseBlockchainAmount(amount, decimals) {
1124
+ const trimmed = amount.trim();
1125
+ if (trimmed === "") return { valid: false, reason: { type: "empty" } };
1126
+ if (trimmed.startsWith("-")) {
1127
+ return { valid: false, reason: { type: "negative" } };
1128
+ }
1129
+ if (/[eE]/.test(trimmed)) {
1130
+ return { valid: false, reason: { type: "invalid-format" } };
1131
+ }
1132
+ if (!/^\d+(\.\d+)?$/.test(trimmed)) {
1133
+ return { valid: false, reason: { type: "invalid-format" } };
1134
+ }
1135
+ const [, fraction = ""] = trimmed.split(".");
1136
+ if (fraction.length > decimals) {
1137
+ return {
1138
+ valid: false,
1139
+ reason: { type: "too-many-decimals", maxDecimals: decimals }
1140
+ };
1141
+ }
1142
+ try {
1143
+ const raw = (0, import_viem2.parseUnits)(trimmed, decimals);
1144
+ if (raw > MAX_UINT_256) {
1145
+ return { valid: false, reason: { type: "overflow" } };
1146
+ }
1147
+ return {
1148
+ valid: true,
1149
+ amount: BlockchainAmount({ raw, decimals })
1150
+ };
1151
+ } catch {
1152
+ return { valid: false, reason: { type: "invalid-format" } };
1153
+ }
1154
+ }
1155
+
1156
+ // src/shared/core/blockchain/token-registry.ts
1157
+ var USDC_SYMBOL = StablecoinSymbol("USDC");
1158
+ var USDC = {
1159
+ name: "USD Coin",
1160
+ symbol: USDC_SYMBOL,
1161
+ decimals: AssetDecimals(6)
1162
+ };
1163
+ var USDT_SYMBOL = StablecoinSymbol("USDT");
1164
+ var USDT = {
1165
+ name: "Tether USD",
1166
+ symbol: USDT_SYMBOL,
1167
+ decimals: AssetDecimals(6)
1168
+ };
1169
+ var USDC_ADDRESSES = {
1170
+ ethereum_mainnet: EvmContractAddress(
1171
+ "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
1172
+ ),
1173
+ ethereum_sepolia: EvmContractAddress(
1174
+ "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
1175
+ )
1176
+ };
1177
+ var USDT_ADDRESSES = {
1178
+ ethereum_mainnet: EvmContractAddress(
1179
+ "0xdac17f958d2ee523a2206206994597c13d831ec7"
1180
+ ),
1181
+ ethereum_sepolia: EvmContractAddress(
1182
+ "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
1183
+ )
1184
+ };
1185
+ var TOKEN_REGISTRY = {
1186
+ erc20: (symbol) => {
1187
+ switch (symbol) {
1188
+ case "USDC":
1189
+ return USDC;
1190
+ case "USDT":
1191
+ return USDT;
1192
+ default:
1193
+ throw new InvariantError(`Unknown asset symbol: ${symbol}`);
1194
+ }
1195
+ },
1196
+ contractAddress: (symbol, chain) => {
1197
+ switch (symbol) {
1198
+ case "USDC":
1199
+ return USDC_ADDRESSES[chain];
1200
+ case "USDT":
1201
+ return USDT_ADDRESSES[chain];
1202
+ default:
1203
+ throw new InvariantError(`Unknown asset symbol: ${symbol}`);
1204
+ }
1205
+ }
1206
+ };
1207
+
1208
+ // src/shared/types/pagination.ts
1209
+ var Cursor = (value) => value;
1210
+ var PaginatedResponse = {
1211
+ fromDto: (dto, itemMapper) => ({
1212
+ data: dto.data.map(itemMapper),
1213
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
1214
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
1215
+ })
1216
+ };
1217
+ var PaginationParams = {
1218
+ toQueryParams: (params) => {
1219
+ const queryParams = {};
1220
+ if (params.after) {
1221
+ queryParams.starting_after = params.after;
1222
+ }
1223
+ if (params.before) {
1224
+ queryParams.starting_before = params.before;
1225
+ }
1226
+ if (params.limit) {
1227
+ queryParams.limit = params.limit;
1228
+ }
1229
+ return queryParams;
1230
+ }
1231
+ };
1232
+
1233
+ // src/shared/types/asset.ts
1234
+ var AssetId = (value) => value;
1235
+ var AssetCode = (value) => value;
1236
+ var Asset = {
1237
+ fromDto: (dto) => ({
1238
+ id: AssetId(dto.id),
1239
+ code: AssetCode(dto.code),
1240
+ name: dto.name,
1241
+ fractionalDigits: dto.fractional_digits
1242
+ })
1243
+ };
1244
+
1245
+ // src/shared/types/offer.ts
1246
+ var OfferId = (value) => value;
1247
+ var OfferSlug = (value) => value;
1248
+ var Offer = {
1249
+ fromDto: (dto) => {
1250
+ if (!Array.isArray(dto.tokens)) {
1251
+ throw new ValidationError(
1252
+ `Offer.tokens: expected an array, got ${typeof dto.tokens}`
1253
+ );
1254
+ }
1255
+ return {
1256
+ id: OfferId(dto.id),
1257
+ slug: OfferSlug(dto.slug),
1258
+ type: dto.type,
1259
+ tagline: dto.tagline,
1260
+ bannerUrl: dto.banner_url,
1261
+ logoUrl: dto.logo_url,
1262
+ startsAt: new Date(dto.starts_at),
1263
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1264
+ tokens: dto.tokens.map(OfferToken.fromDto)
1265
+ };
1266
+ }
1267
+ };
1268
+ var OfferToken = {
1269
+ fromDto: (dto) => ({
1270
+ role: dto.role,
1271
+ chain: Chain(dto.chain),
1272
+ address: EvmContractAddress(dto.address)
1273
+ })
1274
+ };
1275
+
1276
+ // src/shared/types/offer-detail.ts
1277
+ var OfferOptionId = (value) => value;
1278
+ var OfferOptionSlug = (value) => value;
1279
+ var OfferDetail = {
1280
+ fromDto: (dto) => {
1281
+ if (!Array.isArray(dto.funding_assets)) {
1282
+ throw new ValidationError(
1283
+ `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
1284
+ );
1285
+ }
1286
+ if (!Array.isArray(dto.options)) {
1287
+ throw new ValidationError(
1288
+ `OfferDetail.options: expected an array, got ${typeof dto.options}`
1289
+ );
1290
+ }
1291
+ if (!Array.isArray(dto.terms)) {
1292
+ throw new ValidationError(
1293
+ `OfferDetail.terms: expected an array, got ${typeof dto.terms}`
1294
+ );
1295
+ }
1296
+ if (!Array.isArray(dto.links)) {
1297
+ throw new ValidationError(
1298
+ `OfferDetail.links: expected an array, got ${typeof dto.links}`
1299
+ );
1300
+ }
1301
+ if (!Array.isArray(dto.faqs)) {
1302
+ throw new ValidationError(
1303
+ `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
1304
+ );
1305
+ }
1306
+ if (!Array.isArray(dto.milestones)) {
1307
+ throw new ValidationError(
1308
+ `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
1309
+ );
1310
+ }
1311
+ if (!Array.isArray(dto.tokens)) {
1312
+ throw new ValidationError(
1313
+ `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
1314
+ );
1315
+ }
1316
+ return {
1317
+ id: OfferId(dto.id),
1318
+ slug: OfferSlug(dto.slug),
1319
+ type: dto.type,
1320
+ name: dto.name,
1321
+ asset: Asset.fromDto(dto.asset),
1322
+ fundingAssets: dto.funding_assets.map(Asset.fromDto),
1323
+ tokens: dto.tokens.map(OfferToken.fromDto),
1324
+ about: notBlankStringOrNull(dto.about),
1325
+ tagline: dto.tagline,
1326
+ bannerUrl: dto.banner_url,
1327
+ logoUrl: dto.logo_url,
1328
+ category: dto.category,
1329
+ startsAt: new Date(dto.starts_at),
1330
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1331
+ faqs: dto.faqs.map(FaqItem.fromDto),
1332
+ links: dto.links.map(Link.fromDto),
1333
+ milestones: dto.milestones.map(Milestone.fromDto),
1334
+ options: dto.options.map(OfferOption.fromDto),
1335
+ terms: dto.terms.map(TermItem.fromDto)
1336
+ };
1337
+ }
1338
+ };
1339
+ var OfferOption = {
1340
+ fromDto: (dto) => ({
1341
+ id: OfferOptionId(dto.id),
1342
+ slug: OfferOptionSlug(dto.slug),
1343
+ bidIncrement: dto.bid_increment,
1344
+ floorPriceUsd: dto.floor_price_usd,
1345
+ minimumPurchaseUsd: dto.minimum_purchase_usd,
1346
+ priceUsd: dto.price_usd,
1347
+ saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),
1348
+ totalTokenSupply: dto.total_token_supply
1349
+ })
1350
+ };
1351
+ var FaqItem = {
1352
+ fromDto: (dto) => ({
1353
+ question: notBlankStringOrNull(dto.question),
1354
+ answer: notBlankStringOrNull(dto.answer)
1355
+ })
1356
+ };
1357
+ var Link = {
1358
+ fromDto: (dto) => ({
1359
+ label: notBlankStringOrNull(dto.label),
1360
+ url: notBlankStringOrNull(dto.url)
1361
+ })
1362
+ };
1363
+ var TermItem = {
1364
+ fromDto: (dto) => ({
1365
+ key: notBlankStringOrNull(dto.key),
1366
+ value: notBlankStringOrNull(dto.value)
1367
+ })
1368
+ };
1369
+ var Milestone = {
1370
+ fromDto: (dto) => ({
1371
+ name: notBlankStringOrNull(dto.name),
1372
+ schedule: notBlankStringOrNull(dto.schedule),
1373
+ status: dto.status
1374
+ })
1375
+ };
1376
+
1377
+ // src/shared/types/providers/coin-list/token-sale.ts
1378
+ var ParticipationId = (value) => value;
1379
+ var Blockchain = (value) => value;
1380
+ var WalletAddress = (value) => value;
1381
+ var ParticipationsPaginationParams = {
1382
+ toQueryParams: (params) => {
1383
+ const queryParams = PaginationParams.toQueryParams(params);
1384
+ if (params.offerId) {
1385
+ queryParams["filters[0][field]"] = "offer_id";
1386
+ queryParams["filters[0][op]"] = "==";
1387
+ queryParams["filters[0][value]"] = params.offerId;
1388
+ }
1389
+ return queryParams;
1390
+ }
1391
+ };
1392
+ var Participation = {
1393
+ /** Maps API DTO shape into the SDK participation domain model. */
1394
+ fromDto: (dto) => {
1395
+ const walletAddress = notBlankStringOrNull(dto.wallet_address);
1396
+ return {
1397
+ id: ParticipationId(dto.id),
1398
+ offerId: OfferId(dto.offer_id),
1399
+ offerOptionId: OfferOptionId(dto.offer_option_id),
1400
+ status: dto.status,
1401
+ amount: dto.amount,
1402
+ displayAmount: dto.amount_string,
1403
+ asset: Asset.fromDto(dto.asset),
1404
+ chain: Blockchain(dto.chain),
1405
+ insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,
1406
+ updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,
1407
+ walletAddress: walletAddress ? WalletAddress(walletAddress) : null
1408
+ };
1409
+ }
1410
+ };
1411
+ var CreateParticipationParams = {
1412
+ /** Maps participation creation params into API DTO payload. */
1413
+ toDto: (params) => ({
1414
+ offer_id: params.offerId,
1415
+ offer_option_id: params.offerOptionId,
1416
+ chain: params.chain,
1417
+ wallet_address: params.walletAddress,
1418
+ amount: params.amount,
1419
+ asset_id: params.assetId,
1420
+ approval_transaction_hash: params.approvalTransactionHash
1421
+ })
1422
+ };
1423
+
1424
+ // src/shared/api/frontline/providers/coin-list/token-sale.ts
1425
+ async function fetchParticipations(api, offerId) {
1426
+ return fetchAllPages(
1427
+ (params) => fetchParticipationsPage(api, params),
1428
+ { offerId }
1429
+ );
1430
+ }
1431
+ async function fetchParticipationsPage(api, params) {
1432
+ const pageDto = await api.send({
1433
+ method: "GET",
1434
+ url: "/v1/participations",
1435
+ queryParams: ParticipationsPaginationParams.toQueryParams(params),
1436
+ attributes: Attributes.protected()
1437
+ });
1438
+ return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
1439
+ }
1440
+ async function fetchParticipation(api, id) {
1441
+ const dto = await api.send({
1442
+ method: "GET",
1443
+ url: `/v1/participations/${id}`,
1444
+ attributes: Attributes.protected()
1445
+ });
1446
+ return Participation.fromDto(dto);
1447
+ }
1448
+ async function createParticipation(api, params) {
1449
+ const dto = await api.send({
1450
+ method: "POST",
1451
+ url: "/v1/participations",
1452
+ body: CreateParticipationParams.toDto(params),
1453
+ attributes: Attributes.protected()
1454
+ });
1455
+ return Participation.fromDto(dto);
1456
+ }
1457
+
1458
+ // src/shared/core/checkout/coin-list/token-sale-namespace.ts
1459
+ var CoinListTokenSaleNamespaceImpl = class {
1460
+ constructor(ctx) {
1461
+ this.ctx = ctx;
1462
+ this.log = internalLogger(ctx.logger, "TOKEN_SALE");
1463
+ }
1464
+ async list(offerId) {
1465
+ return this.log.wrap("list", offerId, async () => {
1466
+ await this.ctx.ensureUserAuthenticated();
1467
+ return fetchParticipations(this.ctx.api, offerId);
1468
+ });
1469
+ }
1470
+ async listPage(params) {
1471
+ return this.log.wrap("listPage", params, async () => {
1472
+ await this.ctx.ensureUserAuthenticated();
1473
+ return fetchParticipationsPage(this.ctx.api, params);
1474
+ });
1475
+ }
1476
+ async get(id) {
1477
+ return this.log.wrap("get", id, async () => {
1478
+ await this.ctx.ensureUserAuthenticated();
1479
+ return fetchParticipation(this.ctx.api, id);
1480
+ });
1481
+ }
1482
+ async createParticipation(params) {
1483
+ return this.log.wrap("createParticipation", params, async () => {
1484
+ await this.ctx.ensureUserAuthenticated();
1485
+ return createParticipation(this.ctx.api, params);
1486
+ });
1487
+ }
1488
+ };
1489
+
1490
+ // src/shared/core/checkout/ondo/constants.ts
1491
+ var ONDO_SWAP_CONTRACT_ADDRESSES = {
1492
+ ethereum_sepolia: EvmContractAddress(
1493
+ "0xFF9c5Ade32d9B4102469Bd5F3817CB0061b25feC"
1494
+ )
1495
+ };
1496
+ function ondoSwapContractAddress(chain) {
1497
+ return ONDO_SWAP_CONTRACT_ADDRESSES[chain] ?? null;
1498
+ }
1499
+ var ONDO_POLL_INTERVAL_MS = 15e3;
1500
+ var ONDO_QUOTE_EXPIRY_THRESHOLD_MS = 5e3;
1501
+ var DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE = DecimalString("1000");
1502
+ var ONDO_SUPPORTED_INPUT_ASSETS = [
1503
+ USDC_SYMBOL
1504
+ ];
1505
+
1506
+ // src/shared/core/checkout/ondo/math.ts
1507
+ function computeOndoPrice(transaction) {
1508
+ const { notionalValue, receiveOutputAmount } = transaction;
1509
+ if (receiveOutputAmount.raw <= 0n) {
1510
+ throw new ValidationError(
1511
+ "Ondo price: receiveOutputAmount must be greater than zero"
1512
+ );
1513
+ }
1514
+ const scaled = notionalValue.raw * 10n ** BigInt(receiveOutputAmount.decimals);
1515
+ const raw = scaled / receiveOutputAmount.raw;
1516
+ return BlockchainAmount({
1517
+ raw: assertPriceFits(raw),
1518
+ decimals: notionalValue.decimals
1519
+ });
1520
+ }
1521
+ function assertPriceFits(raw) {
1522
+ try {
1523
+ return assertUint256(raw);
1524
+ } catch {
1525
+ throw new ValidationError(`Ondo price: out of uint256 bounds (${raw})`);
1526
+ }
1527
+ }
1528
+
1529
+ // src/shared/types/trading.ts
1530
+ var Ticker = (value) => value;
1531
+
1532
+ // src/shared/types/providers/ondo/ondo.ts
1533
+ var OndoTradingStatus = {
1534
+ fromDto: (dto) => {
1535
+ if (!dto.tradable) return { type: "not-tradable", side: dto.side };
1536
+ return {
1537
+ type: "tradable",
1538
+ side: dto.side,
1539
+ grossMaxTokens: decimalOrNull(dto.gross_max_tokens),
1540
+ grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),
1541
+ grossMaxActiveNotionalValue: decimalOrNull(
1542
+ dto.gross_max_active_notional_value
1543
+ )
1544
+ };
1545
+ }
1546
+ };
1547
+ var decimalOrNull = (value) => value === null ? null : DecimalString(value);
1548
+ var OndoQuote = {
1549
+ fromDto: (dto) => {
1550
+ const assetDecimals = AssetDecimals(dto.asset_decimals);
1551
+ return {
1552
+ chain: chainFromId(dto.chain_id),
1553
+ ticker: Ticker(dto.ticker),
1554
+ assetAddress: EvmContractAddress(dto.asset_address),
1555
+ asset: {
1556
+ name: dto.ticker,
1557
+ symbol: AssetSymbol(dto.symbol),
1558
+ decimals: assetDecimals
1559
+ },
1560
+ side: dto.side,
1561
+ tokenBaseUnits: blockchainAmountFromRawOrThrow({
1562
+ label: "tokenBaseUnits",
1563
+ raw: dto.token_base_units,
1564
+ decimals: assetDecimals
1565
+ }),
1566
+ price: DecimalString(dto.price)
1567
+ };
1568
+ }
1569
+ };
1570
+ var OndoSwapTransaction = {
1571
+ fromDto: (dto) => {
1572
+ const inputDecimals = AssetDecimals(dto.pay_input_decimals);
1573
+ const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1574
+ return {
1575
+ tx: {
1576
+ to: EvmContractAddress(dto.to),
1577
+ data: HexEncodedTransactionData(dto.data)
1578
+ },
1579
+ expiresAt: parseExpiresAt(dto.expires_at),
1580
+ payInputAmount: blockchainAmountFromRawOrThrow({
1581
+ label: "pay_input_amount",
1582
+ raw: dto.pay_input_amount,
1583
+ decimals: inputDecimals
1584
+ }),
1585
+ fee: blockchainAmountFromRawOrThrow({
1586
+ label: "fee",
1587
+ raw: dto.fee,
1588
+ decimals: inputDecimals
1589
+ }),
1590
+ notionalValue: blockchainAmountFromRawOrThrow({
1591
+ label: "notional_value",
1592
+ raw: dto.notional_value,
1593
+ decimals: inputDecimals
1594
+ }),
1595
+ receiveOutputAmount: parseReceiveOutputAmount(
1596
+ dto.receive_output_amount,
1597
+ outputDecimals
1598
+ )
1599
+ };
1600
+ }
1601
+ };
1602
+ function parseReceiveOutputAmount(raw, decimals) {
1603
+ const amount = blockchainAmountFromRawOrThrow({
1604
+ label: "receive_output_amount",
1605
+ raw,
1606
+ decimals
1607
+ });
1608
+ if (amount.raw <= 0n) {
1609
+ throw new ValidationError(
1610
+ `receive_output_amount: must be greater than zero ("${raw}")`
1611
+ );
1612
+ }
1613
+ return amount;
1614
+ }
1615
+ function parseExpiresAt(value) {
1616
+ const date = new Date(value);
1617
+ if (Number.isNaN(date.getTime())) {
1618
+ throw new ValidationError(`expires_at: not a date ("${value}")`);
1619
+ }
1620
+ return date;
1621
+ }
1622
+
1623
+ // src/shared/api/frontline/providers/ondo/ondo.ts
1624
+ async function getOndoTradingStatus(api, params) {
1625
+ const dto = await api.send({
1626
+ method: "GET",
1627
+ url: "/v1/ondo/swap/trading-status",
1628
+ queryParams: { symbol: params.symbol, side: params.side },
1629
+ attributes: Attributes.protected()
1630
+ });
1631
+ return OndoTradingStatus.fromDto(dto);
1632
+ }
1633
+ async function getOndoQuote(api, params) {
1634
+ const dto = await api.send({
1635
+ method: "GET",
1636
+ url: "/v1/ondo/swap/quote",
1637
+ queryParams: {
1638
+ symbol: params.symbol,
1639
+ side: params.side,
1640
+ duration: params.duration,
1641
+ ...sizeParam(params)
1642
+ },
1643
+ attributes: Attributes.protected()
1644
+ });
1645
+ return OndoQuote.fromDto(dto);
1646
+ }
1647
+ async function buildOndoSwapTransaction(api, params) {
1648
+ const dto = await api.send({
1649
+ method: "POST",
1650
+ url: "/v1/ondo/swap/transaction",
1651
+ body: {
1652
+ symbol: params.symbol,
1653
+ chain: params.chain,
1654
+ wallet_address: params.walletAddress,
1655
+ amount: params.amount.raw.toString()
1656
+ },
1657
+ attributes: Attributes.protected()
1658
+ });
1659
+ assertFundingScaleAgrees(dto, params);
1660
+ return OndoSwapTransaction.fromDto(dto);
1661
+ }
1662
+ function assertFundingScaleAgrees(dto, params) {
1663
+ if (dto.pay_input_decimals !== params.amount.decimals) {
1664
+ throw new ValidationError(
1665
+ `pay_input_decimals: the swap was priced in ${dto.pay_input_decimals} decimals but the order was sized in ${params.amount.decimals}`
1666
+ );
1667
+ }
1668
+ }
1669
+ function sizeParam(params) {
1670
+ const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
1671
+ const notionalValue = "notionalValue" in params ? params.notionalValue : void 0;
1672
+ if (tokenAmount !== void 0) {
1673
+ if (notionalValue !== void 0) {
1674
+ throw new ValidationError(
1675
+ "An Ondo quote takes tokenAmount or notionalValue, not both"
1676
+ );
1677
+ }
1678
+ return { token_amount: formatRawAmount(tokenAmount) };
1679
+ }
1680
+ if (notionalValue === void 0) {
1681
+ throw new ValidationError(
1682
+ "An Ondo quote must be sized by tokenAmount or notionalValue"
1683
+ );
1684
+ }
1685
+ return { notional_value: notionalValue };
1686
+ }
1687
+
1688
+ // src/shared/core/checkout/ondo/ondo-namespace.ts
1689
+ var OndoNamespaceImpl = class {
1690
+ constructor(ctx) {
1691
+ this.ctx = ctx;
1692
+ this.log = internalLogger(ctx.logger, "ONDO");
1693
+ }
1694
+ async getTradingStatus(params) {
1695
+ return this.log.wrap("getTradingStatus", params, async () => {
1696
+ await this.ctx.ensureUserAuthenticated();
1697
+ return getOndoTradingStatus(this.ctx.api, params);
1698
+ });
1699
+ }
1700
+ async getQuote(params) {
1701
+ return this.log.wrap("getQuote", params, async () => {
1702
+ await this.ctx.ensureUserAuthenticated();
1703
+ return getOndoQuote(this.ctx.api, params);
1704
+ });
1705
+ }
1706
+ async buildSwapTransaction(params) {
1707
+ return this.log.wrap("buildSwapTransaction", params, async () => {
1708
+ await this.ctx.ensureUserAuthenticated();
1709
+ return buildOndoSwapTransaction(this.ctx.api, params);
1710
+ });
1711
+ }
1712
+ };
278
1713
 
279
- // src/shared/core/blockchain/abis/superstate-swap.ts
1714
+ // src/shared/core/checkout/superstate/blockchain/abi.ts
280
1715
  var SUPERSTATE_SWAP_ABI = [
281
1716
  {
282
1717
  type: "function",
@@ -478,281 +1913,45 @@ var SUPERSTATE_SWAP_ABI = [
478
1913
  name: "InvalidAddress",
479
1914
  inputs: []
480
1915
  },
481
- {
482
- type: "error",
483
- name: "InsufficientAmount",
484
- inputs: []
485
- },
486
- {
487
- type: "error",
488
- name: "InvalidAmount",
489
- inputs: []
490
- },
491
- {
492
- type: "error",
493
- name: "SwapFailed",
494
- inputs: [
495
- { name: "user", type: "address", internalType: "address" },
496
- { name: "token", type: "address", internalType: "address" }
497
- ]
498
- }
499
- ];
500
-
501
- // src/shared/types/blockchain/core.ts
502
- var EvmWalletAddress = (value) => value;
503
- var EvmContractAddress = (value) => value;
504
- var HexEncodedTransactionData = (value) => value;
505
- var AssetDecimals = (value) => value;
506
- var MAX_UINT_256 = 2n ** 256n - 1n;
507
- var assertUint256 = (value) => {
508
- if (value < 0n || value > MAX_UINT_256) {
509
- throw new Error(`Value out of uint256 bounds: ${value}`);
510
- }
511
- return value;
512
- };
513
- var BlockchainAmount = Object.assign(
514
- (value) => value,
515
- {
516
- add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
517
- sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
518
- }
519
- );
520
- function combineAmounts(a, b, op) {
521
- if (a.decimals !== b.decimals) {
522
- throw new Error(
523
- `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
524
- );
525
- }
526
- const raw = op(a.raw, b.raw);
527
- if (raw < 0n || raw > MAX_UINT_256) {
528
- throw new Error(`BlockchainAmount out of uint256 bounds: ${raw}`);
529
- }
530
- return BlockchainAmount({ raw, decimals: a.decimals });
531
- }
532
- var AssetSymbol = (value) => value;
533
- var StablecoinSymbol = (value) => value;
534
- var KnownAssetSymbol = StablecoinSymbol;
535
- var Bps = (value) => value;
536
-
537
- // src/shared/core/blockchain/bps.ts
538
- var BPS_DENOM = Bps(10000n);
539
- function applyBps(amount, bps) {
540
- return assertUint256(amount * bps / BPS_DENOM);
541
- }
542
-
543
- // src/shared/types/blockchain/ui.ts
544
- var FormattedAmountUi = (value) => value;
545
- var FormattedPercentUi = (value) => value;
546
- var TxExplorerUrl = (value) => value;
547
- var ShortenedWalletAddress = (value) => value;
548
- var FormattedAmountAssetUi = (value) => value;
549
- var AssetIconUrl = (value) => value;
550
-
551
- // src/shared/core/blockchain/chain.ts
552
- function getChainId(chain) {
553
- switch (chain) {
554
- case "ethereum_mainnet":
555
- return 1;
556
- case "ethereum_sepolia":
557
- return 11155111;
558
- default: {
559
- const _exhaustive = chain;
560
- return _exhaustive;
561
- }
562
- }
563
- }
564
- function getNetworkName(chain) {
565
- switch (chain) {
566
- case "ethereum_mainnet":
567
- return "Ethereum";
568
- case "ethereum_sepolia":
569
- return "Ethereum Sepolia";
570
- default: {
571
- const _exhaustive = chain;
572
- return _exhaustive;
573
- }
574
- }
575
- }
576
- function txExplorerUrl(chain, txHash) {
577
- return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);
578
- }
579
- function explorerBaseUrl(chain) {
580
- switch (chain) {
581
- case "ethereum_mainnet":
582
- return "https://etherscan.io";
583
- case "ethereum_sepolia":
584
- return "https://sepolia.etherscan.io";
585
- default: {
586
- const _exhaustive = chain;
587
- return _exhaustive;
588
- }
589
- }
590
- }
591
-
592
- // src/shared/core/blockchain/formatters.ts
593
- var import_viem = require("viem");
594
-
595
- // src/shared/core/blockchain/swap/math.ts
596
- function computePrice({
597
- inputTokenAmount,
598
- outputTokenAmount
599
- }) {
600
- if (outputTokenAmount.raw === 0n) return null;
601
- const scale = 10n ** BigInt(outputTokenAmount.decimals);
602
- const raw = assertUint256(
603
- inputTokenAmount.raw * scale / outputTokenAmount.raw
604
- );
605
- return BlockchainAmount({ raw, decimals: inputTokenAmount.decimals });
606
- }
607
- function computeSlip(amount, slippage) {
608
- const retained = Bps(assertUint256(BPS_DENOM - slippage));
609
- const slipRaw = applyBps(amount.raw, retained);
610
- return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });
611
- }
612
-
613
- // src/shared/core/blockchain/formatters.ts
614
- function shortenAddress(address) {
615
- const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
616
- return ShortenedWalletAddress(short);
617
- }
618
- function formatAmount(amount, locale, options) {
619
- const decimal = formatRawAmount(amount);
620
- let [integerPart, fractionPart = ""] = decimal.split(".");
621
- const maxFractionDigits = options?.maxFractionDigits;
622
- const minFractionDigits = maxFractionDigits !== void 0 ? Math.min(maxFractionDigits, amount.decimals) : Math.min(2, amount.decimals);
623
- if (maxFractionDigits !== void 0 && fractionPart.length > maxFractionDigits) {
624
- ({ integerPart, fractionPart } = roundFractionHalfUp(
625
- integerPart,
626
- fractionPart,
627
- maxFractionDigits
628
- ));
629
- }
630
- const fraction = minFractionDigits === 0 ? "" : fractionPart.padEnd(minFractionDigits, "0");
631
- const integerFormatted = BigInt(integerPart).toLocaleString(locale);
632
- if (minFractionDigits === 0 && fraction === "") {
633
- return FormattedAmountUi(integerFormatted);
634
- }
635
- const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
636
- return FormattedAmountUi(`${integerFormatted}${decimalSeparator}${fraction}`);
637
- }
638
- function roundFractionHalfUp(integerPart, fractionPart, maxFractionDigits) {
639
- if (fractionPart.length <= maxFractionDigits) {
640
- return { integerPart, fractionPart };
641
- }
642
- if (maxFractionDigits === 0) {
643
- const roundUp = fractionPart[0] >= "5";
644
- const integer = BigInt(integerPart) + (roundUp ? 1n : 0n);
645
- return { integerPart: integer.toString(), fractionPart: "" };
646
- }
647
- const trimmed = fractionPart.slice(0, maxFractionDigits);
648
- if (fractionPart[maxFractionDigits] < "5") {
649
- return { integerPart, fractionPart: trimmed };
650
- }
651
- const digits = trimmed.split("").map((digit) => Number.parseInt(digit, 10));
652
- let carry = 1;
653
- for (let i = digits.length - 1; i >= 0 && carry > 0; i -= 1) {
654
- const sum = digits[i] + carry;
655
- if (sum === 10) {
656
- digits[i] = 0;
657
- carry = 1;
658
- } else {
659
- digits[i] = sum;
660
- carry = 0;
661
- }
662
- }
663
- return {
664
- integerPart: carry > 0 ? (BigInt(integerPart) + 1n).toString() : integerPart,
665
- fractionPart: digits.join("")
666
- };
667
- }
668
- function formatRawAmount(amount) {
669
- return (0, import_viem.formatUnits)(amount.raw, amount.decimals);
670
- }
671
- function formatCompactAmount(amount, locale) {
672
- const value = Number(formatRawAmount(amount));
673
- const formatted = new Intl.NumberFormat(locale, {
674
- notation: "compact",
675
- maximumFractionDigits: 2
676
- }).format(value);
677
- return FormattedAmountUi(formatted);
678
- }
679
- function formatBpsAsPercent(bps, locale) {
680
- const whole = bps / 100n;
681
- const fraction = bps % 100n;
682
- const wholeFormatted = whole.toLocaleString(locale);
683
- const decimalSeparator = new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
684
- if (fraction === 0n) {
685
- return FormattedPercentUi(`${wholeFormatted}%`);
686
- }
687
- const fractionFormatted = fraction.toString().padStart(2, "0").replace(/0+$/, "");
688
- return FormattedPercentUi(
689
- `${wholeFormatted}${decimalSeparator}${fractionFormatted}%`
690
- );
691
- }
692
- function usdAmount(amount) {
693
- return FormattedAmountAssetUi(`$${amount}`);
694
- }
695
- function assetAmount(amount, symbol) {
696
- return FormattedAmountAssetUi(`${amount} ${symbol}`);
697
- }
698
- var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
699
- var USD_FRACTION_DIGITS = AssetDecimals(2);
700
- function formattedUsdPrice(amount, locale) {
701
- if (!amount) return NA_AMOUNT_ASSET_UI;
702
- return usdAmount(
703
- formatAmount(amount, locale, { maxFractionDigits: USD_FRACTION_DIGITS })
704
- );
705
- }
706
- function formattedPricePerShare(quote, locale) {
707
- if (!quote) return NA_AMOUNT_ASSET_UI;
708
- return formattedUsdPrice(computePrice(quote), locale);
709
- }
710
-
711
- // src/shared/core/blockchain/math.ts
712
- var import_viem2 = require("viem");
713
- function parseBlockchainAmount(amount, decimals) {
714
- const trimmed = amount.trim();
715
- if (trimmed === "") return { valid: false, reason: { type: "empty" } };
716
- if (trimmed.startsWith("-")) {
717
- return { valid: false, reason: { type: "negative" } };
718
- }
719
- if (/[eE]/.test(trimmed)) {
720
- return { valid: false, reason: { type: "invalid-format" } };
721
- }
722
- if (!/^\d+(\.\d+)?$/.test(trimmed)) {
723
- return { valid: false, reason: { type: "invalid-format" } };
724
- }
725
- const [, fraction = ""] = trimmed.split(".");
726
- if (fraction.length > decimals) {
727
- return {
728
- valid: false,
729
- reason: { type: "too-many-decimals", maxDecimals: decimals }
730
- };
731
- }
732
- try {
733
- return {
734
- valid: true,
735
- amount: BlockchainAmount({
736
- raw: (0, import_viem2.parseUnits)(trimmed, decimals),
737
- decimals
738
- })
739
- };
740
- } catch {
741
- return { valid: false, reason: { type: "invalid-format" } };
1916
+ {
1917
+ type: "error",
1918
+ name: "InsufficientAmount",
1919
+ inputs: []
1920
+ },
1921
+ {
1922
+ type: "error",
1923
+ name: "InvalidAmount",
1924
+ inputs: []
1925
+ },
1926
+ {
1927
+ type: "error",
1928
+ name: "SwapFailed",
1929
+ inputs: [
1930
+ { name: "user", type: "address", internalType: "address" },
1931
+ { name: "token", type: "address", internalType: "address" }
1932
+ ]
742
1933
  }
743
- }
1934
+ ];
744
1935
 
745
- // src/shared/core/blockchain/swap/constants.ts
746
- var SUPERSTATE_TOS_URL = "https://superstate.com/terms";
747
- var SWAP_POLL_INTERVAL_MS = 15e3;
748
- var DEFAULT_AMOUNT_TO_COMPUTE_PRICE = 1000000n;
749
- var SLIPPAGE_OPTIONS_BPS = [25n, 50n, 100n, 200n, 500n].map(
750
- (n) => Bps(n)
751
- );
752
- var DEFAULT_SLIPPAGE_BPS = Bps(50n);
753
- var SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA = EvmContractAddress("0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557");
1936
+ // src/shared/core/checkout/superstate/blockchain/math.ts
1937
+ function computePrice({
1938
+ inputTokenAmount,
1939
+ outputTokenAmount
1940
+ }) {
1941
+ if (outputTokenAmount.raw === 0n) return null;
1942
+ const scale = 10n ** BigInt(outputTokenAmount.decimals);
1943
+ const raw = assertUint256(
1944
+ inputTokenAmount.raw * scale / outputTokenAmount.raw
1945
+ );
1946
+ return BlockchainAmount({ raw, decimals: inputTokenAmount.decimals });
1947
+ }
1948
+ function computeSlip(amount, slippage) {
1949
+ const retained = Bps(assertUint256(BPS_DENOM - slippage));
1950
+ const slipRaw = applyBps(amount.raw, retained);
1951
+ return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });
1952
+ }
754
1953
 
755
- // src/shared/core/blockchain/swap/quote.ts
1954
+ // src/shared/core/checkout/superstate/blockchain/quote.ts
756
1955
  var SwapQuote = {
757
1956
  /**
758
1957
  * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The
@@ -772,12 +1971,12 @@ var SwapQuote = {
772
1971
  })
773
1972
  };
774
1973
 
775
- // src/shared/core/blockchain/swap/status.ts
1974
+ // src/shared/core/checkout/superstate/blockchain/status.ts
776
1975
  function isStopped(status) {
777
1976
  return (status.stopped & status.swapLevel) !== 0n;
778
1977
  }
779
1978
 
780
- // src/shared/core/blockchain/swap/swapped-event.ts
1979
+ // src/shared/core/checkout/superstate/blockchain/swapped-event.ts
781
1980
  var import_viem3 = require("viem");
782
1981
  function decodeSwappedOutputAmount(receipt, outputDecimals) {
783
1982
  try {
@@ -795,420 +1994,615 @@ function decodeSwappedOutputAmount(receipt, outputDecimals) {
795
1994
  }
796
1995
  }
797
1996
 
798
- // src/shared/core/blockchain/token-registry.ts
799
- var USDC_SYMBOL = StablecoinSymbol("USDC");
800
- var USDC = {
801
- name: "USD Coin",
802
- symbol: USDC_SYMBOL,
803
- decimals: AssetDecimals(6)
804
- };
805
- var USDT_SYMBOL = StablecoinSymbol("USDT");
806
- var USDT = {
807
- name: "Tether USD",
808
- symbol: USDT_SYMBOL,
809
- decimals: AssetDecimals(6)
810
- };
811
- var USDC_ADDRESSES = {
812
- ethereum_mainnet: EvmContractAddress(
813
- "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
814
- ),
815
- ethereum_sepolia: EvmContractAddress(
816
- "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
817
- )
818
- };
819
- var USDT_ADDRESSES = {
820
- ethereum_mainnet: EvmContractAddress(
821
- "0xdac17f958d2ee523a2206206994597c13d831ec7"
822
- ),
823
- ethereum_sepolia: EvmContractAddress(
824
- "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
825
- )
826
- };
827
- var TOKEN_REGISTRY = {
828
- erc20: (symbol) => {
829
- switch (symbol) {
830
- case "USDC":
831
- return USDC;
832
- case "USDT":
833
- return USDT;
834
- default:
835
- throw new Error(`Unknown asset symbol: ${symbol}`);
836
- }
837
- },
838
- contractAddress: (symbol, chain) => {
839
- switch (symbol) {
840
- case "USDC":
841
- return USDC_ADDRESSES[chain];
842
- case "USDT":
843
- return USDT_ADDRESSES[chain];
844
- default:
845
- throw new Error(`Unknown asset symbol: ${symbol}`);
846
- }
847
- }
1997
+ // src/shared/core/checkout/superstate/constants.ts
1998
+ var SUPERSTATE_ISSUER_NAME = "Superstate";
1999
+ var SUPERSTATE_SUPPORTED_INPUT_ASSETS = [USDC_SYMBOL];
2000
+ var SWAP_POLL_INTERVAL_MS = 15e3;
2001
+ var DEFAULT_AMOUNT_TO_COMPUTE_PRICE = 1000000n;
2002
+ var SLIPPAGE_OPTIONS_BPS = [25n, 50n, 100n, 200n, 500n].map(
2003
+ (n) => Bps(n)
2004
+ );
2005
+ var DEFAULT_SLIPPAGE_BPS = Bps(50n);
2006
+ var SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA = EvmContractAddress("0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557");
2007
+ var SUPERSTATE_SWAP_CONTRACT_ADDRESSES = {
2008
+ ethereum_sepolia: SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA
848
2009
  };
2010
+ function superstateSwapContractAddress(chain) {
2011
+ return SUPERSTATE_SWAP_CONTRACT_ADDRESSES[chain] ?? null;
2012
+ }
849
2013
 
850
- // src/shared/api/http-attributes.ts
851
- var empty = {};
852
- var concat = (left, right) => ({
853
- ...left,
854
- ...right
855
- });
856
- var concatAll = (...items) => {
857
- let result = empty;
858
- for (const item of items) {
859
- result = concat(result, item);
860
- }
861
- return result;
862
- };
863
- var protectedRequest = () => ({ protected: true });
864
- var userAgent = () => ({ userAgent: true });
865
- var idempotencyKey = () => ({
866
- idempotencyKey: true
867
- });
868
- var clientCredentials = (credentials) => ({
869
- clientCredentials: credentials
870
- });
871
- var retryAttempt = (attempt) => ({
872
- retryAttempt: attempt
873
- });
874
- var renewAttempted = (value) => ({
875
- renewAttempted: value
876
- });
877
- var isProtected = (attrs) => attrs?.protected === true;
878
- var needUserAgent = (attrs) => attrs?.userAgent === true;
879
- var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
880
- var getRetryAttempt = (attrs) => attrs?.retryAttempt ?? 0;
881
- var wasRenewAttempted = (attrs) => attrs?.renewAttempted === true;
882
- var getClientCredentials = (attrs) => attrs?.clientCredentials;
883
- var Attributes = {
884
- empty,
885
- concat,
886
- concatAll,
887
- protected: protectedRequest,
888
- isProtected,
889
- userAgent,
890
- needUserAgent,
891
- idempotencyKey,
892
- isIdempotent,
893
- retryAttempt,
894
- getRetryAttempt,
895
- renewAttempted,
896
- wasRenewAttempted,
897
- clientCredentials,
898
- getClientCredentials
899
- };
2014
+ // src/shared/core/checkout/superstate/formatters.ts
2015
+ function formattedPricePerShare(quote, locale) {
2016
+ if (!quote) return NA_AMOUNT_ASSET_UI;
2017
+ return formattedUsdPrice(computePrice(quote), locale);
2018
+ }
900
2019
 
901
- // src/shared/types/swap.ts
902
- var SwapAuthorization = {
903
- fromDto: (dto) => ({
904
- authorized: dto.authorized
905
- })
906
- };
907
- var SwapPreview = {
908
- fromDto: (dto) => ({
909
- inputAmount: assertUint256(BigInt(dto.pay_input_amount)),
910
- fee: assertUint256(BigInt(dto.fee)),
911
- outputAmount: assertUint256(BigInt(dto.receive_output_amount))
912
- })
913
- };
914
- var SwapStatus = {
915
- fromDto: (dto) => ({
916
- stopped: assertUint256(BigInt(dto.stopped)),
917
- swapLevel: assertUint256(BigInt(dto.swap_level))
918
- })
919
- };
920
- var TokenAllowance = {
921
- fromDto: (dto) => ({
922
- allowance: assertUint256(BigInt(dto.allowance))
923
- })
924
- };
925
- var TokenBalance = {
926
- fromDto: (dto) => ({
927
- balance: assertUint256(BigInt(dto.balance))
928
- })
929
- };
930
- var AllowWalletResponse = {
931
- fromDto: (dto) => {
932
- switch (dto.action) {
933
- case "broadcast_transaction":
934
- return {
935
- action: "broadcast_transaction",
936
- to: EvmContractAddress(dto.to),
937
- data: HexEncodedTransactionData(dto.data)
938
- };
939
- case "none":
940
- return {
941
- action: "none",
942
- alreadyAllowed: dto.already_allowed
943
- };
944
- default: {
945
- const _exhaustive = dto;
946
- return _exhaustive;
947
- }
948
- }
2020
+ // src/shared/core/checkout/superstate/swap-namespace.ts
2021
+ var SuperstateSwapNamespaceImpl = class {
2022
+ constructor(ctx) {
2023
+ this.ctx = ctx;
2024
+ this.log = internalLogger(ctx.logger, "SUPERSTATE");
2025
+ }
2026
+ async getAuthorization(params) {
2027
+ return this.log.wrap("getAuthorization", params, async () => {
2028
+ await this.ctx.ensureUserAuthenticated();
2029
+ return getSwapAuthorization(this.ctx.api, params);
2030
+ });
2031
+ }
2032
+ async getPreview(params) {
2033
+ return this.log.wrap("getPreview", params, async () => {
2034
+ await this.ctx.ensureUserAuthenticated();
2035
+ return getSwapPreview(this.ctx.api, params);
2036
+ });
2037
+ }
2038
+ async getStatus(params) {
2039
+ return this.log.wrap("getStatus", params, async () => {
2040
+ await this.ctx.ensureUserAuthenticated();
2041
+ return getSwapStatus(this.ctx.api, params);
2042
+ });
2043
+ }
2044
+ async getOutputToken(params) {
2045
+ return this.log.wrap("getOutputToken", params, async () => {
2046
+ await this.ctx.ensureUserAuthenticated();
2047
+ return getSwapOutputToken(this.ctx.api, params);
2048
+ });
2049
+ }
2050
+ async allowWallet(params) {
2051
+ return this.log.wrap("allowWallet", params, async () => {
2052
+ await this.ctx.ensureUserAuthenticated();
2053
+ return allowWallet(this.ctx.api, params);
2054
+ });
949
2055
  }
950
2056
  };
951
2057
 
952
- // src/shared/api/frontline/swap.ts
953
- async function getSwapAuthorization(api, params) {
954
- const dto = await api.send({
955
- method: "GET",
956
- url: "/v1/wallet/authorized",
957
- queryParams: {
958
- chain: params.chain,
959
- contract_address: params.contractAddress,
960
- wallet_address: params.walletAddress
961
- },
962
- attributes: Attributes.protected()
963
- });
964
- return SwapAuthorization.fromDto(dto);
965
- }
966
- async function getSwapOutputToken(api, params) {
967
- const dto = await api.send({
968
- method: "GET",
969
- url: "/v1/swap/output-token",
970
- queryParams: {
971
- chain: params.chain,
972
- contract_address: params.contractAddress
973
- },
974
- attributes: Attributes.protected()
975
- });
976
- return toErc20Asset(dto);
977
- }
978
- async function getSwapPreview(api, params) {
979
- const dto = await api.send({
980
- method: "GET",
981
- url: "/v1/swap/preview",
982
- queryParams: {
983
- chain: params.chain,
984
- contract_address: params.contractAddress,
985
- input_token: params.inputToken,
986
- amount: params.amount.toString()
987
- },
988
- attributes: Attributes.protected()
989
- });
990
- return SwapPreview.fromDto(dto);
991
- }
992
- async function getSwapStatus(api, params) {
993
- const dto = await api.send({
994
- method: "GET",
995
- url: "/v1/swap/status",
996
- queryParams: {
997
- chain: params.chain,
998
- contract_address: params.contractAddress
999
- },
1000
- attributes: Attributes.protected()
2058
+ // src/shared/api/frontline/offers.ts
2059
+ async function fetchOffers(api, clientCreds) {
2060
+ return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
2061
+ }
2062
+ async function fetchOffersPage(api, params, clientCreds) {
2063
+ const queryParams = PaginationParams.toQueryParams(params);
2064
+ const pageDto = await api.send({
2065
+ method: "GET",
2066
+ url: "/v1/offers",
2067
+ queryParams,
2068
+ attributes: Attributes.concat(
2069
+ Attributes.protected(),
2070
+ Attributes.clientCredentials(clientCreds)
2071
+ )
1001
2072
  });
1002
- return SwapStatus.fromDto(dto);
2073
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
1003
2074
  }
1004
- async function getTokenAllowance(api, params) {
2075
+ async function fetchOfferDetails(api, id, clientCreds) {
1005
2076
  const dto = await api.send({
1006
2077
  method: "GET",
1007
- url: "/v1/token/allowance",
1008
- queryParams: {
1009
- chain: params.chain,
1010
- token_address: params.tokenAddress,
1011
- owner: params.owner,
1012
- spender: params.spender
1013
- },
1014
- attributes: Attributes.protected()
2078
+ url: `/v1/offers/${id}`,
2079
+ attributes: Attributes.concat(
2080
+ Attributes.protected(),
2081
+ Attributes.clientCredentials(clientCreds)
2082
+ )
1015
2083
  });
1016
- return TokenAllowance.fromDto(dto);
2084
+ return OfferDetail.fromDto(dto);
1017
2085
  }
1018
- async function getTokenBalance(api, params) {
2086
+
2087
+ // src/shared/core/offers/offers-namespace.ts
2088
+ var OffersNamespaceImpl = class {
2089
+ constructor(ctx) {
2090
+ this.ctx = ctx;
2091
+ this.log = internalLogger(ctx.logger, "OFFERS");
2092
+ }
2093
+ async list() {
2094
+ return this.log.wrap("list", void 0, async () => {
2095
+ await this.ctx.ensureUserAuthenticated();
2096
+ return fetchOffers(this.ctx.api, void 0);
2097
+ });
2098
+ }
2099
+ async listPage(params) {
2100
+ return this.log.wrap("listPage", params, async () => {
2101
+ await this.ctx.ensureUserAuthenticated();
2102
+ return fetchOffersPage(this.ctx.api, params, void 0);
2103
+ });
2104
+ }
2105
+ async get(id) {
2106
+ return this.log.wrap("get", id, async () => {
2107
+ await this.ctx.ensureUserAuthenticated();
2108
+ return fetchOfferDetails(this.ctx.api, id, void 0);
2109
+ });
2110
+ }
2111
+ };
2112
+
2113
+ // src/shared/types/document-submission.ts
2114
+ var DocumentSubmission = {
2115
+ fromDto: (dto) => ({
2116
+ status: dto.status,
2117
+ formType: dto.form_type
2118
+ })
2119
+ };
2120
+
2121
+ // src/shared/api/frontline/documents.ts
2122
+ async function submitDocument(api, documentType, fields) {
1019
2123
  const dto = await api.send({
1020
- method: "GET",
1021
- url: "/v1/token/balance",
1022
- queryParams: {
1023
- chain: params.chain,
1024
- token_address: params.tokenAddress,
1025
- owner: params.owner
1026
- },
2124
+ method: "POST",
2125
+ url: `/v1/documents/${documentType}/submission`,
2126
+ body: fields,
1027
2127
  attributes: Attributes.protected()
1028
2128
  });
1029
- return TokenBalance.fromDto(dto);
2129
+ return DocumentSubmission.fromDto(dto);
1030
2130
  }
1031
- async function allowWallet(api, params) {
2131
+
2132
+ // src/shared/types/kyc.ts
2133
+ var KycToken = {
2134
+ fromDto: (dto) => ({
2135
+ token: dto.token
2136
+ })
2137
+ };
2138
+
2139
+ // src/shared/api/frontline/kyc.ts
2140
+ async function createKycToken(api, levelName, reset) {
1032
2141
  const dto = await api.send({
1033
2142
  method: "POST",
1034
- url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,
2143
+ url: "/v1/kyc-token",
1035
2144
  body: {
1036
- wallet_address: params.walletAddress,
1037
- chain: params.chain,
1038
- signature: params.signature
2145
+ ...levelName === void 0 ? {} : { level_name: levelName },
2146
+ ...reset === void 0 ? {} : { reset }
1039
2147
  },
1040
2148
  attributes: Attributes.protected()
1041
2149
  });
1042
- return AllowWalletResponse.fromDto(dto);
1043
- }
1044
- function toErc20Asset(dto) {
1045
- return {
1046
- name: dto.name,
1047
- symbol: AssetSymbol(dto.symbol),
1048
- decimals: AssetDecimals(dto.decimals)
1049
- };
2150
+ return KycToken.fromDto(dto);
1050
2151
  }
1051
2152
 
1052
- // src/shared/core/erc20-namespace.ts
1053
- var Erc20NamespaceImpl = class {
1054
- constructor(ctx) {
1055
- this.ctx = ctx;
1056
- }
1057
- async getTokenAllowance(params) {
1058
- await this.ctx.ensureUserAuthenticated();
1059
- return getTokenAllowance(this.ctx.api, params);
1060
- }
1061
- async getTokenBalance(params) {
1062
- await this.ctx.ensureUserAuthenticated();
1063
- return getTokenBalance(this.ctx.api, params);
1064
- }
2153
+ // src/shared/types/pii.ts
2154
+ var Iso2CountryCode = (value) => value;
2155
+ var PiiJurisdiction = {
2156
+ fromDto: (dto) => ({
2157
+ iso2: Iso2CountryCode(dto.iso_2),
2158
+ name: dto.name
2159
+ })
1065
2160
  };
1066
-
1067
- // src/shared/types/asset.ts
1068
- var AssetId = (value) => value;
1069
- var AssetCode = (value) => value;
1070
- var Asset = {
2161
+ var PiiAddress = {
1071
2162
  fromDto: (dto) => ({
1072
- id: AssetId(dto.id),
1073
- code: AssetCode(dto.code),
1074
- name: dto.name,
1075
- fractionalDigits: dto.fractional_digits
2163
+ street: dto.street,
2164
+ city: dto.city,
2165
+ state: dto.state,
2166
+ postalCode: dto.postal_code,
2167
+ country: dto.country
2168
+ })
2169
+ };
2170
+ var Pii = {
2171
+ fromDto: (dto) => ({
2172
+ kind: dto.kind,
2173
+ fullLegalName: dto.full_legal_name,
2174
+ dateOfBirth: dto.date_of_birth,
2175
+ jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
2176
+ taxId: dto.tax_id,
2177
+ permanentAddress: PiiAddress.fromDto(dto.permanent_address)
1076
2178
  })
1077
2179
  };
1078
2180
 
1079
- // src/shared/types/offer.ts
1080
- var OfferId = (value) => value;
1081
- var OfferSlug = (value) => value;
1082
- var Offer = {
2181
+ // src/shared/api/frontline/pii.ts
2182
+ async function fetchPii(api) {
2183
+ const dto = await api.send({
2184
+ method: "GET",
2185
+ url: "/v1/pii",
2186
+ attributes: Attributes.protected()
2187
+ });
2188
+ return Pii.fromDto(dto);
2189
+ }
2190
+
2191
+ // src/shared/types/requirement.ts
2192
+ var RequirementId = (value) => value;
2193
+ var Requirement = {
1083
2194
  fromDto: (dto) => ({
1084
- id: OfferId(dto.id),
1085
- slug: OfferSlug(dto.slug),
2195
+ id: RequirementId(dto.id),
1086
2196
  type: dto.type,
1087
- tagline: dto.tagline,
1088
- bannerUrl: dto.banner_url,
1089
- logoUrl: dto.logo_url,
1090
- startsAt: new Date(dto.starts_at),
1091
- endsAt: dto.ends_at ? new Date(dto.ends_at) : null
2197
+ details: dto.details
1092
2198
  })
1093
2199
  };
2200
+ var RequirementStatusInfo = {
2201
+ fromStatusesDto: (dto) => Object.entries(dto.statuses).map(
2202
+ ([id, value]) => typeof value === "string" ? { id: RequirementId(id), status: value, action: null } : {
2203
+ id: RequirementId(id),
2204
+ status: value.status,
2205
+ action: value.action ?? null,
2206
+ kycLevel: value.kyc_level,
2207
+ kycReset: value.kyc_reset
2208
+ }
2209
+ )
2210
+ };
1094
2211
 
1095
- // src/shared/utils.ts
1096
- async function sha256(data) {
1097
- const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
1098
- const buffer = bytes.buffer.slice(
1099
- bytes.byteOffset,
1100
- bytes.byteOffset + bytes.byteLength
2212
+ // src/shared/api/frontline/requirements.ts
2213
+ async function fetchOfferRequirements(api, offerId, clientCreds) {
2214
+ const response = await api.send({
2215
+ method: "GET",
2216
+ url: `/v1/offers/${offerId}/requirements`,
2217
+ attributes: Attributes.concat(
2218
+ Attributes.protected(),
2219
+ Attributes.clientCredentials(clientCreds)
2220
+ )
2221
+ });
2222
+ return Object.fromEntries(
2223
+ Object.entries(response.options).map(([optionId, list]) => [
2224
+ optionId,
2225
+ list.data.map(Requirement.fromDto)
2226
+ ])
1101
2227
  );
1102
- return crypto.subtle.digest("SHA-256", buffer);
1103
2228
  }
1104
- function arrayBufferToBase64Url(buffer, padding = true) {
1105
- const bytes = new Uint8Array(buffer);
1106
- let binary = "";
1107
- for (let i = 0; i < bytes.length; i++) {
1108
- binary += String.fromCharCode(bytes[i]);
2229
+ async function fetchRequirementStatuses(api, offerId) {
2230
+ const response = await api.send({
2231
+ method: "GET",
2232
+ url: `/v1/offers/${offerId}/requirements/statuses`,
2233
+ attributes: Attributes.protected()
2234
+ });
2235
+ return RequirementStatusInfo.fromStatusesDto(response);
2236
+ }
2237
+
2238
+ // src/shared/core/requirements/requirements-namespace.ts
2239
+ var RequirementsNamespaceImpl = class {
2240
+ constructor(ctx) {
2241
+ this.ctx = ctx;
2242
+ this.log = internalLogger(ctx.logger, "REQUIREMENTS");
1109
2243
  }
1110
- let base64 = btoa(binary);
1111
- base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
1112
- if (!padding) {
1113
- base64 = base64.replace(/=+$/, "");
2244
+ async forOffer(offerId) {
2245
+ return this.log.wrap("forOffer", offerId, async () => {
2246
+ await this.ctx.ensureUserAuthenticated();
2247
+ return fetchOfferRequirements(
2248
+ this.ctx.api,
2249
+ offerId,
2250
+ void 0
2251
+ );
2252
+ });
1114
2253
  }
1115
- return base64;
1116
- }
1117
- function generateSecureRandomBase64Url(byteLength) {
1118
- const bytes = new Uint8Array(byteLength);
1119
- crypto.getRandomValues(bytes);
1120
- const buffer = bytes.buffer;
1121
- return arrayBufferToBase64Url(buffer, false);
1122
- }
1123
- function notBlankStringOrNull(value) {
1124
- if (value?.trim()) {
1125
- return value;
1126
- } else {
1127
- return null;
2254
+ async statuses(offerId) {
2255
+ return this.log.wrap("statuses", offerId, async () => {
2256
+ await this.ctx.ensureUserAuthenticated();
2257
+ return fetchRequirementStatuses(this.ctx.api, offerId);
2258
+ });
1128
2259
  }
1129
- }
2260
+ async createKycToken(params) {
2261
+ return this.log.wrap("createKycToken", params, async () => {
2262
+ await this.ctx.ensureUserAuthenticated();
2263
+ return createKycToken(
2264
+ this.ctx.api,
2265
+ params?.levelName,
2266
+ params?.reset
2267
+ );
2268
+ });
2269
+ }
2270
+ async getPii() {
2271
+ return this.log.wrap("getPii", void 0, async () => {
2272
+ await this.ctx.ensureUserAuthenticated();
2273
+ return fetchPii(this.ctx.api);
2274
+ });
2275
+ }
2276
+ async submitDocument(params) {
2277
+ return this.log.wrap("submitDocument", params, async () => {
2278
+ await this.ctx.ensureUserAuthenticated();
2279
+ return submitDocument(
2280
+ this.ctx.api,
2281
+ params.documentType,
2282
+ params.fields
2283
+ );
2284
+ });
2285
+ }
2286
+ };
1130
2287
 
1131
- // src/shared/types/offer-detail.ts
1132
- var OfferOptionId = (value) => value;
1133
- var OfferOptionSlug = (value) => value;
1134
- var OfferDetail = {
1135
- fromDto: (dto) => {
1136
- if (!Array.isArray(dto.funding_assets)) {
1137
- throw new Error(`funding_assets must be an array`);
1138
- }
1139
- if (!Array.isArray(dto.options)) {
1140
- throw new Error(`options must be an array`);
1141
- }
1142
- if (!Array.isArray(dto.terms)) {
1143
- throw new Error(`terms must be an array`);
2288
+ // src/shared/api/nabu/tokens.ts
2289
+ var import_viem4 = require("viem");
2290
+
2291
+ // src/shared/api/frontline/config.ts
2292
+ var HEADER_API_VERSION = "X-API-Version";
2293
+
2294
+ // src/shared/api/http-client.ts
2295
+ var HttpClient = class {
2296
+ constructor(config, middleware = {}, logger = null, options = {}) {
2297
+ this.config = config;
2298
+ this.middleware = middleware;
2299
+ this.log = internalLogger(logger, "HTTP");
2300
+ this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;
2301
+ }
2302
+ async send(request) {
2303
+ return this.runRequestWithAfterMiddleware(request);
2304
+ }
2305
+ /**
2306
+ * Runs beforeRequest, executeRequest, then the full afterRequest middleware
2307
+ * chain. Used by send() and by the retry() callback so that when a
2308
+ * middleware calls retry(), the retried response also goes through all
2309
+ * afterRequest middleware (e.g. session renewal, retry). Middleware
2310
+ * must use request.attributes.retryAttempt (or similar) to avoid infinite
2311
+ * recursion when they trigger retries.
2312
+ */
2313
+ async runRequestWithAfterMiddleware(request) {
2314
+ const preparedRequest = await this.runBeforeRequestMiddleware(
2315
+ this.withClientDefaults(request)
2316
+ );
2317
+ let response = await this.executeRequest(preparedRequest);
2318
+ for (const middleware of this.middleware.afterRequest ?? []) {
2319
+ response = await middleware({
2320
+ request: preparedRequest,
2321
+ response,
2322
+ retry: (nextRequest = preparedRequest) => this.runRequestWithAfterMiddleware(nextRequest)
2323
+ });
1144
2324
  }
1145
- if (!Array.isArray(dto.links)) {
1146
- throw new Error(`links must be an array`);
2325
+ return response;
2326
+ }
2327
+ withClientDefaults(request) {
2328
+ const url = this.resolveUrl(request.url);
2329
+ const headers = {
2330
+ ...request.headers ?? {},
2331
+ ...this.config.xApiVersion !== void 0 ? { [HEADER_API_VERSION]: this.config.xApiVersion } : {}
2332
+ };
2333
+ return {
2334
+ ...request,
2335
+ url,
2336
+ headers,
2337
+ // Only when absent: a retry or a post-renewal re-send arrives with the
2338
+ // first attempt's id already on it, and keeping it is the whole point.
2339
+ attributes: Attributes.getRequestId(request.attributes) === null ? Attributes.concat(
2340
+ request.attributes ?? Attributes.empty,
2341
+ Attributes.requestId(this.makeRequestId())
2342
+ ) : request.attributes
2343
+ };
2344
+ }
2345
+ /**
2346
+ * Resolves a request URL against the client's baseUrl.
2347
+ *
2348
+ * @internal Public only for testing. Do not use in application code; use
2349
+ * {@link HttpClient.send} with a path and the client will resolve the URL.
2350
+ */
2351
+ resolveUrl(url) {
2352
+ if (url.startsWith("http://") || url.startsWith("https://")) {
2353
+ return url;
1147
2354
  }
1148
- if (!Array.isArray(dto.faqs)) {
1149
- throw new Error(`faqs must be an array`);
2355
+ const base = this.config.baseUrl.replace(/\/$/, "");
2356
+ const path = url.startsWith("/") ? url : `/${url}`;
2357
+ return base + path;
2358
+ }
2359
+ async runBeforeRequestMiddleware(initialRequest) {
2360
+ let request = initialRequest;
2361
+ for (const middleware of this.middleware.beforeRequest ?? []) {
2362
+ request = await middleware(request);
1150
2363
  }
1151
- if (!Array.isArray(dto.milestones)) {
1152
- throw new Error(`milestones must be an array`);
2364
+ return request;
2365
+ }
2366
+ /**
2367
+ * One physical attempt, logged as one line.
2368
+ *
2369
+ * A non-2xx is a `warn` rather than an `error` because the wire does not
2370
+ * know whether it is a failure: the retry middleware may turn a 503 into a
2371
+ * success, and the token registry reads a 404 as "not listed". The namespace
2372
+ * above decides, and logs the `error` when it does.
2373
+ */
2374
+ async executeRequest(request) {
2375
+ const requestId2 = Attributes.getRequestId(request.attributes);
2376
+ const log = requestId2 === null ? this.log : this.log.child({ requestId: requestId2 });
2377
+ const attempt = Attributes.getRetryAttempt(request.attributes) + 1;
2378
+ const startedAt = Date.now();
2379
+ log.debug(() => ({
2380
+ msg: "request sent",
2381
+ fields: describeRequestUnredacted(request)
2382
+ }));
2383
+ try {
2384
+ const response = await makeRequest(request);
2385
+ const elapsed = Date.now() - startedAt;
2386
+ const outcome = () => ({
2387
+ msg: "request completed",
2388
+ fields: {
2389
+ ...identifyRequest(request),
2390
+ "http.response.status_code": response.status,
2391
+ duration_ms: elapsed,
2392
+ attempt
2393
+ }
2394
+ });
2395
+ if (response.status >= 200 && response.status < 300) {
2396
+ log.info(outcome);
2397
+ } else {
2398
+ log.warn(outcome);
2399
+ }
2400
+ log.debug(() => ({
2401
+ msg: "response received",
2402
+ fields: { body: response.body }
2403
+ }));
2404
+ return requestId2 === null ? response : { ...response, requestId: requestId2 };
2405
+ } catch (error) {
2406
+ const elapsed = Date.now() - startedAt;
2407
+ log.warning(
2408
+ () => ({
2409
+ msg: "request threw",
2410
+ fields: {
2411
+ ...identifyRequest(request),
2412
+ duration_ms: elapsed,
2413
+ attempt
2414
+ }
2415
+ }),
2416
+ error
2417
+ );
2418
+ throw error;
1153
2419
  }
1154
- return {
1155
- id: OfferId(dto.id),
1156
- slug: OfferSlug(dto.slug),
1157
- type: dto.type,
1158
- name: dto.name,
1159
- asset: Asset.fromDto(dto.asset),
1160
- fundingAssets: dto.funding_assets.map(Asset.fromDto),
1161
- about: notBlankStringOrNull(dto.about),
1162
- tagline: dto.tagline,
1163
- bannerUrl: dto.banner_url,
1164
- logoUrl: dto.logo_url,
1165
- category: dto.category,
1166
- startsAt: new Date(dto.starts_at),
1167
- endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1168
- faqs: dto.faqs.map(FaqItem.fromDto),
1169
- links: dto.links.map(Link.fromDto),
1170
- milestones: dto.milestones.map(Milestone.fromDto),
1171
- options: dto.options.map(OfferOption.fromDto),
1172
- terms: dto.terms.map(TermItem.fromDto)
1173
- };
1174
2420
  }
1175
2421
  };
1176
- var OfferOption = {
1177
- fromDto: (dto) => ({
1178
- id: OfferOptionId(dto.id),
1179
- slug: OfferOptionSlug(dto.slug),
1180
- bidIncrement: dto.bid_increment,
1181
- floorPriceUsd: dto.floor_price_usd,
1182
- minimumPurchaseUsd: dto.minimum_purchase_usd,
1183
- priceUsd: dto.price_usd,
1184
- saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),
1185
- totalTokenSupply: dto.total_token_supply
1186
- })
1187
- };
1188
- var FaqItem = {
1189
- fromDto: (dto) => ({
1190
- question: notBlankStringOrNull(dto.question),
1191
- answer: notBlankStringOrNull(dto.answer)
1192
- })
1193
- };
1194
- var Link = {
1195
- fromDto: (dto) => ({
1196
- label: notBlankStringOrNull(dto.label),
1197
- url: notBlankStringOrNull(dto.url)
1198
- })
2422
+ function identifyRequest(request) {
2423
+ const { host, path } = splitUrl(request.url);
2424
+ return {
2425
+ "http.request.method": request.method,
2426
+ "server.address": host,
2427
+ "url.path": path
2428
+ };
2429
+ }
2430
+ function splitUrl(url) {
2431
+ try {
2432
+ const parsed = new URL(url);
2433
+ return { host: parsed.host, path: parsed.pathname };
2434
+ } catch (_) {
2435
+ return { host: null, path: url };
2436
+ }
2437
+ }
2438
+ function defaultMakeRequestId() {
2439
+ return Math.random().toString(36).slice(2, 10).padEnd(8, "0");
2440
+ }
2441
+ function describeRequestUnredacted(request) {
2442
+ return {
2443
+ "http.request.method": request.method,
2444
+ "url.full": buildUrlWithQueryParams(request.url, request.queryParams),
2445
+ headers: request.headers,
2446
+ ...request.method === "POST" ? { body: request.body } : {}
2447
+ };
2448
+ }
2449
+
2450
+ // src/shared/types/token-metadata.ts
2451
+ var TokenLogoUrl = (value) => value;
2452
+ var TokenLogo = {
2453
+ /** `baseUrl` is the registry origin; registry URLs are root-relative. */
2454
+ fromDto: (dto, baseUrl) => dto.kind === "VECTOR" ? { kind: "VECTOR", url: resolveLogoUrl(dto.url, baseUrl) } : {
2455
+ kind: "RASTER",
2456
+ original: logoImageFromDto(dto.original, baseUrl),
2457
+ variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl))
2458
+ }
1199
2459
  };
1200
- var TermItem = {
1201
- fromDto: (dto) => ({
1202
- key: notBlankStringOrNull(dto.key),
1203
- value: notBlankStringOrNull(dto.value)
1204
- })
2460
+ var TokenMetadata = {
2461
+ /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */
2462
+ fromDto: (dto, baseUrl) => {
2463
+ assertSupportedSchemaVersion(dto.schema_version);
2464
+ return {
2465
+ identifier: {
2466
+ chain: EthereumChain(dto.chain),
2467
+ address: EvmContractAddress(dto.address)
2468
+ },
2469
+ name: dto.name,
2470
+ symbol: AssetSymbol(dto.symbol),
2471
+ decimals: AssetDecimals(dto.decimals),
2472
+ logo: TokenLogo.fromDto(dto.logo, baseUrl),
2473
+ logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
2474
+ };
2475
+ },
2476
+ /**
2477
+ * Maps a chain snapshot to the tokens it lists, skipping the chain's native
2478
+ * coin (`kind: 'COIN'`, no contract address).
2479
+ */
2480
+ fromChainAssetsDto: (dto, baseUrl) => {
2481
+ assertSupportedSchemaVersion(dto.schema_version);
2482
+ const chain = EthereumChain(dto.chain);
2483
+ return dto.assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
2484
+ identifier: {
2485
+ chain,
2486
+ // The filter above cannot narrow `address` for the type checker.
2487
+ address: EvmContractAddress(asset.address)
2488
+ },
2489
+ name: asset.name,
2490
+ symbol: AssetSymbol(asset.symbol),
2491
+ decimals: AssetDecimals(asset.decimals),
2492
+ logo: TokenLogo.fromDto(asset.logo, baseUrl),
2493
+ logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
2494
+ }));
2495
+ }
1205
2496
  };
1206
- var Milestone = {
1207
- fromDto: (dto) => ({
1208
- name: notBlankStringOrNull(dto.name),
1209
- schedule: notBlankStringOrNull(dto.schedule),
1210
- status: dto.status
1211
- })
2497
+ function assertSupportedSchemaVersion(version) {
2498
+ if (version !== 1) {
2499
+ throw new ValidationError(
2500
+ `Unsupported token registry schema_version: ${version}`
2501
+ );
2502
+ }
2503
+ }
2504
+ var logoImageFromDto = (dto, baseUrl) => ({
2505
+ url: resolveLogoUrl(dto.url, baseUrl),
2506
+ width: dto.width,
2507
+ height: dto.height
2508
+ });
2509
+ var resolveLogoUrl = (url, baseUrl) => TokenLogoUrl(
2510
+ url.startsWith("http") ? url : `${baseUrl.replace(/\/$/, "")}${url}`
2511
+ );
2512
+
2513
+ // src/shared/api/nabu/tokens.ts
2514
+ function createNabuApiClient(baseUrl, logger = null) {
2515
+ return new HttpClient({ baseUrl }, {}, logger);
2516
+ }
2517
+ async function fetchTokenMetadata(client, token) {
2518
+ const address = checksummed(token.address);
2519
+ let response;
2520
+ try {
2521
+ response = await client.send({
2522
+ method: "GET",
2523
+ url: `/${token.chain}/token/${address}`
2524
+ });
2525
+ } catch (error) {
2526
+ if (isRegistryHtmlFallback(error)) {
2527
+ return null;
2528
+ }
2529
+ throw error;
2530
+ }
2531
+ if (response.status === 404) {
2532
+ return null;
2533
+ }
2534
+ assertOk(response);
2535
+ if (response.body === null) {
2536
+ throw new ValidationError(
2537
+ `Token registry returned an empty body for token "${address}" on "${token.chain}"`
2538
+ );
2539
+ }
2540
+ return TokenMetadata.fromDto(response.body, client.config.baseUrl);
2541
+ }
2542
+ async function fetchTokensMetadata(client, chain) {
2543
+ let response;
2544
+ try {
2545
+ response = await client.send({
2546
+ method: "GET",
2547
+ url: `/${chain}/assets.json`
2548
+ });
2549
+ } catch (error) {
2550
+ if (isRegistryHtmlFallback(error)) {
2551
+ throw new ValidationError(
2552
+ `Token registry returned non-JSON for the "${chain}" snapshot`
2553
+ );
2554
+ }
2555
+ throw error;
2556
+ }
2557
+ assertOk(response);
2558
+ if (response.body === null) {
2559
+ throw new ValidationError(
2560
+ `Token registry returned an empty "${chain}" snapshot`
2561
+ );
2562
+ }
2563
+ return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
2564
+ }
2565
+ function isRegistryHtmlFallback(error) {
2566
+ return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
2567
+ }
2568
+ function assertOk(response) {
2569
+ if (response.status < 200 || response.status >= 300) {
2570
+ throw new HttpError(response);
2571
+ }
2572
+ }
2573
+ function checksummed(address) {
2574
+ try {
2575
+ return (0, import_viem4.getAddress)(address);
2576
+ } catch (_) {
2577
+ throw new ValidationError(`Invalid EVM contract address: "${address}"`);
2578
+ }
2579
+ }
2580
+
2581
+ // src/shared/core/tokens/tokens-namespace.ts
2582
+ var TokensNamespaceImpl = class {
2583
+ /**
2584
+ * Takes the registry origin rather than a `SharedNamespaceContext`: the
2585
+ * registry is unauthenticated and on its own host, so the frontline sender
2586
+ * and the auth check would both be dead weight here.
2587
+ */
2588
+ constructor(baseUrl, logger = null) {
2589
+ this.api = createNabuApiClient(baseUrl, logger);
2590
+ this.log = internalLogger(logger, "TOKENS");
2591
+ }
2592
+ get(token) {
2593
+ return this.log.wrap(
2594
+ "get",
2595
+ token,
2596
+ () => fetchTokenMetadata(this.api, token)
2597
+ );
2598
+ }
2599
+ list(chain) {
2600
+ return this.log.wrap(
2601
+ "list",
2602
+ chain,
2603
+ () => fetchTokensMetadata(this.api, chain)
2604
+ );
2605
+ }
1212
2606
  };
1213
2607
 
1214
2608
  // src/shared/types/offer-option-address.ts
@@ -1282,195 +2676,79 @@ async function createWalletOwnershipChallenge(api, params) {
1282
2676
  });
1283
2677
  return WalletOwnershipChallenge.fromDto(dto);
1284
2678
  }
1285
-
1286
- // src/shared/core/swap-namespace.ts
1287
- var SwapNamespaceImpl = class {
1288
- constructor(ctx) {
1289
- this.ctx = ctx;
1290
- }
1291
- async getAuthorization(params) {
1292
- await this.ctx.ensureUserAuthenticated();
1293
- return getSwapAuthorization(this.ctx.api, params);
1294
- }
1295
- async getPreview(params) {
1296
- await this.ctx.ensureUserAuthenticated();
1297
- return getSwapPreview(this.ctx.api, params);
1298
- }
1299
- async getStatus(params) {
1300
- await this.ctx.ensureUserAuthenticated();
1301
- return getSwapStatus(this.ctx.api, params);
1302
- }
1303
- async getOutputToken(params) {
1304
- await this.ctx.ensureUserAuthenticated();
1305
- return getSwapOutputToken(this.ctx.api, params);
1306
- }
1307
- async requestWalletOwnershipChallenge(params) {
1308
- await this.ctx.ensureUserAuthenticated();
1309
- return createWalletOwnershipChallenge(this.ctx.api, params);
1310
- }
1311
- async allowWallet(params) {
1312
- await this.ctx.ensureUserAuthenticated();
1313
- return allowWallet(this.ctx.api, params);
1314
- }
1315
- };
1316
-
1317
- // src/shared/types/participation.ts
1318
- var ParticipationId = (value) => value;
1319
- var Blockchain = (value) => value;
1320
- var WalletAddress = (value) => value;
1321
- var ParticipationsPaginationParams = {
1322
- toQueryParams: (params) => {
1323
- const queryParams = PaginationParams.toQueryParams(params);
1324
- if (params.offerId) {
1325
- queryParams["filters[0][field]"] = "offer_id";
1326
- queryParams["filters[0][op]"] = "==";
1327
- queryParams["filters[0][value]"] = params.offerId;
1328
- }
1329
- return queryParams;
1330
- }
1331
- };
1332
- var Participation = {
1333
- /** Maps API DTO shape into the SDK participation domain model. */
1334
- fromDto: (dto) => {
1335
- const walletAddress = notBlankStringOrNull(dto.wallet_address);
1336
- return {
1337
- id: ParticipationId(dto.id),
1338
- offerId: OfferId(dto.offer_id),
1339
- offerOptionId: OfferOptionId(dto.offer_option_id),
1340
- status: dto.status,
1341
- amount: dto.amount,
1342
- displayAmount: dto.amount_string,
1343
- asset: Asset.fromDto(dto.asset),
1344
- chain: Blockchain(dto.chain),
1345
- insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,
1346
- updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,
1347
- walletAddress: walletAddress ? WalletAddress(walletAddress) : null
1348
- };
1349
- }
1350
- };
1351
- var CreateParticipationParams = {
1352
- /** Maps participation creation params into API DTO payload. */
1353
- toDto: (params) => ({
1354
- offer_id: params.offerId,
1355
- offer_option_id: params.offerOptionId,
1356
- chain: params.chain,
1357
- wallet_address: params.walletAddress,
1358
- amount: params.amount,
1359
- asset_id: params.assetId,
1360
- approval_transaction_hash: params.approvalTransactionHash
1361
- })
1362
- };
1363
-
1364
- // src/shared/api/frontline/participations.ts
1365
- async function fetchParticipations(api, offerId) {
1366
- return fetchAllPages(
1367
- (params) => fetchParticipationsPage(api, params),
1368
- { offerId }
1369
- );
1370
- }
1371
- async function fetchParticipationsPage(api, params) {
1372
- const pageDto = await api.send({
1373
- method: "GET",
1374
- url: "/v1/participations",
1375
- queryParams: ParticipationsPaginationParams.toQueryParams(params),
2679
+ async function connectExternalWallet(api, params) {
2680
+ const dto = await api.send({
2681
+ method: "POST",
2682
+ url: `/v1/offers/${params.offerId}/addresses`,
2683
+ body: ConnectExternalWalletParams.toDto(params),
1376
2684
  attributes: Attributes.protected()
1377
2685
  });
1378
- return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
2686
+ return OfferOptionAddress.fromDto(dto);
1379
2687
  }
1380
- async function fetchParticipation(api, id) {
1381
- const dto = await api.send({
2688
+ async function listOptionAddresses(api, offerId, offerOptionId) {
2689
+ const { data } = await api.send({
1382
2690
  method: "GET",
1383
- url: `/v1/participations/${id}`,
2691
+ url: `/v1/offers/${offerId}/addresses`,
2692
+ queryParams: { offer_option_id: offerOptionId },
1384
2693
  attributes: Attributes.protected()
1385
2694
  });
1386
- return Participation.fromDto(dto);
2695
+ return data.map(OfferOptionAddress.fromDto);
1387
2696
  }
1388
- async function createParticipation(api, params) {
2697
+ async function removeOptionAddress(api, offerId, addressId) {
1389
2698
  const dto = await api.send({
1390
- method: "POST",
1391
- url: "/v1/participations",
1392
- body: CreateParticipationParams.toDto(params),
2699
+ method: "DELETE",
2700
+ url: `/v1/offers/${offerId}/addresses/${addressId}`,
1393
2701
  attributes: Attributes.protected()
1394
2702
  });
1395
- return Participation.fromDto(dto);
2703
+ return OfferOptionAddress.fromDto(dto);
1396
2704
  }
1397
2705
 
1398
- // src/shared/core/token-sale-namespace.ts
1399
- var TokenSaleNamespaceImpl = class {
2706
+ // src/shared/core/wallets/wallets-namespace.ts
2707
+ var WalletsNamespaceImpl = class {
1400
2708
  constructor(ctx) {
1401
2709
  this.ctx = ctx;
2710
+ this.log = internalLogger(ctx.logger, "WALLETS");
1402
2711
  }
1403
- async fetchParticipations(offerId) {
1404
- await this.ctx.ensureUserAuthenticated();
1405
- return fetchParticipations(this.ctx.api, offerId);
1406
- }
1407
- async fetchParticipationsPage(params) {
1408
- await this.ctx.ensureUserAuthenticated();
1409
- return fetchParticipationsPage(this.ctx.api, params);
1410
- }
1411
- async fetchParticipation(id) {
1412
- await this.ctx.ensureUserAuthenticated();
1413
- return fetchParticipation(this.ctx.api, id);
2712
+ async createOwnershipChallenge(params) {
2713
+ return this.log.wrap("createOwnershipChallenge", params, async () => {
2714
+ await this.ctx.ensureUserAuthenticated();
2715
+ return createWalletOwnershipChallenge(
2716
+ this.ctx.api,
2717
+ params
2718
+ );
2719
+ });
1414
2720
  }
1415
- async createParticipation(params) {
1416
- await this.ctx.ensureUserAuthenticated();
1417
- return createParticipation(this.ctx.api, params);
2721
+ async connectExternal(params) {
2722
+ return this.log.wrap("connectExternal", params, async () => {
2723
+ await this.ctx.ensureUserAuthenticated();
2724
+ return connectExternalWallet(this.ctx.api, params);
2725
+ });
1418
2726
  }
1419
- };
1420
-
1421
- // src/shared/types/oauth.ts
1422
- var AuthorizationCode = (value) => value;
1423
- var CodeVerifier = (value) => value;
1424
- var CodeChallenge = (value) => value;
1425
- var PKCEState = (value) => value;
1426
- var RedirectUri = (value) => value;
1427
- var ClientId = (value) => value;
1428
- var ClientSecret = (value) => value;
1429
-
1430
- // src/shared/pkce.ts
1431
- async function generatePKCEParams(config) {
1432
- const state = generateSecureRandomBase64Url(32);
1433
- const codeVerifier = generateSecureRandomBase64Url(32);
1434
- const codeChallengeRaw = await sha256(codeVerifier);
1435
- const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);
1436
- return {
1437
- clientId: config.clientId,
1438
- responseType: "code",
1439
- redirectUri: config.redirectUri,
1440
- codeChallenge: CodeChallenge(codeChallenge),
1441
- codeChallengeMethod: "S256",
1442
- state: PKCEState(state),
1443
- codeVerifier: CodeVerifier(codeVerifier)
1444
- };
1445
- }
1446
-
1447
- // src/shared/types/document-submission.ts
1448
- var DocumentSubmission = {
1449
- fromDto: (dto) => ({
1450
- status: dto.status,
1451
- formType: dto.form_type
1452
- })
1453
- };
1454
-
1455
- // src/shared/types/errors.ts
1456
- var NotImplementedError = class extends Error {
1457
- constructor(message = "Not implemented yet") {
1458
- super(message);
1459
- this.name = "NotImplementedError";
2727
+ async list(params) {
2728
+ return this.log.wrap("list", params, async () => {
2729
+ await this.ctx.ensureUserAuthenticated();
2730
+ return listOptionAddresses(
2731
+ this.ctx.api,
2732
+ params.offerId,
2733
+ params.offerOptionId
2734
+ );
2735
+ });
1460
2736
  }
1461
- };
1462
- var NotAuthenticatedError = class extends Error {
1463
- constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
1464
- super(message);
1465
- this.name = "NotAuthenticatedError";
2737
+ async remove(params) {
2738
+ return this.log.wrap("remove", params, async () => {
2739
+ await this.ctx.ensureUserAuthenticated();
2740
+ return removeOptionAddress(
2741
+ this.ctx.api,
2742
+ params.offerId,
2743
+ params.addressId
2744
+ );
2745
+ });
1466
2746
  }
1467
2747
  };
1468
2748
 
1469
- // src/shared/types/kyc.ts
1470
- var KycToken = {
1471
- fromDto: (dto) => ({
1472
- token: dto.token
1473
- })
2749
+ // src/shared/types/blockchain/wallet-error.ts
2750
+ var RedactedWalletError = {
2751
+ fromWalletError: (error) => error.type === "unknown" ? { type: "unknown" } : error
1474
2752
  };
1475
2753
 
1476
2754
  // src/shared/types/oauth-session.ts
@@ -1489,55 +2767,6 @@ var OAuthSession = {
1489
2767
  }
1490
2768
  };
1491
2769
 
1492
- // src/shared/types/pii.ts
1493
- var Iso2CountryCode = (value) => value;
1494
- var PiiJurisdiction = {
1495
- fromDto: (dto) => ({
1496
- iso2: Iso2CountryCode(dto.iso_2),
1497
- name: dto.name
1498
- })
1499
- };
1500
- var PiiAddress = {
1501
- fromDto: (dto) => ({
1502
- street: dto.street,
1503
- city: dto.city,
1504
- state: dto.state,
1505
- postalCode: dto.postal_code,
1506
- country: dto.country
1507
- })
1508
- };
1509
- var Pii = {
1510
- fromDto: (dto) => ({
1511
- kind: dto.kind,
1512
- fullLegalName: dto.full_legal_name,
1513
- dateOfBirth: dto.date_of_birth,
1514
- jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
1515
- taxId: dto.tax_id,
1516
- permanentAddress: PiiAddress.fromDto(dto.permanent_address)
1517
- })
1518
- };
1519
-
1520
- // src/shared/types/requirement.ts
1521
- var RequirementId = (value) => value;
1522
- var Requirement = {
1523
- fromDto: (dto) => ({
1524
- id: RequirementId(dto.id),
1525
- type: dto.type,
1526
- details: dto.details
1527
- })
1528
- };
1529
- var RequirementStatusInfo = {
1530
- fromStatusesDto: (dto) => Object.entries(dto.statuses).map(
1531
- ([id, value]) => typeof value === "string" ? { id: RequirementId(id), status: value, action: null } : {
1532
- id: RequirementId(id),
1533
- status: value.status,
1534
- action: value.action ?? null,
1535
- kycLevel: value.kyc_level,
1536
- kycReset: value.kyc_reset
1537
- }
1538
- )
1539
- };
1540
-
1541
2770
  // src/shared/types/user.ts
1542
2771
  var UserId = (value) => value;
1543
2772
  var UserEmail = (value) => value;
@@ -1561,20 +2790,26 @@ var User = {
1561
2790
  Blockchain,
1562
2791
  BlockchainAmount,
1563
2792
  Bps,
2793
+ Chain,
1564
2794
  ClientCredentialsOAuth,
1565
2795
  ClientId,
1566
2796
  ClientSecret,
1567
2797
  CodeChallenge,
1568
2798
  CodeVerifier,
2799
+ CoinListTokenSaleNamespaceImpl,
1569
2800
  ConnectExternalWalletParams,
1570
2801
  CreateParticipationParams,
1571
2802
  CreateWalletOwnershipChallengeParams,
1572
2803
  Cursor,
1573
2804
  DEFAULT_AMOUNT_TO_COMPUTE_PRICE,
2805
+ DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE,
1574
2806
  DEFAULT_SLIPPAGE_BPS,
2807
+ DecimalString,
1575
2808
  DocumentSubmission,
1576
2809
  ERC20_ABI,
2810
+ ETHEREUM_CHAINS,
1577
2811
  Erc20NamespaceImpl,
2812
+ EthereumChain,
1578
2813
  EvmContractAddress,
1579
2814
  EvmWalletAddress,
1580
2815
  FaqItem,
@@ -1582,10 +2817,13 @@ var User = {
1582
2817
  FormattedAmountUi,
1583
2818
  FormattedPercentUi,
1584
2819
  HexEncodedTransactionData,
2820
+ HttpError,
2821
+ InvariantError,
1585
2822
  Iso2CountryCode,
1586
2823
  KnownAssetSymbol,
1587
2824
  KycToken,
1588
2825
  Link,
2826
+ MAX_ASSET_DECIMALS,
1589
2827
  MAX_UINT_256,
1590
2828
  Milestone,
1591
2829
  NA_AMOUNT_ASSET_UI,
@@ -1593,6 +2831,9 @@ var User = {
1593
2831
  NotImplementedError,
1594
2832
  OAuthRefreshToken,
1595
2833
  OAuthSession,
2834
+ ONDO_POLL_INTERVAL_MS,
2835
+ ONDO_QUOTE_EXPIRY_THRESHOLD_MS,
2836
+ ONDO_SUPPORTED_INPUT_ASSETS,
1596
2837
  Offer,
1597
2838
  OfferDetail,
1598
2839
  OfferId,
@@ -1602,6 +2843,12 @@ var User = {
1602
2843
  OfferOptionId,
1603
2844
  OfferOptionSlug,
1604
2845
  OfferSlug,
2846
+ OfferToken,
2847
+ OffersNamespaceImpl,
2848
+ OndoNamespaceImpl,
2849
+ OndoQuote,
2850
+ OndoSwapTransaction,
2851
+ OndoTradingStatus,
1605
2852
  PKCEState,
1606
2853
  PaginatedResponse,
1607
2854
  PaginationParams,
@@ -1611,27 +2858,37 @@ var User = {
1611
2858
  Pii,
1612
2859
  PiiAddress,
1613
2860
  PiiJurisdiction,
2861
+ RedactedWalletError,
1614
2862
  RedirectUri,
1615
2863
  Requirement,
1616
2864
  RequirementId,
1617
2865
  RequirementStatusInfo,
2866
+ RequirementsNamespaceImpl,
1618
2867
  SLIPPAGE_OPTIONS_BPS,
2868
+ SOLANA_CHAINS,
2869
+ STABLE_DECIMALS,
2870
+ SUPERSTATE_ISSUER_NAME,
2871
+ SUPERSTATE_SUPPORTED_INPUT_ASSETS,
1619
2872
  SUPERSTATE_SWAP_ABI,
1620
2873
  SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA,
1621
- SUPERSTATE_TOS_URL,
1622
2874
  SWAP_POLL_INTERVAL_MS,
1623
2875
  ShortenedWalletAddress,
2876
+ SolanaChain,
1624
2877
  StablecoinSymbol,
2878
+ SuperstateSwapNamespaceImpl,
1625
2879
  SwapAuthorization,
1626
- SwapNamespaceImpl,
1627
2880
  SwapPreview,
1628
2881
  SwapQuote,
1629
2882
  SwapStatus,
1630
2883
  TOKEN_REGISTRY,
1631
2884
  TermItem,
2885
+ Ticker,
1632
2886
  TokenAllowance,
1633
2887
  TokenBalance,
1634
- TokenSaleNamespaceImpl,
2888
+ TokenLogo,
2889
+ TokenLogoUrl,
2890
+ TokenMetadata,
2891
+ TokensNamespaceImpl,
1635
2892
  TxExplorerUrl,
1636
2893
  USDC,
1637
2894
  USDC_SYMBOL,
@@ -1640,11 +2897,17 @@ var User = {
1640
2897
  User,
1641
2898
  UserEmail,
1642
2899
  UserId,
2900
+ ValidationError,
1643
2901
  WalletAddress,
1644
2902
  WalletOwnershipChallenge,
2903
+ WalletsNamespaceImpl,
2904
+ apiErrorCode,
1645
2905
  applyBps,
1646
2906
  assertUint256,
1647
2907
  assetAmount,
2908
+ blockchainAmountFromRawOrThrow,
2909
+ chainFromId,
2910
+ computeOndoPrice,
1648
2911
  computePrice,
1649
2912
  computeSlip,
1650
2913
  decodeSwappedOutputAmount,
@@ -1659,8 +2922,11 @@ var User = {
1659
2922
  getChainId,
1660
2923
  getNetworkName,
1661
2924
  isStopped,
2925
+ ondoSwapContractAddress,
1662
2926
  parseBlockchainAmount,
2927
+ parseUint256,
1663
2928
  shortenAddress,
2929
+ superstateSwapContractAddress,
1664
2930
  txExplorerUrl,
1665
2931
  usdAmount
1666
2932
  });