@coinlist-co/react 0.9.0 → 0.10.1

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 (34) hide show
  1. package/dist/{chunk-I5YTJ5SL.js → chunk-AQVCOWOV.js} +163 -69
  2. package/dist/chunk-AQVCOWOV.js.map +1 -0
  3. package/dist/{chunk-MKCOK3DF.js → chunk-TBU3EBNM.js} +2 -43
  4. package/dist/chunk-TBU3EBNM.js.map +1 -0
  5. package/dist/{chunk-Z2HAA2TI.js → chunk-UOHD7US2.js} +150 -63
  6. package/dist/chunk-UOHD7US2.js.map +1 -0
  7. package/dist/client/index.cjs +415 -292
  8. package/dist/client/index.cjs.map +1 -1
  9. package/dist/client/index.d.cts +131 -49
  10. package/dist/client/index.d.ts +131 -49
  11. package/dist/client/index.js +169 -76
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/{collections-BQbFJS3g.d.ts → collections-Bv1Oxzu_.d.ts} +1 -1
  14. package/dist/{collections-B84Vw55t.d.cts → collections-DDyxbOPZ.d.cts} +1 -1
  15. package/dist/{requirement-C2w45Q11.d.cts → requirement-oVZA1INj.d.cts} +271 -200
  16. package/dist/{requirement-C2w45Q11.d.ts → requirement-oVZA1INj.d.ts} +271 -200
  17. package/dist/server/index.cjs +135 -116
  18. package/dist/server/index.cjs.map +1 -1
  19. package/dist/server/index.d.cts +20 -27
  20. package/dist/server/index.d.ts +20 -27
  21. package/dist/server/index.js +10 -27
  22. package/dist/server/index.js.map +1 -1
  23. package/dist/shared/index.cjs +145 -75
  24. package/dist/shared/index.cjs.map +1 -1
  25. package/dist/shared/index.d.cts +4 -4
  26. package/dist/shared/index.d.ts +4 -4
  27. package/dist/shared/index.js +16 -92
  28. package/dist/shared/index.js.map +1 -1
  29. package/package.json +1 -1
  30. package/dist/chunk-AAER5LOL.js +0 -22
  31. package/dist/chunk-AAER5LOL.js.map +0 -1
  32. package/dist/chunk-I5YTJ5SL.js.map +0 -1
  33. package/dist/chunk-MKCOK3DF.js.map +0 -1
  34. package/dist/chunk-Z2HAA2TI.js.map +0 -1
