@0xsequence/marketplace-sdk 0.3.2 → 0.3.4

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 (139) hide show
  1. package/dist/{chunk-NII6JJGH.js → chunk-3CXEYH2I.js} +5 -3
  2. package/dist/chunk-3CXEYH2I.js.map +1 -0
  3. package/dist/{chunk-GJAKQ5Q3.js → chunk-53Q7BNZH.js} +8 -2
  4. package/dist/chunk-53Q7BNZH.js.map +1 -0
  5. package/dist/{chunk-O7UQGT43.js → chunk-6LQST3KZ.js} +553 -283
  6. package/dist/chunk-6LQST3KZ.js.map +1 -0
  7. package/dist/{chunk-GZG2QO64.js → chunk-D3HRXVYJ.js} +72 -21
  8. package/dist/chunk-D3HRXVYJ.js.map +1 -0
  9. package/dist/{chunk-4YU2UPYH.js → chunk-FFCNYF3S.js} +61 -61
  10. package/dist/chunk-FFCNYF3S.js.map +1 -0
  11. package/dist/chunk-G2FYRJMK.js +38 -0
  12. package/dist/chunk-G2FYRJMK.js.map +1 -0
  13. package/dist/{chunk-WA433WAJ.js → chunk-L6GSYPCR.js} +20 -6
  14. package/dist/chunk-L6GSYPCR.js.map +1 -0
  15. package/dist/{chunk-SPW24Y7I.js → chunk-OUZ42I6B.js} +7 -2
  16. package/dist/chunk-OUZ42I6B.js.map +1 -0
  17. package/dist/{chunk-22NLQ3AS.js → chunk-PMDJARYX.js} +1081 -980
  18. package/dist/chunk-PMDJARYX.js.map +1 -0
  19. package/dist/chunk-T2AMWIKD.js +277 -0
  20. package/dist/chunk-T2AMWIKD.js.map +1 -0
  21. package/dist/{chunk-G33554LK.js → chunk-WQCWBXBM.js} +8 -16
  22. package/dist/chunk-WQCWBXBM.js.map +1 -0
  23. package/dist/index.css +40 -0
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +172 -71
  26. package/dist/index.js.map +1 -1
  27. package/dist/{marketplace.gen-BLP7822q.d.ts → marketplace.gen-jdKqutnd.d.ts} +57 -18
  28. package/dist/react/_internal/api/index.d.ts +4 -2
  29. package/dist/react/_internal/api/index.js +8 -3
  30. package/dist/react/_internal/index.d.ts +3 -3
  31. package/dist/react/_internal/index.js +9 -4
  32. package/dist/react/_internal/wagmi/index.js +2 -1
  33. package/dist/react/hooks/index.d.ts +285 -12
  34. package/dist/react/hooks/index.js +14 -5
  35. package/dist/react/index.css +29 -29
  36. package/dist/react/index.css.map +1 -1
  37. package/dist/react/index.d.ts +4 -4
  38. package/dist/react/index.js +17 -8
  39. package/dist/react/ssr/index.js +55 -4
  40. package/dist/react/ssr/index.js.map +1 -1
  41. package/dist/react/ui/components/index.css +13 -13
  42. package/dist/react/ui/components/index.css.map +1 -1
  43. package/dist/react/ui/components/index.d.ts +3 -3
  44. package/dist/react/ui/components/index.js +9 -8
  45. package/dist/react/ui/icons/index.js +1 -1
  46. package/dist/react/ui/icons/index.js.map +1 -1
  47. package/dist/react/ui/index.css +29 -29
  48. package/dist/react/ui/index.css.map +1 -1
  49. package/dist/react/ui/index.d.ts +3 -3
  50. package/dist/react/ui/index.js +9 -8
  51. package/dist/react/ui/modals/_internal/components/actionModal/index.js +3 -2
  52. package/dist/react/ui/styles/index.d.ts +1 -1
  53. package/dist/{services-C9-lvWcC.d.ts → services-C2O-7p_M.d.ts} +2 -2
  54. package/dist/styles/index.css +40 -0
  55. package/dist/styles/index.css.map +1 -1
  56. package/dist/styles/index.d.ts +9 -2
  57. package/dist/styles/index.js +14 -2
  58. package/dist/types/index.d.ts +2 -2
  59. package/dist/types/index.js +3 -2
  60. package/dist/{types-QqXjNuUP.d.ts → types-BlDoGvJV.d.ts} +1 -1
  61. package/dist/utils/index.d.ts +2 -2
  62. package/dist/utils/index.js +2 -1
  63. package/package.json +18 -15
  64. package/src/react/_internal/api/marketplace.gen.ts +85 -20
  65. package/src/react/_internal/api/query-keys.ts +2 -0
  66. package/src/react/_internal/api/services.ts +4 -3
  67. package/src/react/_internal/api/zod-schema.ts +20 -0
  68. package/src/react/_internal/transaction-machine/execute-transaction.ts +311 -224
  69. package/src/react/_internal/transaction-machine/logger.ts +66 -0
  70. package/src/react/_internal/transaction-machine/useTransactionMachine.ts +69 -19
  71. package/src/react/_internal/wagmi/embedded.ts +2 -2
  72. package/src/react/hooks/index.ts +2 -0
  73. package/src/react/hooks/options/marketplaceConfigOptions.ts +6 -2
  74. package/src/react/hooks/useBuyCollectable.tsx +14 -8
  75. package/src/react/hooks/useCancelOrder.tsx +4 -3
  76. package/src/react/hooks/useCheckoutOptions.tsx +2 -2
  77. package/src/react/hooks/useConfig.tsx +2 -3
  78. package/src/react/hooks/useCountListingsForCollectible.tsx +64 -0
  79. package/src/react/hooks/useCountOffersForCollectible.tsx +64 -0
  80. package/src/react/hooks/useCreateListing.tsx +13 -14
  81. package/src/react/hooks/useCurrencies.tsx +9 -8
  82. package/src/react/hooks/useCurrency.tsx +6 -6
  83. package/src/react/hooks/useGenerateBuyTransaction.tsx +3 -3
  84. package/src/react/hooks/useMakeOffer.tsx +14 -13
  85. package/src/react/hooks/useRoyaltyPercentage.tsx +1 -1
  86. package/src/react/hooks/useSell.tsx +12 -12
  87. package/src/react/hooks/useTransferTokens.tsx +2 -1
  88. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +3 -2
  89. package/src/react/ui/components/_internals/custom-select/CustomSelect.tsx +4 -4
  90. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +2 -2
  91. package/src/react/ui/components/collectible-card/Footer.tsx +33 -29
  92. package/src/react/ui/icons/ArrowUp.tsx +1 -1
  93. package/src/react/ui/modals/BuyModal/_store.ts +8 -6
  94. package/src/react/ui/modals/BuyModal/index.tsx +120 -81
  95. package/src/react/ui/modals/CreateListingModal/_store.ts +1 -0
  96. package/src/react/ui/modals/CreateListingModal/index.tsx +34 -14
  97. package/src/react/ui/modals/MakeOfferModal/_store.ts +2 -0
  98. package/src/react/ui/modals/MakeOfferModal/index.tsx +21 -11
  99. package/src/react/ui/modals/SellModal/index.tsx +21 -13
  100. package/src/react/ui/modals/SuccessfulPurchaseModal/_store.ts +1 -1
  101. package/src/react/ui/modals/SuccessfulPurchaseModal/index.tsx +1 -1
  102. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/index.tsx +12 -7
  103. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +2 -1
  104. package/src/react/ui/modals/TransferModal/_views/followWalletInstructions/index.tsx +2 -2
  105. package/src/react/ui/modals/TransferModal/styles.css.ts +1 -1
  106. package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +1 -1
  107. package/src/react/ui/modals/_internal/components/actionModal/LoadingModal.tsx +1 -1
  108. package/src/react/ui/modals/_internal/components/alertMessage/index.tsx +7 -2
  109. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +2 -7
  110. package/src/react/ui/modals/_internal/components/expirationDateSelect/index.tsx +2 -1
  111. package/src/react/ui/modals/_internal/components/floorPriceText/index.tsx +1 -0
  112. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +42 -102
  113. package/src/react/ui/modals/_internal/components/switchChainModal/styles.css.ts +1 -1
  114. package/src/react/ui/modals/_internal/components/timeAgo/index.tsx +1 -1
  115. package/src/react/ui/modals/_internal/components/tokenPreview/index.tsx +1 -1
  116. package/src/react/ui/modals/_internal/components/transaction-footer/index.tsx +32 -11
  117. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +2 -2
  118. package/src/react/ui/modals/_internal/components/transactionHeader/index.tsx +14 -2
  119. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +17 -5
  120. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +12 -4
  121. package/src/react/ui/modals/_internal/components/transactionStatusModal/styles.css.ts +1 -1
  122. package/src/react/ui/modals/modal-provider.tsx +3 -3
  123. package/src/styles/index.ts +3 -0
  124. package/src/utils/_internal/error/base.ts +32 -0
  125. package/src/utils/_internal/error/context.ts +13 -0
  126. package/src/utils/_internal/error/transaction.ts +369 -0
  127. package/src/utils/get-public-rpc-client.ts +4 -1
  128. package/tsconfig.tsbuildinfo +1 -1
  129. package/tsup.config.ts +3 -0
  130. package/dist/chess-tile-6BS5MQT5.png +0 -0
  131. package/dist/chunk-22NLQ3AS.js.map +0 -1
  132. package/dist/chunk-4YU2UPYH.js.map +0 -1
  133. package/dist/chunk-G33554LK.js.map +0 -1
  134. package/dist/chunk-GJAKQ5Q3.js.map +0 -1
  135. package/dist/chunk-GZG2QO64.js.map +0 -1
  136. package/dist/chunk-NII6JJGH.js.map +0 -1
  137. package/dist/chunk-O7UQGT43.js.map +0 -1
  138. package/dist/chunk-SPW24Y7I.js.map +0 -1
  139. package/dist/chunk-WA433WAJ.js.map +0 -1
