@coinlist-co/react 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,18 +13,14 @@ import {
13
13
  VERIFY_IDENTITY_VERIFIED_PATH,
14
14
  WALLET_PATH,
15
15
  createKycToken,
16
- createParticipation,
17
16
  fetchOfferDetails,
18
17
  fetchOfferRequirements,
19
18
  fetchOffers,
20
19
  fetchOffersPage,
21
- fetchParticipation,
22
- fetchParticipations,
23
- fetchParticipationsPage,
24
20
  fetchPii,
25
21
  fetchRequirementStatuses,
26
22
  submitDocument
27
- } from "../chunk-MKCOK3DF.js";
23
+ } from "../chunk-7BJ2HAG7.js";
28
24
  import {
29
25
  AuthorizationCode,
30
26
  CodeVerifier,
@@ -39,20 +35,24 @@ import {
39
35
  generatePKCEParams,
40
36
  isStopped,
41
37
  shortenAddress
42
- } from "../chunk-I5YTJ5SL.js";
38
+ } from "../chunk-GSSAB4K5.js";
43
39
  import {
44
40
  Attributes,
41
+ Blockchain,
45
42
  BlockchainAmount,
43
+ Erc20NamespaceImpl,
46
44
  KycToken,
47
45
  NotAuthenticatedError,
48
46
  OfferOptionAddressId,
49
47
  SwapNamespaceImpl,
48
+ TokenSaleNamespaceImpl,
49
+ WalletAddress,
50
50
  connectExternalWallet,
51
51
  createWalletOwnershipChallenge,
52
52
  getUUIDv4,
53
53
  listOptionAddresses,
54
54
  removeOptionAddress
55
- } from "../chunk-Z2HAA2TI.js";
55
+ } from "../chunk-TUZKKFNW.js";
56
56
 
57
57
  // src/client/CoinListProvider.tsx
