@subwallet/extension-base 1.0.5-1 → 1.0.5-3
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/background/KoniTypes.d.ts +2 -1
- package/cjs/koni/api/staking/bonding/relayChain.js +2 -7
- package/cjs/koni/api/staking/bonding/utils.js +9 -0
- package/cjs/koni/background/handlers/Extension.js +4 -2
- package/cjs/koni/background/handlers/Tabs.js +24 -23
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +2 -2
- package/cjs/services/chain-service/index.js +5 -0
- package/cjs/services/chain-service/utils.js +15 -10
- package/cjs/services/history-service/helpers/recoverHistoryStatus.js +157 -38
- package/cjs/services/history-service/index.js +26 -19
- package/cjs/services/history-service/subsquid-multi-chain-history.js +2 -2
- package/cjs/services/notification-service/NotificationService.js +1 -1
- package/cjs/services/storage-service/DatabaseService.js +1 -1
- package/cjs/services/transaction-service/index.js +41 -14
- package/cjs/services/transaction-service/utils.js +3 -0
- package/cjs/utils/index.js +3 -0
- package/koni/api/staking/bonding/relayChain.js +3 -8
- package/koni/api/staking/bonding/utils.d.ts +1 -0
- package/koni/api/staking/bonding/utils.js +8 -0
- package/koni/background/handlers/Extension.js +5 -3
- package/koni/background/handlers/Tabs.js +24 -23
- package/package.json +6 -6
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.js +2 -2
- package/services/chain-service/index.js +5 -0
- package/services/chain-service/utils.d.ts +1 -0
- package/services/chain-service/utils.js +14 -10
- package/services/history-service/helpers/recoverHistoryStatus.d.ts +7 -1
- package/services/history-service/helpers/recoverHistoryStatus.js +151 -35
- package/services/history-service/index.d.ts +1 -1
- package/services/history-service/index.js +26 -19
- package/services/history-service/subsquid-multi-chain-history.js +2 -2
- package/services/notification-service/NotificationService.js +1 -1
- package/services/storage-service/DatabaseService.d.ts +1 -1
- package/services/storage-service/DatabaseService.js +1 -1
- package/services/transaction-service/index.js +41 -14
- package/services/transaction-service/types.d.ts +5 -3
- package/services/transaction-service/utils.js +3 -0
- package/utils/index.js +3 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import { isSameAddress } from '@subwallet/extension-base/utils';
|
|
4
5
|
export let HistoryRecoverStatus;
|
|
5
6
|
(function (HistoryRecoverStatus) {
|
|
6
7
|
HistoryRecoverStatus["SUCCESS"] = "SUCCESS";
|
|
@@ -10,75 +11,188 @@ export let HistoryRecoverStatus;
|
|
|
10
11
|
HistoryRecoverStatus["FAIL_DETECT"] = "FAIL_DETECT";
|
|
11
12
|
HistoryRecoverStatus["UNKNOWN"] = "UNKNOWN";
|
|
12
13
|
})(HistoryRecoverStatus || (HistoryRecoverStatus = {}));
|
|
14
|
+
const BLOCK_LIMIT = 6;
|
|
13
15
|
const substrateRecover = async (history, chainService) => {
|
|
14
16
|
const {
|
|
17
|
+
address,
|
|
15
18
|
blockHash,
|
|
16
19
|
chain,
|
|
17
|
-
extrinsicHash
|
|
20
|
+
extrinsicHash,
|
|
21
|
+
from,
|
|
22
|
+
nonce,
|
|
23
|
+
startBlock
|
|
18
24
|
} = history;
|
|
25
|
+
const result = {
|
|
26
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
27
|
+
};
|
|
19
28
|
try {
|
|
20
29
|
const substrateApi = chainService.getSubstrateApi(chain);
|
|
21
30
|
if (substrateApi) {
|
|
22
31
|
const _api = await substrateApi.isReady;
|
|
23
32
|
const api = _api.api;
|
|
24
33
|
if (!blockHash) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const extrinsics = block.block.extrinsics;
|
|
31
|
-
let index;
|
|
32
|
-
extrinsics.forEach((extrinsic, _idx) => {
|
|
33
|
-
if (extrinsicHash === extrinsic.hash.toHex()) {
|
|
34
|
-
index = _idx;
|
|
34
|
+
if (!nonce || !startBlock) {
|
|
35
|
+
console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
|
|
36
|
+
return {
|
|
37
|
+
status: HistoryRecoverStatus.LACK_INFO
|
|
38
|
+
};
|
|
35
39
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
const currentBlock = (await api.query.system.number()).toPrimitive();
|
|
41
|
+
for (let i = 1, found = false; i < BLOCK_LIMIT && !found && startBlock + i <= currentBlock; i++) {
|
|
42
|
+
const blockHash = (await api.rpc.chain.getBlockHash(startBlock + i)).toHex();
|
|
43
|
+
const block = await api.rpc.chain.getBlock(blockHash);
|
|
44
|
+
const extrinsics = block.block.extrinsics;
|
|
45
|
+
let index;
|
|
46
|
+
for (const [idx, extrinsic] of Object.entries(extrinsics)) {
|
|
47
|
+
if (extrinsic.signer && isSameAddress(from, extrinsic.signer.toString()) && nonce === extrinsic.nonce.toNumber()) {
|
|
48
|
+
index = parseInt(idx);
|
|
49
|
+
found = true;
|
|
50
|
+
result.extrinsicHash = extrinsic.hash.toHex();
|
|
51
|
+
result.blockHash = block.block.hash.toHex();
|
|
52
|
+
result.blockNumber = block.block.header.number.toNumber();
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (index !== undefined) {
|
|
57
|
+
const allEvents = await api.query.system.events.at(blockHash);
|
|
58
|
+
const events = allEvents.filter(({
|
|
59
|
+
phase
|
|
60
|
+
}) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index));
|
|
61
|
+
for (const {
|
|
62
|
+
event
|
|
63
|
+
} of events) {
|
|
64
|
+
if (api.events.system.ExtrinsicSuccess.is(event)) {
|
|
65
|
+
return {
|
|
66
|
+
...result,
|
|
67
|
+
status: HistoryRecoverStatus.SUCCESS
|
|
68
|
+
};
|
|
69
|
+
} else if (api.events.system.ExtrinsicFailed.is(event)) {
|
|
70
|
+
return {
|
|
71
|
+
...result,
|
|
72
|
+
status: HistoryRecoverStatus.FAILED
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const block = await api.rpc.chain.getBlock(blockHash);
|
|
80
|
+
const allEvents = await api.query.system.events.at(blockHash);
|
|
81
|
+
const extrinsics = block.block.extrinsics;
|
|
82
|
+
let index;
|
|
83
|
+
for (const [idx, extrinsic] of Object.entries(extrinsics)) {
|
|
84
|
+
if (extrinsicHash === extrinsic.hash.toHex()) {
|
|
85
|
+
index = parseInt(idx);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (index === undefined) {
|
|
90
|
+
console.log(`Fail to find extrinsic ${extrinsicHash} on ${chain}`);
|
|
91
|
+
return {
|
|
92
|
+
status: HistoryRecoverStatus.FAIL_DETECT
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const events = allEvents.filter(({
|
|
96
|
+
phase
|
|
97
|
+
}) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index));
|
|
98
|
+
for (const {
|
|
99
|
+
event
|
|
100
|
+
} of events) {
|
|
101
|
+
if (api.events.system.ExtrinsicSuccess.is(event)) {
|
|
102
|
+
return {
|
|
103
|
+
...result,
|
|
104
|
+
status: HistoryRecoverStatus.SUCCESS
|
|
105
|
+
};
|
|
106
|
+
} else if (api.events.system.ExtrinsicFailed.is(event)) {
|
|
107
|
+
return {
|
|
108
|
+
...result,
|
|
109
|
+
status: HistoryRecoverStatus.FAILED
|
|
110
|
+
};
|
|
111
|
+
}
|
|
51
112
|
}
|
|
52
113
|
}
|
|
53
|
-
return
|
|
114
|
+
return {
|
|
115
|
+
status: HistoryRecoverStatus.FAIL_DETECT
|
|
116
|
+
};
|
|
54
117
|
} else {
|
|
55
118
|
console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`);
|
|
56
|
-
return
|
|
119
|
+
return {
|
|
120
|
+
status: HistoryRecoverStatus.API_INACTIVE
|
|
121
|
+
};
|
|
57
122
|
}
|
|
58
123
|
} catch (e) {
|
|
59
124
|
console.error(`Fail to update history ${chain}-${extrinsicHash}:`, e.message);
|
|
60
|
-
return
|
|
125
|
+
return {
|
|
126
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
127
|
+
};
|
|
61
128
|
}
|
|
62
129
|
};
|
|
63
130
|
const evmRecover = async (history, chainService) => {
|
|
64
131
|
const {
|
|
132
|
+
address,
|
|
65
133
|
chain,
|
|
66
|
-
extrinsicHash
|
|
134
|
+
extrinsicHash,
|
|
135
|
+
from,
|
|
136
|
+
nonce,
|
|
137
|
+
startBlock
|
|
67
138
|
} = history;
|
|
139
|
+
const result = {
|
|
140
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
141
|
+
};
|
|
68
142
|
try {
|
|
69
143
|
const evmApi = chainService.getEvmApi(chain);
|
|
70
144
|
if (evmApi) {
|
|
71
145
|
const _api = await evmApi.isReady;
|
|
72
146
|
const api = _api.api;
|
|
73
|
-
|
|
74
|
-
|
|
147
|
+
if (extrinsicHash) {
|
|
148
|
+
const transactionReceipt = await api.eth.getTransactionReceipt(extrinsicHash);
|
|
149
|
+
return {
|
|
150
|
+
...result,
|
|
151
|
+
status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED
|
|
152
|
+
};
|
|
153
|
+
} else {
|
|
154
|
+
if (!nonce || !startBlock) {
|
|
155
|
+
console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
|
|
156
|
+
return {
|
|
157
|
+
...result,
|
|
158
|
+
status: HistoryRecoverStatus.LACK_INFO
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const currentBlock = await api.eth.getBlockNumber();
|
|
162
|
+
for (let i = 1, found = false; i < BLOCK_LIMIT && !found && startBlock + i <= currentBlock; i++) {
|
|
163
|
+
const block = await api.eth.getBlock(startBlock + i, true);
|
|
164
|
+
for (const transaction of block.transactions) {
|
|
165
|
+
if (isSameAddress(transaction.from, from) && nonce === transaction.nonce) {
|
|
166
|
+
result.extrinsicHash = transaction.hash;
|
|
167
|
+
result.blockHash = block.hash;
|
|
168
|
+
result.blockNumber = block.number;
|
|
169
|
+
found = true;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (result.extrinsicHash) {
|
|
174
|
+
const transactionReceipt = await api.eth.getTransactionReceipt(result.extrinsicHash);
|
|
175
|
+
return {
|
|
176
|
+
...result,
|
|
177
|
+
status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
status: HistoryRecoverStatus.FAIL_DETECT
|
|
184
|
+
};
|
|
75
185
|
} else {
|
|
76
186
|
console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`);
|
|
77
|
-
return
|
|
187
|
+
return {
|
|
188
|
+
status: HistoryRecoverStatus.API_INACTIVE
|
|
189
|
+
};
|
|
78
190
|
}
|
|
79
191
|
} catch (e) {
|
|
80
192
|
console.error(`Fail to update history ${chain}-${extrinsicHash}:`, e.message);
|
|
81
|
-
return
|
|
193
|
+
return {
|
|
194
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
195
|
+
};
|
|
82
196
|
}
|
|
83
197
|
};
|
|
84
198
|
|
|
@@ -93,6 +207,8 @@ export const historyRecover = async (history, chainService) => {
|
|
|
93
207
|
const checkFunction = chainType === 'substrate' ? substrateRecover : evmRecover;
|
|
94
208
|
return await checkFunction(history, chainService);
|
|
95
209
|
} else {
|
|
96
|
-
return
|
|
210
|
+
return {
|
|
211
|
+
status: HistoryRecoverStatus.LACK_INFO
|
|
212
|
+
};
|
|
97
213
|
}
|
|
98
214
|
};
|
|
@@ -38,7 +38,7 @@ export declare class HistoryService implements StoppableServiceInterface, Persis
|
|
|
38
38
|
promise: Promise<void>;
|
|
39
39
|
};
|
|
40
40
|
init(): Promise<void>;
|
|
41
|
-
|
|
41
|
+
recoverProcessingHistory(): Promise<void>;
|
|
42
42
|
start(): Promise<void>;
|
|
43
43
|
waitForStarted(): Promise<void>;
|
|
44
44
|
stopPromiseHandler: {
|
|
@@ -11,7 +11,7 @@ import { BehaviorSubject } from 'rxjs';
|
|
|
11
11
|
import { fetchMultiChainHistories } from "./subsquid-multi-chain-history.js";
|
|
12
12
|
export class HistoryService {
|
|
13
13
|
historySubject = new BehaviorSubject([]);
|
|
14
|
-
#
|
|
14
|
+
#needRecoveryHistories = {};
|
|
15
15
|
constructor(dbService, chainService, eventService, keyringService) {
|
|
16
16
|
this.dbService = dbService;
|
|
17
17
|
this.chainService = chainService;
|
|
@@ -73,7 +73,7 @@ export class HistoryService {
|
|
|
73
73
|
await this.addHistoryItems(updatedRecords);
|
|
74
74
|
}
|
|
75
75
|
async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
|
|
76
|
-
await this.dbService.
|
|
76
|
+
await this.dbService.updateHistoryByExtrinsicHash(extrinsicHash, updateData);
|
|
77
77
|
this.historySubject.next(await this.dbService.getHistories());
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -132,7 +132,7 @@ export class HistoryService {
|
|
|
132
132
|
}
|
|
133
133
|
async recoverHistories() {
|
|
134
134
|
const list = [];
|
|
135
|
-
for (const processingHistory of Object.values(this.#
|
|
135
|
+
for (const processingHistory of Object.values(this.#needRecoveryHistories)) {
|
|
136
136
|
const chainState = this.chainService.getChainStateByKey(processingHistory.chain);
|
|
137
137
|
if (chainState.active) {
|
|
138
138
|
list.push(processingHistory);
|
|
@@ -142,24 +142,28 @@ export class HistoryService {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
const promises = list.map(history => historyRecover(history, this.chainService));
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
145
|
+
const results = await Promise.all(promises);
|
|
146
|
+
results.forEach((recoverResult, index) => {
|
|
147
|
+
const currentExtrinsicHash = list[index].extrinsicHash;
|
|
148
|
+
const updateData = {
|
|
149
|
+
...recoverResult,
|
|
150
|
+
status: ExtrinsicStatus.UNKNOWN
|
|
151
|
+
};
|
|
152
|
+
switch (recoverResult.status) {
|
|
149
153
|
case HistoryRecoverStatus.API_INACTIVE:
|
|
150
154
|
break;
|
|
151
155
|
case HistoryRecoverStatus.FAILED:
|
|
152
156
|
case HistoryRecoverStatus.SUCCESS:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
delete this.#processingHistories[extrinsicHash];
|
|
157
|
+
updateData.status = recoverResult.status === HistoryRecoverStatus.SUCCESS ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL;
|
|
158
|
+
this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
|
|
159
|
+
delete this.#needRecoveryHistories[currentExtrinsicHash];
|
|
157
160
|
break;
|
|
158
161
|
default:
|
|
159
|
-
|
|
162
|
+
this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
|
|
163
|
+
delete this.#needRecoveryHistories[currentExtrinsicHash];
|
|
160
164
|
}
|
|
161
165
|
});
|
|
162
|
-
if (!Object.keys(this.#
|
|
166
|
+
if (!Object.keys(this.#needRecoveryHistories).length) {
|
|
163
167
|
await this.stopRecoverHistories();
|
|
164
168
|
}
|
|
165
169
|
}
|
|
@@ -169,7 +173,7 @@ export class HistoryService {
|
|
|
169
173
|
await this.loadData();
|
|
170
174
|
Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
|
|
171
175
|
this.getHistories().catch(console.log);
|
|
172
|
-
this.
|
|
176
|
+
this.recoverProcessingHistory().catch(console.error);
|
|
173
177
|
this.eventService.on('account.add', () => {
|
|
174
178
|
(async () => {
|
|
175
179
|
await this.stopCron();
|
|
@@ -182,14 +186,18 @@ export class HistoryService {
|
|
|
182
186
|
}).catch(console.error);
|
|
183
187
|
this.status = ServiceStatus.INITIALIZED;
|
|
184
188
|
}
|
|
185
|
-
async
|
|
189
|
+
async recoverProcessingHistory() {
|
|
186
190
|
const histories = await this.dbService.getHistories();
|
|
187
|
-
this.#
|
|
191
|
+
this.#needRecoveryHistories = {};
|
|
188
192
|
histories.filter(history => {
|
|
189
|
-
return history.status
|
|
193
|
+
return [ExtrinsicStatus.PROCESSING, ExtrinsicStatus.SUBMITTING].includes(history.status);
|
|
190
194
|
}).forEach(history => {
|
|
191
|
-
this.#
|
|
195
|
+
this.#needRecoveryHistories[history.extrinsicHash] = history;
|
|
192
196
|
});
|
|
197
|
+
const recoverNumber = Object.keys(this.#needRecoveryHistories).length;
|
|
198
|
+
if (recoverNumber > 0) {
|
|
199
|
+
console.log(`Recover ${recoverNumber} processing history`);
|
|
200
|
+
}
|
|
193
201
|
this.startRecoverHistories().catch(console.error);
|
|
194
202
|
}
|
|
195
203
|
async start() {
|
|
@@ -197,7 +205,6 @@ export class HistoryService {
|
|
|
197
205
|
this.startPromiseHandler = createPromiseHandler();
|
|
198
206
|
this.status = ServiceStatus.STARTING;
|
|
199
207
|
await this.startCron();
|
|
200
|
-
await this.startRecoverHistories();
|
|
201
208
|
this.status = ServiceStatus.STARTED;
|
|
202
209
|
this.startPromiseHandler.resolve();
|
|
203
210
|
} catch (e) {
|
|
@@ -244,7 +244,7 @@ export async function fetchMultiChainHistories(addresses, chainMap, maxPage = 25
|
|
|
244
244
|
const usedAddresses = relatedAddresses.filter(a => lowerAddresses.includes(a.toLowerCase()));
|
|
245
245
|
const chainInfo = chainMap[chainId];
|
|
246
246
|
if (chainInfo === undefined) {
|
|
247
|
-
console.
|
|
247
|
+
console.debug(`Not found chain info for chain id: ${chainId}`); // TODO: resolve conflicting chainId
|
|
248
248
|
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
@@ -253,7 +253,7 @@ export async function fetchMultiChainHistories(addresses, chainMap, maxPage = 25
|
|
|
253
253
|
const transactionData = parseSubsquidTransactionData(address, name, historyItem, chainInfo, parseData(args), parseData(_data));
|
|
254
254
|
histories.push(transactionData);
|
|
255
255
|
} catch (e) {
|
|
256
|
-
console.
|
|
256
|
+
console.debug('Parse transaction data failed', address, e);
|
|
257
257
|
}
|
|
258
258
|
});
|
|
259
259
|
});
|
|
@@ -30,7 +30,7 @@ export default class NotificationService {
|
|
|
30
30
|
type: 'basic',
|
|
31
31
|
title,
|
|
32
32
|
message,
|
|
33
|
-
iconUrl: '
|
|
33
|
+
iconUrl: './images/icon-128.png',
|
|
34
34
|
priority: 2,
|
|
35
35
|
isClickable: !!link
|
|
36
36
|
}, notificationId => {
|
|
@@ -41,7 +41,7 @@ export default class DatabaseService {
|
|
|
41
41
|
subscribeNominatorMetadata(callback: (data: NominatorMetadata[]) => void): void;
|
|
42
42
|
getHistories(query?: HistoryQuery): Promise<import("@subwallet/extension-base/services/storage-service/databases").ITransactionHistoryItem[]>;
|
|
43
43
|
upsertHistory(histories: TransactionHistoryItem[]): Promise<unknown>;
|
|
44
|
-
|
|
44
|
+
updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<unknown>;
|
|
45
45
|
addNftCollection(collection: NftCollection): Promise<unknown>;
|
|
46
46
|
deleteNftCollection(chain: string, collectionId: string): Promise<void>;
|
|
47
47
|
getAllNftCollection(chainHashes?: string[]): import("dexie").PromiseExtended<NftCollection[]>;
|
|
@@ -113,7 +113,7 @@ export default class DatabaseService {
|
|
|
113
113
|
const cleanedHistory = histories.filter(x => x && x.address && x.chain && x.extrinsicHash);
|
|
114
114
|
return this.stores.transaction.bulkUpsert(cleanedHistory);
|
|
115
115
|
}
|
|
116
|
-
async
|
|
116
|
+
async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
|
|
117
117
|
const canUpdate = updateData && extrinsicHash;
|
|
118
118
|
if (!canUpdate) {
|
|
119
119
|
return;
|
|
@@ -161,8 +161,8 @@ export default class TransactionService {
|
|
|
161
161
|
const transactionId = getTransactionId(transaction.chainType, transaction.chain, isInternal);
|
|
162
162
|
return {
|
|
163
163
|
...transaction,
|
|
164
|
-
createdAt: new Date(),
|
|
165
|
-
updatedAt: new Date(),
|
|
164
|
+
createdAt: new Date().getTime(),
|
|
165
|
+
updatedAt: new Date().getTime(),
|
|
166
166
|
errors: transaction.errors || [],
|
|
167
167
|
warnings: transaction.warnings || [],
|
|
168
168
|
url: transaction.url || EXTENSION_REQUEST_URL,
|
|
@@ -203,6 +203,9 @@ export default class TransactionService {
|
|
|
203
203
|
const stopByErrors = validatedTransaction.errors.length > 0;
|
|
204
204
|
const stopByWarnings = validatedTransaction.warnings.length > 0 && !validatedTransaction.ignoreWarnings;
|
|
205
205
|
if (stopByErrors || stopByWarnings) {
|
|
206
|
+
// @ts-ignore
|
|
207
|
+
'transaction' in validatedTransaction && delete validatedTransaction.transaction;
|
|
208
|
+
'additionalValidator' in validatedTransaction && delete validatedTransaction.additionalValidator;
|
|
206
209
|
return validatedTransaction;
|
|
207
210
|
}
|
|
208
211
|
validatedTransaction.warnings = [];
|
|
@@ -220,6 +223,10 @@ export default class TransactionService {
|
|
|
220
223
|
}
|
|
221
224
|
});
|
|
222
225
|
});
|
|
226
|
+
|
|
227
|
+
// @ts-ignore
|
|
228
|
+
'transaction' in validatedTransaction && delete validatedTransaction.transaction;
|
|
229
|
+
'additionalValidator' in validatedTransaction && delete validatedTransaction.additionalValidator;
|
|
223
230
|
return validatedTransaction;
|
|
224
231
|
}
|
|
225
232
|
async sendTransaction(transaction) {
|
|
@@ -272,7 +279,7 @@ export default class TransactionService {
|
|
|
272
279
|
const chainInfo = this.chainService.getChainInfoByKey(transaction.chain);
|
|
273
280
|
return getExplorerLink(chainInfo, transaction.extrinsicHash, 'tx');
|
|
274
281
|
}
|
|
275
|
-
transactionToHistories(id, eventLogs) {
|
|
282
|
+
transactionToHistories(id, startBlock, nonce, eventLogs) {
|
|
276
283
|
const transaction = this.getTransaction(id);
|
|
277
284
|
const historyItem = {
|
|
278
285
|
origin: 'app',
|
|
@@ -286,13 +293,15 @@ export default class TransactionService {
|
|
|
286
293
|
status: transaction.status,
|
|
287
294
|
transactionId: transaction.id,
|
|
288
295
|
extrinsicHash: transaction.extrinsicHash,
|
|
289
|
-
time: transaction.createdAt
|
|
296
|
+
time: transaction.createdAt,
|
|
290
297
|
fee: transaction.estimateFee,
|
|
291
298
|
blockNumber: 0,
|
|
292
299
|
// Will be added in next step
|
|
293
|
-
blockHash: ''
|
|
300
|
+
blockHash: '',
|
|
301
|
+
// Will be added in next step
|
|
302
|
+
nonce: nonce || 0,
|
|
303
|
+
startBlock: startBlock || 0
|
|
294
304
|
};
|
|
295
|
-
|
|
296
305
|
const chainInfo = this.chainService.getChainInfoByKey(transaction.chain);
|
|
297
306
|
const nativeAsset = _getChainNativeTokenBasicInfo(chainInfo);
|
|
298
307
|
const baseNativeAmount = {
|
|
@@ -459,7 +468,9 @@ export default class TransactionService {
|
|
|
459
468
|
console.debug(`Transaction "${id}" is signed`);
|
|
460
469
|
}
|
|
461
470
|
onSend({
|
|
462
|
-
id
|
|
471
|
+
id,
|
|
472
|
+
nonce,
|
|
473
|
+
startBlock
|
|
463
474
|
}) {
|
|
464
475
|
// Update transaction status
|
|
465
476
|
this.updateTransaction(id, {
|
|
@@ -467,7 +478,7 @@ export default class TransactionService {
|
|
|
467
478
|
});
|
|
468
479
|
|
|
469
480
|
// Create Input History Transaction History
|
|
470
|
-
this.historyService.insertHistories(this.transactionToHistories(id)).catch(console.error);
|
|
481
|
+
this.historyService.insertHistories(this.transactionToHistories(id, startBlock, nonce)).catch(console.error);
|
|
471
482
|
console.debug(`Transaction "${id}" is sent`);
|
|
472
483
|
}
|
|
473
484
|
onHasTransactionHash({
|
|
@@ -516,15 +527,18 @@ export default class TransactionService {
|
|
|
516
527
|
onSuccess({
|
|
517
528
|
blockHash,
|
|
518
529
|
blockNumber,
|
|
530
|
+
extrinsicHash,
|
|
519
531
|
id
|
|
520
532
|
}) {
|
|
521
533
|
const transaction = this.getTransaction(id);
|
|
522
534
|
this.updateTransaction(id, {
|
|
523
|
-
status: ExtrinsicStatus.SUCCESS
|
|
535
|
+
status: ExtrinsicStatus.SUCCESS,
|
|
536
|
+
extrinsicHash
|
|
524
537
|
});
|
|
525
538
|
|
|
526
539
|
// Write success transaction history
|
|
527
|
-
this.historyService.
|
|
540
|
+
this.historyService.updateHistoryByExtrinsicHash(transaction.extrinsicHash, {
|
|
541
|
+
extrinsicHash,
|
|
528
542
|
status: ExtrinsicStatus.SUCCESS,
|
|
529
543
|
blockNumber: blockNumber || 0,
|
|
530
544
|
blockHash: blockHash || ''
|
|
@@ -544,6 +558,7 @@ export default class TransactionService {
|
|
|
544
558
|
blockHash,
|
|
545
559
|
blockNumber,
|
|
546
560
|
errors,
|
|
561
|
+
extrinsicHash,
|
|
547
562
|
id
|
|
548
563
|
}) {
|
|
549
564
|
const transaction = this.getTransaction(id);
|
|
@@ -551,11 +566,13 @@ export default class TransactionService {
|
|
|
551
566
|
if (transaction) {
|
|
552
567
|
this.updateTransaction(id, {
|
|
553
568
|
status: nextStatus,
|
|
554
|
-
errors
|
|
569
|
+
errors,
|
|
570
|
+
extrinsicHash
|
|
555
571
|
});
|
|
556
572
|
|
|
557
573
|
// Write failed transaction history
|
|
558
|
-
this.historyService.
|
|
574
|
+
this.historyService.updateHistoryByExtrinsicHash(transaction.extrinsicHash, {
|
|
575
|
+
extrinsicHash: extrinsicHash || transaction.extrinsicHash,
|
|
559
576
|
status: nextStatus,
|
|
560
577
|
blockNumber: blockNumber || 0,
|
|
561
578
|
blockHash: blockHash || ''
|
|
@@ -654,7 +671,7 @@ export default class TransactionService {
|
|
|
654
671
|
errors: [],
|
|
655
672
|
warnings: []
|
|
656
673
|
};
|
|
657
|
-
this.requestService.addConfirmation(id, url || EXTENSION_REQUEST_URL, 'evmSendTransactionRequest', payload, {}).then(({
|
|
674
|
+
this.requestService.addConfirmation(id, url || EXTENSION_REQUEST_URL, 'evmSendTransactionRequest', payload, {}).then(async ({
|
|
658
675
|
isApproved,
|
|
659
676
|
payload
|
|
660
677
|
}) => {
|
|
@@ -680,11 +697,16 @@ export default class TransactionService {
|
|
|
680
697
|
|
|
681
698
|
// Send transaction
|
|
682
699
|
this.handleTransactionTimeout(emitter, eventData);
|
|
700
|
+
|
|
701
|
+
// Add start info
|
|
702
|
+
eventData.nonce = txObject.nonce;
|
|
703
|
+
eventData.startBlock = await web3Api.eth.getBlockNumber();
|
|
683
704
|
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
684
705
|
signedTransaction && web3Api.eth.sendSignedTransaction(signedTransaction).once('transactionHash', hash => {
|
|
685
706
|
eventData.extrinsicHash = hash;
|
|
686
707
|
emitter.emit('extrinsicHash', eventData);
|
|
687
708
|
}).once('receipt', rs => {
|
|
709
|
+
eventData.extrinsicHash = rs.transactionHash;
|
|
688
710
|
eventData.blockHash = rs.blockHash;
|
|
689
711
|
eventData.blockNumber = rs.blockNumber;
|
|
690
712
|
emitter.emit('success', eventData);
|
|
@@ -709,6 +731,7 @@ export default class TransactionService {
|
|
|
709
731
|
}
|
|
710
732
|
signAndSendSubstrateTransaction({
|
|
711
733
|
address,
|
|
734
|
+
chain,
|
|
712
735
|
id,
|
|
713
736
|
transaction,
|
|
714
737
|
url
|
|
@@ -729,11 +752,14 @@ export default class TransactionService {
|
|
|
729
752
|
};
|
|
730
753
|
}
|
|
731
754
|
}
|
|
732
|
-
}).then(rs => {
|
|
755
|
+
}).then(async rs => {
|
|
733
756
|
// Emit signed event
|
|
734
757
|
emitter.emit('signed', eventData);
|
|
735
758
|
|
|
736
759
|
// Send transaction
|
|
760
|
+
const api = this.chainService.getSubstrateApi(chain);
|
|
761
|
+
eventData.nonce = rs.nonce.toNumber();
|
|
762
|
+
eventData.startBlock = (await api.api.query.system.number()).toPrimitive();
|
|
737
763
|
this.handleTransactionTimeout(emitter, eventData);
|
|
738
764
|
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
739
765
|
|
|
@@ -751,6 +777,7 @@ export default class TransactionService {
|
|
|
751
777
|
}
|
|
752
778
|
}
|
|
753
779
|
if (txState.status.isFinalized) {
|
|
780
|
+
eventData.extrinsicHash = txState.txHash.toHex();
|
|
754
781
|
eventData.eventLogs = txState.events;
|
|
755
782
|
// TODO: push block hash and block number into eventData
|
|
756
783
|
txState.events.filter(({
|
|
@@ -14,14 +14,14 @@ export interface SWTransaction extends ValidateTransactionResponse, Partial<Pick
|
|
|
14
14
|
status: ExtrinsicStatus;
|
|
15
15
|
extrinsicHash: string;
|
|
16
16
|
extrinsicType: ExtrinsicType;
|
|
17
|
-
createdAt:
|
|
18
|
-
updatedAt:
|
|
17
|
+
createdAt: number;
|
|
18
|
+
updatedAt: number;
|
|
19
19
|
estimateFee?: AmountData;
|
|
20
20
|
transaction: SubmittableExtrinsic | TransactionConfig;
|
|
21
21
|
additionalValidator?: (inputTransaction: SWTransactionResponse) => Promise<void>;
|
|
22
22
|
eventsHandler?: (eventEmitter: TransactionEmitter) => void;
|
|
23
23
|
}
|
|
24
|
-
export declare type SWTransactionResult = Omit<SWTransaction, 'transaction'>;
|
|
24
|
+
export declare type SWTransactionResult = Omit<SWTransaction, 'transaction' | 'additionalValidator'>;
|
|
25
25
|
declare type SwInputBase = Pick<SWTransaction, 'address' | 'url' | 'data' | 'extrinsicType' | 'chain' | 'chainType' | 'ignoreWarnings' | 'transferNativeAmount'> & Partial<Pick<SWTransaction, 'additionalValidator'>>;
|
|
26
26
|
export interface SWTransactionInput extends SwInputBase {
|
|
27
27
|
transaction?: SWTransaction['transaction'] | null;
|
|
@@ -39,6 +39,8 @@ export interface TransactionEventResponse extends ValidateTransactionResponse {
|
|
|
39
39
|
blockHash?: string;
|
|
40
40
|
blockNumber?: number;
|
|
41
41
|
eventLogs?: EventRecord[];
|
|
42
|
+
nonce?: number;
|
|
43
|
+
startBlock?: number;
|
|
42
44
|
}
|
|
43
45
|
export interface TransactionEventMap {
|
|
44
46
|
send: (response: TransactionEventResponse) => void;
|
|
@@ -21,6 +21,9 @@ function getBlockExplorerTxRoute(chainInfo) {
|
|
|
21
21
|
if (_isPureEvmChain(chainInfo)) {
|
|
22
22
|
return 'tx';
|
|
23
23
|
}
|
|
24
|
+
if (['aventus'].includes(chainInfo.slug)) {
|
|
25
|
+
return 'transaction';
|
|
26
|
+
}
|
|
24
27
|
return 'extrinsic';
|
|
25
28
|
}
|
|
26
29
|
export function getExplorerLink(chainInfo, value, type) {
|
package/utils/index.js
CHANGED