diff --git a/packages/extension/src/libs/utils/accounts.ts b/packages/extension/src/libs/utils/accounts.ts index 0f008bd32..6b36593fe 100644 --- a/packages/extension/src/libs/utils/accounts.ts +++ b/packages/extension/src/libs/utils/accounts.ts @@ -1,6 +1,7 @@ import { EnkryptAccount, NetworkNames, SignerType } from "@enkryptcom/types"; import PublicKeyRing from "../keyring/public-keyring"; import { getNetworkByName } from "./networks"; +import { ProviderName } from "@/types/provider"; const getOtherSigners = (signers: SignerType[]): SignerType[] => { const otherSigners: SignerType[] = []; @@ -22,16 +23,13 @@ export const getAccountsByNetworkName = async ( const accounts = await keyring.getAccounts(network.signer); const filtered = accounts.filter((account) => { - if (account.isHardware && account.HWOptions !== undefined) { - // Polkadot and Kusama ledger apps only work for those networks - if ( - account.HWOptions.networkName === NetworkNames.Kusama || - account.HWOptions.networkName === NetworkNames.Polkadot - ) { - return account.HWOptions.networkName === networkName; - } + if ( + account.isHardware && + account.HWOptions !== undefined && + network.provider !== ProviderName.ethereum + ) { + return account.HWOptions.networkName === networkName; } - return true; }); return filtered.map((f) => { diff --git a/packages/extension/src/providers/bitcoin/libs/api-ss.ts b/packages/extension/src/providers/bitcoin/libs/api-ss.ts index 88b3e5426..cbcdb7172 100644 --- a/packages/extension/src/providers/bitcoin/libs/api-ss.ts +++ b/packages/extension/src/providers/bitcoin/libs/api-ss.ts @@ -28,6 +28,15 @@ class API implements ProviderAPIInterface { } // eslint-disable-next-line @typescript-eslint/no-empty-function async init(): Promise {} + async getRawTransaction(hash: string): Promise { + return fetch(`${this.node}/api/v1/tx/${hash}/raw`) + .then((res) => res.json()) + .then((tx: { hex: string; error: unknown }) => { + if ((tx as any).error) return null; + if (!tx.hex) return null; + return `0x${tx.hex}`; + }); + } async getTransactionStatus(hash: string): Promise { return fetch(`${this.node}/api/v1/tx/${hash}`) .then((res) => res.json()) diff --git a/packages/extension/src/providers/bitcoin/libs/api.ts b/packages/extension/src/providers/bitcoin/libs/api.ts index 80dc94e41..4a1d52351 100644 --- a/packages/extension/src/providers/bitcoin/libs/api.ts +++ b/packages/extension/src/providers/bitcoin/libs/api.ts @@ -27,6 +27,15 @@ class API implements ProviderAPIInterface { } // eslint-disable-next-line @typescript-eslint/no-empty-function async init(): Promise {} + async getRawTransaction(hash: string): Promise { + return fetch(`${this.node}transaction/${hash}/raw`) + .then((res) => res.json()) + .then((tx: { result: string; error: unknown }) => { + if ((tx as any).error) return null; + if (!tx.result) return null; + return `0x${tx.result}`; + }); + } async getTransactionStatus(hash: string): Promise { return fetch(`${this.node}transaction/${hash}`) .then((res) => res.json()) diff --git a/packages/extension/src/providers/bitcoin/ui/btc-connect-dapp.vue b/packages/extension/src/providers/bitcoin/ui/btc-connect-dapp.vue index 0dd5ec9b8..a9e670239 100644 --- a/packages/extension/src/providers/bitcoin/ui/btc-connect-dapp.vue +++ b/packages/extension/src/providers/bitcoin/ui/btc-connect-dapp.vue @@ -76,10 +76,10 @@ import { DEFAULT_BTC_NETWORK, getNetworkByName } from "@/libs/utils/networks"; import { WindowPromiseHandler } from "@/libs/window-promise"; import { BitcoinNetwork } from "../types/bitcoin-network"; import { ProviderRequestOptions } from "@/types/provider"; -import PublicKeyRing from "@/libs/keyring/public-keyring"; import { fromBase } from "@enkryptcom/utils"; import { getError } from "@/libs/error"; import { ErrorCodes } from "@/providers/ethereum/types"; +import { getAccountsByNetworkName } from "@/libs/utils/accounts"; import AccountState from "../libs/accounts-state"; const windowPromise = WindowPromiseHandler(1); @@ -109,9 +109,8 @@ onBeforeMount(async () => { network.value = (await getNetworkByName( Request.value.params![0] )) as BitcoinNetwork; - const keyring = new PublicKeyRing(); Options.value = options; - const accounts = await keyring.getAccounts(network.value.signer); + const accounts = await getAccountsByNetworkName(network.value.name); displayAddress.value = network.value.displayAddress(accounts[0].address); identicon.value = network.value.identicon(accounts[0].address); accountHeaderData.value = { diff --git a/packages/extension/src/providers/bitcoin/ui/libs/signer.ts b/packages/extension/src/providers/bitcoin/ui/libs/signer.ts index 161fdc71d..9c79b48ab 100644 --- a/packages/extension/src/providers/bitcoin/ui/libs/signer.ts +++ b/packages/extension/src/providers/bitcoin/ui/libs/signer.ts @@ -2,11 +2,13 @@ import { InternalMethods, InternalOnMessageResponse } from "@/types/messenger"; import { SignerTransactionOptions, SignerMessageOptions } from "../types"; import sendUsingInternalMessengers from "@/libs/messenger/internal-messenger"; import { hexToBuffer, bufferToHex } from "@enkryptcom/utils"; -import { Psbt } from "bitcoinjs-lib"; +import { Psbt, Transaction } from "bitcoinjs-lib"; import { BitcoinNetwork, PaymentType } from "../../types/bitcoin-network"; -import { EnkryptAccount } from "@enkryptcom/types"; +import { EnkryptAccount, HWwalletType } from "@enkryptcom/types"; import { signMessageOfBIP322Simple } from "../../libs/bip322-message-sign"; import { magicHash, toCompact } from "../../libs/sign-message-utils"; +import HWwallet from "@enkryptcom/hw-wallets"; +import type BitcoinAPI from "@/providers/bitcoin/libs/api"; const PSBTSigner = (account: EnkryptAccount, network: BitcoinNetwork) => { return { @@ -29,44 +31,67 @@ const PSBTSigner = (account: EnkryptAccount, network: BitcoinNetwork) => { }; }; -const TransactionSigner = ( +const TransactionSigner = async ( options: SignerTransactionOptions -): Promise => { +): Promise => { const { account, network, payload } = options; - if (account.isHardware) { - throw new Error("btc-hardware not implemented"); - } else { - const tx = new Psbt({ - network: network.networkInfo, - maximumFeeRate: network.networkInfo.maxFeeRate, - }); - payload.inputs - .map((u) => { - const res: { - hash: string; - index: number; - witnessUtxo?: { script: Buffer; value: number }; - nonWitnessUtxo?: Buffer; - } = { - hash: u.hash, - index: u.index, + const tx = new Psbt({ + network: network.networkInfo, + maximumFeeRate: network.networkInfo.maxFeeRate, + }); + payload.inputs + .map((u) => { + const res: { + hash: string; + index: number; + witnessUtxo?: { script: Buffer; value: number }; + nonWitnessUtxo?: Buffer; + } = { + hash: u.hash, + index: u.index, + }; + if (network.networkInfo.paymentType === PaymentType.P2WPKH) { + res.witnessUtxo = { + script: Buffer.from(u.witnessUtxo.script, "hex"), + value: u.witnessUtxo.value, }; - if (network.networkInfo.paymentType === PaymentType.P2WPKH) { - res.witnessUtxo = { - script: Buffer.from(u.witnessUtxo.script, "hex"), - value: u.witnessUtxo.value, - }; - } else if (network.networkInfo.paymentType === PaymentType.P2PKH) { - res.nonWitnessUtxo = Buffer.from(u.raw, "hex"); - } - return res; + } else if (network.networkInfo.paymentType === PaymentType.P2PKH) { + res.nonWitnessUtxo = Buffer.from(u.raw, "hex"); + } + return res; + }) + .forEach((input) => tx.addInput(input)); + payload.outputs.forEach((output) => tx.addOutput(output)); + if (account.isHardware) { + const hwwallets = new HWwallet(); + const api = (await network.api()) as BitcoinAPI; + const txPromises = payload.inputs.map((u) => api.getRawTransaction(u.hash)); + const rawTxs = await Promise.all(txPromises); + for (const t of rawTxs) { + if (t === null) throw new Error("bitcoin-signer: Invalid tx hash"); + } + return hwwallets + .signTransaction({ + transaction: { + rawTxs: rawTxs as string[], + psbtTx: tx, + }, + networkName: network.name, + pathIndex: account.pathIndex.toString(), + pathType: { + basePath: account.basePath, + path: account.HWOptions!.pathTemplate, + }, + wallet: account.walletType as unknown as HWwalletType, }) - .forEach((input) => tx.addInput(input)); - payload.outputs.forEach((output) => tx.addOutput(output)); + .then((strTx) => { + return Transaction.fromHex(strTx); + }); + } else { const signer = PSBTSigner(account, network); return tx.signAllInputsAsync(signer).then(() => { tx.finalizeAllInputs(); - return tx; + return tx.extractTransaction(); }); } }; diff --git a/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue b/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue index 8d309b56d..6a6652295 100644 --- a/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue +++ b/packages/extension/src/providers/bitcoin/ui/send-transaction/index.vue @@ -493,8 +493,8 @@ const sendAction = async () => { await Browser.windows.create({ url: Browser.runtime.getURL( getUiPath( - `eth-hw-verify?id=${routedRoute.query.id}&txData=${routedRoute.query.txData}`, - ProviderName.ethereum + `btc-hw-verify?id=${routedRoute.query.id}&txData=${routedRoute.query.txData}`, + ProviderName.bitcoin ) ), type: "popup", diff --git a/packages/extension/src/providers/bitcoin/ui/send-transaction/verify-transaction/index.vue b/packages/extension/src/providers/bitcoin/ui/send-transaction/verify-transaction/index.vue index 081c6d6fb..6fb162920 100644 --- a/packages/extension/src/providers/bitcoin/ui/send-transaction/verify-transaction/index.vue +++ b/packages/extension/src/providers/bitcoin/ui/send-transaction/verify-transaction/index.vue @@ -163,7 +163,7 @@ const sendAction = async () => { }) .then((signedTx) => { api - .broadcastTx(signedTx.extractTransaction().toHex()) + .broadcastTx(signedTx.toHex()) .then(() => { trackSendEvents(SendEventType.SendComplete, { network: network.value.name, @@ -172,7 +172,7 @@ const sendAction = async () => { [ { ...txActivity, - ...{ transactionHash: signedTx.extractTransaction().getId() }, + ...{ transactionHash: signedTx.getId() }, }, ], { diff --git a/packages/extension/src/providers/common/ui/send-transaction/send-contacts-list.vue b/packages/extension/src/providers/common/ui/send-transaction/send-contacts-list.vue index 864517573..9fcc89771 100644 --- a/packages/extension/src/providers/common/ui/send-transaction/send-contacts-list.vue +++ b/packages/extension/src/providers/common/ui/send-transaction/send-contacts-list.vue @@ -166,7 +166,7 @@ const pasteFromClipboard = () => { position: relative; margin: auto; width: 100%; - max-height: 380px; + max-height: 330px; } h3 { diff --git a/packages/extension/src/providers/kadena/ui/send-transaction/components/send-contacts-list.vue b/packages/extension/src/providers/kadena/ui/send-transaction/components/send-contacts-list.vue deleted file mode 100644 index a5bd4ef1a..000000000 --- a/packages/extension/src/providers/kadena/ui/send-transaction/components/send-contacts-list.vue +++ /dev/null @@ -1,265 +0,0 @@ - - - - - diff --git a/packages/extension/src/providers/kadena/ui/send-transaction/components/send-from-contacts-list.vue b/packages/extension/src/providers/kadena/ui/send-transaction/components/send-from-contacts-list.vue deleted file mode 100644 index fa52defff..000000000 --- a/packages/extension/src/providers/kadena/ui/send-transaction/components/send-from-contacts-list.vue +++ /dev/null @@ -1,148 +0,0 @@ - - - - - diff --git a/packages/extension/src/providers/kadena/ui/send-transaction/index.vue b/packages/extension/src/providers/kadena/ui/send-transaction/index.vue index f671df28d..3952334df 100644 --- a/packages/extension/src/providers/kadena/ui/send-transaction/index.vue +++ b/packages/extension/src/providers/kadena/ui/send-transaction/index.vue @@ -22,10 +22,9 @@ @@ -41,9 +40,9 @@ -
-
-
- -
-
- - - - Paste - -
-

Recent

-
- -
-
-
-
- - - -

My accounts

-
- -
- -
-
- - -
-
-
- - - - - diff --git a/packages/extension/src/providers/polkadot/ui/send-transaction/components/send-from-contacts-list.vue b/packages/extension/src/providers/polkadot/ui/send-transaction/components/send-from-contacts-list.vue deleted file mode 100644 index fa52defff..000000000 --- a/packages/extension/src/providers/polkadot/ui/send-transaction/components/send-from-contacts-list.vue +++ /dev/null @@ -1,148 +0,0 @@ - - - - - diff --git a/packages/extension/src/providers/polkadot/ui/send-transaction/index.vue b/packages/extension/src/providers/polkadot/ui/send-transaction/index.vue index 36e767183..5e9db5f06 100644 --- a/packages/extension/src/providers/polkadot/ui/send-transaction/index.vue +++ b/packages/extension/src/providers/polkadot/ui/send-transaction/index.vue @@ -21,10 +21,9 @@ @@ -39,9 +38,9 @@ { trackSwapEvents(SwapEventType.SwapOpen, { network: props.network.name }); if ( @@ -368,19 +368,22 @@ const setToTokens = () => { ); }); if (toTokens.value.length === 1) toToken.value = toTokens.value[0]; - keyring.getAccounts(toNetwork.value?.signerType).then((accounts) => { - toAccounts.value = accounts; - const currentAccount = accounts.find( - (a) => a.address === props.accountInfo.selectedAccount!.address - ); - if (currentAccount) { - address.value = currentAccount.address; - isValidToAddress(); - } else if (accounts.length) { - address.value = accounts[0].address; - isValidToAddress(); + + getAccountsByNetworkName(toNetwork.value!.id as unknown as NetworkNames).then( + (accounts) => { + toAccounts.value = accounts; + const currentAccount = accounts.find( + (a) => a.address === props.accountInfo.selectedAccount!.address + ); + if (currentAccount) { + address.value = currentAccount.address; + isValidToAddress(); + } else if (accounts.length) { + address.value = accounts[0].address; + isValidToAddress(); + } } - }); + ); }; const setMax = () => { diff --git a/packages/extension/src/ui/action/views/swap/libs/send-transactions.ts b/packages/extension/src/ui/action/views/swap/libs/send-transactions.ts index d2858a2de..bce5b87d4 100644 --- a/packages/extension/src/ui/action/views/swap/libs/send-transactions.ts +++ b/packages/extension/src/ui/action/views/swap/libs/send-transactions.ts @@ -76,13 +76,13 @@ export const executeSwap = async ( }); const bitcoinApi = api as BitcoinAPI; bitcoinApi - .broadcastTx(signedTx.extractTransaction().toHex()) + .broadcastTx(signedTx.toHex()) .then(() => { activityState.addActivities( [ { ...JSON.parse(JSON.stringify(txActivity)), - ...{ transactionHash: signedTx.extractTransaction().getId() }, + ...{ transactionHash: signedTx.getId() }, }, ], { address: txActivity.from, network: options.network.name } @@ -95,7 +95,7 @@ export const executeSwap = async ( network: options.network.name, }); }); - return [signedTx.extractTransaction().getId() as `0x${string}`]; + return [signedTx.getId() as `0x${string}`]; } else if (options.networkType === NetworkType.Substrate) { const substrateTx = await getSubstrateNativeTransation( options.network as SubstrateNetwork, diff --git a/packages/extension/src/ui/onboard/hardware-wallet/views/select-account.vue b/packages/extension/src/ui/onboard/hardware-wallet/views/select-account.vue index 731cfbc61..4c90fa6ef 100644 --- a/packages/extension/src/ui/onboard/hardware-wallet/views/select-account.vue +++ b/packages/extension/src/ui/onboard/hardware-wallet/views/select-account.vue @@ -57,8 +57,10 @@ import { polkadotEncodeAddress } from "@enkryptcom/utils"; import { useHWStore } from "../store"; import { BaseNetwork } from "@/types/base-network"; import SubstrateAPI from "@/providers/polkadot/libs/api"; -import EvmAPI from "@/providers/ethereum/libs/api"; -import BtcApi from "@/providers/bitcoin/libs/api"; +import type EvmAPI from "@/providers/ethereum/libs/api"; +import type BtcApi from "@/providers/bitcoin/libs/api"; +import type SolApi from "@/providers/solana/libs/api"; +import type KdaApi from "@/providers/kadena/libs/api"; const store = useHWStore(); const router = useRouter(); @@ -78,7 +80,7 @@ const loading = ref(false); const currentAddressIndex = ref(0); const keyring = new PublicKeyRing(); const existingAccounts = ref([]); -const networkApi = ref(); +const networkApi = ref(); const accounts = ref([]); const visibleAccounts = computed(() => { return accounts.value.slice( diff --git a/packages/hw-wallets/package.json b/packages/hw-wallets/package.json index c84a04cc9..9e85883ad 100644 --- a/packages/hw-wallets/package.json +++ b/packages/hw-wallets/package.json @@ -50,14 +50,17 @@ "@ethereumjs/rlp": "^5.0.2", "@ethereumjs/tx": "^5.3.0", "@ethereumjs/util": "^9.0.3", + "@ledgerhq/hw-app-btc": "^10.4.1", "@ledgerhq/hw-app-eth": "^6.37.3", "@ledgerhq/hw-transport": "^6.31.2", "@ledgerhq/hw-transport-webusb": "^6.29.2", "@ledgerhq/live-common": "^34.1.0", "@polkadot/types": "^12.2.3", "@polkadot/util": "^13.0.2", + "@trezor/connect": "^9.4.0", "@trezor/connect-web": "^9.3.0", "@zondax/ledger-substrate": "^0.44.7", + "bitcoinjs-lib": "^6.1.6", "hdkey": "^2.1.0", "webextension-polyfill": "^0.12.0" } diff --git a/packages/hw-wallets/src/configs.ts b/packages/hw-wallets/src/configs.ts index f7454fb4f..782de1736 100644 --- a/packages/hw-wallets/src/configs.ts +++ b/packages/hw-wallets/src/configs.ts @@ -11,8 +11,6 @@ const walletConfigs: WalletConfigs = { }; const ledgerAppNames = { [NetworkNames.Ethereum]: "Ethereum", - [NetworkNames.Matic]: "Ethereum", - [NetworkNames.Binance]: "Ethereum", [NetworkNames.Rootstock]: "RSK", [NetworkNames.EthereumClassic]: "Ethereum Classic", [NetworkNames.Acala]: "Acala", @@ -20,6 +18,9 @@ const ledgerAppNames = { [NetworkNames.Polkadot]: "Polkadot", [NetworkNames.Karura]: "Karura", [NetworkNames.Edgeware]: "Edgeware", + [NetworkNames.Bitcoin]: "Bitcoin", + [NetworkNames.Litecoin]: "Litecoin", + [NetworkNames.Dogecoin]: "Dogecoin", }; const MessengerName = "enkrypt_hw_wallets"; @@ -74,5 +75,35 @@ const bip44Paths = { basePath: "m/0'/0'/0", label: "Substrate", }, + bitcoinSegwitLedger: { + path: "m/84'/0'/{index}'/0/0", + basePath: "m/84'/0'", + label: "Bitcoin", + }, + litecoinSegwitLedger: { + path: "m/84'/2'/{index}'/0/0", + basePath: "m/84'/2'", + label: "Litecoin", + }, + dogecoinLedger: { + path: "m/44'/3'/{index}'/0/0", + basePath: "m/44'/3'", + label: "Dogecoin", + }, + bitcoinSegwitTrezor: { + path: "m/84'/0'/0'/0/{index}", + basePath: "m/84'/0'/0'/0", + label: "Bitcoin", + }, + litecoinSegwitTrezor: { + path: "m/84'/2'/0'/0/{index}", + basePath: "m/84'/2'/0'/0", + label: "Litecoin", + }, + dogecoinTrezor: { + path: "m/44'/3'/0'/0/{index}", + basePath: "m/44'/3'/0'/0", + label: "Dogecoin", + }, }; export { walletConfigs, MessengerName, ledgerAppNames, bip44Paths }; diff --git a/packages/hw-wallets/src/index.ts b/packages/hw-wallets/src/index.ts index 41d968edd..05da80c6a 100644 --- a/packages/hw-wallets/src/index.ts +++ b/packages/hw-wallets/src/index.ts @@ -1,7 +1,9 @@ import { NetworkNames, HWwalletType } from "@enkryptcom/types"; import LedgerEthereum from "./ledger/ethereum"; +import LedgerBitcoin from "./ledger/bitcoin"; import LedgerSubstrate from "./ledger/substrate"; -import TrezorEthereum from "./trezor"; +import TrezorEthereum from "./trezor/ethereum"; +import TrezorBitcoin from "./trezor/bitcoin"; import { AddressResponse, getAddressRequest, @@ -16,7 +18,9 @@ import { ledgerAppNames } from "./configs"; type ProviderType = | typeof LedgerEthereum | typeof LedgerSubstrate - | typeof TrezorEthereum; + | typeof TrezorEthereum + | typeof LedgerBitcoin + | typeof TrezorBitcoin; class HWwalletManager { providerTypes: Record; @@ -24,8 +28,8 @@ class HWwalletManager { constructor() { this.providerTypes = { - [HWwalletType.ledger]: [LedgerEthereum, LedgerSubstrate], - [HWwalletType.trezor]: [TrezorEthereum], + [HWwalletType.ledger]: [LedgerEthereum, LedgerSubstrate, LedgerBitcoin], + [HWwalletType.trezor]: [TrezorEthereum, TrezorBitcoin], }; this.providers = {}; } diff --git a/packages/hw-wallets/src/ledger/bitcoin/configs.ts b/packages/hw-wallets/src/ledger/bitcoin/configs.ts new file mode 100644 index 000000000..015b0e323 --- /dev/null +++ b/packages/hw-wallets/src/ledger/bitcoin/configs.ts @@ -0,0 +1,9 @@ +import { NetworkNames } from "@enkryptcom/types"; +import { bip44Paths } from "../../configs"; + +const supportedPaths = { + [NetworkNames.Bitcoin]: [bip44Paths.bitcoinSegwitLedger], + [NetworkNames.Litecoin]: [bip44Paths.litecoinSegwitLedger], + [NetworkNames.Dogecoin]: [bip44Paths.dogecoinLedger], +}; +export { supportedPaths }; diff --git a/packages/hw-wallets/src/ledger/bitcoin/index.ts b/packages/hw-wallets/src/ledger/bitcoin/index.ts new file mode 100644 index 000000000..33fe32948 --- /dev/null +++ b/packages/hw-wallets/src/ledger/bitcoin/index.ts @@ -0,0 +1,173 @@ +import type Transport from "@ledgerhq/hw-transport"; +import webUsbTransport from "@ledgerhq/hw-transport-webusb"; +import { HWwalletCapabilities, NetworkNames } from "@enkryptcom/types"; +import BtcApp from "@ledgerhq/hw-app-btc"; +import HDKey from "hdkey"; +import type { CreateTransactionArg } from "@ledgerhq/hw-app-btc/lib/createTransaction"; +import { serializeTransactionOutputs } from "@ledgerhq/hw-app-btc/lib/serializeTransaction"; +import { bufferToHex } from "@enkryptcom/utils"; +import { + AddressResponse, + BTCSignTransaction, + getAddressRequest, + HWWalletProvider, + PathType, + SignMessageRequest, + SignTransactionRequest, +} from "../../types"; +import { supportedPaths } from "./configs"; +import ConnectToLedger from "../ledgerConnect"; + +class LedgerBitcoin implements HWWalletProvider { + transport: Transport | null; + + network: NetworkNames; + + HDNodes: Record; + + isSegwit: boolean; + + constructor(network: NetworkNames) { + this.transport = null; + this.network = network; + this.HDNodes = {}; + this.isSegwit = !!( + this.network === NetworkNames.Bitcoin || + this.network === NetworkNames.Litecoin + ); + } + + async init(): Promise { + if (!this.transport) { + const support = await webUsbTransport.isSupported(); + if (support) { + this.transport = await webUsbTransport.openConnected().then((res) => { + if (!res) return webUsbTransport.create(); + return res; + }); + } else { + return Promise.reject( + new Error("ledger-bitcoin: webusb is not supported") + ); + } + } + return true; + } + + async getAddress(options: getAddressRequest): Promise { + if (!supportedPaths[this.network]) + return Promise.reject(new Error("ledger-bitcoin: Invalid network name")); + const isHardened = options.pathType.basePath.split("/").length - 1 === 2; + const connection = new BtcApp({ transport: this.transport }); + const hdKey = new HDKey(); + if (!isHardened) { + if (!this.HDNodes[options.pathType.basePath]) { + const rootPub = await connection.getWalletPublicKey( + options.pathType.basePath, + { format: this.isSegwit ? "bech32" : "legacy" } + ); + hdKey.publicKey = Buffer.from(rootPub.publicKey, "hex"); + hdKey.chainCode = Buffer.from(rootPub.chainCode, "hex"); + this.HDNodes[options.pathType.basePath] = hdKey; + } + const pubkey = this.HDNodes[options.pathType.basePath].derive( + `m/${options.pathIndex}` + ).publicKey; + return { + address: bufferToHex(pubkey), + publicKey: bufferToHex(pubkey), + }; + } + + return connection + .getWalletPublicKey( + options.pathType.path.replace(`{index}`, options.pathIndex), + { format: this.isSegwit ? "bech32" : "legacy" } + ) + .then((res) => { + hdKey.publicKey = Buffer.from(res.publicKey, "hex"); + hdKey.chainCode = Buffer.from(res.chainCode, "hex"); + return { + address: bufferToHex(hdKey.publicKey), + publicKey: bufferToHex(hdKey.publicKey), + }; + }); + } + + signPersonalMessage(options: SignMessageRequest): Promise { + const connection = new BtcApp({ transport: this.transport }); + return connection + .signMessage( + options.pathType.path.replace(`{index}`, options.pathIndex), + options.message.toString("hex") + ) + .then((result) => { + const v = result.v + 27 + 4; + const signature = Buffer.from( + v.toString(16) + result.r + result.s, + "hex" + ); + return bufferToHex(signature); + }); + } + + async signTransaction(options: SignTransactionRequest): Promise { + const connection = new BtcApp({ transport: this.transport }); + const transactionOptions = options.transaction as BTCSignTransaction; + const txOutputs = transactionOptions.psbtTx.txOutputs.map((out) => { + const valLE = Buffer.alloc(8); + valLE.writeBigInt64LE(BigInt(out.value)); + return { + amount: valLE, + script: Buffer.from(out.script), + }; + }); + const txArg: CreateTransactionArg = { + inputs: transactionOptions.rawTxs.map((rTx, idx) => [ + connection.splitTransaction(rTx.replace("0x", ""), true), + transactionOptions.psbtTx.txInputs[idx].index, + transactionOptions.psbtTx.data.inputs[idx].witnessScript + ? transactionOptions.psbtTx.data.inputs[idx].witnessScript.toString( + "hex" + ) + : undefined, + undefined, + ]), + associatedKeysets: transactionOptions.rawTxs.map(() => + options.pathType.path.replace(`{index}`, options.pathIndex) + ), + outputScriptHex: serializeTransactionOutputs({ + outputs: txOutputs, + } as any).toString("hex"), + segwit: this.isSegwit, + additionals: [], + }; + if (this.isSegwit) { + txArg.additionals.push("bech32"); + } + return connection.createPaymentTransaction(txArg).then((result) => result); + } + + getSupportedPaths(): PathType[] { + return supportedPaths[this.network]; + } + + close(): Promise { + // eslint-disable-next-line @typescript-eslint/no-empty-function + return this.transport.close().catch(() => {}); + } + + isConnected(networkName: NetworkNames): Promise { + return ConnectToLedger.bind(this)(networkName); + } + + static getSupportedNetworks(): NetworkNames[] { + return Object.keys(supportedPaths) as NetworkNames[]; + } + + static getCapabilities(): string[] { + return [HWwalletCapabilities.signMessage, HWwalletCapabilities.signTx]; + } +} + +export default LedgerBitcoin; diff --git a/packages/hw-wallets/src/ledger/ethereum/configs.ts b/packages/hw-wallets/src/ledger/ethereum/configs.ts index 5698e8109..bbd6dfaf8 100644 --- a/packages/hw-wallets/src/ledger/ethereum/configs.ts +++ b/packages/hw-wallets/src/ledger/ethereum/configs.ts @@ -1,35 +1,39 @@ import { NetworkNames } from "@enkryptcom/types"; import { bip44Paths } from "../../configs"; +const DEFAULT_PATHS = [ + bip44Paths.ethereumLedger, + bip44Paths.ethereumLedgerLive, +]; +// https://github.com/LedgerHQ/app-ethereum/blob/develop/src/network.c +// last updated: 08-29-2024 const supportedPaths = { - [NetworkNames.Ethereum]: [ - bip44Paths.ethereumLedger, - bip44Paths.ethereumLedgerLive, - ], - [NetworkNames.Matic]: [ - bip44Paths.ethereumLedger, - bip44Paths.ethereumLedgerLive, - ], - [NetworkNames.Binance]: [ - bip44Paths.ethereumLedger, - bip44Paths.ethereumLedgerLive, - ], + [NetworkNames.Ethereum]: DEFAULT_PATHS, + [NetworkNames.Matic]: DEFAULT_PATHS, + [NetworkNames.MaticZK]: DEFAULT_PATHS, + [NetworkNames.Binance]: DEFAULT_PATHS, [NetworkNames.Rootstock]: [bip44Paths.rootstock], [NetworkNames.EthereumClassic]: [ bip44Paths.ethereumClassicLedger, bip44Paths.ethereumClassicLedgerLive, ], - [NetworkNames.Moonbeam]: [ - bip44Paths.ethereumLedger, - bip44Paths.ethereumLedgerLive, - ], - [NetworkNames.Moonriver]: [ - bip44Paths.ethereumLedger, - bip44Paths.ethereumLedgerLive, - ], - [NetworkNames.Avalanche]: [ - bip44Paths.ethereumLedger, - bip44Paths.ethereumLedgerLive, - ], + [NetworkNames.Moonbeam]: DEFAULT_PATHS, + [NetworkNames.Moonriver]: DEFAULT_PATHS, + [NetworkNames.Avalanche]: DEFAULT_PATHS, + [NetworkNames.Optimism]: DEFAULT_PATHS, + [NetworkNames.Sepolia]: [bip44Paths.ethereumTestnetLedger, ...DEFAULT_PATHS], + [NetworkNames.Okc]: DEFAULT_PATHS, + [NetworkNames.ShidenEVM]: DEFAULT_PATHS, + [NetworkNames.AstarEVM]: DEFAULT_PATHS, + [NetworkNames.ZkSync]: DEFAULT_PATHS, + [NetworkNames.Arbitrum]: DEFAULT_PATHS, + [NetworkNames.Gnosis]: DEFAULT_PATHS, + [NetworkNames.Fantom]: DEFAULT_PATHS, + [NetworkNames.Klaytn]: DEFAULT_PATHS, + [NetworkNames.Base]: DEFAULT_PATHS, + [NetworkNames.Celo]: DEFAULT_PATHS, + [NetworkNames.Syscoin]: DEFAULT_PATHS, + [NetworkNames.Telos]: DEFAULT_PATHS, + [NetworkNames.Blast]: DEFAULT_PATHS, }; export { supportedPaths }; diff --git a/packages/hw-wallets/src/ledger/ledgerConnect.ts b/packages/hw-wallets/src/ledger/ledgerConnect.ts index f97e3dee8..c5f6fa102 100644 --- a/packages/hw-wallets/src/ledger/ledgerConnect.ts +++ b/packages/hw-wallets/src/ledger/ledgerConnect.ts @@ -10,23 +10,24 @@ function connect( this: LedgerEthereum | LedgerSubstrate, networkName: NetworkNames ): Promise { + const appName = ledgerAppNames[networkName] + ? ledgerAppNames[networkName] + : ledgerAppNames[NetworkNames.Ethereum]; return getDeviceInfo(this.transport) .then(() => - openApp(this.transport, ledgerAppNames[networkName]) + openApp(this.transport, appName) .then(() => true) .catch(() => { throw new Error( - `Make sure you have ${ledgerAppNames[networkName]} App installed on your ledger` + `Make sure you have ${appName} App installed on your ledger` ); }) ) .catch((e) => { if (e.message === "DeviceOnDashboardExpected") { return getAppAndVersion(this.transport).then((appInfo) => { - if (appInfo.name !== ledgerAppNames[networkName]) - throw new Error( - `Make sure you have ${ledgerAppNames[networkName]} App opened` - ); + if (appInfo.name !== appName) + throw new Error(`Make sure you have ${appName} App opened`); return true; }); } diff --git a/packages/hw-wallets/src/trezor/bitcoin/configs.ts b/packages/hw-wallets/src/trezor/bitcoin/configs.ts new file mode 100644 index 000000000..0e534fe94 --- /dev/null +++ b/packages/hw-wallets/src/trezor/bitcoin/configs.ts @@ -0,0 +1,24 @@ +import { NetworkNames } from "@enkryptcom/types"; +import { bip44Paths } from "../../configs"; + +const supportedPaths = { + [NetworkNames.Bitcoin]: [bip44Paths.bitcoinSegwitTrezor], + [NetworkNames.Litecoin]: [bip44Paths.litecoinSegwitTrezor], + [NetworkNames.Dogecoin]: [bip44Paths.dogecoinTrezor], +}; + +const TrezorNetworkConfigs = { + [NetworkNames.Bitcoin]: { + symbol: "btc", + isSegwit: true, + }, + [NetworkNames.Litecoin]: { + symbol: "ltc", + isSegwit: true, + }, + [NetworkNames.Dogecoin]: { + symbol: "doge", + isSegwit: false, + }, +}; +export { supportedPaths, TrezorNetworkConfigs }; diff --git a/packages/hw-wallets/src/trezor/bitcoin/index.ts b/packages/hw-wallets/src/trezor/bitcoin/index.ts new file mode 100644 index 000000000..e2b46dc78 --- /dev/null +++ b/packages/hw-wallets/src/trezor/bitcoin/index.ts @@ -0,0 +1,123 @@ +import TrezorConnect from "@trezor/connect-web"; +import { getHDPath } from "@trezor/connect/lib/utils/pathUtils"; +import { HWwalletCapabilities, NetworkNames } from "@enkryptcom/types"; +import HDKey from "hdkey"; +import { bufferToHex } from "@enkryptcom/utils"; +import { + AddressResponse, + BTCSignTransaction, + getAddressRequest, + HWWalletProvider, + PathType, + SignMessageRequest, + SignTransactionRequest, +} from "../../types"; +import { supportedPaths, TrezorNetworkConfigs } from "./configs"; + +class TrezorEthereum implements HWWalletProvider { + network: NetworkNames; + + HDNodes: Record; + + constructor(network: NetworkNames) { + this.network = network; + this.HDNodes = {}; + } + + async init(): Promise { + TrezorConnect.manifest({ + email: "info@enkrypt.com", + appUrl: "https://www.enkrypt.com", + }); + return true; + } + + async getAddress(options: getAddressRequest): Promise { + if (!supportedPaths[this.network]) + return Promise.reject(new Error("trezor-bitcoin: Invalid network name")); + + if (!this.HDNodes[options.pathType.basePath]) { + const rootPub = await TrezorConnect.getPublicKey({ + path: options.pathType.basePath, + showOnTrezor: options.confirmAddress, + }); + if (!rootPub.payload) { + throw new Error("popup failed to open"); + } + if (!rootPub.success) + throw new Error((rootPub.payload as any).error as string); + + const hdKey = new HDKey(); + hdKey.publicKey = Buffer.from(rootPub.payload.publicKey, "hex"); + hdKey.chainCode = Buffer.from(rootPub.payload.chainCode, "hex"); + this.HDNodes[options.pathType.basePath] = hdKey; + } + const pubkey = this.HDNodes[options.pathType.basePath].derive( + `m/${options.pathIndex}` + ).publicKey; + return { + address: bufferToHex(pubkey), + publicKey: bufferToHex(pubkey), + }; + } + + getSupportedPaths(): PathType[] { + return supportedPaths[this.network]; + } + + close(): Promise { + return Promise.resolve(); + } + + isConnected(): Promise { + return Promise.resolve(true); + } + + async signPersonalMessage(options: SignMessageRequest): Promise { + const result = await TrezorConnect.signMessage({ + path: options.pathType.path.replace(`{index}`, options.pathIndex), + message: options.message.toString("hex"), + hex: true, + }); + if (!result.success) + throw new Error((result.payload as any).error as string); + return bufferToHex(Buffer.from(result.payload.signature, "base64")); + } + + async signTransaction(options: SignTransactionRequest): Promise { + const transactionOptions = options.transaction as BTCSignTransaction; + const addressN = getHDPath( + options.pathType.path.replace(`{index}`, options.pathIndex) + ); + return TrezorConnect.signTransaction({ + coin: TrezorNetworkConfigs[this.network].symbol, + inputs: transactionOptions.psbtTx.txInputs.map((tx) => ({ + address_n: addressN, + prev_hash: tx.hash.reverse().toString("hex"), + prev_index: tx.index, + amount: 0, // doesnt seem like this do anything + script_type: TrezorNetworkConfigs[this.network].isSegwit + ? "SPENDWITNESS" + : "SPENDADDRESS", + })), + outputs: transactionOptions.psbtTx.txOutputs.map((out) => ({ + amount: out.value, + address: out.address, + script_type: "PAYTOADDRESS", + })), + }).then((res) => { + if (!res.success) throw new Error((res.payload as any).error as string); + return res.payload.serializedTx; + }); + } + + static getSupportedNetworks(): NetworkNames[] { + return Object.keys(supportedPaths) as NetworkNames[]; + } + + static getCapabilities(): string[] { + return [HWwalletCapabilities.signMessage, HWwalletCapabilities.signTx]; + } +} + +export default TrezorEthereum; diff --git a/packages/hw-wallets/src/trezor/configs.ts b/packages/hw-wallets/src/trezor/configs.ts deleted file mode 100644 index c73ca4c79..000000000 --- a/packages/hw-wallets/src/trezor/configs.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NetworkNames } from "@enkryptcom/types"; -import { bip44Paths } from "../configs"; - -const supportedPaths = { - [NetworkNames.Ethereum]: [bip44Paths.ethereum], - [NetworkNames.Matic]: [bip44Paths.ethereum], - [NetworkNames.Avalanche]: [bip44Paths.ethereum], - [NetworkNames.Binance]: [bip44Paths.ethereum], - [NetworkNames.EthereumClassic]: [bip44Paths.ethereumClassic], - [NetworkNames.Rootstock]: [bip44Paths.rootstock], -}; -export { supportedPaths }; diff --git a/packages/hw-wallets/src/trezor/ethereum/configs.ts b/packages/hw-wallets/src/trezor/ethereum/configs.ts new file mode 100644 index 000000000..943cf8e6f --- /dev/null +++ b/packages/hw-wallets/src/trezor/ethereum/configs.ts @@ -0,0 +1,31 @@ +import { NetworkNames } from "@enkryptcom/types"; +import { bip44Paths } from "../../configs"; + +const DEFAULT_PATHS = [bip44Paths.ethereum]; +const supportedPaths = { + [NetworkNames.Ethereum]: DEFAULT_PATHS, + [NetworkNames.Matic]: DEFAULT_PATHS, + [NetworkNames.Avalanche]: DEFAULT_PATHS, + [NetworkNames.Binance]: DEFAULT_PATHS, + [NetworkNames.EthereumClassic]: [bip44Paths.ethereumClassic], + [NetworkNames.Rootstock]: [bip44Paths.rootstock], + [NetworkNames.MaticZK]: DEFAULT_PATHS, + [NetworkNames.Moonbeam]: DEFAULT_PATHS, + [NetworkNames.Moonriver]: DEFAULT_PATHS, + [NetworkNames.Optimism]: DEFAULT_PATHS, + [NetworkNames.Sepolia]: [bip44Paths.ethereumTestnetLedger, ...DEFAULT_PATHS], + [NetworkNames.Okc]: DEFAULT_PATHS, + [NetworkNames.ShidenEVM]: DEFAULT_PATHS, + [NetworkNames.AstarEVM]: DEFAULT_PATHS, + [NetworkNames.ZkSync]: DEFAULT_PATHS, + [NetworkNames.Arbitrum]: DEFAULT_PATHS, + [NetworkNames.Gnosis]: DEFAULT_PATHS, + [NetworkNames.Fantom]: DEFAULT_PATHS, + [NetworkNames.Klaytn]: DEFAULT_PATHS, + [NetworkNames.Base]: DEFAULT_PATHS, + [NetworkNames.Celo]: DEFAULT_PATHS, + [NetworkNames.Syscoin]: DEFAULT_PATHS, + [NetworkNames.Telos]: DEFAULT_PATHS, + [NetworkNames.Blast]: DEFAULT_PATHS, +}; +export { supportedPaths }; diff --git a/packages/hw-wallets/src/trezor/index.ts b/packages/hw-wallets/src/trezor/ethereum/index.ts similarity index 98% rename from packages/hw-wallets/src/trezor/index.ts rename to packages/hw-wallets/src/trezor/ethereum/index.ts index 77fb3e0c5..402f7e9aa 100644 --- a/packages/hw-wallets/src/trezor/index.ts +++ b/packages/hw-wallets/src/trezor/ethereum/index.ts @@ -11,7 +11,7 @@ import { PathType, SignMessageRequest, SignTransactionRequest, -} from "../types"; +} from "../../types"; import { supportedPaths } from "./configs"; class TrezorEthereum implements HWWalletProvider { @@ -61,10 +61,6 @@ class TrezorEthereum implements HWWalletProvider { }; } - signMessage() { - throw new Error("Not Supported"); - } - getSupportedPaths(): PathType[] { return supportedPaths[this.network]; } diff --git a/packages/hw-wallets/src/types.ts b/packages/hw-wallets/src/types.ts index 597c03122..42fe695ba 100644 --- a/packages/hw-wallets/src/types.ts +++ b/packages/hw-wallets/src/types.ts @@ -4,6 +4,7 @@ import type { LegacyTransaction, } from "@ethereumjs/tx"; import type { ExtrinsicPayload } from "@polkadot/types/interfaces"; +import type { Psbt } from "bitcoinjs-lib"; export type WalletConfigs = Record; @@ -42,11 +43,17 @@ export interface SignMessageRequest extends BaseRequest { message: Buffer; } +export interface BTCSignTransaction { + rawTxs: string[]; + psbtTx: Psbt; +} + export interface SignTransactionRequest extends BaseRequest { transaction: | FeeMarketEIP1559Transaction | LegacyTransaction - | ExtrinsicPayload; + | ExtrinsicPayload + | BTCSignTransaction; } export interface getAddressRequest extends BaseRequest { diff --git a/yarn.lock b/yarn.lock index f11e09d4a..c334fc9cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1668,7 +1668,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.23.3": +"@babel/preset-typescript@npm:^7.23.3, @babel/preset-typescript@npm:^7.24.7": version: 7.24.7 resolution: "@babel/preset-typescript@npm:7.24.7" dependencies: @@ -2917,12 +2917,14 @@ __metadata: "@ethereumjs/rlp": ^5.0.2 "@ethereumjs/tx": ^5.3.0 "@ethereumjs/util": ^9.0.3 + "@ledgerhq/hw-app-btc": ^10.4.1 "@ledgerhq/hw-app-eth": ^6.37.3 "@ledgerhq/hw-transport": ^6.31.2 "@ledgerhq/hw-transport-webusb": ^6.29.2 "@ledgerhq/live-common": ^34.1.0 "@polkadot/types": ^12.2.3 "@polkadot/util": ^13.0.2 + "@trezor/connect": ^9.4.0 "@trezor/connect-web": ^9.3.0 "@types/chai": ^4.3.17 "@types/mocha": ^10.0.7 @@ -2930,6 +2932,7 @@ __metadata: "@typescript-eslint/eslint-plugin": ^5.62.0 "@typescript-eslint/parser": ^5.62.0 "@zondax/ledger-substrate": ^0.44.7 + bitcoinjs-lib: ^6.1.6 chai: ^4.5.0 eslint: ^8.57.0 eslint-config-airbnb-base: ^15.0.0 @@ -5248,6 +5251,26 @@ __metadata: languageName: node linkType: hard +"@ledgerhq/hw-app-btc@npm:^10.4.1": + version: 10.4.1 + resolution: "@ledgerhq/hw-app-btc@npm:10.4.1" + dependencies: + "@ledgerhq/hw-transport": ^6.31.2 + "@ledgerhq/logs": ^6.12.0 + bip32-path: ^0.4.2 + bitcoinjs-lib: ^5.2.0 + bs58: ^4.0.1 + bs58check: ^2.1.2 + invariant: ^2.2.4 + ripemd160: 2 + semver: ^7.3.5 + sha.js: 2 + tiny-secp256k1: 1.1.6 + varuint-bitcoin: 1.1.2 + checksum: 4024fbb77ee9815d5edec8d39125aa228eb2bec2945fed6d6c7bcfafdb4ac08c296ab2f3ba39348e94ce12e974f0336eb5df4ac901cf2127fb91fa77595c0c58 + languageName: node + linkType: hard + "@ledgerhq/hw-app-cosmos@npm:^6.29.6": version: 6.29.6 resolution: "@ledgerhq/hw-app-cosmos@npm:6.29.6" @@ -8303,6 +8326,29 @@ __metadata: languageName: node linkType: hard +"@solana/web3.js@npm:^1.95.0": + version: 1.95.3 + resolution: "@solana/web3.js@npm:1.95.3" + dependencies: + "@babel/runtime": ^7.25.0 + "@noble/curves": ^1.4.2 + "@noble/hashes": ^1.4.0 + "@solana/buffer-layout": ^4.0.1 + agentkeepalive: ^4.5.0 + bigint-buffer: ^1.1.5 + bn.js: ^5.2.1 + borsh: ^0.7.0 + bs58: ^4.0.1 + buffer: 6.0.3 + fast-stable-stringify: ^1.0.0 + jayson: ^4.1.1 + node-fetch: ^2.7.0 + rpc-websockets: ^9.0.2 + superstruct: ^2.0.2 + checksum: 6951eb12275de09ef9422fc65982b7496f3d11253b4cd1b09694dd2135d92aa272a04a7adf50ef0136a459b08ea40e07f6e7cbf1970cae44d6193d93fe6acc1f + languageName: node + linkType: hard + "@solana/web3.js@npm:^1.95.2": version: 1.95.2 resolution: "@solana/web3.js@npm:1.95.2" @@ -9000,6 +9046,18 @@ __metadata: languageName: node linkType: hard +"@trezor/analytics@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/analytics@npm:1.2.0" + dependencies: + "@trezor/env-utils": 1.2.0 + "@trezor/utils": 9.2.0 + peerDependencies: + tslib: ^2.6.2 + checksum: 652dea1b54515c10931fe67671a5043b22557629224da3ae8fff153a4a9af45eb27c7cc2cdef68e0dbfab53b7544df0dce1a903adf4e0c0c27531a6abc1d2a19 + languageName: node + linkType: hard + "@trezor/blockchain-link-types@npm:1.1.0": version: 1.1.0 resolution: "@trezor/blockchain-link-types@npm:1.1.0" @@ -9014,6 +9072,20 @@ __metadata: languageName: node linkType: hard +"@trezor/blockchain-link-types@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/blockchain-link-types@npm:1.2.0" + dependencies: + "@solana/web3.js": ^1.95.0 + "@trezor/type-utils": 1.1.0 + "@trezor/utxo-lib": 2.2.0 + socks-proxy-agent: 6.1.1 + peerDependencies: + tslib: ^2.6.2 + checksum: 622c2b23cc4f9c9f660f676cea43292c4b0ea9af0abb5b7879bc28bdece24f0ecaaa46492a13f4ffc3791113fc9342c695fc2838db690727b7273f74559d21b7 + languageName: node + linkType: hard + "@trezor/blockchain-link-utils@npm:1.1.0": version: 1.1.0 resolution: "@trezor/blockchain-link-utils@npm:1.1.0" @@ -9028,6 +9100,20 @@ __metadata: languageName: node linkType: hard +"@trezor/blockchain-link-utils@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/blockchain-link-utils@npm:1.2.0" + dependencies: + "@mobily/ts-belt": ^3.13.1 + "@solana/web3.js": ^1.95.0 + "@trezor/env-utils": 1.2.0 + "@trezor/utils": 9.2.0 + peerDependencies: + tslib: ^2.6.2 + checksum: 172f0d52470048af0cd6af19e5f05a718c3dc78a087bc311ab7a24445cfc495a63f447a542d49746b3d31f4cb6377190a32f5fccbed98db17cc8e36999c6945b + languageName: node + linkType: hard + "@trezor/blockchain-link@npm:2.2.0": version: 2.2.0 resolution: "@trezor/blockchain-link@npm:2.2.0" @@ -9049,6 +9135,27 @@ __metadata: languageName: node linkType: hard +"@trezor/blockchain-link@npm:2.3.0": + version: 2.3.0 + resolution: "@trezor/blockchain-link@npm:2.3.0" + dependencies: + "@solana/buffer-layout": ^4.0.1 + "@solana/web3.js": ^1.95.0 + "@trezor/blockchain-link-types": 1.2.0 + "@trezor/blockchain-link-utils": 1.2.0 + "@trezor/utils": 9.2.0 + "@trezor/utxo-lib": 2.2.0 + "@types/web": ^0.0.138 + events: ^3.3.0 + ripple-lib: ^1.10.1 + socks-proxy-agent: 6.1.1 + ws: ^8.18.0 + peerDependencies: + tslib: ^2.6.2 + checksum: d2f5cee0c58e30d8c1ce153f4d0fbce5222897d73850896e328d79f817bf56f2df29929e9627b289d9d08d85eea170c91a097b86a2d8a850cd3c8ae72edbe804 + languageName: node + linkType: hard + "@trezor/connect-analytics@npm:1.1.0": version: 1.1.0 resolution: "@trezor/connect-analytics@npm:1.1.0" @@ -9060,6 +9167,17 @@ __metadata: languageName: node linkType: hard +"@trezor/connect-analytics@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/connect-analytics@npm:1.2.0" + dependencies: + "@trezor/analytics": 1.2.0 + peerDependencies: + tslib: ^2.6.2 + checksum: 15763dc7ddd3c8b8033c9e14cce2104639b47b1e5c4f1faabe61d4275ad2ab00368216949d1085d17b6ba1c106ab2ee3627a0afb4923152e71eb9f92db5c4459 + languageName: node + linkType: hard + "@trezor/connect-common@npm:0.1.0": version: 0.1.0 resolution: "@trezor/connect-common@npm:0.1.0" @@ -9072,6 +9190,18 @@ __metadata: languageName: node linkType: hard +"@trezor/connect-common@npm:0.2.0": + version: 0.2.0 + resolution: "@trezor/connect-common@npm:0.2.0" + dependencies: + "@trezor/env-utils": 1.2.0 + "@trezor/utils": 9.2.0 + peerDependencies: + tslib: ^2.6.2 + checksum: 684b5c0ca2c360856d557dabf6be4175d6675847cdab22fdcc630c8d4d5815e9aacbaf52d825415120bf1f61871486d1794e7ddbe6505600c8c2d2a764618bd1 + languageName: node + linkType: hard + "@trezor/connect-web@npm:^9.3.0": version: 9.3.0 resolution: "@trezor/connect-web@npm:9.3.0" @@ -9113,6 +9243,34 @@ __metadata: languageName: node linkType: hard +"@trezor/connect@npm:^9.4.0": + version: 9.4.0 + resolution: "@trezor/connect@npm:9.4.0" + dependencies: + "@babel/preset-typescript": ^7.24.7 + "@ethereumjs/common": ^4.3.0 + "@ethereumjs/tx": ^5.3.0 + "@fivebinaries/coin-selection": 2.2.1 + "@trezor/blockchain-link": 2.3.0 + "@trezor/blockchain-link-types": 1.2.0 + "@trezor/connect-analytics": 1.2.0 + "@trezor/connect-common": 0.2.0 + "@trezor/protobuf": 1.2.0 + "@trezor/protocol": 1.2.0 + "@trezor/schema-utils": 1.2.0 + "@trezor/transport": 1.3.0 + "@trezor/utils": 9.2.0 + "@trezor/utxo-lib": 2.2.0 + blakejs: ^1.2.1 + bs58: ^5.0.0 + bs58check: ^3.0.1 + cross-fetch: ^4.0.0 + peerDependencies: + tslib: ^2.6.2 + checksum: acb5a7bbbd82ffb0be580536fb74ea8ed3dc898801bd004f89d39f3ed1955806e3f24b4d4a5fbc116e67a5f33db6bdd0fb523d8abbed6da3dd1ef64c05494b53 + languageName: node + linkType: hard + "@trezor/env-utils@npm:1.1.0": version: 1.1.0 resolution: "@trezor/env-utils@npm:1.1.0" @@ -9134,6 +9292,27 @@ __metadata: languageName: node linkType: hard +"@trezor/env-utils@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/env-utils@npm:1.2.0" + dependencies: + ua-parser-js: ^1.0.37 + peerDependencies: + expo-constants: "*" + expo-localization: "*" + react-native: "*" + tslib: ^2.6.2 + peerDependenciesMeta: + expo-constants: + optional: true + expo-localization: + optional: true + react-native: + optional: true + checksum: 8b63897816ceb4437847f8672bb2767394addfae47964e5435c417600b8e3b24388d1d928c30e3acccf84547508f330829db7adb517008225da76dbd3c403a19 + languageName: node + linkType: hard + "@trezor/protobuf@npm:1.1.0": version: 1.1.0 resolution: "@trezor/protobuf@npm:1.1.0" @@ -9146,6 +9325,18 @@ __metadata: languageName: node linkType: hard +"@trezor/protobuf@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/protobuf@npm:1.2.0" + dependencies: + "@trezor/schema-utils": 1.2.0 + protobufjs: 7.2.6 + peerDependencies: + tslib: ^2.6.2 + checksum: d7bf82db7022de26b4536ebf187e54f696f61b3b488ace8f7c9a4f8b52868b318e844daa446e80bddf31f4136f56dabf5a51bd0fccd87d40d3f6803305cbb268 + languageName: node + linkType: hard + "@trezor/protocol@npm:1.1.0": version: 1.1.0 resolution: "@trezor/protocol@npm:1.1.0" @@ -9155,6 +9346,15 @@ __metadata: languageName: node linkType: hard +"@trezor/protocol@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/protocol@npm:1.2.0" + peerDependencies: + tslib: ^2.6.2 + checksum: 4440973bc20cc3f58c489f7a90292591c8994bace7477205287b504947d0a1e4ea7bf9e029e6a6bdd438281a8d9ff7ea54567dc377b39b8eaa7028522d12adca + languageName: node + linkType: hard + "@trezor/schema-utils@npm:1.1.0": version: 1.1.0 resolution: "@trezor/schema-utils@npm:1.1.0" @@ -9167,6 +9367,18 @@ __metadata: languageName: node linkType: hard +"@trezor/schema-utils@npm:1.2.0": + version: 1.2.0 + resolution: "@trezor/schema-utils@npm:1.2.0" + dependencies: + "@sinclair/typebox": ^0.31.28 + ts-mixer: ^6.0.3 + peerDependencies: + tslib: ^2.6.2 + checksum: 1e5f0627fa87be591e4d6e78469764305e38af1abf5fa65058a0e018d97525244fe5b1f86db29ec905bfb2e8a37290dafb9ef2a874819424148112b18507b383 + languageName: node + linkType: hard + "@trezor/transport@npm:1.2.0": version: 1.2.0 resolution: "@trezor/transport@npm:1.2.0" @@ -9185,6 +9397,23 @@ __metadata: languageName: node linkType: hard +"@trezor/transport@npm:1.3.0": + version: 1.3.0 + resolution: "@trezor/transport@npm:1.3.0" + dependencies: + "@trezor/protobuf": 1.2.0 + "@trezor/protocol": 1.2.0 + "@trezor/utils": 9.2.0 + cross-fetch: ^4.0.0 + long: ^4.0.0 + protobufjs: 7.2.6 + usb: ^2.11.0 + peerDependencies: + tslib: ^2.6.2 + checksum: b7158f36732e75065235dc31e1015c1d6d9ec9f7235da28e2883e650cd8626f5e9906fcf8032c24763f3a0501a48935c36dcc7f1302b12a1104cd3a8dfc6fbcf + languageName: node + linkType: hard + "@trezor/type-utils@npm:1.1.0": version: 1.1.0 resolution: "@trezor/type-utils@npm:1.1.0" @@ -9203,6 +9432,17 @@ __metadata: languageName: node linkType: hard +"@trezor/utils@npm:9.2.0": + version: 9.2.0 + resolution: "@trezor/utils@npm:9.2.0" + dependencies: + bignumber.js: ^9.1.2 + peerDependencies: + tslib: ^2.6.2 + checksum: 755c80193391c9f69a0fc0ef0147d7ca8d8c794cf6cf44ef91a022231075806b92364baca61dcb35c95c47a091359a10b72ca06e8d96c8f810178084ee25786c + languageName: node + linkType: hard + "@trezor/utxo-lib@npm:2.1.0": version: 2.1.0 resolution: "@trezor/utxo-lib@npm:2.1.0" @@ -9230,6 +9470,33 @@ __metadata: languageName: node linkType: hard +"@trezor/utxo-lib@npm:2.2.0": + version: 2.2.0 + resolution: "@trezor/utxo-lib@npm:2.2.0" + dependencies: + "@trezor/utils": 9.2.0 + bchaddrjs: ^0.5.2 + bech32: ^2.0.0 + bip66: ^1.1.5 + bitcoin-ops: ^1.4.1 + blake-hash: ^2.0.0 + blakejs: ^1.2.1 + bn.js: ^5.2.1 + bs58: ^5.0.0 + bs58check: ^3.0.1 + create-hmac: ^1.1.7 + int64-buffer: ^1.0.1 + pushdata-bitcoin: ^1.0.1 + tiny-secp256k1: ^1.1.6 + typeforce: ^1.18.0 + varuint-bitcoin: ^1.1.2 + wif: ^4.0.0 + peerDependencies: + tslib: ^2.6.2 + checksum: d7af8fc2101cdfad4a010ca44ef2be6c504b0b7067342f4407de5c599350d453623aa49bc0c500d5efb82276c98555abd9b91401dcda215795b146c5467bcd60 + languageName: node + linkType: hard + "@tronweb3/google-protobuf@npm:^3.21.2": version: 3.21.2 resolution: "@tronweb3/google-protobuf@npm:3.21.2"