@subwallet/extension-base 1.3.41-0 → 1.3.43-0

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 (219) hide show
  1. package/background/KoniTypes.d.ts +134 -5
  2. package/background/KoniTypes.js +18 -0
  3. package/background/errors/BitcoinProviderError.d.ts +6 -0
  4. package/background/errors/BitcoinProviderError.js +47 -0
  5. package/background/types.d.ts +1 -1
  6. package/cjs/background/KoniTypes.js +20 -1
  7. package/cjs/background/errors/BitcoinProviderError.js +54 -0
  8. package/cjs/constants/bitcoin.js +22 -0
  9. package/cjs/constants/index.js +16 -1
  10. package/cjs/core/logic-validation/recipientAddress.js +9 -0
  11. package/cjs/core/logic-validation/request.js +316 -3
  12. package/cjs/core/logic-validation/transfer.js +25 -5
  13. package/cjs/core/types.js +1 -0
  14. package/cjs/core/utils.js +15 -1
  15. package/cjs/koni/background/handlers/Extension.js +477 -93
  16. package/cjs/koni/background/handlers/State.js +249 -16
  17. package/cjs/koni/background/handlers/Tabs.js +119 -6
  18. package/cjs/packageInfo.js +1 -1
  19. package/cjs/page/bitcoin/index.js +67 -0
  20. package/cjs/page/index.js +5 -0
  21. package/cjs/services/balance-service/helpers/subscribe/bitcoin.js +94 -0
  22. package/cjs/services/balance-service/helpers/subscribe/index.js +19 -7
  23. package/cjs/services/balance-service/index.js +32 -4
  24. package/cjs/services/balance-service/transfer/bitcoin-transfer.js +119 -0
  25. package/cjs/services/balance-service/transfer/token.js +2 -0
  26. package/cjs/services/base/types.js +2 -0
  27. package/cjs/services/buy-service/index.js +17 -2
  28. package/cjs/services/chain-service/constants.js +14 -3
  29. package/cjs/services/chain-service/handler/bitcoin/BitcoinApi.js +105 -0
  30. package/cjs/services/chain-service/handler/bitcoin/BitcoinChainHandler.js +78 -0
  31. package/cjs/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.js +371 -0
  32. package/cjs/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/index.js +19 -0
  33. package/cjs/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.js +368 -0
  34. package/cjs/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.js +302 -0
  35. package/cjs/services/chain-service/handler/bitcoin/strategy/types.js +1 -0
  36. package/cjs/services/chain-service/index.js +27 -3
  37. package/cjs/services/chain-service/utils/index.js +57 -4
  38. package/cjs/services/chain-service/utils/patch.js +1 -1
  39. package/cjs/services/earning-service/handlers/native-staking/para-chain.js +27 -5
  40. package/cjs/services/event-service/index.js +4 -0
  41. package/cjs/services/fee-service/service.js +8 -3
  42. package/cjs/services/hiro-service/index.js +96 -0
  43. package/cjs/services/hiro-service/utils/index.js +85 -0
  44. package/cjs/services/history-service/bitcoin-history.js +58 -0
  45. package/cjs/services/history-service/helpers/recoverHistoryStatus.js +96 -4
  46. package/cjs/services/history-service/index.js +41 -3
  47. package/cjs/services/keyring-service/context/handlers/Derive.js +1 -1
  48. package/cjs/services/keyring-service/context/handlers/Migration.js +2 -2
  49. package/cjs/services/keyring-service/context/handlers/Mnemonic.js +4 -3
  50. package/cjs/services/migration-service/scripts/MigrateNewUnifiedAccount.js +29 -0
  51. package/cjs/services/migration-service/scripts/index.js +3 -1
  52. package/cjs/services/request-service/handler/AuthRequestHandler.js +18 -0
  53. package/cjs/services/request-service/handler/BitcoinRequestHandler.js +427 -0
  54. package/cjs/services/request-service/index.js +29 -3
  55. package/cjs/services/rune-service/index.js +105 -0
  56. package/cjs/services/transaction-service/helpers/index.js +7 -1
  57. package/cjs/services/transaction-service/index.js +206 -16
  58. package/cjs/services/transaction-service/utils.js +6 -3
  59. package/cjs/strategy/api-request-strategy/context/base.js +31 -0
  60. package/cjs/strategy/api-request-strategy/index.js +90 -0
  61. package/cjs/strategy/api-request-strategy/types.js +1 -0
  62. package/cjs/strategy/api-request-strategy/utils/index.js +33 -0
  63. package/cjs/types/account/info/keyring.js +1 -1
  64. package/cjs/types/bitcoin.js +24 -0
  65. package/cjs/types/fee/bitcoin.js +1 -0
  66. package/cjs/types/fee/index.js +11 -0
  67. package/cjs/types/index.js +11 -0
  68. package/cjs/utils/account/analyze.js +3 -3
  69. package/cjs/utils/account/common.js +16 -6
  70. package/cjs/utils/account/derive/info/solo.js +68 -19
  71. package/cjs/utils/account/derive/info/unified.js +2 -0
  72. package/cjs/utils/account/derive/validate.js +70 -2
  73. package/cjs/utils/account/transform.js +11 -5
  74. package/cjs/utils/auth.js +2 -1
  75. package/cjs/utils/bitcoin/common.js +98 -0
  76. package/cjs/utils/bitcoin/fee.js +21 -0
  77. package/cjs/utils/bitcoin/index.js +38 -0
  78. package/cjs/utils/bitcoin/utxo-management.js +281 -0
  79. package/cjs/utils/fee/transfer.js +48 -0
  80. package/cjs/utils/index.js +15 -1
  81. package/constants/bitcoin.d.ts +3 -0
  82. package/constants/bitcoin.js +13 -0
  83. package/constants/index.d.ts +2 -0
  84. package/constants/index.js +3 -1
  85. package/core/logic-validation/recipientAddress.js +10 -1
  86. package/core/logic-validation/request.d.ts +6 -2
  87. package/core/logic-validation/request.js +309 -3
  88. package/core/logic-validation/transfer.d.ts +2 -2
  89. package/core/logic-validation/transfer.js +27 -7
  90. package/core/types.d.ts +1 -0
  91. package/core/types.js +1 -0
  92. package/core/utils.d.ts +1 -0
  93. package/core/utils.js +15 -2
  94. package/koni/background/handlers/Extension.d.ts +5 -0
  95. package/koni/background/handlers/Extension.js +387 -9
  96. package/koni/background/handlers/State.d.ts +10 -3
  97. package/koni/background/handlers/State.js +240 -15
  98. package/koni/background/handlers/Tabs.d.ts +7 -2
  99. package/koni/background/handlers/Tabs.js +119 -9
  100. package/package.json +149 -8
  101. package/packageInfo.js +1 -1
  102. package/page/bitcoin/index.d.ts +17 -0
  103. package/page/bitcoin/index.js +60 -0
  104. package/page/index.d.ts +2 -1
  105. package/page/index.js +4 -0
  106. package/services/balance-service/helpers/subscribe/bitcoin.d.ts +2 -0
  107. package/services/balance-service/helpers/subscribe/bitcoin.js +87 -0
  108. package/services/balance-service/helpers/subscribe/index.d.ts +2 -2
  109. package/services/balance-service/helpers/subscribe/index.js +20 -8
  110. package/services/balance-service/index.d.ts +2 -0
  111. package/services/balance-service/index.js +32 -4
  112. package/services/balance-service/transfer/bitcoin-transfer.d.ts +14 -0
  113. package/services/balance-service/transfer/bitcoin-transfer.js +112 -0
  114. package/services/balance-service/transfer/cardano-transfer.d.ts +2 -0
  115. package/services/balance-service/transfer/token.js +2 -0
  116. package/services/base/types.d.ts +2 -0
  117. package/services/base/types.js +2 -0
  118. package/services/buy-service/index.js +17 -2
  119. package/services/chain-service/constants.d.ts +6 -0
  120. package/services/chain-service/constants.js +8 -2
  121. package/services/chain-service/handler/bitcoin/BitcoinApi.d.ts +31 -0
  122. package/services/chain-service/handler/bitcoin/BitcoinApi.js +98 -0
  123. package/services/chain-service/handler/bitcoin/BitcoinChainHandler.d.ts +16 -0
  124. package/services/chain-service/handler/bitcoin/BitcoinChainHandler.js +70 -0
  125. package/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.d.ts +28 -0
  126. package/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.js +362 -0
  127. package/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/index.d.ts +2 -0
  128. package/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/index.js +5 -0
  129. package/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.d.ts +28 -0
  130. package/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.js +359 -0
  131. package/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.d.ts +28 -0
  132. package/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.js +293 -0
  133. package/services/chain-service/handler/bitcoin/strategy/types.d.ts +291 -0
  134. package/services/chain-service/handler/bitcoin/strategy/types.js +1 -0
  135. package/services/chain-service/index.d.ts +3 -0
  136. package/services/chain-service/index.js +31 -5
  137. package/services/chain-service/types.d.ts +20 -0
  138. package/services/chain-service/utils/index.d.ts +4 -0
  139. package/services/chain-service/utils/index.js +50 -4
  140. package/services/chain-service/utils/patch.js +1 -1
  141. package/services/earning-service/handlers/native-staking/para-chain.js +27 -5
  142. package/services/event-service/index.d.ts +3 -0
  143. package/services/event-service/index.js +4 -0
  144. package/services/event-service/types.d.ts +3 -0
  145. package/services/fee-service/service.js +8 -3
  146. package/services/hiro-service/index.d.ts +17 -0
  147. package/services/hiro-service/index.js +88 -0
  148. package/services/hiro-service/utils/index.d.ts +6 -0
  149. package/services/hiro-service/utils/index.js +72 -0
  150. package/services/history-service/bitcoin-history.d.ts +4 -0
  151. package/services/history-service/bitcoin-history.js +52 -0
  152. package/services/history-service/helpers/recoverHistoryStatus.d.ts +3 -1
  153. package/services/history-service/helpers/recoverHistoryStatus.js +96 -4
  154. package/services/history-service/index.d.ts +1 -0
  155. package/services/history-service/index.js +42 -4
  156. package/services/keyring-service/context/handlers/Derive.js +2 -2
  157. package/services/keyring-service/context/handlers/Migration.js +2 -2
  158. package/services/keyring-service/context/handlers/Mnemonic.js +4 -3
  159. package/services/migration-service/scripts/MigrateNewUnifiedAccount.d.ts +4 -0
  160. package/services/migration-service/scripts/MigrateNewUnifiedAccount.js +21 -0
  161. package/services/migration-service/scripts/index.js +3 -1
  162. package/services/request-service/handler/AuthRequestHandler.js +19 -1
  163. package/services/request-service/handler/BitcoinRequestHandler.d.ts +22 -0
  164. package/services/request-service/handler/BitcoinRequestHandler.js +414 -0
  165. package/services/request-service/index.d.ts +8 -2
  166. package/services/request-service/index.js +25 -3
  167. package/services/rune-service/index.d.ts +17 -0
  168. package/services/rune-service/index.js +97 -0
  169. package/services/transaction-service/helpers/index.d.ts +3 -1
  170. package/services/transaction-service/helpers/index.js +5 -0
  171. package/services/transaction-service/index.d.ts +4 -5
  172. package/services/transaction-service/index.js +205 -17
  173. package/services/transaction-service/types.d.ts +13 -2
  174. package/services/transaction-service/utils.js +7 -4
  175. package/strategy/api-request-strategy/context/base.d.ts +15 -0
  176. package/strategy/api-request-strategy/context/base.js +24 -0
  177. package/strategy/api-request-strategy/index.d.ts +15 -0
  178. package/strategy/api-request-strategy/index.js +83 -0
  179. package/strategy/api-request-strategy/types.d.ts +22 -0
  180. package/strategy/api-request-strategy/types.js +1 -0
  181. package/strategy/api-request-strategy/utils/index.d.ts +2 -0
  182. package/strategy/api-request-strategy/utils/index.js +23 -0
  183. package/types/account/info/keyring.d.ts +1 -1
  184. package/types/account/info/keyring.js +1 -1
  185. package/types/balance/index.d.ts +4 -1
  186. package/types/balance/transfer.d.ts +19 -0
  187. package/types/bitcoin.d.ts +93 -0
  188. package/types/bitcoin.js +17 -0
  189. package/types/buy.d.ts +1 -1
  190. package/types/fee/base.d.ts +4 -1
  191. package/types/fee/bitcoin.d.ts +18 -0
  192. package/types/fee/bitcoin.js +1 -0
  193. package/types/fee/index.d.ts +1 -0
  194. package/types/fee/index.js +2 -1
  195. package/types/fee/subscription.d.ts +4 -3
  196. package/types/index.d.ts +1 -0
  197. package/types/index.js +1 -0
  198. package/utils/account/analyze.js +4 -4
  199. package/utils/account/common.d.ts +7 -8
  200. package/utils/account/common.js +16 -6
  201. package/utils/account/derive/info/solo.js +70 -21
  202. package/utils/account/derive/info/unified.js +2 -0
  203. package/utils/account/derive/validate.d.ts +1 -0
  204. package/utils/account/derive/validate.js +68 -1
  205. package/utils/account/transform.d.ts +1 -1
  206. package/utils/account/transform.js +11 -5
  207. package/utils/auth.js +3 -2
  208. package/utils/bitcoin/common.d.ts +22 -0
  209. package/utils/bitcoin/common.js +88 -0
  210. package/utils/bitcoin/fee.d.ts +2 -0
  211. package/utils/bitcoin/fee.js +14 -0
  212. package/utils/bitcoin/index.d.ts +3 -0
  213. package/utils/bitcoin/index.js +6 -0
  214. package/utils/bitcoin/utxo-management.d.ts +33 -0
  215. package/utils/bitcoin/utxo-management.js +266 -0
  216. package/utils/fee/transfer.d.ts +3 -1
  217. package/utils/fee/transfer.js +47 -1
  218. package/utils/index.d.ts +1 -0
  219. package/utils/index.js +6 -3