58
58
  import {
@@ -132,10 +132,55 @@ function classifyWalletError(error, ctx) {
132
132
  return { type: "unknown", cause: error };
133
133
  }
134
134
 
135
+ // src/client/core/blockchain/erc20-approval.ts
136
+ async function submitErc20Approval(args) {
137
+ const {
138
+ wallet,
139
+ tokenAddress,
140
+ spender,
141
+ chain,
142
+ value,
143
+ pending,
144
+ confirming,
145
+ emit
146
+ } = args;
147
+ emit(pending);
148
+ let hash;
149
+ try {
150
+ hash = await wallet.writeContract({
151
+ abi: ERC20_ABI,
152
+ address: tokenAddress,
153
+ functionName: "approve",
154
+ args: [spender, value],
155
+ chain
156
+ });
157
+ } catch (error) {
158
+ return {
159
+ type: "error",
160
+ error: { step: "approval", cause: classifyWalletError(error) }
161
+ };
162
+ }
163
+ emit(confirming);
164
+ let receipt;
165
+ try {
166
+ receipt = await wallet.awaitTx(hash, chain);
167
+ } catch (error) {
168
+ return {
169
+ type: "error",
170
+ error: { step: "approval", cause: classifyWalletError(error, { hash }) }
171
+ };
172
+ }
173
+ if (receipt.status !== "success") {
174
+ return { type: "error", error: { step: "approval-reverted" } };
175
+ }
176
+ return { type: "ok", txHash: hash };
177
+ }
178
+
135
179
  // src/client/core/blockchain/swap-flows.ts
136
180
  async function executeSwap(params) {
137
181
  const {
138
182
  swap,
183
+ erc20,
139
184
  wallet,
140
185
  contractAddress,
141
186
  chain,
@@ -163,7 +208,7 @@ async function executeSwap(params) {
163
208
  emit("checking-allowance");
164
209
  let allowance;
165
210
  try {
166
- allowance = await swap.getTokenAllowance({
211
+ allowance = await erc20.getTokenAllowance({
167
212
  tokenAddress: inputTokenAddress,
168
213
  owner: wallet.address,
169
214
  spender: contractAddress,
@@ -174,7 +219,7 @@ async function executeSwap(params) {
174
219
  }
175
220
  if (allowance.allowance < inputAmount) {
176
221
  if (allowance.allowance > 0n) {
177
- const reset = await submitApproval({
222
+ const reset = await submitErc20Approval({
178
223
  wallet,
179
224
  tokenAddress: inputTokenAddress,
180
225
  spender: contractAddress,
@@ -186,7 +231,7 @@ async function executeSwap(params) {
186
231
  });
187
232
  if (reset.type === "error") return { type: "error", error: reset.error };
188
233
  }
189
- const approve = await submitApproval({
234
+ const approve = await submitErc20Approval({
190
235
  wallet,
191
236
  tokenAddress: inputTokenAddress,
192
237
  spender: contractAddress,
@@ -243,48 +288,6 @@ async function executeSwap(params) {
243
288
  recipientAddress: wallet.address
244
289
  };
245
290
  }
246
- async function submitApproval(args) {
247
- const {
248
- wallet,
249
- tokenAddress,
250
- spender,
251
- chain,
252
- value,
253
- pending,
254
- confirming,
255
- emit
256
- } = args;
257
- emit(pending);
258
- let hash;
259
- try {
260
- hash = await wallet.writeContract({
261
- abi: ERC20_ABI,
262
- address: tokenAddress,
263
- functionName: "approve",
264
- args: [spender, value],
265
- chain
266
- });
267
- } catch (error) {
268
- return {
269
- type: "error",
270
- error: { step: "approval", cause: classifyWalletError(error) }
271
- };
272
- }
273
- emit(confirming);
274
- let receipt;
275
- try {
276
- receipt = await wallet.awaitTx(hash, chain);
277
- } catch (error) {
278
- return {
279
- type: "error",
280
- error: { step: "approval", cause: classifyWalletError(error, { hash }) }
281
- };
282
- }
283
- if (receipt.status !== "success") {
284
- return { type: "error", error: { step: "approval-reverted" } };
285
- }
286
- return { type: "ok" };
287
- }
288
291
  async function authorizeWallet(params) {
289
292
  const { swap, wallet, offerId, contractAddress, chain, onProgress } = params;
290
293
  const emit = (phase) => onProgress?.(phase);
@@ -381,14 +384,108 @@ async function authorizeWallet(params) {
381
384
 
382
385
  // src/client/core/client-swap-namespace.ts
383
386
  var ClientSwapNamespaceImpl = class extends SwapNamespaceImpl {
387
+ constructor(ctx, erc20) {
388
+ super(ctx);
389
+ this.erc20 = erc20;
390
+ }
384
391
  executeSwap(params) {
385
- return executeSwap({ ...params, swap: this });
392
+ return executeSwap({ ...params, swap: this, erc20: this.erc20 });
386
393
  }
387
394
  authorizeWallet(params) {
388
395
  return authorizeWallet({ ...params, swap: this });
389
396
  }
390
397
  };
391
398
 
399
+ // src/client/core/blockchain/token-sale-flow.ts
400
+ async function executeTokenSale(params) {
401
+ const {
402
+ erc20,
403
+ tokenSale,
404
+ wallet,
405
+ offerId,
406
+ offerOptionId,
407
+ assetId,
408
+ paymentTokenAddress,
409
+ fundingContractAddress,
410
+ chain,
411
+ amount,
412
+ onProgress
413
+ } = params;
414
+ const emit = (phase) => onProgress?.(phase);
415
+ emit("checking-allowance");
416
+ let currentAllowance;
417
+ try {
418
+ const allowance = await erc20.getTokenAllowance({
419
+ tokenAddress: paymentTokenAddress,
420
+ owner: wallet.address,
421
+ spender: fundingContractAddress,
422
+ chain
423
+ });
424
+ currentAllowance = allowance.allowance;
425
+ } catch {
426
+ return { type: "error", error: { step: "allowance-check" } };
427
+ }
428
+ if (currentAllowance > 0n) {
429
+ const reset = await submitErc20Approval({
430
+ wallet,
431
+ tokenAddress: paymentTokenAddress,
432
+ spender: fundingContractAddress,
433
+ chain,
434
+ value: 0n,
435
+ pending: "resetting-allowance",
436
+ confirming: "confirming-allowance-reset",
437
+ emit
438
+ });
439
+ if (reset.type === "error") {
440
+ return {
441
+ type: "error",
442
+ error: reset.error.step === "approval-reverted" ? { step: "allowance-reset-reverted" } : { step: "allowance-reset", cause: reset.error.cause }
443
+ };
444
+ }
445
+ }
446
+ const approve = await submitErc20Approval({
447
+ wallet,
448
+ tokenAddress: paymentTokenAddress,
449
+ spender: fundingContractAddress,
450
+ chain,
451
+ value: amount.raw,
452
+ pending: "approving",
453
+ confirming: "confirming-approval",
454
+ emit
455
+ });
456
+ if (approve.type === "error") {
457
+ return { type: "error", error: approve.error };
458
+ }
459
+ const approvalTxHash = approve.txHash;
460
+ emit("recording-participation");
461
+ let participation;
462
+ try {
463
+ participation = await tokenSale.createParticipation({
464
+ offerId,
465
+ offerOptionId,
466
+ chain: Blockchain(chain),
467
+ walletAddress: WalletAddress(wallet.address),
468
+ amount: amount.raw.toString(),
469
+ assetId,
470
+ approvalTransactionHash: approvalTxHash
471
+ });
472
+ } catch {
473
+ return { type: "error", error: { step: "participation", approvalTxHash } };
474
+ }
475
+ return { type: "success", participation, approvalTxHash };
476
+ }
477
+
478
+ // src/client/core/client-token-sale-namespace.ts
479
+ var ClientTokenSaleNamespaceImpl = class extends TokenSaleNamespaceImpl {
480
+ constructor(ctx, erc20) {
481
+ super(ctx);
482
+ this.erc20 = erc20;
483
+ }
484
+ executeTokenSale(params) {
485
+ return executeTokenSale({ ...params, erc20: this.erc20, tokenSale: this });
486
+ }
487
+ };
488
+
392
489
  // src/client/core/coinlist-client.ts
393
490
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
394
491
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -404,10 +501,13 @@ var CoinListClientImpl = class {
404
501
  },
405
502
  this.fetchAccessToken.bind(this)
406
503
  );
407
- this.swap = new ClientSwapNamespaceImpl({
504
+ const ctx = {
408
505
  api: this.api,
409
506
  ensureUserAuthenticated: async () => this.ensureAuthenticated()
410
- });
507
+ };
508
+ this.erc20 = new Erc20NamespaceImpl(ctx);
509
+ this.tokenSale = new ClientTokenSaleNamespaceImpl(ctx, this.erc20);
510
+ this.swap = new ClientSwapNamespaceImpl(ctx, this.erc20);
411
511
  }
412
512
  async init() {
413
513
  await this.fetchAccessToken(true);
@@ -489,22 +589,6 @@ var CoinListClientImpl = class {
489
589
  this.ensureAuthenticated();
490
590
  return fetchOfferDetails(this.api, id, void 0);
491
591
  }
492
- async fetchParticipations(offerId) {
493
- this.ensureAuthenticated();
494
- return fetchParticipations(this.api, offerId);
495
- }
496
- async fetchParticipationsPage(params) {
497
- this.ensureAuthenticated();
498
- return fetchParticipationsPage(this.api, params);
499
- }
500
- async fetchParticipation(id) {
501
- this.ensureAuthenticated();
502
- return fetchParticipation(this.api, id);
503
- }
504
- async createParticipation(params) {
505
- this.ensureAuthenticated();
506
- return createParticipation(this.api, params);
507
- }
508
592
  async createWalletOwnershipChallenge(params) {
509
593
  this.ensureAuthenticated();
510
594
  return createWalletOwnershipChallenge(this.api, params);
@@ -1107,7 +1191,7 @@ var OfferCardUi = {
1107
1191
  bannerUrl: offer.bannerUrl,
1108
1192
  logoUrl: offer.logoUrl,
1109
1193
  formattedStartsAt: monthYearFormatter.format(offer.startsAt),
1110
- formattedEndsAt: monthYearFormatter.format(offer.endsAt)
1194
+ formattedEndsAt: offer.endsAt ? monthYearFormatter.format(offer.endsAt) : null
1111
1195
  })
1112
1196
  };
1113
1197
  function OfferCard({
@@ -1158,7 +1242,7 @@ function OfferCard({
1158
1242
  ),
1159
1243
  /* @__PURE__ */ jsx11("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedStartsAt })
1160
1244
  ] }),
1161
- /* @__PURE__ */ jsxs8("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
1245
+ offer.formattedEndsAt && /* @__PURE__ */ jsxs8("div", { className: "clcosdk:flex clcosdk:flex-col clcosdk:gap-1", children: [
1162
1246
  /* @__PURE__ */ jsx11(
1163
1247
  "span",
1164
1248
  {
@@ -1166,7 +1250,13 @@ function OfferCard({
1166
1250
  children: "Ends"
1167
1251
  }
1168
1252
  ),
1169
- /* @__PURE__ */ jsx11("span", { className: cn(typeClasses.label, "clcosdk:text-text-primary"), children: offer.formattedEndsAt })
1253
+ /* @__PURE__ */ jsx11(
1254
+ "span",
1255
+ {
1256
+ className: cn(typeClasses.label, "clcosdk:text-text-primary"),
1257
+ children: offer.formattedEndsAt
1258
+ }
1259
+ )
1170
1260
  ] })
1171
1261
  ] })
1172
1262
  ] });
@@ -3146,7 +3236,7 @@ function useSwapTokenBalances(options) {
3146
3236
  }
3147
3237
  const results = await Promise.allSettled(
3148
3238
  symbols.map(
3149
- (symbol) => coinlist.swap.getTokenBalance({
3239
+ (symbol) => coinlist.erc20.getTokenBalance({
3150
3240
  tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),
3151
3241
  owner: address,
3152
3242
  chain
@@ -3298,7 +3388,7 @@ function useParticipations(offerId, options = {}) {
3298
3388
  };
3299
3389
  }
3300
3390
  setParticipationsState(LOADING_STATE8);
3301
- coinlist.fetchParticipations(offerId).then((participations) => {
3391
+ coinlist.tokenSale.fetchParticipations(offerId).then((participations) => {
3302
3392
  if (!isCancelled) {
3303
3393
  setParticipationsState({ type: "CONTENT", participations });
3304
3394
  }
@@ -3317,6 +3407,7 @@ function useParticipations(offerId, options = {}) {
3317
3407
  export {
3318
3408
  ChecklistStatus,
3319
3409
  ClientSwapNamespaceImpl,
3410
+ ClientTokenSaleNamespaceImpl,
3320
3411
  CoinListClientInitializationError,
3321
3412
  CoinListContext,
3322
3413
  CoinListContextProvider,
@@ -3343,6 +3434,7 @@ export {
3343
3434
  connectExternalWalletFlow,
3344
3435
  createCoinListClient,
3345
3436
  executeSwap,
3437
+ executeTokenSale,
3346
3438
  useCoinList,
3347
3439
  useCompleteOAuth,
3348
3440
  useConnectWallet,