@subwallet/extension-base 1.2.24-2 → 1.2.25-1

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/background/KoniTypes.d.ts +9 -0
  2. package/background/errors/EvmProviderError.d.ts +1 -1
  3. package/background/errors/EvmProviderError.js +2 -2
  4. package/background/errors/SWError.d.ts +1 -1
  5. package/background/errors/SWError.js +4 -1
  6. package/background/errors/TransactionError.d.ts +1 -1
  7. package/background/errors/TransactionError.js +2 -2
  8. package/cjs/background/errors/EvmProviderError.js +2 -2
  9. package/cjs/background/errors/SWError.js +4 -1
  10. package/cjs/background/errors/TransactionError.js +2 -2
  11. package/cjs/core/logic-validation/index.js +49 -0
  12. package/cjs/core/logic-validation/request.js +488 -0
  13. package/cjs/core/logic-validation/transfer.js +25 -8
  14. package/cjs/koni/api/staking/bonding/utils.js +2 -2
  15. package/cjs/koni/background/handlers/Extension.js +33 -8
  16. package/cjs/koni/background/handlers/State.js +41 -160
  17. package/cjs/koni/background/handlers/Tabs.js +35 -33
  18. package/cjs/packageInfo.js +1 -1
  19. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +16 -8
  20. package/cjs/services/chain-service/constants.js +6 -1
  21. package/cjs/services/chain-service/index.js +32 -2
  22. package/cjs/services/chain-service/utils/index.js +2 -2
  23. package/cjs/services/earning-service/constants/chains.js +2 -2
  24. package/cjs/services/earning-service/handlers/liquid-staking/bifrost.js +1 -1
  25. package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +5 -4
  26. package/cjs/services/earning-service/service.js +1 -1
  27. package/cjs/services/event-service/index.js +1 -0
  28. package/cjs/services/request-service/handler/EvmRequestHandler.js +2 -1
  29. package/cjs/services/transaction-service/index.js +11 -7
  30. package/cjs/services/wallet-connect-service/handler/Eip155RequestHandler.js +12 -36
  31. package/core/logic-validation/index.d.ts +4 -0
  32. package/core/logic-validation/index.js +7 -0
  33. package/core/logic-validation/request.d.ts +23 -0
  34. package/core/logic-validation/request.js +475 -0
  35. package/core/logic-validation/transfer.d.ts +1 -1
  36. package/core/logic-validation/transfer.js +25 -8
  37. package/koni/api/staking/bonding/utils.js +2 -2
  38. package/koni/background/handlers/Extension.d.ts +1 -0
  39. package/koni/background/handlers/Extension.js +33 -8
  40. package/koni/background/handlers/State.d.ts +2 -2
  41. package/koni/background/handlers/State.js +42 -161
  42. package/koni/background/handlers/Tabs.d.ts +0 -1
  43. package/koni/background/handlers/Tabs.js +36 -34
  44. package/package.json +16 -6
  45. package/packageInfo.js +1 -1
  46. package/services/balance-service/helpers/subscribe/substrate/index.js +16 -8
  47. package/services/chain-service/constants.js +6 -1
  48. package/services/chain-service/index.d.ts +9 -0
  49. package/services/chain-service/index.js +32 -2
  50. package/services/chain-service/utils/index.js +2 -2
  51. package/services/earning-service/constants/chains.js +2 -2
  52. package/services/earning-service/handlers/liquid-staking/bifrost.js +1 -1
  53. package/services/earning-service/handlers/native-staking/relay-chain.js +5 -4
  54. package/services/earning-service/service.js +1 -1
  55. package/services/event-service/index.d.ts +1 -0
  56. package/services/event-service/index.js +1 -0
  57. package/services/event-service/types.d.ts +1 -0
  58. package/services/request-service/handler/EvmRequestHandler.js +2 -1
  59. package/services/transaction-service/index.js +11 -7
  60. package/services/wallet-connect-service/handler/Eip155RequestHandler.js +9 -33