@@ -32,6 +32,7 @@ var client_exports = {};
32
32
  __export(client_exports, {
33
33
  ChecklistStatus: () => ChecklistStatus,
34
34
  ClientSwapNamespaceImpl: () => ClientSwapNamespaceImpl,
35
+ ClientTokenSaleNamespaceImpl: () => ClientTokenSaleNamespaceImpl,
35
36
  CoinListClientInitializationError: () => CoinListClientInitializationError,
36
37
  CoinListContext: () => CoinListContext,
37
38
  CoinListContextProvider: () => CoinListContextProvider,
@@ -58,6 +59,7 @@ __export(client_exports, {
58
59
  connectExternalWalletFlow: () => connectExternalWalletFlow,
59
60
  createCoinListClient: () => createCoinListClient,
60
61
  executeSwap: () => executeSwap,
62
+ executeTokenSale: () => executeTokenSale,
61
63
  useCoinList: () => useCoinList,
62
64
  useCompleteOAuth: () => useCompleteOAuth,
63
65
  useConnectWallet: () => useConnectWallet,
@@ -655,6 +657,50 @@ var ERC20_ABI = [
655
657
  }
656
658
  ];
657
659
 
660
+ // src/client/core/blockchain/erc20-approval.ts
661
+ async function submitErc20Approval(args) {
662
+ const {
663
+ wallet,
664
+ tokenAddress,
665
+ spender,
666
+ chain,
667
+ value,
668
+ pending,
669
+ confirming,
670
+ emit
671
+ } = args;
672
+ emit(pending);
673
+ let hash;
674
+ try {
675
+ hash = await wallet.writeContract({
676
+ abi: ERC20_ABI,
677
+ address: tokenAddress,
678
+ functionName: "approve",
679
+ args: [spender, value],
680
+ chain
681
+ });
682
+ } catch (error) {
683
+ return {
684
+ type: "error",
685
+ error: { step: "approval", cause: classifyWalletError(error) }
686
+ };
687
+ }
688
+ emit(confirming);
689
+ let receipt;
690
+ try {
691
+ receipt = await wallet.awaitTx(hash, chain);
692
+ } catch (error) {
693
+ return {
694
+ type: "error",
695
+ error: { step: "approval", cause: classifyWalletError(error, { hash }) }
696
+ };
697
+ }
698
+ if (receipt.status !== "success") {
699
+ return { type: "error", error: { step: "approval-reverted" } };
700
+ }
701
+ return { type: "ok", txHash: hash };
702
+ }
703
+
658
704
  // src/shared/core/blockchain/abis/superstate-swap.ts
659
705
  var SUPERSTATE_SWAP_ABI = [
660
706
  {
@@ -963,6 +1009,7 @@ function decodeSwappedOutputAmount(receipt, outputDecimals) {
963
1009
  async function executeSwap(params) {
964
1010
  const {
965
1011
  swap,
1012
+ erc20,
966
1013
  wallet,
967
1014
  contractAddress,
968
1015
  chain,
@@ -990,7 +1037,7 @@ async function executeSwap(params) {
990
1037
  emit("checking-allowance");
991
1038
  let allowance;
992
1039
  try {
993
- allowance = await swap.getTokenAllowance({
1040
+ allowance = await erc20.getTokenAllowance({
994
1041
  tokenAddress: inputTokenAddress,
995
1042
  owner: wallet.address,
996
1043
  spender: contractAddress,
@@ -1001,7 +1048,7 @@ async function executeSwap(params) {
1001
1048
  }
1002
1049
  if (allowance.allowance < inputAmount) {
1003
1050
  if (allowance.allowance > 0n) {
1004
- const reset = await submitApproval({
1051
+ const reset = await submitErc20Approval({
1005
1052
  wallet,
1006
1053
  tokenAddress: inputTokenAddress,
1007
1054
  spender: contractAddress,
@@ -1013,7 +1060,7 @@ async function executeSwap(params) {
1013
1060
  });
1014
1061
  if (reset.type === "error") return { type: "error", error: reset.error };
1015
1062
  }
1016
- const approve = await submitApproval({
1063
+ const approve = await submitErc20Approval({
1017
1064
  wallet,
1018
1065
  tokenAddress: inputTokenAddress,
1019
1066
  spender: contractAddress,
@@ -1070,48 +1117,6 @@ async function executeSwap(params) {
1070
1117
  recipientAddress: wallet.address
1071
1118
  };
1072
1119
  }
1073
- async function submitApproval(args) {
1074
- const {
1075
- wallet,
1076
- tokenAddress,
1077
- spender,
1078
- chain,
1079
- value,
1080
- pending,
1081
- confirming,
1082
- emit
1083
- } = args;
1084
- emit(pending);
1085
- let hash;
1086
- try {
1087
- hash = await wallet.writeContract({
1088
- abi: ERC20_ABI,
1089
- address: tokenAddress,
1090
- functionName: "approve",
1091
- args: [spender, value],
1092
- chain
1093
- });
1094
- } catch (error) {
1095
- return {
1096
- type: "error",
1097
- error: { step: "approval", cause: classifyWalletError(error) }
1098
- };
1099
- }
1100
- emit(confirming);
1101
- let receipt;
1102
- try {
1103
- receipt = await wallet.awaitTx(hash, chain);
1104
- } catch (error) {
1105
- return {
1106
- type: "error",
1107
- error: { step: "approval", cause: classifyWalletError(error, { hash }) }
1108
- };
1109
- }
1110
- if (receipt.status !== "success") {
1111
- return { type: "error", error: { step: "approval-reverted" } };
1112
- }
1113
- return { type: "ok" };
1114
- }
1115
1120
  async function authorizeWallet(params) {
1116
1121
  const { swap, wallet, offerId, contractAddress, chain, onProgress } = params;
1117
1122
  const emit = (phase) => onProgress?.(phase);
@@ -1376,11 +1381,12 @@ var Offer = {
1376
1381
  fromDto: (dto) => ({
1377
1382
  id: OfferId(dto.id),
1378
1383
  slug: OfferSlug(dto.slug),
1379
- tagline: notBlankStringOrNull(dto.tagline),
1380
- bannerUrl: notBlankStringOrNull(dto.banner_url),
1381
- logoUrl: notBlankStringOrNull(dto.logo_url),
1384
+ type: dto.type,
1385
+ tagline: dto.tagline,
1386
+ bannerUrl: dto.banner_url,
1387
+ logoUrl: dto.logo_url,
1382
1388
  startsAt: new Date(dto.starts_at),
1383
- endsAt: new Date(dto.ends_at)
1389
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null
1384
1390
  })
1385
1391
  };
1386
1392
 
@@ -1410,16 +1416,17 @@ var OfferDetail = {
1410
1416
  return {
1411
1417
  id: OfferId(dto.id),
1412
1418
  slug: OfferSlug(dto.slug),
1419
+ type: dto.type,
1413
1420
  name: dto.name,
1414
1421
  asset: Asset.fromDto(dto.asset),
1415
1422
  fundingAssets: dto.funding_assets.map(Asset.fromDto),
1416
1423
  about: notBlankStringOrNull(dto.about),
1417
- tagline: notBlankStringOrNull(dto.tagline),
1418
- bannerUrl: notBlankStringOrNull(dto.banner_url),
1419
- logoUrl: notBlankStringOrNull(dto.logo_url),
1420
- category: notBlankStringOrNull(dto.category),
1424
+ tagline: dto.tagline,
1425
+ bannerUrl: dto.banner_url,
1426
+ logoUrl: dto.logo_url,
1427
+ category: dto.category,
1421
1428
  startsAt: new Date(dto.starts_at),
1422
- endsAt: new Date(dto.ends_at),
1429
+ endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
1423
1430
  faqs: dto.faqs.map(FaqItem.fromDto),
1424
1431
  links: dto.links.map(Link.fromDto),
1425
1432
  milestones: dto.milestones.map(Milestone.fromDto),
@@ -1581,14 +1588,6 @@ var SwapNamespaceImpl = class {
1581
1588
  await this.ctx.ensureUserAuthenticated();
1582
1589
  return getSwapStatus(this.ctx.api, params);
1583
1590
  }
1584
- async getTokenAllowance(params) {
1585
- await this.ctx.ensureUserAuthenticated();
1586
- return getTokenAllowance(this.ctx.api, params);
1587
- }
1588
- async getTokenBalance(params) {
1589
- await this.ctx.ensureUserAuthenticated();
1590
- return getTokenBalance(this.ctx.api, params);
1591
- }
1592
1591
  async getOutputToken(params) {
1593
1592
  await this.ctx.ensureUserAuthenticated();
1594
1593
  return getSwapOutputToken(this.ctx.api, params);
@@ -1605,54 +1604,18 @@ var SwapNamespaceImpl = class {
1605
1604
 
1606
1605
  // src/client/core/client-swap-namespace.ts
1607
1606
  var ClientSwapNamespaceImpl = class extends SwapNamespaceImpl {
1607
+ constructor(ctx, erc20) {
1608
+ super(ctx);
1609
+ this.erc20 = erc20;
1610
+ }
1608
1611
  executeSwap(params) {
1609
- return executeSwap({ ...params, swap: this });
1612
+ return executeSwap({ ...params, swap: this, erc20: this.erc20 });
1610
1613
  }
1611
1614
  authorizeWallet(params) {
1612
1615
  return authorizeWallet({ ...params, swap: this });
1613
1616
  }
1614
1617
  };
1615
1618
 
1616
- // src/shared/types/document-submission.ts
1617
- var DocumentSubmission = {
1618
- fromDto: (dto) => ({
1619
- status: dto.status,
1620
- formType: dto.form_type
1621
- })
1622
- };
1623
-
1624
- // src/shared/api/frontline/documents.ts
1625
- async function submitDocument(api, documentType, fields) {
1626
- const dto = await api.send({
1627
- method: "POST",
1628
- url: `/v1/documents/${documentType}/submission`,
1629
- body: fields,
1630
- attributes: Attributes.protected()
1631
- });
1632
- return DocumentSubmission.fromDto(dto);
1633
- }
1634
-
1635
- // src/shared/types/kyc.ts
1636
- var KycToken = {
1637
- fromDto: (dto) => ({
1638
- token: dto.token
1639
- })
1640
- };
1641
-
1642
- // src/shared/api/frontline/kyc.ts
1643
- async function createKycToken(api, levelName, reset) {
1644
- const dto = await api.send({
1645
- method: "POST",
1646
- url: "/v1/kyc-token",
1647
- body: {
1648
- ...levelName === void 0 ? {} : { level_name: levelName },
1649
- ...reset === void 0 ? {} : { reset }
1650
- },
1651
- attributes: Attributes.protected()
1652
- });
1653
- return KycToken.fromDto(dto);
1654
- }
1655
-
1656
1619
  // src/shared/api/pagination.ts
1657
1620
  var Cursor = (value) => value;
1658
1621
  async function fetchAllPages(fetchPage, baseParams) {
@@ -1692,34 +1655,116 @@ var PaginationParams = {
1692
1655
  }
1693
1656
  };
1694
1657
 
1695
- // src/shared/api/frontline/offers.ts
1696
- async function fetchOffers(api, clientCreds) {
1697
- return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
1698
- }
1699
- async function fetchOffersPage(api, params, clientCreds) {
1700
- const queryParams = PaginationParams.toQueryParams(params);
1701
- const pageDto = await api.send({
1702
- method: "GET",
1703
- url: "/v1/offers",
1704
- queryParams,
1705
- attributes: Attributes.concat(
1706
- Attributes.protected(),
1707
- Attributes.clientCredentials(clientCreds)
1708
- )
1709
- });
1710
- return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
1658
+ // src/shared/types/blockchain/ui.ts
1659
+ var ShortenedWalletAddress = (value) => value;
1660
+ var FormattedAmountAssetUi = (value) => value;
1661
+
1662
+ // src/shared/core/blockchain/formatters.ts
1663
+ var import_viem3 = require("viem");
1664
+ function shortenAddress(address) {
1665
+ const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
1666
+ return ShortenedWalletAddress(short);
1711
1667
  }
1712
- async function fetchOfferDetails(api, id, clientCreds) {
1713
- const dto = await api.send({
1714
- method: "GET",
1715
- url: `/v1/offers/${id}`,
1716
- attributes: Attributes.concat(
1717
- Attributes.protected(),
1718
- Attributes.clientCredentials(clientCreds)
1719
- )
1720
- });
1721
- return OfferDetail.fromDto(dto);
1668
+ function formatRawAmount(amount) {
1669
+ return (0, import_viem3.formatUnits)(amount.raw, amount.decimals);
1722
1670
  }
1671
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
1672
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
1673
+
1674
+ // src/shared/core/blockchain/swap/constants.ts
1675
+ var SWAP_POLL_INTERVAL_MS = 15e3;
1676
+ var SLIPPAGE_OPTIONS_BPS = [25n, 50n, 100n, 200n, 500n].map(
1677
+ (n) => Bps(n)
1678
+ );
1679
+ var DEFAULT_SLIPPAGE_BPS = Bps(50n);
1680
+ var SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA = EvmContractAddress("0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557");
1681
+
1682
+ // src/shared/core/blockchain/swap/quote.ts
1683
+ var SwapQuote = {
1684
+ /**
1685
+ * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The
1686
+ * input and fee are denominated in the input token; the output in the output
1687
+ * token.
1688
+ */
1689
+ fromPreview: (preview, inputDecimals, outputDecimals) => ({
1690
+ inputTokenAmount: BlockchainAmount({
1691
+ raw: preview.inputAmount,
1692
+ decimals: inputDecimals
1693
+ }),
1694
+ fee: BlockchainAmount({ raw: preview.fee, decimals: inputDecimals }),
1695
+ outputTokenAmount: BlockchainAmount({
1696
+ raw: preview.outputAmount,
1697
+ decimals: outputDecimals
1698
+ })
1699
+ })
1700
+ };
1701
+
1702
+ // src/shared/core/blockchain/token-registry.ts
1703
+ var USDC_SYMBOL = StablecoinSymbol("USDC");
1704
+ var USDC = {
1705
+ name: "USD Coin",
1706
+ symbol: USDC_SYMBOL,
1707
+ decimals: AssetDecimals(6)
1708
+ };
1709
+ var USDT_SYMBOL = StablecoinSymbol("USDT");
1710
+ var USDT = {
1711
+ name: "Tether USD",
1712
+ symbol: USDT_SYMBOL,
1713
+ decimals: AssetDecimals(6)
1714
+ };
1715
+ var USDC_ADDRESSES = {
1716
+ ethereum_mainnet: EvmContractAddress(
1717
+ "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
1718
+ ),
1719
+ ethereum_sepolia: EvmContractAddress(
1720
+ "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
1721
+ )
1722
+ };
1723
+ var USDT_ADDRESSES = {
1724
+ ethereum_mainnet: EvmContractAddress(
1725
+ "0xdac17f958d2ee523a2206206994597c13d831ec7"
1726
+ ),
1727
+ ethereum_sepolia: EvmContractAddress(
1728
+ "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
1729
+ )
1730
+ };
1731
+ var TOKEN_REGISTRY = {
1732
+ erc20: (symbol) => {
1733
+ switch (symbol) {
1734
+ case "USDC":
1735
+ return USDC;
1736
+ case "USDT":
1737
+ return USDT;
1738
+ default:
1739
+ throw new Error(`Unknown asset symbol: ${symbol}`);
1740
+ }
1741
+ },
1742
+ contractAddress: (symbol, chain) => {
1743
+ switch (symbol) {
1744
+ case "USDC":
1745
+ return USDC_ADDRESSES[chain];
1746
+ case "USDT":
1747
+ return USDT_ADDRESSES[chain];
1748
+ default:
1749
+ throw new Error(`Unknown asset symbol: ${symbol}`);
1750
+ }
1751
+ }
1752
+ };
1753
+
1754
+ // src/shared/core/erc20-namespace.ts
1755
+ var Erc20NamespaceImpl = class {
1756
+ constructor(ctx) {
1757
+ this.ctx = ctx;
1758
+ }
1759
+ async getTokenAllowance(params) {
1760
+ await this.ctx.ensureUserAuthenticated();
1761
+ return getTokenAllowance(this.ctx.api, params);
1762
+ }
1763
+ async getTokenBalance(params) {
1764
+ await this.ctx.ensureUserAuthenticated();
1765
+ return getTokenBalance(this.ctx.api, params);
1766
+ }
1767
+ };
1723
1768
 
1724
1769
  // src/shared/types/participation.ts
1725
1770
  var ParticipationId = (value) => value;
@@ -1802,6 +1847,75 @@ async function createParticipation(api, params) {
1802
1847
  return Participation.fromDto(dto);
1803
1848
  }
1804
1849
 
1850
+ // src/shared/core/token-sale-namespace.ts
1851
+ var TokenSaleNamespaceImpl = class {
1852
+ constructor(ctx) {
1853
+ this.ctx = ctx;
1854
+ }
1855
+ async fetchParticipations(offerId) {
1856
+ await this.ctx.ensureUserAuthenticated();
1857
+ return fetchParticipations(this.ctx.api, offerId);
1858
+ }
1859
+ async fetchParticipationsPage(params) {
1860
+ await this.ctx.ensureUserAuthenticated();
1861
+ return fetchParticipationsPage(this.ctx.api, params);
1862
+ }
1863
+ async fetchParticipation(id) {
1864
+ await this.ctx.ensureUserAuthenticated();
1865
+ return fetchParticipation(this.ctx.api, id);
1866
+ }
1867
+ async createParticipation(params) {
1868
+ await this.ctx.ensureUserAuthenticated();
1869
+ return createParticipation(this.ctx.api, params);
1870
+ }
1871
+ };
1872
+
1873
+ // src/shared/types/oauth.ts
1874
+ var AuthorizationCode = (value) => value;
1875
+ var CodeVerifier = (value) => value;
1876
+ var CodeChallenge = (value) => value;
1877
+ var PKCEState = (value) => value;
1878
+
1879
+ // src/shared/pkce.ts
1880
+ async function generatePKCEParams(config) {
1881
+ const state = generateSecureRandomBase64Url(32);
1882
+ const codeVerifier = generateSecureRandomBase64Url(32);
1883
+ const codeChallengeRaw = await sha256(codeVerifier);
1884
+ const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);
1885
+ return {
1886
+ clientId: config.clientId,
1887
+ responseType: "code",
1888
+ redirectUri: config.redirectUri,
1889
+ codeChallenge: CodeChallenge(codeChallenge),
1890
+ codeChallengeMethod: "S256",
1891
+ state: PKCEState(state),
1892
+ codeVerifier: CodeVerifier(codeVerifier)
1893
+ };
1894
+ }
1895
+
1896
+ // src/shared/types/document-submission.ts
1897
+ var DocumentSubmission = {
1898
+ fromDto: (dto) => ({
1899
+ status: dto.status,
1900
+ formType: dto.form_type
1901
+ })
1902
+ };
1903
+
1904
+ // src/shared/types/errors.ts
1905
+ var NotAuthenticatedError = class extends Error {
1906
+ constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
1907
+ super(message);
1908
+ this.name = "NotAuthenticatedError";
1909
+ }
1910
+ };
1911
+
1912
+ // src/shared/types/kyc.ts
1913
+ var KycToken = {
1914
+ fromDto: (dto) => ({
1915
+ token: dto.token
1916
+ })
1917
+ };
1918
+
1805
1919
  // src/shared/types/pii.ts
1806
1920
  var Iso2CountryCode = (value) => value;
1807
1921
  var PiiJurisdiction = {
@@ -1830,16 +1944,6 @@ var Pii = {
1830
1944
  })
1831
1945
  };
1832
1946
 
1833
- // src/shared/api/frontline/pii.ts
1834
- async function fetchPii(api) {
1835
- const dto = await api.send({
1836
- method: "GET",
1837
- url: "/v1/pii",
1838
- attributes: Attributes.protected()
1839
- });
1840
- return Pii.fromDto(dto);
1841
- }
1842
-
1843
1947
  // src/shared/types/requirement.ts
1844
1948
  var RequirementId = (value) => value;
1845
1949
  var Requirement = {
@@ -1861,6 +1965,160 @@ var RequirementStatusInfo = {
1861
1965
  )
1862
1966
  };
1863
1967
 
1968
+ // src/client/core/blockchain/token-sale-flow.ts
1969
+ async function executeTokenSale(params) {
1970
+ const {
1971
+ erc20,
1972
+ tokenSale,
1973
+ wallet,
1974
+ offerId,
1975
+ offerOptionId,
1976
+ assetId,
1977
+ paymentTokenAddress,
1978
+ fundingContractAddress,
1979
+ chain,
1980
+ amount,
1981
+ onProgress
1982
+ } = params;
1983
+ const emit = (phase) => onProgress?.(phase);
1984
+ emit("checking-allowance");
1985
+ let currentAllowance;
1986
+ try {
1987
+ const allowance = await erc20.getTokenAllowance({
1988
+ tokenAddress: paymentTokenAddress,
1989
+ owner: wallet.address,
1990
+ spender: fundingContractAddress,
1991
+ chain
1992
+ });
1993
+ currentAllowance = allowance.allowance;
1994
+ } catch {
1995
+ return { type: "error", error: { step: "allowance-check" } };
1996
+ }
1997
+ if (currentAllowance > 0n) {
1998
+ const reset = await submitErc20Approval({
1999
+ wallet,
2000
+ tokenAddress: paymentTokenAddress,
2001
+ spender: fundingContractAddress,
2002
+ chain,
2003
+ value: 0n,
2004
+ pending: "resetting-allowance",
2005
+ confirming: "confirming-allowance-reset",
2006
+ emit
2007
+ });
2008
+ if (reset.type === "error") {
2009
+ return {
2010
+ type: "error",
2011
+ error: reset.error.step === "approval-reverted" ? { step: "allowance-reset-reverted" } : { step: "allowance-reset", cause: reset.error.cause }
2012
+ };
2013
+ }
2014
+ }
2015
+ const approve = await submitErc20Approval({
2016
+ wallet,
2017
+ tokenAddress: paymentTokenAddress,
2018
+ spender: fundingContractAddress,
2019
+ chain,
2020
+ value: amount.raw,
2021
+ pending: "approving",
2022
+ confirming: "confirming-approval",
2023
+ emit
2024
+ });
2025
+ if (approve.type === "error") {
2026
+ return { type: "error", error: approve.error };
2027
+ }
2028
+ const approvalTxHash = approve.txHash;
2029
+ emit("recording-participation");
2030
+ let participation;
2031
+ try {
2032
+ participation = await tokenSale.createParticipation({
2033
+ offerId,
2034
+ offerOptionId,
2035
+ chain: Blockchain(chain),
2036
+ walletAddress: WalletAddress(wallet.address),
2037
+ amount: formatRawAmount(amount),
2038
+ assetId,
2039
+ approvalTransactionHash: approvalTxHash
2040
+ });
2041
+ } catch {
2042
+ return { type: "error", error: { step: "participation", approvalTxHash } };
2043
+ }
2044
+ return { type: "success", participation, approvalTxHash };
2045
+ }
2046
+
2047
+ // src/client/core/client-token-sale-namespace.ts
2048
+ var ClientTokenSaleNamespaceImpl = class extends TokenSaleNamespaceImpl {
2049
+ constructor(ctx, erc20) {
2050
+ super(ctx);
2051
+ this.erc20 = erc20;
2052
+ }
2053
+ executeTokenSale(params) {
2054
+ return executeTokenSale({ ...params, erc20: this.erc20, tokenSale: this });
2055
+ }
2056
+ };
2057
+
2058
+ // src/shared/api/frontline/documents.ts
2059
+ async function submitDocument(api, documentType, fields) {
2060
+ const dto = await api.send({
2061
+ method: "POST",
2062
+ url: `/v1/documents/${documentType}/submission`,
2063
+ body: fields,
2064
+ attributes: Attributes.protected()
2065
+ });
2066
+ return DocumentSubmission.fromDto(dto);
2067
+ }
2068
+
2069
+ // src/shared/api/frontline/kyc.ts
2070
+ async function createKycToken(api, levelName, reset) {
2071
+ const dto = await api.send({
2072
+ method: "POST",
2073
+ url: "/v1/kyc-token",
2074
+ body: {
2075
+ ...levelName === void 0 ? {} : { level_name: levelName },
2076
+ ...reset === void 0 ? {} : { reset }
2077
+ },
2078
+ attributes: Attributes.protected()
2079
+ });
2080
+ return KycToken.fromDto(dto);
2081
+ }
2082
+
2083
+ // src/shared/api/frontline/offers.ts
2084
+ async function fetchOffers(api, clientCreds) {
2085
+ return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
2086
+ }
2087
+ async function fetchOffersPage(api, params, clientCreds) {
2088
+ const queryParams = PaginationParams.toQueryParams(params);
2089
+ const pageDto = await api.send({
2090
+ method: "GET",
2091
+ url: "/v1/offers",
2092
+ queryParams,
2093
+ attributes: Attributes.concat(
2094
+ Attributes.protected(),
2095
+ Attributes.clientCredentials(clientCreds)
2096
+ )
2097
+ });
2098
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
2099
+ }
2100
+ async function fetchOfferDetails(api, id, clientCreds) {
2101
+ const dto = await api.send({
2102
+ method: "GET",
2103
+ url: `/v1/offers/${id}`,
2104
+ attributes: Attributes.concat(
2105
+ Attributes.protected(),
2106
+ Attributes.clientCredentials(clientCreds)
2107
+ )
2108
+ });
2109
+ return OfferDetail.fromDto(dto);
2110
+ }
2111
+
2112
+ // src/shared/api/frontline/pii.ts
2113
+ async function fetchPii(api) {
2114
+ const dto = await api.send({
2115
+ method: "GET",
2116
+ url: "/v1/pii",
2117
+ attributes: Attributes.protected()
2118
+ });
2119
+ return Pii.fromDto(dto);
2120
+ }
2121
+
1864
2122
  // src/shared/api/frontline/requirements.ts
1865
2123
  async function fetchOfferRequirements(api, offerId, clientCreds) {
1866
2124
  const response = await api.send({
@@ -1887,37 +2145,6 @@ async function fetchRequirementStatuses(api, offerId) {
1887
2145
  return RequirementStatusInfo.fromStatusesDto(response);
1888
2146
  }
1889
2147
 
1890
- // src/shared/types/oauth.ts
1891
- var AuthorizationCode = (value) => value;
1892
- var CodeVerifier = (value) => value;
1893
- var CodeChallenge = (value) => value;
1894
- var PKCEState = (value) => value;
1895
-
1896
- // src/shared/pkce.ts
1897
- async function generatePKCEParams(config) {
1898
- const state = generateSecureRandomBase64Url(32);
1899
- const codeVerifier = generateSecureRandomBase64Url(32);
1900
- const codeChallengeRaw = await sha256(codeVerifier);
1901
- const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);
1902
- return {
1903
- clientId: config.clientId,
1904
- responseType: "code",
1905
- redirectUri: config.redirectUri,
1906
- codeChallenge: CodeChallenge(codeChallenge),
1907
- codeChallengeMethod: "S256",
1908
- state: PKCEState(state),
1909
- codeVerifier: CodeVerifier(codeVerifier)
1910
- };
1911
- }
1912
-
1913
- // src/shared/types/errors.ts
1914
- var NotAuthenticatedError = class extends Error {
1915
- constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
1916
- super(message);
1917
- this.name = "NotAuthenticatedError";
1918
- }
1919
- };
1920
-
1921
2148
  // src/client/core/coinlist-client.ts
1922
2149
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
1923
2150
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -1933,10 +2160,13 @@ var CoinListClientImpl = class {
1933
2160
  },
1934
2161
  this.fetchAccessToken.bind(this)
1935
2162
  );
1936
- this.swap = new ClientSwapNamespaceImpl({
2163
+ const ctx = {
1937
2164
  api: this.api,
1938
2165
  ensureUserAuthenticated: async () => this.ensureAuthenticated()
1939
- });
2166
+ };
2167
+ this.erc20 = new Erc20NamespaceImpl(ctx);
2168
+ this.tokenSale = new ClientTokenSaleNamespaceImpl(ctx, this.erc20);
2169
+ this.swap = new ClientSwapNamespaceImpl(ctx, this.erc20);
1940
2170
  }
1941
2171
  async init() {
1942
2172
  await this.fetchAccessToken(true);
@@ -2018,22 +2248,6 @@ var CoinListClientImpl = class {
2018
2248
  this.ensureAuthenticated();
2019
2249
  return fetchOfferDetails(this.api, id, void 0);
2020
2250
  }
2021
- async fetchParticipations(offerId) {
2022
- this.ensureAuthenticated();
2023
- return fetchParticipations(this.api, offerId);
2024
- }
2025
- async fetchParticipationsPage(params) {
2026
- this.ensureAuthenticated();
2027
- return fetchParticipationsPage(this.api, params);
2028
- }
2029
- async fetchParticipation(id) {
2030
- this.ensureAuthenticated();
2031
- return fetchParticipation(this.api, id);
2032
- }
2033
- async createParticipation(params) {
2034
- this.ensureAuthenticated();
2035
- return createParticipation(this.api, params);
2036
- }
2037
2251
  async createWalletOwnershipChallenge(params) {
2038
2252
  this.ensureAuthenticated();
2039
2253
  return createWalletOwnershipChallenge(this.api, params);
@@ -2636,7 +2850,7 @@ var OfferCardUi = {
2636
2850
  bannerUrl: offer.bannerUrl,
2637
2851
  logoUrl: offer.logoUrl,
2638
2852
  formattedStartsAt: monthYearFormatter.format(offer.startsAt),
2639
- formattedEndsAt: monthYearFormatter.format(offer.endsAt)
2853
+ formattedEndsAt: offer.endsAt ? monthYearFormatter.format(offer.endsAt) : null
2640
2854
  })
2641
2855
  };
2642
2856
  function OfferCard({
@@ -2687,7 +2901,7 @@ function OfferCard({
2687
2901
  ),
2688
2902
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedStartsAt })
2689
2903
  ] }),
2690
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
2904
+ offer.formattedEndsAt && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
2691
2905
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2692
2906
  "span",
2693
2907
  {
@@ -2695,7 +2909,13 @@ function OfferCard({
2695
2909
  children: "Ends"
2696
2910
  }
2697
2911
  ),
2698
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedEndsAt })
2912
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2913
+ "span",
2914
+ {
2915
+ className: cn(typeClasses.label, "clcosdk:text-text-primary"),
2916
+ children: offer.formattedEndsAt
2917
+ }
2918
+ )
2699
2919
  ] })
2700
2920
  ] })
2701
2921
  ] });
@@ -3172,21 +3392,6 @@ function useConnectWallet({
3172
3392
  return { state, onSign };
3173
3393
  }
3174
3394
 
3175
- // src/shared/core/blockchain/formatters.ts
3176
- var import_viem3 = require("viem");
3177
-
3178
- // src/shared/types/blockchain/ui.ts
3179
- var ShortenedWalletAddress = (value) => value;
3180
- var FormattedAmountAssetUi = (value) => value;
3181
-
3182
- // src/shared/core/blockchain/formatters.ts
3183
- function shortenAddress(address) {
3184
- const short = address.length > 10 ? `${address.slice(0, 6)}\u2026${address.slice(-4)}` : address;
3185
- return ShortenedWalletAddress(short);
3186
- }
3187
- var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
3188
- var USD_FRACTION_DIGITS = AssetDecimals(2);
3189
-
3190
3395
  // src/client/components/requirements/ConnectWalletModal.tsx
3191
3396
  var import_jsx_runtime14 = require("react/jsx-runtime");
3192
3397
  function ConnectWalletModal({
@@ -4575,36 +4780,6 @@ function useSwapOutputToken(options) {
4575
4780
 
4576
4781
  // src/client/hooks/swap/useSwapQuote.ts
4577
4782
  var import_react17 = require("react");
4578
-
4579
- // src/shared/core/blockchain/swap/constants.ts
4580
- var SWAP_POLL_INTERVAL_MS = 15e3;
4581
- var SLIPPAGE_OPTIONS_BPS = [25n, 50n, 100n, 200n, 500n].map(
4582
- (n) => Bps(n)
4583
- );
4584
- var DEFAULT_SLIPPAGE_BPS = Bps(50n);
4585
- var SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA = EvmContractAddress("0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557");
4586
-
4587
- // src/shared/core/blockchain/swap/quote.ts
4588
- var SwapQuote = {
4589
- /**
4590
- * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The
4591
- * input and fee are denominated in the input token; the output in the output
4592
- * token.
4593
- */
4594
- fromPreview: (preview, inputDecimals, outputDecimals) => ({
4595
- inputTokenAmount: BlockchainAmount({
4596
- raw: preview.inputAmount,
4597
- decimals: inputDecimals
4598
- }),
4599
- fee: BlockchainAmount({ raw: preview.fee, decimals: inputDecimals }),
4600
- outputTokenAmount: BlockchainAmount({
4601
- raw: preview.outputAmount,
4602
- decimals: outputDecimals
4603
- })
4604
- })
4605
- };
4606
-
4607
- // src/client/hooks/swap/useSwapQuote.ts
4608
4783
  function useSwapQuote(options) {
4609
4784
  const {
4610
4785
  contractAddress,
@@ -4688,60 +4863,6 @@ function useSwapQuote(options) {
4688
4863
 
4689
4864
  // src/client/hooks/swap/useSwapTokenBalances.ts
4690
4865
  var import_react18 = require("react");
4691
-
4692
- // src/shared/core/blockchain/token-registry.ts
4693
- var USDC_SYMBOL = StablecoinSymbol("USDC");
4694
- var USDC = {
4695
- name: "USD Coin",
4696
- symbol: USDC_SYMBOL,
4697
- decimals: AssetDecimals(6)
4698
- };
4699
- var USDT_SYMBOL = StablecoinSymbol("USDT");
4700
- var USDT = {
4701
- name: "Tether USD",
4702
- symbol: USDT_SYMBOL,
4703
- decimals: AssetDecimals(6)
4704
- };
4705
- var USDC_ADDRESSES = {
4706
- ethereum_mainnet: EvmContractAddress(
4707
- "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4708
- ),
4709
- ethereum_sepolia: EvmContractAddress(
4710
- "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
4711
- )
4712
- };
4713
- var USDT_ADDRESSES = {
4714
- ethereum_mainnet: EvmContractAddress(
4715
- "0xdac17f958d2ee523a2206206994597c13d831ec7"
4716
- ),
4717
- ethereum_sepolia: EvmContractAddress(
4718
- "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
4719
- )
4720
- };
4721
- var TOKEN_REGISTRY = {
4722
- erc20: (symbol) => {
4723
- switch (symbol) {
4724
- case "USDC":
4725
- return USDC;
4726
- case "USDT":
4727
- return USDT;
4728
- default:
4729
- throw new Error(`Unknown asset symbol: ${symbol}`);
4730
- }
4731
- },
4732
- contractAddress: (symbol, chain) => {
4733
- switch (symbol) {
4734
- case "USDC":
4735
- return USDC_ADDRESSES[chain];
4736
- case "USDT":
4737
- return USDT_ADDRESSES[chain];
4738
- default:
4739
- throw new Error(`Unknown asset symbol: ${symbol}`);
4740
- }
4741
- }
4742
- };
4743
-
4744
- // src/client/hooks/swap/useSwapTokenBalances.ts
4745
4866
  function useSwapTokenBalances(options) {
4746
4867
  const {
4747
4868
  address,
@@ -4774,7 +4895,7 @@ function useSwapTokenBalances(options) {
4774
4895
  }
4775
4896
  const results = await Promise.allSettled(
4776
4897
  symbols.map(
4777
- (symbol) => coinlist.swap.getTokenBalance({
4898
+ (symbol) => coinlist.erc20.getTokenBalance({
4778
4899
  tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),
4779
4900
  owner: address,
4780
4901
  chain
@@ -4926,7 +5047,7 @@ function useParticipations(offerId, options = {}) {
4926
5047
  };
4927
5048
  }
4928
5049
  setParticipationsState(LOADING_STATE8);
4929
- coinlist.fetchParticipations(offerId).then((participations) => {
5050
+ coinlist.tokenSale.fetchParticipations(offerId).then((participations) => {
4930
5051
  if (!isCancelled) {
4931
5052
  setParticipationsState({ type: "CONTENT", participations });
4932
5053
  }
@@ -4946,6 +5067,7 @@ function useParticipations(offerId, options = {}) {
4946
5067
  0 && (module.exports = {
4947
5068
  ChecklistStatus,
4948
5069
  ClientSwapNamespaceImpl,
5070
+ ClientTokenSaleNamespaceImpl,
4949
5071
  CoinListClientInitializationError,
4950
5072
  CoinListContext,
4951
5073
  CoinListContextProvider,
@@ -4972,6 +5094,7 @@ function useParticipations(offerId, options = {}) {
4972
5094
  connectExternalWalletFlow,
4973
5095
  createCoinListClient,
4974
5096
  executeSwap,
5097
+ executeTokenSale,
4975
5098
  useCoinList,
4976
5099
  useCompleteOAuth,
4977
5100
  useConnectWallet,