@subwallet/extension-base 1.3.42-0 → 1.3.44-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 (49) hide show
  1. package/background/KoniTypes.d.ts +35 -23
  2. package/background/errors/BitcoinProviderError.d.ts +1 -1
  3. package/background/errors/BitcoinProviderError.js +2 -2
  4. package/background/types.d.ts +1 -1
  5. package/cjs/background/errors/BitcoinProviderError.js +2 -2
  6. package/cjs/core/logic-validation/recipientAddress.js +8 -2
  7. package/cjs/core/logic-validation/request.js +316 -3
  8. package/cjs/koni/background/handlers/Extension.js +418 -90
  9. package/cjs/koni/background/handlers/State.js +198 -6
  10. package/cjs/koni/background/handlers/Tabs.js +119 -6
  11. package/cjs/packageInfo.js +1 -1
  12. package/cjs/page/bitcoin/index.js +67 -0
  13. package/cjs/page/index.js +5 -0
  14. package/cjs/services/buy-service/index.js +17 -2
  15. package/cjs/services/earning-service/handlers/native-staking/para-chain.js +27 -5
  16. package/cjs/services/request-service/handler/AuthRequestHandler.js +18 -0
  17. package/cjs/services/request-service/handler/BitcoinRequestHandler.js +48 -61
  18. package/cjs/services/request-service/index.js +2 -2
  19. package/cjs/services/transaction-service/index.js +71 -2
  20. package/cjs/utils/auth.js +2 -1
  21. package/core/logic-validation/recipientAddress.js +8 -2
  22. package/core/logic-validation/request.d.ts +6 -2
  23. package/core/logic-validation/request.js +309 -3
  24. package/koni/background/handlers/Extension.d.ts +3 -0
  25. package/koni/background/handlers/Extension.js +330 -6
  26. package/koni/background/handlers/State.d.ts +4 -1
  27. package/koni/background/handlers/State.js +189 -4
  28. package/koni/background/handlers/Tabs.d.ts +7 -2
  29. package/koni/background/handlers/Tabs.js +119 -9
  30. package/package.json +11 -6
  31. package/packageInfo.js +1 -1
  32. package/page/bitcoin/index.d.ts +17 -0
  33. package/page/bitcoin/index.js +60 -0
  34. package/page/index.d.ts +2 -1
  35. package/page/index.js +4 -0
  36. package/services/balance-service/transfer/cardano-transfer.d.ts +2 -0
  37. package/services/buy-service/index.js +17 -2
  38. package/services/earning-service/handlers/native-staking/para-chain.js +27 -5
  39. package/services/request-service/handler/AuthRequestHandler.js +19 -1
  40. package/services/request-service/handler/BitcoinRequestHandler.d.ts +3 -4
  41. package/services/request-service/handler/BitcoinRequestHandler.js +48 -61
  42. package/services/request-service/index.d.ts +1 -2
  43. package/services/request-service/index.js +2 -2
  44. package/services/transaction-service/index.d.ts +1 -0
  45. package/services/transaction-service/index.js +71 -2
  46. package/services/transaction-service/types.d.ts +1 -0
  47. package/types/balance/transfer.d.ts +4 -2
  48. package/types/buy.d.ts +1 -1
  49. package/utils/auth.js +3 -2
@@ -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
  }
@@ -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;