@@ -0,0 +1,488 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.convertErrorMessage = convertErrorMessage;
8
+ exports.generateValidationProcess = generateValidationProcess;
9
+ exports.validationAuthMiddleware = validationAuthMiddleware;
10
+ exports.validationAuthWCMiddleware = validationAuthWCMiddleware;
11
+ exports.validationConnectMiddleware = validationConnectMiddleware;
12
+ exports.validationEvmDataTransactionMiddleware = validationEvmDataTransactionMiddleware;
13
+ exports.validationEvmSignMessageMiddleware = validationEvmSignMessageMiddleware;
14
+ var _EvmProviderError = require("@subwallet/extension-base/background/errors/EvmProviderError");
15
+ var _TransactionError = require("@subwallet/extension-base/background/errors/TransactionError");
16
+ var _KoniTypes = require("@subwallet/extension-base/background/KoniTypes");
17
+ var _utils = require("@subwallet/extension-base/services/fee-service/utils");
18
+ var _utils2 = require("@subwallet/extension-base/utils");
19
+ var _parseTransaction = require("@subwallet/extension-base/utils/eth/parseTransaction");
20
+ var _uiKeyring = require("@subwallet/ui-keyring");
21
+ var _utils3 = require("@walletconnect/utils");
22
+ var _bignumber = _interopRequireDefault(require("bignumber.js"));
23
+ var _bn = _interopRequireDefault(require("bn.js"));
24
+ var _i18next = require("i18next");
25
+ var _util = require("@polkadot/util");
26
+ var _utilCrypto = require("@polkadot/util-crypto");
27
+ // Copyright 2019-2022 @subwallet/extension-base
28
+ // SPDX-License-Identifier: Apache-2.0
29
+
30
+ async function generateValidationProcess(koni, url, payloadValidate, validationMiddlewareSteps, topic) {
31
+ let resultValidated = payloadValidate;
32
+ for (const step of validationMiddlewareSteps) {
33
+ resultValidated = await step(koni, url, resultValidated, topic);
34
+ if (resultValidated.errorPosition === 'dApp') {
35
+ throw resultValidated.errors[0];
36
+ } else if (resultValidated.errorPosition === 'ui') {
37
+ break;
38
+ }
39
+ }
40
+ return resultValidated;
41
+ }
42
+ async function validationAuthMiddleware(koni, url, payload) {
43
+ const {
44
+ address,
45
+ errors
46
+ } = payload;
47
+ if (!address || !(0, _util.isString)(address)) {
48
+ payload.errorPosition = 'dApp';
49
+ const [message] = convertErrorMessage('Not found address to sign');
50
+ errors.push(new Error(message));
51
+ } else {
52
+ try {
53
+ payload.pair = _uiKeyring.keyring.getPair(address);
54
+ if (!payload.pair) {
55
+ payload.errorPosition = 'dApp';
56
+ const [message] = convertErrorMessage('Unable to find account');
57
+ errors.push(new Error(message));
58
+ } else {
59
+ const authList = await koni.getAuthList();
60
+ const authInfo = authList[(0, _utils2.stripUrl)(url)];
61
+ if (!authInfo || !authInfo.isAllowed || !authInfo.isAllowedMap[payload.pair.address]) {
62
+ payload.errorPosition = 'dApp';
63
+ const [message] = convertErrorMessage('Account not in allowed list', '');
64
+ errors.push(new Error(message));
65
+ }
66
+ payload.authInfo = authInfo;
67
+ }
68
+ } catch (e) {
69
+ const [message] = convertErrorMessage(e.message);
70
+ payload.errorPosition = 'dApp';
71
+ errors.push(new Error(message));
72
+ }
73
+ }
74
+ return payload;
75
+ }
76
+ async function validationConnectMiddleware(koni, url, payload) {
77
+ let currentChain;
78
+ let autoActiveChain = false;
79
+ let {
80
+ address,
81
+ authInfo,
82
+ errors,
83
+ networkKey
84
+ } = {
85
+ ...payload
86
+ };
87
+ const handleError = message_ => {
88
+ payload.errorPosition = 'ui';
89
+ payload.confirmationType = 'errorConnectNetwork';
90
+ const [message, name] = convertErrorMessage(message_);
91
+ const error = new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.CHAIN_DISCONNECTED, message, undefined, name);
92
+ console.error(error);
93
+ errors.push(error);
94
+ };
95
+ if (authInfo !== null && authInfo !== void 0 && authInfo.currentEvmNetworkKey) {
96
+ currentChain = authInfo === null || authInfo === void 0 ? void 0 : authInfo.currentEvmNetworkKey;
97
+ }
98
+ if (authInfo !== null && authInfo !== void 0 && authInfo.isAllowed) {
99
+ autoActiveChain = true;
100
+ }
101
+ const currentEvmNetwork = koni.requestService.getDAppChainInfo({
102
+ autoActive: autoActiveChain,
103
+ accessType: 'evm',
104
+ defaultChain: currentChain,
105
+ url
106
+ });
107
+ networkKey = networkKey || (currentEvmNetwork === null || currentEvmNetwork === void 0 ? void 0 : currentEvmNetwork.slug) || '';
108
+ if (networkKey) {
109
+ const chainStatus = koni.getChainStateByKey(networkKey);
110
+ const chainInfo = koni.getChainInfo(networkKey);
111
+ if (!chainStatus.active) {
112
+ try {
113
+ await koni.chainService.enableChain(networkKey);
114
+ } catch (e) {
115
+ handleError('Can not active chain: ' + chainInfo.name);
116
+ }
117
+ }
118
+ const evmApi = koni.getEvmApi(networkKey);
119
+ const web3 = evmApi === null || evmApi === void 0 ? void 0 : evmApi.api;
120
+ let currentProviderConnected = false;
121
+ const checkProviderConnected = async () => {
122
+ try {
123
+ currentProviderConnected = !!(await web3.eth.getBalance(address));
124
+ } catch (e) {
125
+ handleError(e.message);
126
+ }
127
+ };
128
+
129
+ // Calculate transaction data
130
+ try {
131
+ await Promise.race([checkProviderConnected(), (0, _utils2.wait)(3000).then(async () => {
132
+ if (!currentProviderConnected) {
133
+ await koni.chainService.initSingleApi(networkKey);
134
+ await checkProviderConnected();
135
+ }
136
+ })]);
137
+ } catch (e) {
138
+ handleError(e.message);
139
+ }
140
+ } else {
141
+ handleError('This network is currently not supported');
142
+ }
143
+ return {
144
+ ...payload,
145
+ networkKey,
146
+ errors
147
+ };
148
+ }
149
+ async function validationEvmDataTransactionMiddleware(koni, url, payload) {
150
+ const errors = payload.errors || [];
151
+ let estimateGas = '';
152
+ const transactionParams = payload.payloadAfterValidated;
153
+ const {
154
+ address: fromAddress,
155
+ networkKey,
156
+ pair
157
+ } = payload;
158
+ const evmApi = koni.getEvmApi(networkKey || '');
159
+ const web3 = evmApi === null || evmApi === void 0 ? void 0 : evmApi.api;
160
+ const autoFormatNumber = val => {
161
+ if (typeof val === 'string' && val.startsWith('0x')) {
162
+ return new _bn.default(val.replace('0x', ''), 16).toString();
163
+ } else if (typeof val === 'number') {
164
+ return val.toString();
165
+ }
166
+ return val;
167
+ };
168
+ const handleError = message_ => {
169
+ payload.errorPosition = 'ui';
170
+ payload.confirmationType = 'evmWatchTransactionRequest';
171
+ const [message, name] = convertErrorMessage(message_);
172
+ const error = new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.INVALID_PARAMS, message, undefined, name);
173
+ console.error(error);
174
+ errors.push(error);
175
+ };
176
+ if (!web3) {
177
+ handleError('connection error');
178
+ }
179
+ const transaction = {
180
+ from: transactionParams.from,
181
+ to: transactionParams.to,
182
+ value: autoFormatNumber(transactionParams.value),
183
+ gas: autoFormatNumber(transactionParams.gas),
184
+ gasPrice: autoFormatNumber(transactionParams.gasPrice || transactionParams.gasLimit),
185
+ maxPriorityFeePerGas: autoFormatNumber(transactionParams.maxPriorityFeePerGas),
186
+ maxFeePerGas: autoFormatNumber(transactionParams.maxFeePerGas),
187
+ data: transactionParams.data
188
+ };
189
+
190
+ // Address is validated in before step
191
+ if (!fromAddress || !(0, _utilCrypto.isEthereumAddress)(fromAddress)) {
192
+ handleError('the sender address must be the ethereum address type');
193
+ }
194
+ if (transaction.to && !(0, _utilCrypto.isEthereumAddress)(transaction.to)) {
195
+ handleError('invalid recipient address');
196
+ }
197
+ if (fromAddress === transaction.to) {
198
+ handleError('receiving address must be different from sending address');
199
+ }
200
+ if (!transaction.to) {
201
+ if (transaction.data) {
202
+ if (transaction.value) {
203
+ try {
204
+ const valueBn = new _bignumber.default(transaction.value.toString());
205
+ if (!valueBn.eq(_utils2.BN_ZERO)) {
206
+ handleError('Recipient address not found');
207
+ }
208
+ } catch (e) {
209
+ handleError('invalid number');
210
+ }
211
+ }
212
+ } else {
213
+ handleError('Recipient address not found');
214
+ }
215
+ }
216
+ if (!transaction.gas) {
217
+ const getTransactionGas = async () => {
218
+ try {
219
+ transaction.gas = await web3.eth.estimateGas({
220
+ ...transaction
221
+ });
222
+ } catch (e) {
223
+ handleError(e.message);
224
+ }
225
+ };
226
+
227
+ // Calculate transaction data
228
+ try {
229
+ await Promise.race([getTransactionGas(), (0, _utils2.wait)(3000).then(async () => {
230
+ if (!transaction.gas) {
231
+ await koni.chainService.initSingleApi(networkKey || '');
232
+ await getTransactionGas();
233
+ }
234
+ })]);
235
+ } catch (e) {
236
+ handleError(e.message);
237
+ }
238
+ }
239
+ if (!transaction.gas) {
240
+ handleError(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.INTERNAL_ERROR).message);
241
+ } else {
242
+ if (transactionParams.maxPriorityFeePerGas && transactionParams.maxFeePerGas) {
243
+ const maxFee = new _bignumber.default(transactionParams.maxFeePerGas);
244
+ estimateGas = maxFee.multipliedBy(transaction.gas).toFixed(0);
245
+ } else if (transactionParams.gasPrice) {
246
+ estimateGas = new _bignumber.default(transactionParams.gasPrice).multipliedBy(transaction.gas).toFixed(0);
247
+ } else {
248
+ try {
249
+ const priority = await (0, _utils.calculateGasFeeParams)(evmApi, networkKey || '');
250
+ if (priority.baseGasFee) {
251
+ transaction.maxPriorityFeePerGas = priority.maxPriorityFeePerGas.toString();
252
+ transaction.maxFeePerGas = priority.maxFeePerGas.toString();
253
+ const maxFee = priority.maxFeePerGas;
254
+ estimateGas = maxFee.multipliedBy(transaction.gas).toFixed(0);
255
+ } else {
256
+ transaction.gasPrice = priority.gasPrice;
257
+ estimateGas = new _bignumber.default(priority.gasPrice).multipliedBy(transaction.gas).toFixed(0);
258
+ }
259
+ } catch (e) {
260
+ handleError(e.message);
261
+ }
262
+ }
263
+ try {
264
+ // Validate balance
265
+ const balance = new _bn.default((await web3.eth.getBalance(fromAddress)) || 0);
266
+ if (!estimateGas) {
267
+ handleError('Can\'t calculate estimate gas fee');
268
+ } else if (balance.lt(new _bn.default(estimateGas).add(new _bn.default(autoFormatNumber(transactionParams.value) || '0')))) {
269
+ handleError('Insufficient balance');
270
+ }
271
+ } catch (e) {
272
+ handleError(e.message);
273
+ }
274
+ }
275
+ const pair_ = pair || _uiKeyring.keyring.getPair(fromAddress);
276
+ const account = {
277
+ address: fromAddress,
278
+ ...(pair_ === null || pair_ === void 0 ? void 0 : pair_.meta)
279
+ };
280
+ try {
281
+ transaction.nonce = await web3.eth.getTransactionCount(fromAddress);
282
+ } catch (e) {
283
+ handleError(e.message);
284
+ }
285
+ const hasError = errors && errors.length > 0 || !networkKey;
286
+ const evmNetwork = koni.getChainInfo(networkKey || '');
287
+ let isToContract = false;
288
+ let hashPayload = '';
289
+ let parseData = '';
290
+ try {
291
+ hashPayload = hasError ? '' : koni.transactionService.generateHashPayload(networkKey, transaction);
292
+ isToContract = await (0, _parseTransaction.isContractAddress)(transaction.to || '', evmApi);
293
+ parseData = isToContract ? transaction.data && !hasError ? (await (0, _parseTransaction.parseContractInput)(transaction.data, transaction.to || '', evmNetwork)).result : '' : transaction.data || '';
294
+ } catch (e) {
295
+ handleError(e.message);
296
+ }
297
+ return {
298
+ ...payload,
299
+ errors,
300
+ payloadAfterValidated: {
301
+ ...transaction,
302
+ account,
303
+ estimateGas,
304
+ hashPayload,
305
+ isToContract,
306
+ parseData,
307
+ canSign: !hasError
308
+ }
309
+ };
310
+ }
311
+ async function validationEvmSignMessageMiddleware(koni, url, payload_) {
312
+ const {
313
+ address,
314
+ errors,
315
+ method,
316
+ pair: pair_
317
+ } = payload_;
318
+ let payload = payload_.payloadAfterValidated;
319
+ const {
320
+ promise,
321
+ resolve
322
+ } = (0, _utils2.createPromiseHandler)();
323
+ let hashPayload = '';
324
+ let canSign = false;
325
+ const handleError = message_ => {
326
+ payload_.errorPosition = 'ui';
327
+ payload_.confirmationType = 'evmSignatureRequest';
328
+ const [message, name] = convertErrorMessage(message_);
329
+ const error = new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.INVALID_PARAMS, message, undefined, name);
330
+ console.error(error);
331
+ errors.push(new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.INVALID_PARAMS, message, undefined, name));
332
+ };
333
+ if (address === '' || !payload) {
334
+ handleError('Not found address or payload to sign');
335
+ }
336
+ const pair = pair_ || _uiKeyring.keyring.getPair(address);
337
+ const account = {
338
+ address: pair.address,
339
+ ...pair.meta
340
+ };
341
+ if (method) {
342
+ if (['eth_sign', 'personal_sign', 'eth_signTypedData', 'eth_signTypedData_v1', 'eth_signTypedData_v3', 'eth_signTypedData_v4'].indexOf(method) < 0) {
343
+ handleError('Unsupported action');
344
+ }
345
+ if (['eth_signTypedData_v3', 'eth_signTypedData_v4'].indexOf(method) > -1) {
346
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment
347
+ payload = JSON.parse(payload);
348
+ }
349
+ switch (method) {
350
+ case 'personal_sign':
351
+ canSign = true;
352
+ hashPayload = payload;
353
+ break;
354
+ case 'eth_sign':
355
+ case 'eth_signTypedData':
356
+ case 'eth_signTypedData_v1':
357
+ case 'eth_signTypedData_v3':
358
+ case 'eth_signTypedData_v4':
359
+ if (!account.isExternal) {
360
+ canSign = true;
361
+ }
362
+ break;
363
+ default:
364
+ handleError('Unsupported action');
365
+ }
366
+ } else {
367
+ handleError('Unsupported method');
368
+ }
369
+ const payloadAfterValidated = {
370
+ account: account,
371
+ type: method || '',
372
+ payload: payload,
373
+ hashPayload: hashPayload,
374
+ canSign: canSign,
375
+ id: ''
376
+ };
377
+ resolve({
378
+ ...payload_,
379
+ errors,
380
+ payloadAfterValidated
381
+ });
382
+ return promise;
383
+ }
384
+ function validationAuthWCMiddleware(koni, url, payload, topic) {
385
+ const {
386
+ promise,
387
+ resolve
388
+ } = (0, _utils2.createPromiseHandler)();
389
+ const {
390
+ address,
391
+ errors
392
+ } = payload;
393
+ if (!topic) {
394
+ payload.errorPosition = 'dApp';
395
+ errors.push(new Error((0, _utils3.getSdkError)('UNAUTHORIZED_EXTEND_REQUEST').message));
396
+ } else {
397
+ const requestSession = koni.walletConnectService.getSession(topic);
398
+ let sessionAccounts = [];
399
+ if ((0, _utilCrypto.isEthereumAddress)(address)) {
400
+ var _requestSession$names;
401
+ sessionAccounts = ((_requestSession$names = requestSession.namespaces.eip155.accounts) === null || _requestSession$names === void 0 ? void 0 : _requestSession$names.map(account => account.split(':')[2])) || sessionAccounts;
402
+ } else {
403
+ var _requestSession$names2;
404
+ sessionAccounts = ((_requestSession$names2 = requestSession.namespaces.polkadot.accounts) === null || _requestSession$names2 === void 0 ? void 0 : _requestSession$names2.map(account => account.split(':')[2])) || sessionAccounts;
405
+ }
406
+ if (!address || !(0, _util.isString)(address)) {
407
+ payload.errorPosition = 'dApp';
408
+ const [message] = convertErrorMessage('Unable to find account');
409
+ errors.push(new Error(message));
410
+ } else {
411
+ try {
412
+ payload.pair = _uiKeyring.keyring.getPair(address);
413
+ if (!payload.pair) {
414
+ payload.errorPosition = 'dApp';
415
+ const [message] = convertErrorMessage('Unable to find account');
416
+ errors.push(new Error(message));
417
+ }
418
+ const isExitsAccount = sessionAccounts.find(account => (0, _utils2.isSameAddress)(account, address));
419
+ if (!isExitsAccount) {
420
+ payload.errorPosition = 'dApp';
421
+ const [message] = convertErrorMessage('Account not in allowed list');
422
+ errors.push(new Error(message));
423
+ }
424
+ } catch (e) {
425
+ const [message] = convertErrorMessage(e.message);
426
+ payload.errorPosition = 'dApp';
427
+ errors.push(new Error(message));
428
+ }
429
+ }
430
+ }
431
+ resolve({
432
+ ...payload,
433
+ errors
434
+ });
435
+ return promise;
436
+ }
437
+ function convertErrorMessage(message_, name) {
438
+ const message = message_.toLowerCase();
439
+
440
+ // Network error
441
+ if (message.includes('connection error') || message.includes('connection not open') || message.includes('connection timeout') || message.includes('can not active chain') || message.includes('invalid json rpc')) {
442
+ return [(0, _i18next.t)('Re-enable the network or change RPC on the extension and try again'), (0, _i18next.t)('Unstable network connection')];
443
+ }
444
+ if (message.includes('network is currently not supported')) {
445
+ return [(0, _i18next.t)('This network is not yet supported on SubWallet. |Import the network|https://docs.subwallet.app/main/extension-user-guide/customize-your-networks#import-networks| on SubWallet and try again'), (0, _i18next.t)('Network not supported')];
446
+ }
447
+
448
+ // Authentication
449
+ if (message.includes('not found address to sign') || message.includes('unable to find account') || message.includes('unable to retrieve keypair')) {
450
+ return ['Address not found on SubWallet. Re-check the address information in the extension then try again'];
451
+ }
452
+ if (message.includes('account not in allowed list')) {
453
+ return ['Account disconnected from the dApp. Open the extension to re-connect the account and try again'];
454
+ }
455
+
456
+ // Transaction
457
+
458
+ if (message.includes('recipient address not found')) {
459
+ return [(0, _i18next.t)('Enter recipient address and try again'), (0, _i18next.t)('Recipient address not found')];
460
+ }
461
+ if (message.includes('is not a number') || message.includes('invalid number value') || message.includes('invalid bignumberish')) {
462
+ return [(0, _i18next.t)('Amount must be an integer. Enter an integer and try again'), (0, _i18next.t)('Invalid amount')];
463
+ }
464
+ if (message.includes('calculate estimate gas fee') || message.includes('invalidcode')) {
465
+ return [(0, _i18next.t)('Unable to calculate estimated gas for this transaction. Try again or contact support at agent@subwallet.app'), (0, _i18next.t)('Gas calculation error')];
466
+ }
467
+ if (message.includes('invalid recipient address')) {
468
+ return [(0, _i18next.t)('Make sure the recipient address is valid and in the same type as the sender address, then try again'), (0, _i18next.t)('Invalid recipient address')];
469
+ }
470
+ if (message.includes('must be different from sending address')) {
471
+ return [(0, _i18next.t)('The recipient address must be different from the sender address'), (0, _i18next.t)('Invalid recipient address')];
472
+ }
473
+ if (message.includes('the sender address must be the ethereum address type')) {
474
+ return [(0, _i18next.t)('The sender address must be the ethereum address type'), (0, _i18next.t)('Invalid address type')];
475
+ }
476
+ if (message.includes('insufficient balance') || message.includes('insufficient funds')) {
477
+ return [(0, _i18next.t)('Insufficient balance on the sender address. Top up your balance and try again'), (0, _i18next.t)('Unable to sign transaction')];
478
+ }
479
+
480
+ // Sign Message
481
+ if (message.includes('not found address or payload to sign')) {
482
+ return [(0, _i18next.t)('An error occurred when signing this request. Try again or contact support at agent@subwallet.app'), (0, _i18next.t)('Unable to sign message')];
483
+ }
484
+ if (message.includes('unsupported method') || message.includes('unsupported action')) {
485
+ return [(0, _i18next.t)('This sign method is not supported by SubWallet. Try again or contact support at agent@subwallet.app'), (0, _i18next.t)('Method not supported')];
486
+ }
487
+ return [message, name || ''];
488
+ }
@@ -50,32 +50,49 @@ function validateTransferRequest(tokenInfo, from, to, value, transferAll) {
50
50
  }
