@rango-dev/queue-manager-rango-preset 0.0.0-experimental-936229e8-20251208
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.
- package/CHANGELOG.md +353 -0
- package/dist/actions/checkStatus.d.ts +13 -0
- package/dist/actions/checkStatus.d.ts.map +1 -0
- package/dist/actions/common/checkEnvironmentBeforeExecuteTransaction.d.ts +8 -0
- package/dist/actions/common/checkEnvironmentBeforeExecuteTransaction.d.ts.map +1 -0
- package/dist/actions/common/produceNextStateForTransaction.d.ts +17 -0
- package/dist/actions/common/produceNextStateForTransaction.d.ts.map +1 -0
- package/dist/actions/common/utils.d.ts +5 -0
- package/dist/actions/common/utils.d.ts.map +1 -0
- package/dist/actions/createTransaction.d.ts +12 -0
- package/dist/actions/createTransaction.d.ts.map +1 -0
- package/dist/actions/executeTransaction/executeTransaction.d.ts +14 -0
- package/dist/actions/executeTransaction/executeTransaction.d.ts.map +1 -0
- package/dist/actions/executeTransaction/index.d.ts +2 -0
- package/dist/actions/executeTransaction/index.d.ts.map +1 -0
- package/dist/actions/scheduleNextStep.d.ts +14 -0
- package/dist/actions/scheduleNextStep.d.ts.map +1 -0
- package/dist/actions/start.d.ts +4 -0
- package/dist/actions/start.d.ts.map +1 -0
- package/dist/configs.d.ts +14 -0
- package/dist/configs.d.ts.map +1 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/helpers.d.ts +255 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/hooks.d.ts +19 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/dist/migration.d.ts +15 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/numbers.d.ts +3 -0
- package/dist/numbers.d.ts.map +1 -0
- package/dist/queue-manager-rango-preset.build.json +1 -0
- package/dist/queueDef.d.ts +10 -0
- package/dist/queueDef.d.ts.map +1 -0
- package/dist/services/eventEmitter.d.ts +10 -0
- package/dist/services/eventEmitter.d.ts.map +1 -0
- package/dist/services/httpService.d.ts +3 -0
- package/dist/services/httpService.d.ts.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/shared-errors.d.ts +25 -0
- package/dist/shared-errors.d.ts.map +1 -0
- package/dist/shared.d.ts +81 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/types.d.ts +172 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +45 -0
- package/readme.md +2 -0
- package/src/actions/checkStatus.ts +564 -0
- package/src/actions/common/checkEnvironmentBeforeExecuteTransaction.ts +157 -0
- package/src/actions/common/produceNextStateForTransaction.ts +167 -0
- package/src/actions/common/utils.ts +25 -0
- package/src/actions/createTransaction.ts +117 -0
- package/src/actions/executeTransaction/executeTransaction.ts +107 -0
- package/src/actions/executeTransaction/index.ts +1 -0
- package/src/actions/scheduleNextStep.ts +104 -0
- package/src/actions/start.ts +16 -0
- package/src/configs.ts +38 -0
- package/src/constants.ts +18 -0
- package/src/helpers.ts +1598 -0
- package/src/hooks.ts +94 -0
- package/src/index.ts +68 -0
- package/src/migration.ts +124 -0
- package/src/numbers.ts +68 -0
- package/src/queueDef.ts +39 -0
- package/src/services/eventEmitter.ts +290 -0
- package/src/services/httpService.ts +10 -0
- package/src/services/index.ts +1 -0
- package/src/shared-errors.ts +165 -0
- package/src/shared.ts +473 -0
- package/src/types.ts +305 -0
package/src/hooks.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { LastConnectedWallet, UseQueueManagerParams } from './types';
|
|
2
|
+
|
|
3
|
+
import { useManager } from '@rango-dev/queue-manager-react';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
checkWaitingForConnectWalletChange,
|
|
8
|
+
checkWaitingForNetworkChange,
|
|
9
|
+
retryOn,
|
|
10
|
+
} from './helpers';
|
|
11
|
+
import { migrated, migration } from './migration';
|
|
12
|
+
|
|
13
|
+
let isCalled = 0;
|
|
14
|
+
|
|
15
|
+
function getLastConnectedWalletHash(
|
|
16
|
+
lastConnectedWallet: LastConnectedWallet | null
|
|
17
|
+
) {
|
|
18
|
+
return `${lastConnectedWallet?.walletType}-${
|
|
19
|
+
lastConnectedWallet?.network
|
|
20
|
+
}-${lastConnectedWallet?.accounts?.toString()}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* Runs a migration (old swaps from localstorage to queue manager's IndexedDB)
|
|
26
|
+
* It will be run only once on page load.
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
function useMigration(): {
|
|
30
|
+
status: boolean;
|
|
31
|
+
} {
|
|
32
|
+
const isMigrated = migrated();
|
|
33
|
+
const [status, setStatus] = useState<boolean>(isMigrated);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
void (async () => {
|
|
37
|
+
// Preventing react to be called twice on Strict Mode (development)
|
|
38
|
+
if (isCalled) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
isCalled = 1;
|
|
42
|
+
|
|
43
|
+
void migration().finally(() => {
|
|
44
|
+
setStatus(true);
|
|
45
|
+
});
|
|
46
|
+
})();
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
status,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
* On initial load and also connect/disconnect we may need to update swap's notified message.
|
|
57
|
+
* And also if a new wallet is connected we will retry the queue to see we can resume it or not.
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
function useQueueManager(params: UseQueueManagerParams): void {
|
|
61
|
+
const { manager } = useManager();
|
|
62
|
+
const {
|
|
63
|
+
lastConnectedWallet,
|
|
64
|
+
disconnectedWallet,
|
|
65
|
+
evmChains,
|
|
66
|
+
canSwitchNetworkTo,
|
|
67
|
+
clearDisconnectedWallet,
|
|
68
|
+
} = params;
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (lastConnectedWallet) {
|
|
72
|
+
checkWaitingForConnectWalletChange({
|
|
73
|
+
evmChains,
|
|
74
|
+
lastConnectedWallet,
|
|
75
|
+
manager,
|
|
76
|
+
});
|
|
77
|
+
retryOn(lastConnectedWallet, manager, canSwitchNetworkTo);
|
|
78
|
+
}
|
|
79
|
+
}, [getLastConnectedWalletHash(lastConnectedWallet)]);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (disconnectedWallet) {
|
|
83
|
+
checkWaitingForNetworkChange(manager);
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
*We need to reset the state value, so if a wallet disconnected twice (after reconnect),
|
|
87
|
+
*this effect will be run properly.
|
|
88
|
+
*/
|
|
89
|
+
clearDisconnectedWallet();
|
|
90
|
+
}
|
|
91
|
+
}, [disconnectedWallet]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { useQueueManager, useMigration };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Configs } from './configs';
|
|
2
|
+
import type { SwapQueueDef } from './types';
|
|
3
|
+
|
|
4
|
+
import { initConfig } from './configs';
|
|
5
|
+
import { swapQueueDef } from './queueDef';
|
|
6
|
+
|
|
7
|
+
export { PrettyError, prettifyErrorMessage } from './shared-errors';
|
|
8
|
+
export type {
|
|
9
|
+
SwapQueueContext,
|
|
10
|
+
SwapStorage,
|
|
11
|
+
RouteExecutionEvents,
|
|
12
|
+
Route,
|
|
13
|
+
Step,
|
|
14
|
+
RouteEvent,
|
|
15
|
+
StepEvent,
|
|
16
|
+
RouteEventData,
|
|
17
|
+
StepEventData,
|
|
18
|
+
RouteStartedEvent,
|
|
19
|
+
RouteSucceededEvent,
|
|
20
|
+
RouteFailedEvent,
|
|
21
|
+
StepStartedEvent,
|
|
22
|
+
StepSucceededEvent,
|
|
23
|
+
StepFailedEvent,
|
|
24
|
+
StepTxExecutionUpdatedEvent,
|
|
25
|
+
StepTxExecutionBlockedEvent,
|
|
26
|
+
StepCheckStatusEvent,
|
|
27
|
+
StepApprovalTxSucceededEvent,
|
|
28
|
+
StepOutputRevealedEvent,
|
|
29
|
+
LastConnectedWallet,
|
|
30
|
+
} from './types';
|
|
31
|
+
export {
|
|
32
|
+
WidgetEvents,
|
|
33
|
+
StepEventType,
|
|
34
|
+
RouteEventType,
|
|
35
|
+
StepExecutionEventStatus,
|
|
36
|
+
StepExecutionBlockedEventStatus,
|
|
37
|
+
EventSeverity,
|
|
38
|
+
} from './types';
|
|
39
|
+
export type {
|
|
40
|
+
PendingSwapWithQueueID,
|
|
41
|
+
EventType,
|
|
42
|
+
TargetNamespace,
|
|
43
|
+
} from './shared';
|
|
44
|
+
export {
|
|
45
|
+
getCurrentNamespaceOfOrNull,
|
|
46
|
+
getRelatedWalletOrNull,
|
|
47
|
+
getRelatedWallet,
|
|
48
|
+
MessageSeverity,
|
|
49
|
+
calculatePendingSwap,
|
|
50
|
+
getUsdPrice,
|
|
51
|
+
} from './shared';
|
|
52
|
+
export {
|
|
53
|
+
updateSwapStatus,
|
|
54
|
+
checkWaitingForNetworkChange,
|
|
55
|
+
getCurrentStep,
|
|
56
|
+
cancelSwap,
|
|
57
|
+
getRequiredWallet,
|
|
58
|
+
getRunningSwaps,
|
|
59
|
+
resetRunningSwapNotifsOnPageLoad,
|
|
60
|
+
isApprovalTX,
|
|
61
|
+
getLastSuccessfulStep,
|
|
62
|
+
} from './helpers';
|
|
63
|
+
export { useMigration, useQueueManager } from './hooks';
|
|
64
|
+
|
|
65
|
+
export function makeQueueDefinition(configs: Configs): SwapQueueDef {
|
|
66
|
+
initConfig(configs);
|
|
67
|
+
return swapQueueDef;
|
|
68
|
+
}
|
package/src/migration.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { PersistedQueue } from '@rango-dev/queue-manager-core';
|
|
2
|
+
import type { PendingSwap } from 'rango-types';
|
|
3
|
+
|
|
4
|
+
import { DB_NAME, Persistor, Status } from '@rango-dev/queue-manager-core';
|
|
5
|
+
import { v4 as uuid } from 'uuid';
|
|
6
|
+
|
|
7
|
+
import { SwapActionTypes } from './types';
|
|
8
|
+
|
|
9
|
+
const MIGRATED_KEY = 'migratedToQueueManager';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* If `MIGRATED_KEY` is set, it means we already migrated data from localstorage.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
function migrated(): boolean {
|
|
17
|
+
return !!window.localStorage.getItem(MIGRATED_KEY);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function hasQueueManagerOnIDB(): Promise<boolean> {
|
|
21
|
+
try {
|
|
22
|
+
return (await (window.indexedDB as any).databases())
|
|
23
|
+
.map((db: any) => db.name)
|
|
24
|
+
.includes(DB_NAME);
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* By calling this function, we first check if the data already migrated or not,
|
|
33
|
+
* If not, starting to migrating to IndexedDb with proper format that queue manager is understand.
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
async function migration(): Promise<boolean> {
|
|
37
|
+
const swapsFromStorage = window.localStorage.getItem('pendingSwaps');
|
|
38
|
+
const hasIndexDB = await hasQueueManagerOnIDB();
|
|
39
|
+
|
|
40
|
+
// For new users or already migrated.
|
|
41
|
+
if (!swapsFromStorage || migrated() || hasIndexDB) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// For old users, but they didn't do any swaps yet.
|
|
46
|
+
const swaps: PendingSwap[] = JSON.parse(swapsFromStorage);
|
|
47
|
+
const convertedSwaps: PersistedQueue[] = [];
|
|
48
|
+
|
|
49
|
+
swaps.forEach((swap) => {
|
|
50
|
+
/*
|
|
51
|
+
*For running task we need to add some more work
|
|
52
|
+
*We need to create a queue task to be run and resume the running task from queue manager.
|
|
53
|
+
*/
|
|
54
|
+
if (swap.status === 'running') {
|
|
55
|
+
const taskId = uuid();
|
|
56
|
+
|
|
57
|
+
const convertedSwap: PersistedQueue = {
|
|
58
|
+
id: swap.requestId,
|
|
59
|
+
createdAt: Number(swap.creationTime),
|
|
60
|
+
name: 'swap',
|
|
61
|
+
status: Status.RUNNING,
|
|
62
|
+
storage: {
|
|
63
|
+
swapDetails: swap,
|
|
64
|
+
},
|
|
65
|
+
state: {
|
|
66
|
+
status: Status.RUNNING,
|
|
67
|
+
activeTaskIndex: 0,
|
|
68
|
+
tasks: {
|
|
69
|
+
[taskId]: {
|
|
70
|
+
blockedFor: null,
|
|
71
|
+
status: Status.RUNNING,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
tasks: [
|
|
76
|
+
{
|
|
77
|
+
id: taskId,
|
|
78
|
+
action: SwapActionTypes.SCHEDULE_NEXT_STEP,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
convertedSwaps.push(convertedSwap);
|
|
83
|
+
} else {
|
|
84
|
+
/*
|
|
85
|
+
* For failed or successful swaps, we only move it to IndexedDB,
|
|
86
|
+
* And there is no need to consider them to be run.
|
|
87
|
+
*/
|
|
88
|
+
const status = swap.status === 'success' ? Status.SUCCESS : Status.FAILED;
|
|
89
|
+
|
|
90
|
+
const convertedSwap: PersistedQueue = {
|
|
91
|
+
id: swap.requestId,
|
|
92
|
+
createdAt: Number(swap.creationTime),
|
|
93
|
+
name: 'swap',
|
|
94
|
+
status,
|
|
95
|
+
storage: {
|
|
96
|
+
swapDetails: swap,
|
|
97
|
+
},
|
|
98
|
+
state: {
|
|
99
|
+
status,
|
|
100
|
+
activeTaskIndex: 0,
|
|
101
|
+
tasks: {},
|
|
102
|
+
},
|
|
103
|
+
tasks: [],
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
convertedSwaps.push(convertedSwap);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Getting an instance from persistor, so we can directly put our data inside it.
|
|
111
|
+
const persistor = new Persistor();
|
|
112
|
+
|
|
113
|
+
const promises = convertedSwaps.map(async (queue) =>
|
|
114
|
+
persistor.insertQueue(queue)
|
|
115
|
+
);
|
|
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 };
|
package/src/numbers.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
|
|
3
|
+
export const numberToString = (
|
|
4
|
+
number: BigNumber | string | null,
|
|
5
|
+
minDecimals: number | null = null,
|
|
6
|
+
maxDecimals: number | null = null
|
|
7
|
+
): string => {
|
|
8
|
+
if (number === null) return '';
|
|
9
|
+
if (number === '') return '';
|
|
10
|
+
const n = new BigNumber(number);
|
|
11
|
+
const roundingMode = 1;
|
|
12
|
+
let maxI = 1000;
|
|
13
|
+
for (let i = 0; i < 60; i++) {
|
|
14
|
+
if (new BigNumber(n.toFixed(i, roundingMode)).eq(n)) {
|
|
15
|
+
maxI = i;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (n.gte(10000)) return n.toFormat(0, roundingMode);
|
|
21
|
+
if (n.gte(1000))
|
|
22
|
+
return n.toFormat(
|
|
23
|
+
Math.min(
|
|
24
|
+
maxI,
|
|
25
|
+
Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 1))
|
|
26
|
+
),
|
|
27
|
+
roundingMode
|
|
28
|
+
);
|
|
29
|
+
if (n.gte(100))
|
|
30
|
+
return n.toFormat(
|
|
31
|
+
Math.min(
|
|
32
|
+
maxI,
|
|
33
|
+
Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 1))
|
|
34
|
+
),
|
|
35
|
+
roundingMode
|
|
36
|
+
);
|
|
37
|
+
if (n.gte(1))
|
|
38
|
+
return n.toFormat(
|
|
39
|
+
Math.min(
|
|
40
|
+
maxI,
|
|
41
|
+
Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 2))
|
|
42
|
+
),
|
|
43
|
+
roundingMode
|
|
44
|
+
);
|
|
45
|
+
if (n.gte(0.01))
|
|
46
|
+
return n.toFormat(
|
|
47
|
+
Math.min(
|
|
48
|
+
maxI,
|
|
49
|
+
Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 4))
|
|
50
|
+
),
|
|
51
|
+
roundingMode
|
|
52
|
+
);
|
|
53
|
+
for (let i = minDecimals || 4; i < 17; i++)
|
|
54
|
+
if (n.gte(Math.pow(10, -i)))
|
|
55
|
+
return n.toFormat(
|
|
56
|
+
Math.min(
|
|
57
|
+
maxI,
|
|
58
|
+
Math.min(maxDecimals || 100, Math.max(minDecimals || 0, i))
|
|
59
|
+
),
|
|
60
|
+
roundingMode
|
|
61
|
+
);
|
|
62
|
+
if (n.isEqualTo(0)) return '0';
|
|
63
|
+
|
|
64
|
+
return n.toFormat(
|
|
65
|
+
Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 8))),
|
|
66
|
+
roundingMode
|
|
67
|
+
);
|
|
68
|
+
};
|
package/src/queueDef.ts
ADDED
|
@@ -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,290 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RemoveNameField,
|
|
3
|
+
Route,
|
|
4
|
+
RouteEvent,
|
|
5
|
+
Step,
|
|
6
|
+
StepEvent,
|
|
7
|
+
} from '../types';
|
|
8
|
+
import type { PendingSwap, PendingSwapStep } from 'rango-types';
|
|
9
|
+
|
|
10
|
+
import { getConfig } from '../configs';
|
|
11
|
+
import {
|
|
12
|
+
getCurrentStepTx,
|
|
13
|
+
getFailedStep,
|
|
14
|
+
getLastSuccessfulStep,
|
|
15
|
+
getSwapInputUsd,
|
|
16
|
+
getSwapOutputUsd,
|
|
17
|
+
isApprovalCurrentStepTx,
|
|
18
|
+
} from '../helpers';
|
|
19
|
+
import { getCurrentNamespaceOfOrNull } from '../shared';
|
|
20
|
+
import {
|
|
21
|
+
EventSeverity,
|
|
22
|
+
RouteEventType,
|
|
23
|
+
StepEventType,
|
|
24
|
+
StepExecutionBlockedEventStatus,
|
|
25
|
+
StepExecutionEventStatus,
|
|
26
|
+
WidgetEvents,
|
|
27
|
+
} from '../types';
|
|
28
|
+
|
|
29
|
+
export type NotifierParams = {
|
|
30
|
+
swap: PendingSwap;
|
|
31
|
+
step: PendingSwapStep | null;
|
|
32
|
+
} & {
|
|
33
|
+
event: RemoveNameField<StepEvent, 'message' | 'messageSeverity'>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function createSteps(swapSteps: PendingSwapStep[]): Step[] {
|
|
37
|
+
return swapSteps.map((swapStep) => {
|
|
38
|
+
const {
|
|
39
|
+
diagnosisUrl,
|
|
40
|
+
estimatedTimeInSeconds,
|
|
41
|
+
explorerUrl,
|
|
42
|
+
feeInUsd,
|
|
43
|
+
executedTransactionId,
|
|
44
|
+
executedTransactionTime,
|
|
45
|
+
expectedOutputAmountHumanReadable,
|
|
46
|
+
fromBlockchain,
|
|
47
|
+
toBlockchain,
|
|
48
|
+
fromSymbol,
|
|
49
|
+
toSymbol,
|
|
50
|
+
fromSymbolAddress,
|
|
51
|
+
toSymbolAddress,
|
|
52
|
+
swapperType,
|
|
53
|
+
swapperId,
|
|
54
|
+
outputAmount,
|
|
55
|
+
fromAmountMaxValue,
|
|
56
|
+
fromAmountMinValue,
|
|
57
|
+
fromAmountPrecision,
|
|
58
|
+
fromAmountRestrictionType,
|
|
59
|
+
fromDecimals,
|
|
60
|
+
status: stepStatus,
|
|
61
|
+
} = swapStep;
|
|
62
|
+
|
|
63
|
+
const step: Step = {
|
|
64
|
+
diagnosisUrl,
|
|
65
|
+
estimatedTimeInSeconds,
|
|
66
|
+
explorerUrl,
|
|
67
|
+
feeInUsd,
|
|
68
|
+
executedTransactionId,
|
|
69
|
+
executedTransactionTime,
|
|
70
|
+
expectedOutputAmountHumanReadable,
|
|
71
|
+
fromBlockchain,
|
|
72
|
+
toBlockchain,
|
|
73
|
+
fromSymbol,
|
|
74
|
+
toSymbol,
|
|
75
|
+
fromSymbolAddress,
|
|
76
|
+
toSymbolAddress,
|
|
77
|
+
swapperName: swapperId,
|
|
78
|
+
swapperType,
|
|
79
|
+
outputAmount,
|
|
80
|
+
fromAmountMaxValue,
|
|
81
|
+
fromAmountMinValue,
|
|
82
|
+
fromAmountPrecision,
|
|
83
|
+
fromAmountRestrictionType,
|
|
84
|
+
fromDecimals,
|
|
85
|
+
status: stepStatus,
|
|
86
|
+
transaction: getCurrentStepTx(swapStep),
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return step;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getEventPayload(
|
|
94
|
+
swap: PendingSwap,
|
|
95
|
+
type: StepEventType | RouteEventType,
|
|
96
|
+
swapStep?: PendingSwapStep
|
|
97
|
+
): { route: Route; step: Step } {
|
|
98
|
+
const {
|
|
99
|
+
creationTime,
|
|
100
|
+
finishTime,
|
|
101
|
+
requestId,
|
|
102
|
+
inputAmount,
|
|
103
|
+
status,
|
|
104
|
+
wallets,
|
|
105
|
+
steps,
|
|
106
|
+
settings,
|
|
107
|
+
} = swap;
|
|
108
|
+
|
|
109
|
+
const routeSteps = createSteps(steps);
|
|
110
|
+
const route: Route = {
|
|
111
|
+
creationTime,
|
|
112
|
+
finishTime,
|
|
113
|
+
requestId,
|
|
114
|
+
inputAmount,
|
|
115
|
+
status,
|
|
116
|
+
wallets,
|
|
117
|
+
steps: routeSteps,
|
|
118
|
+
slippage: settings.slippage,
|
|
119
|
+
infiniteApproval: settings.infiniteApprove,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const result: { route: Route; step: Step } = {
|
|
123
|
+
route,
|
|
124
|
+
step: routeSteps[routeSteps.length - 1],
|
|
125
|
+
};
|
|
126
|
+
if (swapStep) {
|
|
127
|
+
result.step = createSteps([swapStep])[0];
|
|
128
|
+
} else {
|
|
129
|
+
if (type === 'failed') {
|
|
130
|
+
const failedStep = getFailedStep(routeSteps);
|
|
131
|
+
if (failedStep) {
|
|
132
|
+
result.step = failedStep;
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
const lastSuccessfulStep = getLastSuccessfulStep(routeSteps);
|
|
136
|
+
if (lastSuccessfulStep) {
|
|
137
|
+
result.step = lastSuccessfulStep;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function emitRouteEvent(stepEvent: StepEvent, route: Route, swap: PendingSwap) {
|
|
146
|
+
let routeEvent: RouteEvent | undefined;
|
|
147
|
+
const { type } = stepEvent;
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
149
|
+
switch (type) {
|
|
150
|
+
case StepEventType.STARTED:
|
|
151
|
+
routeEvent = { ...stepEvent, type: RouteEventType.STARTED };
|
|
152
|
+
break;
|
|
153
|
+
case StepEventType.FAILED:
|
|
154
|
+
routeEvent = {
|
|
155
|
+
...stepEvent,
|
|
156
|
+
type: RouteEventType.FAILED,
|
|
157
|
+
inputAmount: swap.inputAmount,
|
|
158
|
+
inputAmountUsd: getSwapInputUsd(swap),
|
|
159
|
+
swapMode: swap.mode || 'swap',
|
|
160
|
+
};
|
|
161
|
+
break;
|
|
162
|
+
case StepEventType.SUCCEEDED: {
|
|
163
|
+
routeEvent = {
|
|
164
|
+
...stepEvent,
|
|
165
|
+
type: RouteEventType.SUCCEEDED,
|
|
166
|
+
inputAmount: swap.inputAmount,
|
|
167
|
+
inputAmountUsd: getSwapInputUsd(swap),
|
|
168
|
+
outputAmount: swap.steps[swap.steps.length - 1].outputAmount ?? '',
|
|
169
|
+
outputAmountUsd: getSwapOutputUsd(swap),
|
|
170
|
+
swapMode: swap.mode || 'swap',
|
|
171
|
+
};
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (routeEvent) {
|
|
178
|
+
const eventEmitter = getConfig('emitter');
|
|
179
|
+
eventEmitter?.emit(WidgetEvents.RouteEvent, { event: routeEvent, route });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function emitStepEvent(stepEvent: StepEvent, route: Route, step: Step) {
|
|
184
|
+
const eventEmitter = getConfig('emitter');
|
|
185
|
+
eventEmitter?.emit(WidgetEvents.StepEvent, { event: stepEvent, route, step });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function notifier(params: NotifierParams) {
|
|
189
|
+
const { event } = params;
|
|
190
|
+
const { type } = event;
|
|
191
|
+
const { route, step } = getEventPayload(
|
|
192
|
+
params.swap,
|
|
193
|
+
type,
|
|
194
|
+
params.step ?? undefined
|
|
195
|
+
);
|
|
196
|
+
const fromAsset = `${step.fromBlockchain}.${step.fromSymbol}`;
|
|
197
|
+
const toAsset = `${step.toBlockchain}.${step.toSymbol}`;
|
|
198
|
+
const outputAmount = step.outputAmount ?? '';
|
|
199
|
+
const currentFromNamespace = !!params.step
|
|
200
|
+
? getCurrentNamespaceOfOrNull(params.swap, params.step)
|
|
201
|
+
: null;
|
|
202
|
+
let message = '';
|
|
203
|
+
let messageSeverity: StepEvent['messageSeverity'] = EventSeverity.INFO;
|
|
204
|
+
|
|
205
|
+
switch (type) {
|
|
206
|
+
case StepEventType.STARTED:
|
|
207
|
+
message = 'Swap process started';
|
|
208
|
+
messageSeverity = EventSeverity.SUCCESS;
|
|
209
|
+
break;
|
|
210
|
+
case StepEventType.SUCCEEDED:
|
|
211
|
+
message = `You received ${outputAmount} ${toAsset}, hooray!`;
|
|
212
|
+
messageSeverity = EventSeverity.SUCCESS;
|
|
213
|
+
break;
|
|
214
|
+
case StepEventType.FAILED:
|
|
215
|
+
message = `Swap failed: ${
|
|
216
|
+
params.swap?.extraMessage ?? 'Reason is unknown'
|
|
217
|
+
}`;
|
|
218
|
+
messageSeverity = EventSeverity.ERROR;
|
|
219
|
+
break;
|
|
220
|
+
case StepEventType.TX_EXECUTION:
|
|
221
|
+
if (event.status === StepExecutionEventStatus.CREATE_TX) {
|
|
222
|
+
message = 'Please wait while the transaction is created ...';
|
|
223
|
+
messageSeverity = EventSeverity.INFO;
|
|
224
|
+
} else if (event.status === StepExecutionEventStatus.SEND_TX) {
|
|
225
|
+
if (params.step && isApprovalCurrentStepTx(params.step)) {
|
|
226
|
+
message = `Please confirm '${step.swapperName}' smart contract access to ${fromAsset}`;
|
|
227
|
+
} else {
|
|
228
|
+
message = 'Please confirm transaction request in your wallet';
|
|
229
|
+
}
|
|
230
|
+
messageSeverity = EventSeverity.WARNING;
|
|
231
|
+
} else if (event.status === StepExecutionEventStatus.TX_SENT) {
|
|
232
|
+
message = 'Transaction sent successfully';
|
|
233
|
+
messageSeverity = EventSeverity.INFO;
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
case StepEventType.CHECK_STATUS:
|
|
237
|
+
if (params.step && isApprovalCurrentStepTx(params.step)) {
|
|
238
|
+
message = 'Checking approve transaction status ...';
|
|
239
|
+
} else {
|
|
240
|
+
message = 'Checking transaction status ...';
|
|
241
|
+
}
|
|
242
|
+
messageSeverity = EventSeverity.INFO;
|
|
243
|
+
break;
|
|
244
|
+
case StepEventType.APPROVAL_TX_SUCCEEDED:
|
|
245
|
+
message = 'Smart contract called successfully';
|
|
246
|
+
messageSeverity = EventSeverity.SUCCESS;
|
|
247
|
+
break;
|
|
248
|
+
case StepEventType.OUTPUT_REVEALED:
|
|
249
|
+
message = 'Transaction output amount revealed';
|
|
250
|
+
messageSeverity = EventSeverity.SUCCESS;
|
|
251
|
+
break;
|
|
252
|
+
|
|
253
|
+
case StepEventType.TX_EXECUTION_BLOCKED:
|
|
254
|
+
if (
|
|
255
|
+
event.status ===
|
|
256
|
+
StepExecutionBlockedEventStatus.WAITING_FOR_WALLET_CONNECT
|
|
257
|
+
) {
|
|
258
|
+
message = 'Please connect your wallet.';
|
|
259
|
+
messageSeverity = EventSeverity.WARNING;
|
|
260
|
+
} else if (
|
|
261
|
+
event.status === StepExecutionBlockedEventStatus.WAITING_FOR_QUEUE
|
|
262
|
+
) {
|
|
263
|
+
message = 'Waiting for other swaps to complete';
|
|
264
|
+
messageSeverity = EventSeverity.WARNING;
|
|
265
|
+
} else if (
|
|
266
|
+
event.status ===
|
|
267
|
+
StepExecutionBlockedEventStatus.WAITING_FOR_CHANGE_WALLET_ACCOUNT
|
|
268
|
+
) {
|
|
269
|
+
message = 'Please change your wallet account.';
|
|
270
|
+
messageSeverity = EventSeverity.WARNING;
|
|
271
|
+
} else if (
|
|
272
|
+
event.status ===
|
|
273
|
+
StepExecutionBlockedEventStatus.WAITING_FOR_NETWORK_CHANGE
|
|
274
|
+
) {
|
|
275
|
+
message = `Please change your wallet network to ${currentFromNamespace?.network}.`;
|
|
276
|
+
messageSeverity = EventSeverity.WARNING;
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
|
|
280
|
+
default:
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (params.step) {
|
|
285
|
+
emitStepEvent({ ...event, message, messageSeverity }, route, step);
|
|
286
|
+
}
|
|
287
|
+
if (params.event.type === StepEventType.FAILED || !params.step) {
|
|
288
|
+
emitRouteEvent({ ...event, message, messageSeverity }, route, params.swap);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RangoClient } from 'rango-sdk';
|
|
2
|
+
import { getConfig } from '../configs';
|
|
3
|
+
|
|
4
|
+
let rango: RangoClient | undefined = undefined;
|
|
5
|
+
|
|
6
|
+
export const httpService = () => {
|
|
7
|
+
if (rango) return rango;
|
|
8
|
+
rango = new RangoClient(getConfig('API_KEY'), getConfig('BASE_URL'));
|
|
9
|
+
return rango;
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { httpService } from './httpService';
|