@rango-dev/queue-manager-rango-preset 0.1.10-next.101

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 (60) hide show
  1. package/dist/actions/checkStatus.d.ts +12 -0
  2. package/dist/actions/checkStatus.d.ts.map +1 -0
  3. package/dist/actions/createTransaction.d.ts +11 -0
  4. package/dist/actions/createTransaction.d.ts.map +1 -0
  5. package/dist/actions/executeTransaction.d.ts +13 -0
  6. package/dist/actions/executeTransaction.d.ts.map +1 -0
  7. package/dist/actions/scheduleNextStep.d.ts +13 -0
  8. package/dist/actions/scheduleNextStep.d.ts.map +1 -0
  9. package/dist/actions/start.d.ts +4 -0
  10. package/dist/actions/start.d.ts.map +1 -0
  11. package/dist/constants.d.ts +8 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/helpers.d.ts +197 -0
  14. package/dist/helpers.d.ts.map +1 -0
  15. package/dist/hooks.d.ts +19 -0
  16. package/dist/hooks.d.ts.map +1 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +8 -0
  20. package/dist/migration.d.ts +15 -0
  21. package/dist/migration.d.ts.map +1 -0
  22. package/dist/queue-manager-rango-preset.cjs.development.js +2799 -0
  23. package/dist/queue-manager-rango-preset.cjs.development.js.map +1 -0
  24. package/dist/queue-manager-rango-preset.cjs.production.min.js +2 -0
  25. package/dist/queue-manager-rango-preset.cjs.production.min.js.map +1 -0
  26. package/dist/queue-manager-rango-preset.esm.js +2781 -0
  27. package/dist/queue-manager-rango-preset.esm.js.map +1 -0
  28. package/dist/queueDef.d.ts +10 -0
  29. package/dist/queueDef.d.ts.map +1 -0
  30. package/dist/services/httpService.d.ts +3 -0
  31. package/dist/services/httpService.d.ts.map +1 -0
  32. package/dist/services/index.d.ts +2 -0
  33. package/dist/services/index.d.ts.map +1 -0
  34. package/dist/shared-errors.d.ts +25 -0
  35. package/dist/shared-errors.d.ts.map +1 -0
  36. package/dist/shared-sentry.d.ts +4 -0
  37. package/dist/shared-sentry.d.ts.map +1 -0
  38. package/dist/shared.d.ts +148 -0
  39. package/dist/shared.d.ts.map +1 -0
  40. package/dist/types.d.ts +48 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/package.json +62 -0
  43. package/readme.md +8 -0
  44. package/src/actions/checkStatus.ts +269 -0
  45. package/src/actions/createTransaction.ts +122 -0
  46. package/src/actions/executeTransaction.ts +121 -0
  47. package/src/actions/scheduleNextStep.ts +61 -0
  48. package/src/actions/start.ts +10 -0
  49. package/src/constants.ts +22 -0
  50. package/src/helpers.ts +1774 -0
  51. package/src/hooks.ts +76 -0
  52. package/src/index.ts +27 -0
  53. package/src/migration.ts +124 -0
  54. package/src/queueDef.ts +39 -0
  55. package/src/services/httpService.ts +7 -0
  56. package/src/services/index.ts +1 -0
  57. package/src/shared-errors.ts +160 -0
  58. package/src/shared-sentry.ts +24 -0
  59. package/src/shared.ts +342 -0
  60. package/src/types.ts +76 -0