@@ -2,23 +2,26 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { typedSignatureHash } from '@metamask/eth-sig-util';
5
+ import { BitcoinProviderError } from '@subwallet/extension-base/background/errors/BitcoinProviderError';
5
6
  import { CardanoProviderError } from '@subwallet/extension-base/background/errors/CardanoProviderError';
6
7
  import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError';
7
8
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
8
- import { CardanoProviderErrorType, EvmProviderErrorType } from '@subwallet/extension-base/background/KoniTypes';
9
+ import { BitcoinProviderErrorType, CardanoProviderErrorType, EvmProviderErrorType } from '@subwallet/extension-base/background/KoniTypes';
9
10
  import { BasicTxErrorType } from '@subwallet/extension-base/types';
10
11
  import { BN_ZERO, combineEthFee, createPromiseHandler, isSameAddress, reformatAddress, stripUrl, wait } from '@subwallet/extension-base/utils';
11
12
  import { validateAddressNetwork } from '@subwallet/extension-base/utils/cardano';
12
13
  import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction';
13
14
  import { getId } from '@subwallet/extension-base/utils/getId';
14
15
  import { isCardanoAddress, isCardanoBaseAddress, isCardanoRewardAddress, isSubstrateAddress } from '@subwallet/keyring';
16
+ import { getBitcoinAddressInfo } from '@subwallet/keyring/utils';
17
+ import { isBitcoinAddress } from '@subwallet/keyring/utils/address/validate';
15
18
  import { keyring } from '@subwallet/ui-keyring';
