@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.
Files changed (40) hide show
  1. package/background/KoniTypes.d.ts +2 -1
  2. package/cjs/koni/api/staking/bonding/relayChain.js +2 -7
  3. package/cjs/koni/api/staking/bonding/utils.js +9 -0
  4. package/cjs/koni/background/handlers/Extension.js +4 -2
  5. package/cjs/koni/background/handlers/Tabs.js +24 -23
  6. package/cjs/packageInfo.js +1 -1
  7. package/cjs/services/chain-service/constants.js +2 -2
  8. package/cjs/services/chain-service/index.js +5 -0
  9. package/cjs/services/chain-service/utils.js +15 -10
  10. package/cjs/services/history-service/helpers/recoverHistoryStatus.js +157 -38
  11. package/cjs/services/history-service/index.js +26 -19
  12. package/cjs/services/history-service/subsquid-multi-chain-history.js +2 -2
  13. package/cjs/services/notification-service/NotificationService.js +1 -1
  14. package/cjs/services/storage-service/DatabaseService.js +1 -1
  15. package/cjs/services/transaction-service/index.js +41 -14
  16. package/cjs/services/transaction-service/utils.js +3 -0
  17. package/cjs/utils/index.js +3 -0
  18. package/koni/api/staking/bonding/relayChain.js +3 -8
  19. package/koni/api/staking/bonding/utils.d.ts +1 -0
  20. package/koni/api/staking/bonding/utils.js +8 -0
  21. package/koni/background/handlers/Extension.js +5 -3
  22. package/koni/background/handlers/Tabs.js +24 -23
  23. package/package.json +6 -6
  24. package/packageInfo.js +1 -1
  25. package/services/chain-service/constants.js +2 -2
  26. package/services/chain-service/index.js +5 -0
  27. package/services/chain-service/utils.d.ts +1 -0
  28. package/services/chain-service/utils.js +14 -10
  29. package/services/history-service/helpers/recoverHistoryStatus.d.ts +7 -1
  30. package/services/history-service/helpers/recoverHistoryStatus.js +151 -35
  31. package/services/history-service/index.d.ts +1 -1
  32. package/services/history-service/index.js +26 -19
  33. package/services/history-service/subsquid-multi-chain-history.js +2 -2
  34. package/services/notification-service/NotificationService.js +1 -1
  35. package/services/storage-service/DatabaseService.d.ts +1 -1
  36. package/services/storage-service/DatabaseService.js +1 -1
  37. package/services/transaction-service/index.js +41 -14
  38. package/services/transaction-service/types.d.ts +5 -3
  39. package/services/transaction-service/utils.js +3 -0
  40. 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
- console.log(`Fail to find extrinsic ${extrinsicHash} on ${chain}: No block hash`);
26
- return HistoryRecoverStatus.LACK_INFO;
27
- }
28
- const block = await api.rpc.chain.getBlock(blockHash);
29
- const allEvents = await api.query.system.events.at(blockHash);
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
- if (index === undefined) {
38
- console.log(`Fail to find extrinsic ${extrinsicHash} on ${chain}`);
39
- return HistoryRecoverStatus.FAIL_DETECT;
40
- }
41
- const events = allEvents.filter(({
42
- phase
43
- }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index));
44
- for (const {
45
- event
46
- } of events) {
47
- if (api.events.system.ExtrinsicSuccess.is(event)) {
48
- return HistoryRecoverStatus.SUCCESS;
49
- } else if (api.events.system.ExtrinsicFailed.is(event)) {
50
- return HistoryRecoverStatus.FAILED;
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 HistoryRecoverStatus.FAIL_DETECT;
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 HistoryRecoverStatus.API_INACTIVE;
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 HistoryRecoverStatus.UNKNOWN;
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
- const block = await api.eth.getTransactionReceipt(extrinsicHash);
74
- return block.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED;
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 HistoryRecoverStatus.API_INACTIVE;
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 HistoryRecoverStatus.UNKNOWN;
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 HistoryRecoverStatus.LACK_INFO;
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
- getProcessingHistory(): Promise<void>;
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
- #processingHistories = {};
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.updateHistoryByNewExtrinsicHash(extrinsicHash, updateData);
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.#processingHistories)) {
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 result = await Promise.all(promises);
146
- result.forEach((status, index) => {
147
- const extrinsicHash = list[index].extrinsicHash;
148
- switch (status) {
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
- this.updateHistoryByExtrinsicHash(extrinsicHash, {
154
- status: status === HistoryRecoverStatus.SUCCESS ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL
155
- }).catch(console.error);
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
- delete this.#processingHistories[extrinsicHash];
162
+ this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
163
+ delete this.#needRecoveryHistories[currentExtrinsicHash];
160
164
  }
161
165
  });
162
- if (!Object.keys(this.#processingHistories).length) {
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.getProcessingHistory().catch(console.log);
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 getProcessingHistory() {
189
+ async recoverProcessingHistory() {
186
190
  const histories = await this.dbService.getHistories();
187
- this.#processingHistories = {};
191
+ this.#needRecoveryHistories = {};
188
192
  histories.filter(history => {
189
- return history.status === 'processing';
193
+ return [ExtrinsicStatus.PROCESSING, ExtrinsicStatus.SUBMITTING].includes(history.status);
190
194
  }).forEach(history => {
191
- this.#processingHistories[history.extrinsicHash] = history;
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.warn(`Not found chain info for chain id: ${chainId}`); // TODO: resolve conflicting chainId
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.warn('Parse transaction data failed', address, e);
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: 'https://subwallet.app/assets/images/favicon/favicon-192x192.png',
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
- updateHistoryByNewExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<unknown>;
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 updateHistoryByNewExtrinsicHash(extrinsicHash, updateData) {
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.getTime(),
296
+ time: transaction.createdAt,
290
297
  fee: transaction.estimateFee,
291
298
  blockNumber: 0,
292
299
  // Will be added in next step
293
- blockHash: '' // Will be added in next step
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.updateHistories(transaction.chain, transaction.extrinsicHash, {
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.updateHistories(transaction.chain, transaction.extrinsicHash, {
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: Date;
18
- updatedAt: Date;
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
@@ -15,6 +15,9 @@ export function isAccountAll(address) {
15
15
  }
16
16
  export function reformatAddress(address, networkPrefix = 42, isEthereum = false) {
17
17
  try {
18
+ if (!address || address === '') {
19
+ return '';
20
+ }
18
21
  if (isEthereumAddress(address)) {
19
22
  return address;
20
23
  }