package/src/hooks.ts ADDED
@@ -0,0 +1,76 @@
1
+ import { useManager } from '@rango-dev/queue-manager-react';
2
+ import { useEffect, useState } from 'react';
3
+ import {
4
+ checkWaitingForConnectWalletChange,
5
+ checkWaitingForNetworkChange,
6
+ retryOn,
7
+ } from './helpers';
8
+ import { migrated, migration } from './migration';
9
+ import { UseQueueManagerParams } from './types';
10
+
11
+ let isCalled = 0;
12
+
13
+ /**
14
+ *
15
+ * Runs a migration (old swaps from localstorage to queue manager's IndexedDB)
16
+ * It will be run only once on page load.
17
+ *
18
+ */
19
+ function useMigration(): {
20
+ status: boolean;
21
+ } {
22
+ const isMigrated = migrated();
23
+ const [status, setStatus] = useState<boolean>(isMigrated);
24
+
25
+ useEffect(() => {
26
+ (async () => {
27
+ // Preventing react to be called twice on Strict Mode (development)
28
+ if (isCalled) return;
29
+ isCalled = 1;
30
+
31
+ migration().finally(() => {
32
+ setStatus(true);
33
+ });
34
+ })();
35
+ }, []);
36
+
37
+ return {
38
+ status,
39
+ };
40
+ }
41
+
42
+ /**
43
+ *
44
+ * On initial load and also connect/disconnet we may need to update swap's notified message.
45
+ * And also if a new wallet is connected we will retry the queue to see we can resume it or not.
46
+ *
47
+ */
48
+ function useQueueManager(params: UseQueueManagerParams): void {
49
+ const { manager } = useManager();
50
+
51
+ useEffect(() => {
52
+ if (params.lastConnectedWallet) {
53
+ checkWaitingForConnectWalletChange({
54
+ evmChains: params.evmChains,
55
+ wallet_network: params.lastConnectedWallet,
56
+ manager,
57
+ notifier: params.notifier,
58
+ });
59
+ retryOn(params.lastConnectedWallet, params.notifier, manager);
60
+ }
61
+ }, [params.lastConnectedWallet]);
62
+
63
+ useEffect(() => {
64
+ if (params.disconnectedWallet) {
65
+ checkWaitingForNetworkChange(manager);
66
+
67
+ /*
68
+ We need to reset the state value, so if a wallet disconnected twice (after reconnect),
69
+ this effect will be run properly.
70
+ */
71
+ params.clearDisconnectedWallet();
72
+ }
73
+ }, [params.disconnectedWallet]);
74
+ }
75
+
76
+ export { useQueueManager, useMigration };
package/src/index.ts ADDED
@@ -0,0 +1,27 @@
1
+ export { PrettyError, prettifyErrorMessage } from './shared-errors';
2
+ export { SwapQueueContext, SwapStorage } from './types';
3
+ export {
4
+ PendingSwapWithQueueID,
5
+ getCurrentBlockchainOfOrNull,
6
+ getRelatedWalletOrNull,
7
+ getRelatedWallet,
8
+ MessageSeverity,
9
+ PendingSwapStep,
10
+ PendingSwapNetworkStatus,
11
+ PendingSwap,
12
+ EventType,
13
+ SwapProgressNotification,
14
+ } from './shared';
15
+ export {
16
+ updateSwapStatus,
17
+ checkWaitingForNetworkChange,
18
+ getCurrentStep,
19
+ getEvmProvider,
20
+ cancelSwap,
21
+ getRequiredWallet,
22
+ getRunningSwaps,
23
+ splitWalletNetwork,
24
+ resetRunningSwapNotifsOnPageLoad,
25
+ } from './helpers';
26
+ export { swapQueueDef } from './queueDef';
27
+ export { useMigration, useQueueManager } from './hooks';
@@ -0,0 +1,124 @@
1
+ import {
2
+ PersistedQueue,
3
+ Persistor,
4
+ Status,
5
+ DB_NAME,
6
+ } from '@rango-dev/queue-manager-core';
7
+ import { v4 as uuid } from 'uuid';
8
+ import { PendingSwap } from './shared';
9
+ import { SwapActionTypes } from './types';
10
+
11
+ const MIGRATED_KEY = 'migratedToQueueManager';
12
+
13
+ /**
14
+ *
15
+ * If `MIGRATED_KEY` is set, it means we already migrated data from localstorage.
16
+ *
17
+ */
18
+ function migrated(): boolean {
19
+ return !!window.localStorage.getItem(MIGRATED_KEY);
20
+ }
21
+
22
+ async function hasQueueManagerOnIDB(): Promise<boolean> {
23
+ try {
24
+ return (await (window.indexedDB as any).databases())
25
+ .map((db: any) => db.name)
26
+ .includes(DB_NAME);
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+
32
+ /**
33
+ *
34
+ * By calling this function, we first check if the data already migrated or not,
35
+ * If not, starting to migrating to IndexedDb with proper format that queue manager is understand.
36
+ *
37
+ */
38
+ async function migration(): Promise<boolean> {
39
+ const swapsFromStorage = window.localStorage.getItem('pendingSwaps');
40
+ const hasIndexDB = await hasQueueManagerOnIDB();
41
+
42
+ // For new users or already migrated.
43
+ if (!swapsFromStorage || migrated() || hasIndexDB) {
44
+ return true;
45
+ }
46
+
47
+ // For old users, but they didn't do any swaps yet.
48
+ const swaps: PendingSwap[] = JSON.parse(swapsFromStorage);
49
+ const convertedSwaps: PersistedQueue[] = [];
50
+
51
+ swaps.forEach((swap) => {
52
+ /*
53
+ For running task we need to add some more work
54
+ We need to create a queue task to be run and resume the running task from queue manager.
55
+ */
56
+ if (swap.status === 'running') {
57
+ const taskId = uuid();
58
+
59
+ const convertedSwap: PersistedQueue = {
60
+ id: swap.requestId,
61
+ createdAt: Number(swap.creationTime),
62
+ name: 'swap',
63
+ status: Status.RUNNING,
64
+ storage: {
65
+ swapDetails: swap,
66
+ },
67
+ state: {
68
+ status: Status.RUNNING,
69
+ activeTaskIndex: 0,
70
+ tasks: {
71
+ [taskId]: {
72
+ blockedFor: null,
73
+ status: Status.RUNNING,
74
+ },
75
+ },
76
+ },
77
+ tasks: [
78
+ {
79
+ id: taskId,
80
+ action: SwapActionTypes.SCHEDULE_NEXT_STEP,
81
+ },
82
+ ],
83
+ };
84
+ convertedSwaps.push(convertedSwap);
85
+ } else {
86
+ /*
87
+ * For failed or successful swaps, we only move it to IndexedDB,
88
+ * And there is no need to consider them to be run.
89
+ */
90
+ const status = swap.status === 'success' ? Status.SUCCESS : Status.FAILED;
91
+
92
+ const convertedSwap: PersistedQueue = {
93
+ id: swap.requestId,
94
+ createdAt: Number(swap.creationTime),
95
+ name: 'swap',
96
+ status,
97
+ storage: {
98
+ swapDetails: swap,
99
+ },
100
+ state: {
101
+ status,
102
+ activeTaskIndex: 0,
103
+ tasks: {},
104
+ },
105
+ tasks: [],
106
+ };
107
+
108
+ convertedSwaps.push(convertedSwap);
109
+ }
110
+ });
111
+
112
+ // Getting an instance from persistor, so we can directly put our data inside it.
113
+ const persistor = new Persistor();
114
+
115
+ const promises = convertedSwaps.map((queue) => persistor.insertQueue(queue));
116
+ await Promise.all(promises);
117
+
118
+ // Mark as the data has been successfully migrated.
119
+ window.localStorage.setItem(MIGRATED_KEY, '1');
120
+
121
+ return true;
122
+ }
123
+
124
+ export { migration, migrated };
@@ -0,0 +1,39 @@
1
+ import { BlockReason, SwapActionTypes, SwapQueueDef } from './types';
2
+ import { checkStatus } from './actions/checkStatus';
3
+ import { createTransaction } from './actions/createTransaction';
4
+ import { executeTransaction } from './actions/executeTransaction';
5
+ import { scheduleNextStep } from './actions/scheduleNextStep';
6
+ import { start } from './actions/start';
7
+ import {
8
+ onBlockForChangeNetwork,
9
+ onBlockForConnectWallet,
10
+ onDependsOnOtherQueues,
11
+ } from './helpers';
12
+
13
+ /**
14
+ *
15
+ * The idea behind this queue is to be able dynamically add some steps.
16
+ * After running a swap, it can be blocked (like on waiting for switch netwrok)
17
+ * or waits for something happend (like checking status of a transaction from server)
18
+ *
19
+ */
20
+ export const swapQueueDef: SwapQueueDef = {
21
+ name: 'swap',
22
+ actions: {
23
+ [SwapActionTypes.START]: start,
24
+ [SwapActionTypes.SCHEDULE_NEXT_STEP]: scheduleNextStep,
25
+ [SwapActionTypes.CREATE_TRANSACTION]: createTransaction,
26
+ [SwapActionTypes.EXECUTE_TRANSACTION]: executeTransaction,
27
+ [SwapActionTypes.CHECK_TRANSACTION_STATUS]: checkStatus,
28
+ },
29
+ run: [SwapActionTypes.START],
30
+ whenTaskBlocked: (event, meta) => {
31
+ if (event.reason.reason === BlockReason.WAIT_FOR_CONNECT_WALLET) {
32
+ onBlockForConnectWallet(event, meta);
33
+ } else if (event.reason.reason === BlockReason.WAIT_FOR_NETWORK_CHANGE) {
34
+ onBlockForChangeNetwork(event, meta);
35
+ } else if (event.reason.reason === BlockReason.DEPENDS_ON_OTHER_QUEUES) {
36
+ onDependsOnOtherQueues(event, meta);
37
+ }
38
+ },
39
+ };
@@ -0,0 +1,7 @@
1
+ import { RangoClient } from 'rango-sdk';
2
+ import { RANGO_DAPP_API_KEY, RANGO_DAPP_API_BASE_URL } from '../constants';
3
+
4
+ export const httpService = new RangoClient(
5
+ RANGO_DAPP_API_KEY || '',
6
+ RANGO_DAPP_API_BASE_URL
7
+ );
@@ -0,0 +1 @@
1
+ export { httpService } from './httpService';
@@ -0,0 +1,160 @@
1
+ import {
2
+ APIErrorCode,
3
+ SignerError,
4
+ SignerErrorCode,
5
+ isAPIErrorCode,
6
+ isSignerErrorCode,
7
+ } from 'rango-types';
8
+
9
+ export type ErrorDetail = {
10
+ extraMessage: string;
11
+ extraMessageDetail?: string | null | undefined;
12
+ extraMessageErrorCode: SignerErrorCode | APIErrorCode | null;
13
+ };
14
+
15
+ const ERROR_ASSERTION_FAILED = 'Assertion failed (Unexpected behaviour)';
16
+ const ERROR_CREATE_TRANSACTION = 'Create transaction failed in Rango Server';
17
+ const ERROR_INPUT_WALLET_NOT_FOUND = 'Input wallet not found';
18
+
19
+ type ErrorRoot = string | Record<string, string> | null;
20
+
21
+ export class PrettyError extends Error {
22
+ private readonly detail?: string;
23
+ private readonly root?: ErrorRoot;
24
+ private readonly code?: APIErrorCode;
25
+ public _isPrettyError = true;
26
+
27
+ constructor(
28
+ code: APIErrorCode,
29
+ m: string,
30
+ root?: ErrorRoot,
31
+ detail?: string
32
+ ) {
33
+ super(m);
34
+ Object.setPrototypeOf(this, PrettyError.prototype);
35
+ PrettyError.prototype._isPrettyError = true;
36
+ this.code = code;
37
+ this.detail = detail;
38
+ this.root = root;
39
+ }
40
+
41
+ static isPrettyError(obj: unknown): obj is PrettyError {
42
+ return (
43
+ obj instanceof PrettyError ||
44
+ Object.prototype.hasOwnProperty('_isPrettyError')
45
+ );
46
+ }
47
+
48
+ getErrorDetail(): ErrorDetail {
49
+ const rawMessage =
50
+ typeof this.root === 'object' && this.root && this.root.error
51
+ ? this.root.error
52
+ : JSON.stringify(this.root);
53
+ const rootStr =
54
+ typeof this.root === 'string'
55
+ ? this.root
56
+ : this.root instanceof Error
57
+ ? this.root.message
58
+ : rawMessage;
59
+ return {
60
+ extraMessage: this.message,
61
+ extraMessageDetail: this.detail || rootStr,
62
+ extraMessageErrorCode: this.code || null,
63
+ };
64
+ }
65
+
66
+ static AssertionFailed(m: string): PrettyError {
67
+ return new PrettyError(
68
+ 'CLIENT_UNEXPECTED_BEHAVIOUR',
69
+ ERROR_ASSERTION_FAILED,
70
+ m
71
+ );
72
+ }
73
+
74
+ static BadStatusCode(
75
+ message: string,
76
+ statusCode: number | string
77
+ ): PrettyError {
78
+ return new PrettyError(
79
+ 'TX_FAIL',
80
+ message,
81
+ null,
82
+ `status code = ${statusCode}`
83
+ );
84
+ }
85
+
86
+ static CreateTransaction(detail: string): PrettyError {
87
+ return new PrettyError(
88
+ 'FETCH_TX_FAILED',
89
+ ERROR_CREATE_TRANSACTION,
90
+ null,
91
+ detail
92
+ );
93
+ }
94
+
95
+ static WalletMissing(): PrettyError {
96
+ return new PrettyError(
97
+ 'CLIENT_UNEXPECTED_BEHAVIOUR',
98
+ ERROR_INPUT_WALLET_NOT_FOUND,
99
+ null,
100
+ 'Server requested for a blockchain or address not selected by user'
101
+ );
102
+ }
103
+
104
+ static BlockchainMissing(): PrettyError {
105
+ return new PrettyError(
106
+ 'CLIENT_UNEXPECTED_BEHAVIOUR',
107
+ ERROR_INPUT_WALLET_NOT_FOUND,
108
+ null,
109
+ 'Server requested for a blockchain or address not selected by user'
110
+ );
111
+ }
112
+ }
113
+
114
+ export function mapAppErrorCodesToAPIErrorCode(
115
+ errorCode: string | null
116
+ ): APIErrorCode {
117
+ const defaultErrorCode = 'CLIENT_UNEXPECTED_BEHAVIOUR';
118
+ try {
119
+ if (!errorCode) return defaultErrorCode;
120
+ if (isAPIErrorCode(errorCode)) return errorCode;
121
+ if (isSignerErrorCode(errorCode)) {
122
+ const t: { [key in SignerErrorCode]: APIErrorCode } = {
123
+ [SignerErrorCode.REJECTED_BY_USER]: 'USER_REJECT',
124
+ [SignerErrorCode.SIGN_TX_ERROR]: 'CALL_WALLET_FAILED',
125
+ [SignerErrorCode.SEND_TX_ERROR]: 'SEND_TX_FAILED',
126
+ [SignerErrorCode.NOT_IMPLEMENTED]: defaultErrorCode,
127
+ [SignerErrorCode.OPERATION_UNSUPPORTED]: defaultErrorCode,
128
+ [SignerErrorCode.UNEXPECTED_BEHAVIOUR]: defaultErrorCode,
129
+ };
130
+ return t[errorCode];
131
+ }
132
+ return defaultErrorCode;
133
+ } catch (err) {
134
+ return defaultErrorCode;
135
+ }
136
+ }
137
+
138
+ export const prettifyErrorMessage = (obj: unknown): ErrorDetail => {
139
+ if (!obj) return { extraMessage: '', extraMessageErrorCode: null };
140
+ if (PrettyError.isPrettyError(obj)) return obj.getErrorDetail();
141
+ if (SignerError.isSignerError(obj)) {
142
+ const t = obj.getErrorDetail();
143
+ return {
144
+ extraMessage: t.message,
145
+ extraMessageDetail: t.detail,
146
+ extraMessageErrorCode: t.code,
147
+ };
148
+ }
149
+ if (obj instanceof Error)
150
+ return {
151
+ extraMessage: obj.toString(),
152
+ extraMessageErrorCode: null,
153
+ };
154
+ if (typeof obj !== 'string')
155
+ return {
156
+ extraMessage: JSON.stringify(obj),
157
+ extraMessageErrorCode: null,
158
+ };
159
+ return { extraMessage: obj, extraMessageErrorCode: null };
160
+ };
@@ -0,0 +1,24 @@
1
+ import { WalletType } from '@rango-dev/wallets-shared';
2
+ import * as Sentry from '@sentry/browser';
3
+ import { PendingSwap, PendingSwapStep } from './shared';
4
+
5
+ export function logRPCError(
6
+ error: unknown,
7
+ swap: PendingSwap,
8
+ currentStep: PendingSwapStep | undefined,
9
+ walletType: WalletType | undefined
10
+ ): void {
11
+ try {
12
+ Sentry.captureException(error, {
13
+ tags: {
14
+ requestId: swap.requestId,
15
+ rpc: true,
16
+ swapper: currentStep?.swapperId || '',
17
+ walletType: walletType || '',
18
+ },
19
+ level: 'warning' as any,
20
+ });
21
+ } catch (e) {
22
+ console.log({ e });
23
+ }
24
+ }