16
19
  import { getSdkError } from '@walletconnect/utils';
17
20
  import BigN from 'bignumber.js';
18
21
  import BN from 'bn.js';
19
22
  import { t } from 'i18next';
20
23
  import Joi from 'joi';
21
- import { isString } from '@polkadot/util';
24
+ import { isArray, isHex, isString } from '@polkadot/util';
22
25
  import { isEthereumAddress } from '@polkadot/util-crypto';
23
26
  export const joiValidate = Joi.object({
24
27
  types: Joi.object().pattern(Joi.string(),
@@ -151,6 +154,9 @@ export async function validationAuthMiddleware(koni, url, payload) {
151
154
  if (!authInfo || !authInfo.isAllowed || !authInfo.isAllowedMap[payload.pair.address]) {
152
155
  return handleAuthError(payload, 'Account not in allowed list', 'dApp', errors);
153
156
  }
157
+ if (payload.pair.meta.noPublicKey) {
158
+ return handleAuthError(payload, t('This account is not supported for this action'), 'dApp', errors);
159
+ }
154
160
  payload.authInfo = authInfo;
155
161
  }
156
162
  } catch (e) {
@@ -159,6 +165,8 @@ export async function validationAuthMiddleware(koni, url, payload) {
159
165
  }
160
166
  return payload;
161
167
  }
168
+
169
+ // ====== EVM ======
162
170
  export async function validationConnectMiddleware(koni, url, payload) {
163
171
  let currentChain;
164
172
  let autoActiveChain = false;
@@ -580,6 +588,11 @@ export async function validationAuthCardanoMiddleware(koni, url, payload) {
580
588
  }
581
589
  return payload;
582
590
  }
591
+
592
+ // ====== EVM ======
593
+
594
+ // ====== Cardano ======
595
+
583
596
  export async function validationCardanoSignDataMiddleware(koni, url, payload_) {
584
597
  const {
585
598
  address,
@@ -636,11 +649,295 @@ export async function validationCardanoSignDataMiddleware(koni, url, payload_) {
636
649
  });
637
650
  return promise;
638
651
  }
652
+
653
+ // ====== Cardano ======
654
+
655
+ // ====== Bitcoin ======
656
+
657
+ export async function validationBitcoinConnectMiddleware(koni, url, payload) {
658
+ const {
659
+ authInfo,
660
+ errors,
661
+ networkKey
662
+ } = payload;
663
+ let autoActiveChain = false;
664
+ const handleError = message_ => {
665
+ payload.errorPosition = 'ui';
666
+ payload.confirmationType = 'errorConnectNetwork';
667
+ const [message, name] = convertErrorMessage(message_);
668
+ const error = new TransactionError(BasicTxErrorType.INVALID_PARAMS, message, undefined, name);
669
+ console.error(error);
670
+ errors.push(error);
671
+ };
672
+ if (url && authInfo) {
673
+ if (authInfo !== null && authInfo !== void 0 && authInfo.isAllowed) {
674
+ autoActiveChain = true;
675
+ }
676
+ }
677
+ const currentBitcoinNetwork = koni.requestService.getDAppChainInfo({
678
+ autoActive: autoActiveChain,
679
+ accessType: 'bitcoin',
680
+ defaultChain: networkKey,
681
+ url
682
+ });
683
+ if (currentBitcoinNetwork) {
684
+ const chainStatus = koni.getChainStateByKey(networkKey);
685
+ const chainInfo = koni.getChainInfo(networkKey);
686
+ if (!chainStatus.active) {
687
+ try {
688
+ await koni.chainService.enableChain(networkKey);
689
+ } catch (e) {
690
+ handleError('Can not active chain: ' + chainInfo.name);
691
+ }
692
+ }
693
+ } else {
694
+ handleError('This network is currently not supported');
695
+ }
696
+ return {
697
+ ...payload,
698
+ networkKey: (currentBitcoinNetwork === null || currentBitcoinNetwork === void 0 ? void 0 : currentBitcoinNetwork.slug) || networkKey,
699
+ errors
700
+ };
701
+ }
702
+ export async function validationBitcoinSignMessageMiddleware(koni, url, payload_) {
703
+ const {
704
+ address,
705
+ errors,
706
+ pair: pair_
707
+ } = payload_;
708
+ const message = payload_.payloadAfterValidated;
709
+ const {
710
+ promise,
711
+ resolve
712
+ } = createPromiseHandler();
713
+ const handleError = message_ => {
714
+ payload_.errorPosition = 'ui';
715
+ payload_.confirmationType = 'bitcoinSignatureRequest';
716
+ const [message, name] = convertErrorMessage(message_);
717
+ const error = new BitcoinProviderError(BitcoinProviderErrorType.INVALID_PARAMS, message, undefined, name);
718
+ console.error(error);
719
+ errors.push(error);
720
+ };
721
+ if (address === '' || !message) {
722
+ handleError(t('not found address or payload to sign'));
723
+ }
724
+ if (!isBitcoinAddress(address)) {
725
+ handleError(t('Invalid bitcoin address'));
726
+ }
727
+ const pair = pair_ || keyring.getPair(address);
728
+ if (!pair) {
729
+ handleError(t('Unable to find account'));
730
+ }
731
+ const hashPayload = '';
732
+ let canSign = false;
733
+ if (!(pair !== null && pair !== void 0 && pair.meta.isExtneral)) {
734
+ canSign = true;
735
+ }
736
+ const payloadAfterValidated = {
737
+ address,
738
+ payload: message,
739
+ payloadJson: message,
740
+ hashPayload,
741
+ canSign,
742
+ id: ''
743
+ };
744
+ resolve({
745
+ ...payload_,
746
+ errors,
747
+ payloadAfterValidated
748
+ });
749
+ return promise;
750
+ }
751
+ export async function validationBitcoinSignPsbtMiddleware(koni, url, payload_) {
752
+ const {
753
+ errors,
754
+ networkKey,
755
+ pair: pair_
756
+ } = payload_;
757
+ const psbtParams = payload_.payloadAfterValidated;
758
+ const {
759
+ address,
760
+ allowedSighash,
761
+ autoFinalized,
762
+ broadcast,
763
+ psbt,
764
+ signAtIndex
765
+ } = payload_.payloadAfterValidated;
766
+ const {
767
+ promise,
768
+ resolve
769
+ } = createPromiseHandler();
770
+ const handleError = message_ => {
771
+ payload_.errorPosition = 'ui';
772
+ payload_.confirmationType = 'bitcoinSignPsbtRequest';
773
+ const [message, name] = convertErrorMessage(message_);
774
+ const error = new BitcoinProviderError(BitcoinProviderErrorType.INVALID_PARAMS, message, undefined, name);
775
+ console.error(error);
776
+ errors.push(error);
777
+ };
778
+ if (!(psbtParams.network === 'mainnet' || psbtParams.network === 'testnet')) {
779
+ handleError(t('Network to try this request is must be mainnet or testnet'));
780
+ }
781
+ if (!networkKey) {
782
+ handleError(t('Network unavailable. Please switch network or manually add network to wallet'));
783
+ }
784
+ if (!psbt || !address) {
785
+ handleError(t('Not found payload to sign'));
786
+ }
787
+ if (!isHex(`0x${psbt}`)) {
788
+ handleError(t('Psbt to be signed must be hex-encoded'));
789
+ }
790
+ if (!isBitcoinAddress(address)) {
791
+ handleError(t('Not found address'));
792
+ }
793
+ const addressInfo = getBitcoinAddressInfo(address);
794
+ if (psbtParams.network !== addressInfo.network) {
795
+ handleError(t('The account or the network is not matched'));
796
+ }
797
+ const payload = {
798
+ broadcast: !!broadcast,
799
+ network: networkKey,
800
+ signAtIndex: isArray(signAtIndex) && signAtIndex.length === 0 ? undefined : signAtIndex,
801
+ address,
802
+ allowedSighash,
803
+ autoFinalized
804
+ };
805
+ const hashPayload = '';
806
+ const pair = pair_ || keyring.getPair(address);
807
+ const canSign = !(pair !== null && pair !== void 0 && pair.meta.isExternal);
808
+ const signPayload = {
809
+ address,
810
+ payload,
811
+ hashPayload,
812
+ canSign
813
+ };
814
+ resolve({
815
+ ...payload_,
816
+ errors,
817
+ payloadAfterValidated: signPayload
818
+ });
819
+ return promise;
820
+ }
821
+ export async function validationBitcoinSendTransactionMiddleware(koni, url, payload_) {
822
+ var _transactionParams$re, _transactionParams$re2;
823
+ const {
824
+ address,
825
+ errors,
826
+ networkKey,
827
+ pair: pair_
828
+ } = payload_;
829
+ const transactionParams = payload_.payloadAfterValidated;
830
+ const {
831
+ promise,
832
+ resolve
833
+ } = createPromiseHandler();
834
+ const senderAccountInfo = getBitcoinAddressInfo(address);
835
+ const handleError = message_ => {
836
+ payload_.errorPosition = 'ui';
837
+ payload_.confirmationType = 'bitcoinSendTransactionRequestAfterConfirmation';
838
+ const [message, name] = convertErrorMessage(message_);
839
+ const error = new BitcoinProviderError(BitcoinProviderErrorType.INVALID_PARAMS, message, undefined, name);
840
+ console.error(error);
841
+ errors.push(error);
842
+ };
843
+ const autoFormatNumber = val => {
844
+ if (typeof val === 'string' && val.startsWith('0x')) {
845
+ return new BigN(val.replace('0x', ''), 16).toString();
846
+ } else if (typeof val === 'number') {
847
+ return val.toString();
848
+ }
849
+ return val;
850
+ };
851
+ if (transactionParams.network !== senderAccountInfo.network) {
852
+ handleError(t('The account or the network is not matched'));
853
+ }
854
+ if (!((_transactionParams$re = transactionParams.recipients) !== null && _transactionParams$re !== void 0 && _transactionParams$re.length)) {
855
+ handleError(t('please provide the recipient and the amount'));
856
+ }
857
+ if (((_transactionParams$re2 = transactionParams.recipients) === null || _transactionParams$re2 === void 0 ? void 0 : _transactionParams$re2.length) > 1) {
858
+ handleError(t("we don't support multiple recipients yet. Please provide only one for now."));
859
+ }
860
+ if (transactionParams.recipients.filter(({
861
+ address,
862
+ amount
863
+ }) => !address || !amount).length > 0) {
864
+ throw new BitcoinProviderError(BitcoinProviderErrorType.INVALID_PARAMS);
865
+ }
866
+ const recipientAccountInfo = getBitcoinAddressInfo(transactionParams.recipients[0].address);
867
+ if (recipientAccountInfo.network !== transactionParams.network) {
868
+ handleError(t('invalid recipient address'));
869
+ }
870
+ if (transactionParams.recipients.length !== 1) {
871
+ handleError(t('receiving address must be a single account'));
872
+ }
873
+ if (address === transactionParams.recipients[0].address) {
874
+ handleError(t('must be different from sending address'));
875
+ }
876
+ const pair = pair_ || keyring.getPair(address);
877
+ if (!pair) {
878
+ handleError(t('unable to find account'));
879
+ }
880
+ const tokenInfo = koni.getNativeTokenInfo(networkKey);
881
+ let freeBalance = {
882
+ decimals: 0,
883
+ symbol: 'BTC',
884
+ value: '0'
885
+ };
886
+ let totalValue = new BigN('0');
887
+ try {
888
+ freeBalance = await koni.balanceService.getTransferableBalance(address, networkKey, tokenInfo.slug);
889
+ } catch (e) {
890
+ const message = e.message;
891
+ if (message.toLowerCase().includes(t('please enable network'))) {
892
+ const chainInfo = koni.chainService.getChainInfoByKey(networkKey);
893
+ payload_.errorPosition = 'ui';
894
+ payload_.confirmationType = 'bitcoinSendTransactionRequestAfterConfirmation';
895
+ const [message, name] = [t('Enable {{chain}} network on the extension and try again', {
896
+ replace: {
897
+ chain: chainInfo.name
898
+ }
899
+ }), t('Network not enabled')];
900
+ const error = new BitcoinProviderError(BitcoinProviderErrorType.INVALID_PARAMS, message, undefined, name);
901
+ console.error(error);
902
+ errors.push(error);
903
+ } else {
904
+ handleError(message);
905
+ }
906
+ }
907
+ const to = transactionParams.recipients.map(value => {
908
+ const amount = autoFormatNumber(value.amount);
909
+ totalValue = totalValue.plus(amount);
910
+ return {
911
+ ...value,
912
+ amount
913
+ };
914
+ });
915
+ if (new BigN(freeBalance.value).lte(totalValue)) {
916
+ handleError(t('insufficient balance'));
917
+ }
918
+ const sendTransactionRequest = {
919
+ networkKey,
920
+ address,
921
+ canSign: !pair.meta.isExternal,
922
+ value: totalValue.toString(),
923
+ to,
924
+ tokenSlug: tokenInfo.slug
925
+ };
926
+ resolve({
927
+ ...payload_,
928
+ errors,
929
+ payloadAfterValidated: sendTransactionRequest
930
+ });
931
+ return promise;
932
+ }
933
+
934
+ // ====== Bitcoin ======
935
+
639
936
  export function convertErrorMessage(message_, name) {
640
937
  const message = message_.toLowerCase();
641
938
 
642
939
  // Network error
643
- 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')) {
940
+ 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') || message.includes('internet connection')) {
644
941
  return [t('Re-enable the network or change RPC on the extension and try again'), t('Unstable network connection')];
645
942
  }
646
943
  if (message.includes('network is currently not supported')) {
@@ -675,6 +972,15 @@ export function convertErrorMessage(message_, name) {
675
972
  if (message.includes('the sender address must be the ethereum address type')) {
676
973
  return [t('The sender address must be the ethereum address type'), t('Invalid address type')];
677
974
  }
975
+ if (message.includes('the sender address must be the ethereum address type')) {
976
+ return [t('The sender address must be the bitcoin address type'), t('Invalid address type')];
977
+ }
978
+ if (message.includes('account or the network is not matched')) {
979
+ return [t('The account does not match the selected network'), t('Invalid address type')];
980
+ }
981
+ if (message.includes('receiving address must be a single account')) {
982
+ return [t('The receiving address must be a single account'), t('Invalid recipient address')];
983
+ }
678
984
  if (message.includes('insufficient balance') || message.includes('insufficient funds')) {
679
985
  return [t('Insufficient balance on the sender address. Top up your balance and try again'), t('Unable to sign transaction')];
680
986
  }
@@ -5,7 +5,7 @@ import { TransactionWarning } from '@subwallet/extension-base/background/warning
5
5
  import { FrameSystemAccountInfo } from '@subwallet/extension-base/core/substrate/types';
6
6
  import { _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
7
7
  import { OptionalSWTransaction, SWTransactionInput, SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types';
8
- import { EvmFeeInfo } from '@subwallet/extension-base/types';
8
+ import { FeeInfo } from '@subwallet/extension-base/types';
9
9
  import { KeyringPair } from '@subwallet/keyring/types';
10
10
  export declare function validateTransferRequest(tokenInfo: _ChainAsset, from: _Address, to: _Address, value: string | undefined, transferAll: boolean | undefined): TransactionError[];
11
11
  export declare function additionalValidateTransferForRecipient(sendingTokenInfo: _ChainAsset, nativeTokenInfo: _ChainAsset, extrinsicType: ExtrinsicType, receiverSendingTokenKeepAliveBalance: bigint, transferAmount: bigint, senderSendingTokenTransferable?: bigint, receiverSystemAccountInfo?: FrameSystemAccountInfo, isSendingTokenSufficient?: boolean): [TransactionWarning[], TransactionError[]];
@@ -13,7 +13,7 @@ export declare function validateXcmTransferRequest(destTokenInfo: _ChainAsset |
13
13
  export declare function checkSupportForFeature(validationResponse: SWTransactionResponse, blockedFeaturesList: string[], chainInfo: _ChainInfo): void;
14
14
  export declare function checkSupportForAction(validationResponse: SWTransactionResponse, blockedActionsMap: Record<ExtrinsicType, string[]>): void;
15
15
  export declare function checkSupportForTransaction(validationResponse: SWTransactionResponse, transaction: OptionalSWTransaction): void;
16
- export declare function estimateFeeForTransaction(validationResponse: SWTransactionResponse, transaction: OptionalSWTransaction, chainInfo: _ChainInfo, evmApi: _EvmApi, substrateApi: _SubstrateApi, priceMap: Record<string, number>, feeInfo: EvmFeeInfo, nativeTokenInfo: _ChainAsset, nonNativeTokenPayFeeInfo: _ChainAsset | undefined, isTransferLocalTokenAndPayThatTokenAsFee: boolean | undefined): Promise<FeeData>;
16
+ export declare function estimateFeeForTransaction(validationResponse: SWTransactionResponse, transaction: OptionalSWTransaction, chainInfo: _ChainInfo, evmApi: _EvmApi, substrateApi: _SubstrateApi, priceMap: Record<string, number>, feeInfo: FeeInfo, nativeTokenInfo: _ChainAsset, nonNativeTokenPayFeeInfo: _ChainAsset | undefined, isTransferLocalTokenAndPayThatTokenAsFee: boolean | undefined): Promise<FeeData>;
17
17
  export declare function checkSigningAccountForTransaction(validationResponse: SWTransactionResponse, chainInfoMap: Record<string, _ChainInfo>): void;
18
18
  export declare function checkBalanceWithTransactionFee(validationResponse: SWTransactionResponse, transactionInput: SWTransactionInput, nativeTokenInfo: _ChainAsset, nativeTokenAvailable: AmountData): void;
19
19
  export declare function checkTonAddressBounceableAndAccountNotActive(tonApi: _TonApi, validationResponse: SWTransactionResponse): Promise<void>;
@@ -11,9 +11,9 @@ import { isBounceableAddress } from '@subwallet/extension-base/services/balance-
11
11
  import { _TRANSFER_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
12
12
  import { _getAssetDecimals, _getAssetPriceId, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getTokenMinAmount, _isCIP26Token, _isNativeToken, _isNativeTokenBySlug, _isTokenEvmSmartContract, _isTokenTonSmartContract } from '@subwallet/extension-base/services/chain-service/utils';
13
13
  import { calculateToAmountByReservePool, FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE } from '@subwallet/extension-base/services/fee-service/utils';
14
- import { isCardanoTransaction, isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
14
+ import { isBitcoinTransaction, isCardanoTransaction, isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
15
15
  import { AccountSignMode, BasicTxErrorType, BasicTxWarningCode, TransferTxErrorType } from '@subwallet/extension-base/types';
16
- import { balanceFormatter, combineEthFee, formatNumber, pairToAccount } from '@subwallet/extension-base/utils';
16
+ import { balanceFormatter, combineBitcoinFee, combineEthFee, formatNumber, getSizeInfo, pairToAccount } from '@subwallet/extension-base/utils';
17
17
  import { isCardanoAddress, isTonAddress } from '@subwallet/keyring';
18
18
  import { keyring } from '@subwallet/ui-keyring';
19
19
  import BigN from 'bignumber.js';
@@ -312,6 +312,11 @@ export async function estimateFeeForTransaction(validationResponse, transaction,
312
312
  } = _getChainNativeTokenBasicInfo(chainInfo);
313
313
  estimateFee.decimals = decimals;
314
314
  estimateFee.symbol = symbol;
315
+ const {
316
+ address,
317
+ feeCustom,
318
+ feeOption
319
+ } = validationResponse;
315
320
  if (transaction) {
316
321
  try {
317
322
  if (isSubstrateTransaction(transaction)) {
@@ -321,13 +326,28 @@ export async function estimateFeeForTransaction(validationResponse, transaction,
321
326
  estimateFee.value = transaction.estimateFee; // todo: might need to update logic estimate fee inside for future actions excluding normal transfer Ton and Jetton
322
327
  } else if (isCardanoTransaction(transaction)) {
323
328
  estimateFee.value = transaction.estimateCardanoFee;
329
+ } else if (isBitcoinTransaction(transaction)) {
330
+ const feeCombine = combineBitcoinFee(feeInfo, feeOption, feeCustom);
331
+ const recipients = [];
332
+ for (const txOutput of transaction.txOutputs) {
333
+ txOutput.address && recipients.push(txOutput.address);
334
+ }
335
+
336
+ // TODO: Need review
337
+ const sizeInfo = getSizeInfo({
338
+ inputLength: transaction.inputCount,
339
+ recipients: recipients,
340
+ sender: address
341
+ });
342
+ estimateFee.value = Math.ceil(feeCombine.feeRate * sizeInfo.txVBytes).toString();
324
343
  } else {
325
- const gasLimit = transaction.gas || (await evmApi.api.eth.estimateGas(transaction));
344
+ const _transaction = transaction;
345
+ const gasLimit = _transaction.gas || (await evmApi.api.eth.estimateGas(_transaction));
326
346
  const feeCombine = combineEthFee(feeInfo, validationResponse.feeOption, validationResponse.feeCustom);
327
- if (transaction.maxFeePerGas) {
328
- estimateFee.value = new BigN(transaction.maxFeePerGas.toString()).multipliedBy(gasLimit).toFixed(0);
329
- } else if (transaction.gasPrice) {
330
- estimateFee.value = new BigN(transaction.gasPrice.toString()).multipliedBy(gasLimit).toFixed(0);
347
+ if (_transaction.maxFeePerGas) {
348
+ estimateFee.value = new BigN(_transaction.maxFeePerGas.toString()).multipliedBy(gasLimit).toFixed(0);
349
+ } else if (_transaction.gasPrice) {
350
+ estimateFee.value = new BigN(_transaction.gasPrice.toString()).multipliedBy(gasLimit).toFixed(0);
331
351
  } else {
332
352
  if (feeCombine.maxFeePerGas) {
333
353
  const maxFee = new BigN(feeCombine.maxFeePerGas); // TODO: Need review
package/core/types.d.ts CHANGED
@@ -8,6 +8,7 @@ export declare enum ValidationCondition {
8
8
  IS_VALID_SUBSTRATE_ADDRESS_FORMAT = "IS_VALID_SUBSTRATE_ADDRESS_FORMAT",
9
9
  IS_VALID_TON_ADDRESS_FORMAT = "IS_VALID_TON_ADDRESS_FORMAT",
10
10
  IS_VALID_CARDANO_ADDRESS_FORMAT = "IS_VALID_CARDANO_ADDRESS_FORMAT",
11
+ IS_VALID_BITCOIN_ADDRESS_FORMAT = "IS_VALID_BITCOIN_ADDRESS_FORMAT",
11
12
  IS_NOT_DUPLICATE_ADDRESS = "IS_NOT_DUPLICATE_ADDRESS",
12
13
  IS_SUPPORT_LEDGER_ACCOUNT = "IS_SUPPORT_LEDGER_ACCOUNT"
13
14
  }
package/core/types.js CHANGED
@@ -9,6 +9,7 @@ export let ValidationCondition;
9
9
  ValidationCondition["IS_VALID_SUBSTRATE_ADDRESS_FORMAT"] = "IS_VALID_SUBSTRATE_ADDRESS_FORMAT";
10
10
  ValidationCondition["IS_VALID_TON_ADDRESS_FORMAT"] = "IS_VALID_TON_ADDRESS_FORMAT";
11
11
  ValidationCondition["IS_VALID_CARDANO_ADDRESS_FORMAT"] = "IS_VALID_CARDANO_ADDRESS_FORMAT";
12
+ ValidationCondition["IS_VALID_BITCOIN_ADDRESS_FORMAT"] = "IS_VALID_BITCOIN_ADDRESS_FORMAT";
12
13
  ValidationCondition["IS_NOT_DUPLICATE_ADDRESS"] = "IS_NOT_DUPLICATE_ADDRESS";
13
14
  ValidationCondition["IS_SUPPORT_LEDGER_ACCOUNT"] = "IS_SUPPORT_LEDGER_ACCOUNT";
14
15
  })(ValidationCondition || (ValidationCondition = {}));
package/core/utils.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare function _isValidAddressForEcosystem(validateRecipientParams: Val
13
13
  export declare function _isValidSubstrateAddressFormat(validateRecipientParams: ValidateRecipientParams): string;
14
14
  export declare function _isValidTonAddressFormat(validateRecipientParams: ValidateRecipientParams): string;
15
15
  export declare function _isValidCardanoAddressFormat(validateRecipientParams: ValidateRecipientParams): string;
16
+ export declare function _isValidBitcoinAddressFormat(validateRecipientParams: ValidateRecipientParams): string;
16
17
  export declare function _isNotDuplicateAddress(validateRecipientParams: ValidateRecipientParams): string;
17
18
  export declare function _isSupportLedgerAccount(validateRecipientParams: ValidateRecipientParams): string;
18
19
  export declare const _isSufficientToken: (tokenInfo: _ChainAsset, substrateApi: _SubstrateApi, sufficientChain: SufficientChainsDetails) => Promise<boolean>;
package/core/utils.js CHANGED
@@ -5,9 +5,10 @@ import { _AssetType } from '@subwallet/chain-list/types';
5
5
  import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
6
  import { BalanceAccountType } from '@subwallet/extension-base/core/substrate/types';
7
7
  import { tonAddressInfo } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
8
- import { _getTokenOnChainAssetId, _getXcmAssetMultilocation, _isBridgedToken, _isChainCardanoCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible } from '@subwallet/extension-base/services/chain-service/utils';
8
+ import { _getTokenOnChainAssetId, _getXcmAssetMultilocation, _isBridgedToken, _isChainBitcoinCompatible, _isChainCardanoCompatible, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible } from '@subwallet/extension-base/services/chain-service/utils';
9
9
  import { isAddressAndChainCompatible, isSameAddress, reformatAddress } from '@subwallet/extension-base/utils';
10
10
  import { isAddress, isCardanoTestnetAddress, isTonAddress } from '@subwallet/keyring';
11
+ import { getBitcoinAddressInfo, validateBitcoinAddress } from '@subwallet/keyring/utils';
11
12
  import { isEthereumAddress } from '@polkadot/util-crypto';
12
13
  export function getStrictMode(type, extrinsicType) {
13
14
  if (type === BalanceAccountType.FrameSystemAccountInfo) {
@@ -55,7 +56,7 @@ export function _isValidAddressForEcosystem(validateRecipientParams) {
55
56
  toAddress
56
57
  } = validateRecipientParams;
57
58
  if (!isAddressAndChainCompatible(toAddress, destChainInfo)) {
58
- if (_isChainEvmCompatible(destChainInfo) || _isChainSubstrateCompatible(destChainInfo) || _isChainTonCompatible(destChainInfo) || _isChainCardanoCompatible(destChainInfo)) {
59
+ if (_isChainEvmCompatible(destChainInfo) || _isChainSubstrateCompatible(destChainInfo) || _isChainTonCompatible(destChainInfo) || _isChainCardanoCompatible(destChainInfo) || _isChainBitcoinCompatible(destChainInfo)) {
59
60
  return 'Recipient address must be the same type as sender address';
60
61
  }
61
62
  return 'Unknown chain type';
@@ -96,6 +97,18 @@ export function _isValidCardanoAddressFormat(validateRecipientParams) {
96
97
  }
97
98
  return '';
98
99
  }
100
+ export function _isValidBitcoinAddressFormat(validateRecipientParams) {
101
+ var _destChainInfo$bitcoi;
102
+ const {
103
+ destChainInfo,
104
+ toAddress
105
+ } = validateRecipientParams;
106
+ const addressInfo = validateBitcoinAddress(toAddress) ? getBitcoinAddressInfo(toAddress) : null;
107
+ if ((addressInfo === null || addressInfo === void 0 ? void 0 : addressInfo.network) !== ((_destChainInfo$bitcoi = destChainInfo.bitcoinInfo) === null || _destChainInfo$bitcoi === void 0 ? void 0 : _destChainInfo$bitcoi.bitcoinNetwork)) {
108
+ return `Recipient address must be a valid ${destChainInfo.name} address`;
109
+ }
110
+ return '';
111
+ }
99
112
  export function _isNotDuplicateAddress(validateRecipientParams) {
100
113
  const {
101
114
  fromAddress,
@@ -126,6 +126,8 @@ export default class KoniExtension {
126
126
  private approveSpending;
127
127
  private makeTransfer;
128
128
  private makeCrossChainTransfer;
129
+ private makeBitcoinDappTransferConfirmation;
130
+ private makePsbtTransferAfterConfirmation;
129
131
  private getTokensCanPayFee;
130
132
  private getAmountForPair;
131
133
  private evmNftSubmitTransaction;
@@ -145,6 +147,7 @@ export default class KoniExtension {
145
147
  private getAddressTransferableBalance;
146
148
  private getAddressTotalBalance;
147
149
  private subscribeMaxTransferable;
150
+ private subscribeTransferableWhenConfirmation;
148
151
  private subscribeAddressTransferableBalance;
149
152
  private substrateNftSubmitTransaction;
150
153
  private enableChains;
@@ -157,9 +160,11 @@ export default class KoniExtension {
157
160
  private subscribeConfirmations;
158
161
  private subscribeConfirmationsTon;
159
162
  private subscribeConfirmationsCardano;
163
+ private subscribeConfirmationsBitcoin;
160
164
  private completeConfirmation;
161
165
  private completeConfirmationTon;
162
166
  private completeConfirmationCardano;
167
+ private completeConfirmationBitcoin;
163
168
  private getNetworkJsonByChainId;
164
169
  private parseSubstrateTransaction;
165
170
  private parseEVMRLP;