@@ -7,12 +7,13 @@ import type {
7
7
  TypedDataDomain,
8
8
  WalletClient,
9
9
  } from 'viem';
10
- import { avalanche } from 'viem/chains';
10
+ import { avalanche, optimism } from 'viem/chains';
11
11
  import {
12
12
  type AdditionalFee,
13
13
  type SequenceMarketplace,
14
14
  TransactionSwapProvider,
15
15
  type WalletKind,
16
+ WebrpcError,
16
17
  getMarketplaceClient,
17
18
  } from '..';
18
19
  import {
@@ -26,6 +27,29 @@ import {
26
27
  type Step,
27
28
  StepType,
28
29
  } from '../../../types';
30
+ import {
31
+ ChainIdUnavailableError,
32
+ ChainSwitchError,
33
+ CheckoutOptionsError,
34
+ InvalidSignatureStepError,
35
+ MissingPostStepError,
36
+ MissingSignatureDataError,
37
+ MissingStepDataError,
38
+ NoExecutionStepError,
39
+ NoStepsFoundError,
40
+ NoWalletConnectedError,
41
+ OrderNotFoundError,
42
+ OrdersFetchError,
43
+ PaymentModalError,
44
+ PaymentModalTransactionError,
45
+ StepExecutionError,
46
+ StepGenerationError,
47
+ TransactionError,
48
+ TransactionReceiptError,
49
+ UnexpectedStepsError,
50
+ UnknownTransactionTypeError,
51
+ } from '../../../utils/_internal/error/transaction';
52
+ import { type TransactionLogger, createLogger } from './logger';
29
53
 
30
54
  export enum TransactionState {
31
55
  IDLE = 'IDLE',
@@ -60,7 +84,6 @@ interface StateConfig {
60
84
  config: TransactionConfig;
61
85
  onTransactionSent?: (hash: Hash) => void;
62
86
  onSuccess?: (hash: Hash) => void;
63
- onError?: (error: Error) => void;
64
87
  }
65
88
 
66
89
  export interface BuyInput {
@@ -91,6 +114,13 @@ export interface CancelInput {
91
114
  marketplace: MarketplaceKind;
92
115
  }
93
116
 
117
+ export type Input =
118
+ | BuyInput
119
+ | SellInput
120
+ | ListingInput
121
+ | OfferInput
122
+ | CancelInput;
123
+
94
124
  type TransactionInput =
95
125
  | {
96
126
  type: TransactionType.BUY;
@@ -113,13 +143,6 @@ type TransactionInput =
113
143
  props: CancelInput;
114
144
  };
115
145
 
116
- interface StateConfig {
117
- config: TransactionConfig;
118
- onTransactionSent?: (hash: Hash) => void;
119
- onSuccess?: (hash: Hash) => void;
120
- onError?: (error: Error) => void;
121
- }
122
-
123
146
  interface TransactionStep {
124
147
  isPending: boolean;
125
148
  isExecuting: boolean;
@@ -140,15 +163,12 @@ export interface TransactionSteps {
140
163
  };
141
164
  }
142
165
 
143
- const debug = (message: string, data?: any) => {
144
- console.debug(`[TransactionMachine] ${message}`, data || '');
145
- };
146
-
147
166
  export class TransactionMachine {
148
167
  private currentState: TransactionState;
168
+ private readonly logger: TransactionLogger;
149
169
  private marketplaceClient: SequenceMarketplace;
150
170
  private memoizedSteps: TransactionSteps | null = null;
151
- private lastProps: TransactionInput['props'] | null = null;
171
+ private lastProps: Input | null = null;
152
172
 
153
173
  constructor(
154
174
  private readonly config: StateConfig,
@@ -160,6 +180,7 @@ export class TransactionMachine {
160
180
  private readonly switchChainFn: (chainId: string) => Promise<void>,
161
181
  ) {
162
182
  this.currentState = TransactionState.IDLE;
183
+ this.logger = createLogger('TransactionMachine');
163
184
  this.marketplaceClient = getMarketplaceClient(
164
185
  config.config.chainId,
165
186
  config.config.sdkConfig,
@@ -169,7 +190,7 @@ export class TransactionMachine {
169
190
  private getAccount() {
170
191
  const account = this.walletClient.account;
171
192
  if (!account) {
172
- throw new Error('Account not connected');
193
+ throw new NoWalletConnectedError();
173
194
  }
174
195
  return account;
175
196
  }
@@ -187,10 +208,11 @@ export class TransactionMachine {
187
208
  this.getChainId() === Number(collection.chainId),
188
209
  );
189
210
 
190
- const receiver =
191
- this.getChainId() === avalanche.id
192
- ? avalancheAndOptimismPlatformFeeRecipient
193
- : defaultPlatformFeeRecipient;
211
+ const avalancheOrOptimism =
212
+ this.getChainId() === avalanche.id || this.getChainId() === optimism.id;
213
+ const receiver = avalancheOrOptimism
214
+ ? avalancheAndOptimismPlatformFeeRecipient
215
+ : defaultPlatformFeeRecipient;
194
216
 
195
217
  const percentageToBPS = (percentage: string | number) =>
196
218
  (Number(percentage) * 10000) / 100;
@@ -211,97 +233,108 @@ export class TransactionMachine {
211
233
  type,
212
234
  props,
213
235
  }: TransactionInput): Promise<Step[]> {
214
- debug('Generating steps', { type, props });
236
+ this.logger.debug('Generating steps', { type, props });
215
237
  const { collectionAddress } = this.config.config;
216
238
  const address = this.getAccountAddress();
217
- switch (type) {
218
- case TransactionType.BUY:
219
- return this.marketplaceClient
220
- .generateBuyTransaction({
221
- collectionAddress,
222
- buyer: address,
223
- walletType: this.config.config.walletKind,
224
- marketplace: props.marketplace,
225
- ordersData: [
226
- {
227
- orderId: props.orderId,
228
- quantity: props.quantity || '1',
229
- },
230
- ],
231
- additionalFees: [this.getMarketplaceFee(collectionAddress)],
232
- })
233
- .then((resp) => resp.steps);
234
-
235
- case TransactionType.SELL:
236
- return this.marketplaceClient
237
- .generateSellTransaction({
238
- collectionAddress,
239
- seller: address,
240
- walletType: this.config.config.walletKind,
241
- marketplace: props.marketplace,
242
- ordersData: [
243
- {
244
- orderId: props.orderId,
245
- quantity: props.quantity || '1',
246
- },
247
- ],
248
- additionalFees: [],
249
- })
250
- .then((resp) => resp.steps);
251
-
252
- case TransactionType.LISTING:
253
- return this.marketplaceClient
254
- .generateListingTransaction({
255
- collectionAddress,
256
- owner: address,
257
- walletType: this.config.config.walletKind,
258
- contractType: props.contractType,
259
- orderbook: OrderbookKind.sequence_marketplace_v2,
260
- listing: props.listing,
261
- })
262
- .then((resp) => resp.steps);
263
-
264
- case TransactionType.OFFER:
265
- return this.marketplaceClient
266
- .generateOfferTransaction({
267
- collectionAddress,
268
- maker: address,
269
- walletType: this.config.config.walletKind,
270
- contractType: props.contractType,
271
- orderbook: OrderbookKind.sequence_marketplace_v2,
272
- offer: props.offer,
273
- })
274
- .then((resp) => resp.steps);
275
-
276
- case TransactionType.CANCEL:
277
- return this.marketplaceClient
278
- .generateCancelTransaction({
279
- collectionAddress,
280
- maker: address,
281
- marketplace: props.marketplace,
282
- orderId: props.orderId,
283
- })
284
- .then((resp) => resp.steps);
285
239
 
286
- default:
287
- throw new Error(`Unknown transaction type: ${type}`);
240
+ try {
241
+ switch (type) {
242
+ case TransactionType.BUY:
243
+ return await this.marketplaceClient
244
+ .generateBuyTransaction({
245
+ collectionAddress,
246
+ buyer: address,
247
+ walletType: this.config.config.walletKind,
248
+ marketplace: props.marketplace,
249
+ ordersData: [
250
+ {
251
+ orderId: props.orderId,
252
+ quantity: props.quantity || '1',
253
+ },
254
+ ],
255
+ additionalFees: [this.getMarketplaceFee(collectionAddress)],
256
+ })
257
+ .then((resp) => resp.steps);
258
+
259
+ case TransactionType.SELL:
260
+ return await this.marketplaceClient
261
+ .generateSellTransaction({
262
+ collectionAddress,
263
+ seller: address,
264
+ walletType: this.config.config.walletKind,
265
+ marketplace: props.marketplace,
266
+ ordersData: [
267
+ {
268
+ orderId: props.orderId,
269
+ quantity: props.quantity || '1',
270
+ },
271
+ ],
272
+ additionalFees: [],
273
+ })
274
+ .then((resp) => resp.steps);
275
+
276
+ case TransactionType.LISTING:
277
+ return await this.marketplaceClient
278
+ .generateListingTransaction({
279
+ collectionAddress,
280
+ owner: address,
281
+ walletType: this.config.config.walletKind,
282
+ contractType: props.contractType,
283
+ orderbook: OrderbookKind.sequence_marketplace_v2,
284
+ listing: props.listing,
285
+ })
286
+ .then((resp) => resp.steps);
287
+
288
+ case TransactionType.OFFER:
289
+ return await this.marketplaceClient
290
+ .generateOfferTransaction({
291
+ collectionAddress,
292
+ maker: address,
293
+ walletType: this.config.config.walletKind,
294
+ contractType: props.contractType,
295
+ orderbook: OrderbookKind.sequence_marketplace_v2,
296
+ offer: props.offer,
297
+ })
298
+ .then((resp) => resp.steps);
299
+
300
+ case TransactionType.CANCEL:
301
+ return await this.marketplaceClient
302
+ .generateCancelTransaction({
303
+ collectionAddress,
304
+ maker: address,
305
+ marketplace: props.marketplace,
306
+ orderId: props.orderId,
307
+ })
308
+ .then((resp) => resp.steps);
309
+ default:
310
+ throw new UnknownTransactionTypeError(type);
311
+ }
312
+ } catch (error) {
313
+ if (error instanceof WebrpcError) {
314
+ throw new StepGenerationError(type, error);
315
+ }
316
+ throw error;
288
317
  }
289
318
  }
290
319
 
291
320
  private clearMemoizedSteps() {
292
- debug('Clearing memoized steps');
321
+ this.logger.debug('Clearing memoized steps');
293
322
  this.memoizedSteps = null;
294
323
  this.lastProps = null;
295
324
  }
296
325
 
297
326
  private async transition(newState: TransactionState) {
298
- debug(`State transition: ${this.currentState} -> ${newState}`);
327
+ this.logger.state(this.currentState, newState);
299
328
  this.currentState = newState;
300
329
  this.clearMemoizedSteps();
301
330
  }
302
331
 
303
- private getChainId() {
304
- return this.walletClient.chain?.id;
332
+ private getChainId(): number {
333
+ const chainId = this.walletClient.chain?.id;
334
+ if (!chainId) {
335
+ throw new ChainIdUnavailableError();
336
+ }
337
+ return chainId;
305
338
  }
306
339
 
307
340
  private getChainForTransaction() {
@@ -316,42 +349,44 @@ export class TransactionMachine {
316
349
  }
317
350
 
318
351
  private async switchChain(): Promise<void> {
352
+ this.logger.debug('Checking chain', {
353
+ currentChain: this.getChainId(),
354
+ targetChain: Number(this.config.config.chainId),
355
+ });
356
+
319
357
  if (!this.isOnCorrectChain()) {
358
+ const currentChain = this.getChainId();
359
+ const targetChain = Number(this.config.config.chainId);
360
+
320
361
  await this.transition(TransactionState.SWITCH_CHAIN);
321
- await this.switchChainFn(this.config.config.chainId);
322
- await this.walletClient.switchChain({
323
- id: Number(this.config.config.chainId),
324
- });
325
- debug('Switched chain');
362
+ try {
363
+ await this.switchChainFn(this.config.config.chainId);
364
+ await this.walletClient.switchChain({
365
+ id: Number(this.config.config.chainId),
366
+ });
367
+ this.logger.debug('Switched chain');
368
+ } catch (error) {
369
+ throw new ChainSwitchError(currentChain, targetChain);
370
+ }
326
371
  }
327
372
  }
328
373
 
329
- async start({ props }: { props: TransactionInput['props'] }) {
330
- debug('Starting transaction', props);
331
- try {
332
- await this.transition(TransactionState.CHECKING_STEPS);
333
- const { type } = this.config.config;
334
-
335
- const steps = await this.generateSteps({
336
- type,
337
- props,
338
- } as TransactionInput);
339
-
340
- for (const step of steps) {
341
- try {
342
- await this.executeStep({ step, props });
343
- } catch (error) {
344
- await this.transition(TransactionState.ERROR);
345
- throw error;
346
- }
347
- }
374
+ async start(props: Input) {
375
+ this.logger.debug('Starting transaction', props);
348
376
 
349
- await this.transition(TransactionState.SUCCESS);
350
- } catch (error) {
351
- debug('Transaction failed', error);
352
- await this.transition(TransactionState.ERROR);
353
- throw error;
377
+ await this.transition(TransactionState.CHECKING_STEPS);
378
+ const { type } = this.config.config;
379
+
380
+ const steps = await this.generateSteps({
381
+ type,
382
+ props,
383
+ } as TransactionInput);
384
+
385
+ for (const step of steps) {
386
+ await this.executeStep({ step, props });
354
387
  }
388
+
389
+ await this.transition(TransactionState.SUCCESS);
355
390
  }
356
391
 
357
392
  private async handleTransactionSuccess(hash?: Hash) {
@@ -363,39 +398,53 @@ export class TransactionMachine {
363
398
  await this.transition(TransactionState.CONFIRMING);
364
399
  this.config.onTransactionSent?.(hash);
365
400
 
366
- const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
367
- debug('Transaction confirmed', receipt);
401
+ try {
402
+ const receipt = await this.publicClient.waitForTransactionReceipt({
403
+ hash,
404
+ });
405
+ this.logger.debug('Transaction confirmed', receipt);
368
406
 
369
- await this.transition(TransactionState.SUCCESS);
370
- this.config.onSuccess?.(hash);
407
+ await this.transition(TransactionState.SUCCESS);
408
+ this.config.onSuccess?.(hash);
409
+ } catch (error) {
410
+ throw new TransactionReceiptError(hash, error as Error);
411
+ }
371
412
  }
372
413
 
373
414
  private async executeTransaction(step: Step): Promise<Hash> {
374
- const transactionData = {
375
- account: this.getAccount(),
376
- chain: this.getChainForTransaction(),
377
- to: step.to as Hex,
378
- data: step.data as Hex,
379
- value: BigInt(step.value || '0'),
380
- };
381
- debug('Executing transaction', transactionData);
382
- const hash = await this.walletClient.sendTransaction(transactionData);
383
- debug('Transaction submitted', { hash });
384
- await this.handleTransactionSuccess(hash);
385
- return hash;
415
+ try {
416
+ const transactionData = {
417
+ account: this.getAccount(),
418
+ chain: this.getChainForTransaction(),
419
+ to: step.to as Hex,
420
+ data: step.data as Hex,
421
+ value: BigInt(step.value || '0'),
422
+ };
423
+
424
+ this.logger.debug('Executing transaction', transactionData);
425
+ const hash = await this.walletClient.sendTransaction(transactionData);
426
+ this.logger.debug('Transaction submitted', { hash });
427
+
428
+ await this.handleTransactionSuccess(hash);
429
+ return hash;
430
+ } catch (error) {
431
+ throw new StepExecutionError(step.id, error as Error);
432
+ }
386
433
  }
387
434
 
388
435
  private async executeSignature(step: Step) {
389
- debug('Executing signature', { stepId: step.id });
390
- let signature: Hex;
436
+ this.logger.debug('Executing signature', { stepId: step.id });
391
437
  if (!step.post) {
392
- throw new Error('Missing post step');
438
+ throw new MissingPostStepError();
393
439
  }
440
+
441
+ let signature: Hex;
442
+ if (!step.signature) {
443
+ throw new MissingSignatureDataError();
444
+ }
445
+
394
446
  switch (step.id) {
395
447
  case StepType.signEIP712:
396
- if (!step.signature) {
397
- throw new Error('Missing signature data');
398
- }
399
448
  signature = await this.walletClient.signTypedData({
400
449
  domain: step.signature.domain as TypedDataDomain,
401
450
  types: step.signature.types,
@@ -411,7 +460,7 @@ export class TransactionMachine {
411
460
  });
412
461
  break;
413
462
  default:
414
- throw new Error(`Invalid signature step: ${step.id}`);
463
+ throw new InvalidSignatureStepError(step.id);
415
464
  }
416
465
 
417
466
  await this.marketplaceClient.execute({
@@ -429,12 +478,15 @@ export class TransactionMachine {
429
478
  this.openSelectPaymentModal({
430
479
  ...settings,
431
480
  onSuccess: async (hash: string) => {
432
- await this.handleTransactionSuccess(hash as Hash);
433
- resolve();
481
+ try {
482
+ await this.handleTransactionSuccess(hash as Hash);
483
+ resolve();
484
+ } catch (error) {
485
+ reject(error);
486
+ }
434
487
  },
435
488
  onError: (error: Error) => {
436
- this.config.onError?.(error);
437
- reject(error);
489
+ reject(new PaymentModalError(error));
438
490
  },
439
491
  });
440
492
  });
@@ -447,56 +499,85 @@ export class TransactionMachine {
447
499
  step: Step;
448
500
  props: BuyInput;
449
501
  }) {
450
- this.transition(TransactionState.EXECUTING_TRANSACTION);
451
- const [checkoutOptions, orders] = await Promise.all([
452
- this.marketplaceClient.checkoutOptionsMarketplace({
453
- wallet: this.getAccountAddress(),
454
- orders: [
455
- {
456
- contractAddress: this.config.config.collectionAddress,
457
- orderId: props.orderId,
458
- marketplace: props.marketplace,
459
- },
460
- ],
461
- additionalFee: Number(
462
- this.getMarketplaceFee(this.config.config.collectionAddress).amount,
463
- ),
464
- }),
465
- this.marketplaceClient.getOrders({
466
- input: [
467
- {
468
- orderId: props.orderId,
469
- marketplace: props.marketplace,
470
- contractAddress: this.config.config.collectionAddress,
471
- },
472
- ],
473
- }),
474
- ]);
475
-
476
- const order = orders.orders[0];
477
-
478
- await this.openPaymentModalWithPromise({
479
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
480
- chain: this.getChainId()!,
481
- collectibles: [
482
- {
483
- tokenId: order.tokenId,
484
- quantity: props.quantity,
485
- decimals: props.collectableDecimals,
486
- },
487
- ],
488
- currencyAddress: order.priceCurrencyAddress,
489
- price: order.priceAmount,
490
- targetContractAddress: step.to,
491
- txData: step.data as Hex,
492
- collectionAddress: this.config.config.collectionAddress,
493
- recipientAddress: this.getAccountAddress(),
494
- enableMainCurrencyPayment: true,
495
- enableSwapPayments: !!checkoutOptions.options?.swap?.includes(
496
- TransactionSwapProvider.zerox,
497
- ),
498
- creditCardProviders: checkoutOptions?.options.nftCheckout || [],
499
- });
502
+ try {
503
+ await this.transition(TransactionState.EXECUTING_TRANSACTION);
504
+
505
+ try {
506
+ const [checkoutOptions, orders] = await Promise.all([
507
+ this.marketplaceClient
508
+ .checkoutOptionsMarketplace({
509
+ wallet: this.getAccountAddress(),
510
+ orders: [
511
+ {
512
+ contractAddress: this.config.config.collectionAddress,
513
+ orderId: props.orderId,
514
+ marketplace: props.marketplace,
515
+ },
516
+ ],
517
+ additionalFee: Number(
518
+ this.getMarketplaceFee(this.config.config.collectionAddress)
519
+ .amount,
520
+ ),
521
+ })
522
+ .catch((error) => {
523
+ throw new CheckoutOptionsError(error);
524
+ }),
525
+ this.marketplaceClient
526
+ .getOrders({
527
+ input: [
528
+ {
529
+ orderId: props.orderId,
530
+ marketplace: props.marketplace,
531
+ contractAddress: this.config.config.collectionAddress,
532
+ },
533
+ ],
534
+ })
535
+ .catch((error) => {
536
+ throw new OrdersFetchError(props.orderId, error);
537
+ }),
538
+ ]);
539
+
540
+ const order = orders.orders[0];
541
+ if (!order) {
542
+ throw new OrderNotFoundError(props.orderId);
543
+ }
544
+
545
+ const paymentModalProps = {
546
+ chain: this.getChainId()!,
547
+ collectibles: [
548
+ {
549
+ tokenId: order.tokenId,
550
+ quantity: props.quantity,
551
+ decimals: props.collectableDecimals,
552
+ },
553
+ ],
554
+ currencyAddress: order.priceCurrencyAddress,
555
+ price: order.priceAmount,
556
+ targetContractAddress: step.to,
557
+ txData: step.data as Hex,
558
+ collectionAddress: this.config.config.collectionAddress,
559
+ recipientAddress: this.getAccountAddress(),
560
+ enableMainCurrencyPayment: true,
561
+ enableSwapPayments: !!checkoutOptions.options?.swap?.includes(
562
+ TransactionSwapProvider.zerox,
563
+ ),
564
+ creditCardProviders: checkoutOptions?.options.nftCheckout || [],
565
+ };
566
+
567
+ this.logger.debug('Opening payment modal', paymentModalProps);
568
+ await this.openPaymentModalWithPromise(paymentModalProps);
569
+ } catch (error) {
570
+ if (error instanceof TransactionError) {
571
+ throw error;
572
+ }
573
+ throw new PaymentModalTransactionError(step.id, error as Error);
574
+ }
575
+ } catch (error) {
576
+ if (error instanceof TransactionError) {
577
+ throw error;
578
+ }
579
+ throw new StepExecutionError(step.id, error as Error);
580
+ }
500
581
  }
501
582
 
502
583
  private async executeStep({
@@ -506,43 +587,49 @@ export class TransactionMachine {
506
587
  step: Step;
507
588
  props: TransactionInput['props'];
508
589
  }) {
509
- debug('Executing step', { stepId: step.id });
510
- if (!step.to && !step.signature) {
511
- throw new Error('Invalid step data');
512
- }
513
-
514
590
  try {
591
+ this.logger.debug('Executing step', { stepId: step.id });
592
+
593
+ if (!step.to && !step.signature) {
594
+ throw new MissingStepDataError();
595
+ }
596
+
515
597
  await this.switchChain();
598
+
516
599
  if (step.id === StepType.buy) {
517
600
  await this.executeBuyStep({ step, props: props as BuyInput });
518
- } else if (step.signature) {
601
+ return;
602
+ }
603
+
604
+ if (step.signature) {
519
605
  await this.executeSignature(step);
520
- } else if (step.id === StepType.tokenApproval) {
521
- //TODO: Add some sort ofs callback heres
522
- const hash = await this.executeTransaction(step);
523
- return { hash }
524
- } else {
525
- const hash = await this.executeTransaction(step);
606
+ return;
607
+ }
608
+
609
+ const hash = await this.executeTransaction(step);
610
+
611
+ if (step.id !== StepType.tokenApproval) {
526
612
  this.config.onSuccess?.(hash);
527
- return { hash };
528
613
  }
614
+
615
+ return { hash };
529
616
  } catch (error) {
530
- this.config.onError?.(error as Error);
531
- throw error;
617
+ if (error instanceof TransactionError) {
618
+ throw error;
619
+ }
620
+ throw new StepExecutionError(step.id, error as Error);
532
621
  }
533
622
  }
534
623
 
535
- async getTransactionSteps(
536
- props: TransactionInput['props'],
537
- ): Promise<TransactionSteps> {
538
- debug('Getting transaction steps', props);
624
+ async getTransactionSteps(props: Input): Promise<TransactionSteps> {
625
+ this.logger.debug('Getting transaction steps', props);
539
626
  // Return memoized value if props and state haven't changed
540
627
  if (
541
628
  this.memoizedSteps &&
542
629
  this.lastProps &&
543
630
  JSON.stringify(props) === JSON.stringify(this.lastProps)
544
631
  ) {
545
- debug('Returning memoized steps');
632
+ this.logger.debug('Returning memoized steps');
546
633
  return this.memoizedSteps;
547
634
  }
548
635
 
@@ -554,15 +641,15 @@ export class TransactionMachine {
554
641
  // Extract execution step, it should always be the last step
555
642
  const executionStep = steps.pop();
556
643
  if (!executionStep) {
557
- throw new Error('No steps found');
644
+ throw new NoStepsFoundError();
558
645
  }
559
646
  if (executionStep.id === StepType.tokenApproval) {
560
- throw new Error('No execution step found, only approval step');
647
+ throw new NoExecutionStepError();
561
648
  }
562
649
  const approvalStep = steps.pop();
563
650
 
564
651
  if (steps.length > 0) {
565
- throw new Error('Unexpected steps found');
652
+ throw new UnexpectedStepsError();
566
653
  }
567
654
 
568
655
  this.lastProps = props;
@@ -586,7 +673,7 @@ export class TransactionMachine {
586
673
  },
587
674
  } as const;
588
675
 
589
- debug('Generated new transaction steps', this.memoizedSteps);
676
+ this.logger.debug('Generated new transaction steps', this.memoizedSteps);
590
677
  return this.memoizedSteps;
591
678
  }
592
679
  }