51
51
  return [errors, keypair, transferValue];
52
52
  }
53
- function additionalValidateTransfer(tokenInfo, extrinsicType, receiverTransferTokenFreeBalance, transferAmount, senderTransferTokenTransferable) {
53
+ function additionalValidateTransfer(tokenInfo, nativeTokenInfo, extrinsicType, receiverTransferTokenFreeBalance, transferAmount, senderTransferTokenTransferable, receiverNativeTransferable) {
54
54
  const minAmount = (0, _utils._getTokenMinAmount)(tokenInfo);
55
- let warning;
56
- let error;
55
+ const nativeMinAmount = (0, _utils._getTokenMinAmount)(nativeTokenInfo);
56
+ const warnings = [];
57
+ const errors = [];
57
58
 
58
- // Check ed of not native token for sender
59
+ // Check ed of not native token for sender after sending
59
60
  if (extrinsicType === _KoniTypes.ExtrinsicType.TRANSFER_TOKEN && senderTransferTokenTransferable) {
60
61
  if (new _bignumber.default(senderTransferTokenTransferable).minus(transferAmount).lt(minAmount)) {
61
- warning = new _TransactionWarning.TransactionWarning(_KoniTypes.BasicTxWarningCode.NOT_ENOUGH_EXISTENTIAL_DEPOSIT);
62
+ const warning = new _TransactionWarning.TransactionWarning(_KoniTypes.BasicTxWarningCode.NOT_ENOUGH_EXISTENTIAL_DEPOSIT);
63
+ warnings.push(warning);
64
+ }
65
+ }
66
+
67
+ // Check ed for receiver before sending
68
+ if (extrinsicType === _KoniTypes.ExtrinsicType.TRANSFER_TOKEN && receiverNativeTransferable) {
69
+ if (new _bignumber.default(receiverNativeTransferable).lt(nativeMinAmount)) {
70
+ const error = new _TransactionError.TransactionError(_KoniTypes.TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, (0, _i18next.t)('The recipient account has {{amount}} {{nativeSymbol}} which can lead to your {{localSymbol}} being lost. Change recipient account and try again', {
71
+ replace: {
72
+ amount: receiverNativeTransferable,
73
+ nativeSymbol: nativeTokenInfo.symbol,
74
+ localSymbol: tokenInfo.symbol
75
+ }
76
+ }));
77
+ errors.push(error);
62
78
  }
63
79
  }
64
80
 
65
- // Check ed for receiver
81
+ // Check ed for receiver after sending
66
82
  if (new _bignumber.default(receiverTransferTokenFreeBalance).plus(transferAmount).lt(minAmount)) {
67
83
  const atLeast = new _bignumber.default(minAmount).minus(receiverTransferTokenFreeBalance).plus((tokenInfo.decimals || 0) === 0 ? 0 : 1);
68
84
  const atLeastStr = (0, _utils3.formatNumber)(atLeast, tokenInfo.decimals || 0, _utils3.balanceFormatter, {
69
85
  maxNumberFormat: tokenInfo.decimals || 6
70
86
  });
71
- error = new _TransactionError.TransactionError(_KoniTypes.TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, (0, _i18next.t)('You must transfer at least {{amount}} {{symbol}} to keep the destination account alive', {
87
+ const error = new _TransactionError.TransactionError(_KoniTypes.TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, (0, _i18next.t)('You must transfer at least {{amount}} {{symbol}} to keep the destination account alive', {
72
88
  replace: {
73
89
  amount: atLeastStr,
74
90
  symbol: tokenInfo.symbol
75
91
  }
76
92
  }));
93
+ errors.push(error);
77
94
  }
78
- return [warning, error];
95
+ return [warnings, errors];
79
96
  }
80
97
 
81
98
  // xcm transfer
@@ -129,7 +129,7 @@ function calculateChainStakedReturnV2(chainInfo, totalIssuance, erasPerDay, last
129
129
  const multiplier = dayRewardRate.dividedBy(100).plus(1).exponentiatedBy(365);
130
130
  inflationToStakers = new _bignumber.default(100).multipliedBy(multiplier).minus(100);
131
131
  }
132
- const averageRewardRate = (['avail_mainnet'].includes(chainInfo.slug) ? inflation : inflationToStakers).dividedBy(supplyStaked);
132
+ const averageRewardRate = (['avail_mainnet', 'dentnet'].includes(chainInfo.slug) ? inflation : inflationToStakers).dividedBy(supplyStaked);
133
133
  return averageRewardRate.toNumber();
134
134
  }
135
135
  function calculateAlephZeroValidatorReturn(chainStakedReturn, commission) {
@@ -388,7 +388,7 @@ function getAvgValidatorEraReward(supportedDays, eraRewardHistory) {
388
388
  return sumEraReward.dividedBy(new _bignumber.default(supportedDays - failEra));
389
389
  }
390
390
  function getSupportedDaysByHistoryDepth(erasPerDay, maxSupportedEras, liveDay) {
391
- const maxSupportDay = maxSupportedEras / erasPerDay;
391
+ const maxSupportDay = Math.floor(maxSupportedEras / erasPerDay);
392
392
  if (liveDay && liveDay <= 30) {
393
393
  return Math.min(liveDay - 1, maxSupportDay);
394
394
  }
@@ -1706,18 +1706,23 @@ class KoniExtension {
1706
1706
  const transferNativeAmount = isTransferNativeToken ? transferAmount.value : '0';
1707
1707
  const additionalValidator = async inputTransaction => {
1708
1708
  let senderTransferTokenTransferable;
1709
+ let receiverNativeTransferable;
1709
1710
 
1710
1711
  // Check ed for sender
1711
1712
  if (!isTransferNativeToken) {
1712
- const {
1713
- value
1714
- } = await this.getAddressTransferableBalance({
1713
+ const [_senderTransferTokenTransferable, _receiverNativeTransferable] = await Promise.all([this.getAddressTransferableBalance({
1715
1714
  address: from,
1716
1715
  networkKey,
1717
1716
  token: tokenSlug,
1718
1717
  extrinsicType
1719
- });
1720
- senderTransferTokenTransferable = value;
1718
+ }), this.getAddressTransferableBalance({
1719
+ address: to,
1720
+ networkKey,
1721
+ token: nativeTokenSlug,
1722
+ extrinsicType: _KoniTypes.ExtrinsicType.TRANSFER_BALANCE
1723
+ })]);
1724
+ senderTransferTokenTransferable = _senderTransferTokenTransferable.value;
1725
+ receiverNativeTransferable = _receiverNativeTransferable.value;
1721
1726
  }
1722
1727
  const {
1723
1728
  value: receiverTransferTokenTransferable
@@ -1728,9 +1733,9 @@ class KoniExtension {
1728
1733
  extrinsicType
1729
1734
  }); // todo: shouldn't be just transferable, locked also counts
1730
1735
 
1731
- const [warning, error] = (0, _transfer.additionalValidateTransfer)(transferTokenInfo, extrinsicType, receiverTransferTokenTransferable, transferAmount.value, senderTransferTokenTransferable);
1732
- warning && inputTransaction.warnings.push(warning);
1733
- error && inputTransaction.errors.push(error);
1736
+ const [warnings, errors] = (0, _transfer.additionalValidateTransfer)(transferTokenInfo, nativeTokenInfo, extrinsicType, receiverTransferTokenTransferable, transferAmount.value, senderTransferTokenTransferable, receiverNativeTransferable);
1737
+ warnings.length && inputTransaction.warnings.push(...warnings);
1738
+ errors.length && inputTransaction.errors.push(...errors);
1734
1739
  };
1735
1740
  return this.#koniState.transactionService.handleTransaction({
1736
1741
  errors,
@@ -4251,6 +4256,21 @@ class KoniExtension {
4251
4256
  }
4252
4257
  /* Swap service */
4253
4258
 
4259
+ /* Ledger */
4260
+
4261
+ async subscribeLedgerGenericAllowChains(id, port) {
4262
+ const cb = (0, _subscriptions.createSubscription)(id, port);
4263
+ await this.#koniState.eventService.waitLedgerReady;
4264
+ const subscription = this.#koniState.chainService.observable.ledgerGenericAllowChains.subscribe(cb);
4265
+ this.createUnsubscriptionHandle(id, subscription.unsubscribe);
4266
+ port.onDisconnect.addListener(() => {
4267
+ this.cancelSubscription(id);
4268
+ });
4269
+ return this.#koniState.chainService.value.ledgerGenericAllowChains;
4270
+ }
4271
+
4272
+ /* Ledger */
4273
+
4254
4274
  // --------------------------------------------------------------
4255
4275
  // eslint-disable-next-line @typescript-eslint/require-await
4256
4276
  async handle(id, type, request, port) {
@@ -4815,6 +4835,11 @@ class KoniExtension {
4815
4835
  case 'pri(swapService.handleSwapStep)':
4816
4836
  return this.handleSwapStep(request);
4817
4837
  /* Swap service */
4838
+
4839
+ /* Ledger */
4840
+ case 'pri(ledger.generic.allow)':
4841
+ return this.subscribeLedgerGenericAllowChains(id, port);
4842
+ /* Ledger */
4818
4843
  // Default
4819
4844
  default:
4820
4845
  throw new Error(`Unable to handle message of type ${type}`);