From 507e34271f86facb46494ca0107ff32a14c64c36 Mon Sep 17 00:00:00 2001
From: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
Date: Fri, 6 Sep 2024 10:51:14 +0200
Subject: [PATCH 01/52] feat: implement phantom
---
examples/sandbox/index.html | 1 +
examples/sandbox/index.ts | 22 ++
examples/sandbox/package.json | 1 +
packages/hdwallet-phantom/package.json | 24 ++
packages/hdwallet-phantom/src/adapter.ts | 57 +++
packages/hdwallet-phantom/src/ethereum.ts | 132 +++++++
packages/hdwallet-phantom/src/index.ts | 2 +
packages/hdwallet-phantom/src/phantom.test.ts | 168 ++++++++
packages/hdwallet-phantom/src/phantom.ts | 363 ++++++++++++++++++
packages/hdwallet-phantom/tsconfig.json | 10 +
tsconfig.json | 1 +
11 files changed, 781 insertions(+)
create mode 100644 packages/hdwallet-phantom/package.json
create mode 100644 packages/hdwallet-phantom/src/adapter.ts
create mode 100644 packages/hdwallet-phantom/src/ethereum.ts
create mode 100644 packages/hdwallet-phantom/src/index.ts
create mode 100644 packages/hdwallet-phantom/src/phantom.test.ts
create mode 100644 packages/hdwallet-phantom/src/phantom.ts
create mode 100644 packages/hdwallet-phantom/tsconfig.json
diff --git a/examples/sandbox/index.html b/examples/sandbox/index.html
index f70b1a1b5..a24103b82 100644
--- a/examples/sandbox/index.html
+++ b/examples/sandbox/index.html
@@ -116,6 +116,7 @@
Select
+
diff --git a/examples/sandbox/index.ts b/examples/sandbox/index.ts
index 51a3d2875..0065fddfc 100644
--- a/examples/sandbox/index.ts
+++ b/examples/sandbox/index.ts
@@ -11,6 +11,7 @@ import * as keplr from "@shapeshiftoss/hdwallet-keplr";
import * as ledgerWebHID from "@shapeshiftoss/hdwallet-ledger-webhid";
import * as ledgerWebUSB from "@shapeshiftoss/hdwallet-ledger-webusb";
import * as metaMask from "@shapeshiftoss/hdwallet-metamask";
+import * as phantom from "@shapeshiftoss/hdwallet-phantom";
import * as native from "@shapeshiftoss/hdwallet-native";
import * as portis from "@shapeshiftoss/hdwallet-portis";
import * as tallyHo from "@shapeshiftoss/hdwallet-tallyho";
@@ -127,6 +128,7 @@ const kkbridgeAdapter = keepkeyTcp.TCPKeepKeyAdapter.useKeyring(keyring);
const kkemuAdapter = keepkeyTcp.TCPKeepKeyAdapter.useKeyring(keyring);
const portisAdapter = portis.PortisAdapter.useKeyring(keyring, { portisAppId });
const metaMaskAdapter = metaMask.MetaMaskAdapter.useKeyring(keyring);
+const phantomAdapter = phantom.PhantomAdapter.useKeyring(keyring);
const tallyHoAdapter = tallyHo.TallyHoAdapter.useKeyring(keyring);
const walletConnectAdapter = walletConnect.WalletConnectAdapter.useKeyring(keyring, walletConnectOptions);
const walletConnectV2Adapter = walletConnectv2.WalletConnectV2Adapter.useKeyring(keyring, walletConnectV2Options);
@@ -159,6 +161,7 @@ const $ledgerwebhid = $("#ledgerwebhid");
const $portis = $("#portis");
const $native = $("#native");
const $metaMask = $("#metaMask");
+const $phantom = $("#phantom");
const $coinbase = $("#coinbase");
const $tallyHo = $("#tallyHo");
const $walletConnect = $("#walletConnect");
@@ -243,6 +246,19 @@ $metaMask.on("click", async (e) => {
}
});
+$phantom.on("click", async (e) => {
+ e.preventDefault();
+ wallet = await phantomAdapter.pairDevice();
+ window["wallet"] = wallet;
+ let deviceID = "nothing";
+ try {
+ deviceID = await wallet.getDeviceID();
+ $("#keyring select").val(deviceID);
+ } catch (err) {
+ console.error(err);
+ }
+});
+
$coinbase.on("click", async (e) => {
e.preventDefault();
wallet = await coinbaseAdapter.pairDevice();
@@ -405,6 +421,12 @@ async function deviceConnected(deviceId) {
console.error("Could not initialize MetaMaskAdapter", e);
}
+ try {
+ await phantomAdapter.initialize();
+ } catch (e) {
+ console.error("Could not initialize PhantomAdapter", e);
+ }
+
try {
await tallyHoAdapter.initialize();
} catch (e) {
diff --git a/examples/sandbox/package.json b/examples/sandbox/package.json
index c90a15065..9e92e8657 100644
--- a/examples/sandbox/package.json
+++ b/examples/sandbox/package.json
@@ -19,6 +19,7 @@
"@shapeshiftoss/hdwallet-ledger-webhid": "1.54.2",
"@shapeshiftoss/hdwallet-ledger-webusb": "1.54.2",
"@shapeshiftoss/hdwallet-metamask": "1.54.2",
+ "@shapeshiftoss/hdwallet-phantom": "1.54.2",
"@shapeshiftoss/hdwallet-native": "1.54.2",
"@shapeshiftoss/hdwallet-portis": "1.54.2",
"@shapeshiftoss/hdwallet-tallyho": "1.54.2",
diff --git a/packages/hdwallet-phantom/package.json b/packages/hdwallet-phantom/package.json
new file mode 100644
index 000000000..3c454984d
--- /dev/null
+++ b/packages/hdwallet-phantom/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@shapeshiftoss/hdwallet-phantom",
+ "version": "1.54.2",
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public"
+ },
+ "main": "dist/index.js",
+ "source": "src/index.ts",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "tsc --build",
+ "clean": "rm -rf dist node_modules tsconfig.tsbuildinfo",
+ "prepublishOnly": "yarn clean && yarn build"
+ },
+ "dependencies": {
+ "@shapeshiftoss/hdwallet-core": "1.54.2",
+ "eth-rpc-errors": "^4.0.3",
+ "lodash": "^4.17.21"
+ },
+ "devDependencies": {
+ "@types/lodash": "^4.14.168"
+ }
+}
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
new file mode 100644
index 000000000..58d01661b
--- /dev/null
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -0,0 +1,57 @@
+import * as core from "@shapeshiftoss/hdwallet-core";
+import { providers } from "ethers";
+
+import { PhantomHDWallet } from "./phantom";
+
+declare global {
+ interface Window {
+ phantom?: {
+ ethereum?: providers.ExternalProvider;
+ };
+ }
+}
+
+export class PhantomAdapter {
+ keyring: core.Keyring;
+
+ private constructor(keyring: core.Keyring) {
+ this.keyring = keyring;
+ }
+
+ public static useKeyring(keyring: core.Keyring) {
+ return new PhantomAdapter(keyring);
+ }
+
+ public async initialize(): Promise {
+ return Object.keys(this.keyring.wallets).length;
+ }
+
+ public async pairDevice(): Promise {
+ const provider = window.phantom?.ethereum;
+
+ if (!provider) {
+ window.open("https://phantom.app/", "_blank");
+ console.error("Please install Phantom!");
+ throw new Error("Phantom provider not found");
+ }
+
+ try {
+ await provider.request?.({ method: "eth_requestAccounts" }).catch(() =>
+ provider.request?.({
+ method: "wallet_requestPermissions",
+ params: [{ eth_accounts: {} }],
+ })
+ );
+ } catch (error) {
+ console.error("Could not get Phantom accounts. ");
+ throw error;
+ }
+ const wallet = new PhantomHDWallet(provider);
+ await wallet.initialize();
+ const deviceID = await wallet.getDeviceID();
+ this.keyring.add(wallet, deviceID);
+ this.keyring.emit(["Phantom", deviceID, core.Events.CONNECT], deviceID);
+
+ return wallet;
+ }
+}
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
new file mode 100644
index 000000000..3f910a826
--- /dev/null
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -0,0 +1,132 @@
+import * as core from "@shapeshiftoss/hdwallet-core";
+import { ETHSignedMessage } from "@shapeshiftoss/hdwallet-core";
+import { isHexString } from "ethers/lib/utils";
+
+export function describeETHPath(path: core.BIP32Path): core.PathDescription {
+ const pathStr = core.addressNListToBIP32(path);
+ const unknown: core.PathDescription = {
+ verbose: pathStr,
+ coin: "Ethereum",
+ isKnown: false,
+ };
+
+ if (path.length !== 5) return unknown;
+
+ if (path[0] !== 0x80000000 + 44) return unknown;
+
+ if (path[1] !== 0x80000000 + core.slip44ByCoin("Ethereum")) return unknown;
+
+ if ((path[2] & 0x80000000) >>> 0 !== 0x80000000) return unknown;
+
+ if (path[3] !== 0) return unknown;
+
+ if (path[4] !== 0) return unknown;
+
+ const index = path[2] & 0x7fffffff;
+ return {
+ verbose: `Ethereum Account #${index}`,
+ accountIdx: index,
+ wholeAccount: true,
+ coin: "Ethereum",
+ isKnown: true,
+ };
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export async function ethVerifyMessage(msg: core.ETHVerifyMessage, ethereum: any): Promise {
+ console.error("Method ethVerifyMessage unsupported for Phantom wallet!");
+ return null;
+}
+
+export function ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
+ const slip44 = core.slip44ByCoin(msg.coin);
+ if (slip44 === undefined) return [];
+ return [
+ {
+ addressNList: [0x80000000 + 44, 0x80000000 + slip44, 0x80000000 + msg.accountIdx, 0, 0],
+ hardenedPath: [0x80000000 + 44, 0x80000000 + slip44, 0x80000000 + msg.accountIdx],
+ relPath: [0, 0],
+ description: "Phantom",
+ },
+ ];
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export async function ethSignTx(msg: core.ETHSignTx, ethereum: any, from: string): Promise {
+ console.error("Method ethSignTx unsupported for Phantom wallet!");
+ return null;
+}
+
+export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string): Promise {
+ try {
+ const utxBase = {
+ from: from,
+ to: msg.to,
+ value: msg.value,
+ chainId: msg.chainId,
+ data: msg.data && msg.data !== "" ? msg.data : undefined,
+ // Phantom, like other Web3 libraries, derives its transaction schema from Ethereum's official JSON-RPC API specification
+ // (https://github.com/ethereum/execution-apis/blob/d63d2a02bcd2a8cef54ae2fc5bbff8b4fac944eb/src/schemas/transaction.json).
+ // That schema defines the use of the label `gas` to set the transaction's gas limit and not `gasLimit` as used in other
+ // libraries and as stated in the official yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf).
+ gas: msg.gasLimit,
+ };
+
+ const utx = msg.maxFeePerGas
+ ? {
+ ...utxBase,
+ maxFeePerGas: msg.maxFeePerGas,
+ maxPriorityFeePerGas: msg.maxPriorityFeePerGas,
+ }
+ : { ...utxBase, gasPrice: msg.gasPrice };
+
+ const signedTx = await ethereum.request({
+ method: "eth_sendTransaction",
+ params: [utx],
+ });
+
+ return {
+ hash: signedTx,
+ } as core.ETHTxHash;
+ } catch (error) {
+ console.error(error);
+ return null;
+ }
+}
+
+export async function ethSignMessage(
+ msg: core.ETHSignMessage,
+ ethereum: any,
+ address: string
+): Promise {
+ try {
+ if (!isHexString(msg.message)) throw new Error("data is not an hex string");
+ const signedMsg = await ethereum.request({
+ method: "personal_sign",
+ params: [msg.message, address],
+ });
+
+ return {
+ address: address,
+ signature: signedMsg,
+ } as ETHSignedMessage;
+ } catch (error) {
+ console.error(error);
+ return null;
+ }
+}
+
+export async function ethGetAddress(ethereum: any): Promise {
+ if (!(ethereum && ethereum.request)) {
+ return null;
+ }
+ try {
+ const ethAccounts = await ethereum.request({
+ method: "eth_accounts",
+ });
+ return ethAccounts[0];
+ } catch (error) {
+ console.error(error);
+ return null;
+ }
+}
diff --git a/packages/hdwallet-phantom/src/index.ts b/packages/hdwallet-phantom/src/index.ts
new file mode 100644
index 000000000..ee1fe48d8
--- /dev/null
+++ b/packages/hdwallet-phantom/src/index.ts
@@ -0,0 +1,2 @@
+export * from "./adapter";
+export * from "./phantom";
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
new file mode 100644
index 000000000..c363f60a7
--- /dev/null
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -0,0 +1,168 @@
+import * as core from "@shapeshiftoss/hdwallet-core";
+
+import { PhantomHDWallet, PhantomHDWalletInfo } from ".";
+
+describe("HDWalletInfo", () => {
+ const info = new PhantomHDWalletInfo();
+
+ it("should have correct metadata", async () => {
+ expect(info.getVendor()).toBe("Phantom");
+ expect(info.hasOnDevicePinEntry()).toBe(false);
+ expect(info.hasOnDevicePassphrase()).toBe(true);
+ expect(info.hasOnDeviceDisplay()).toBe(true);
+ expect(info.hasOnDeviceRecovery()).toBe(true);
+ expect(await info.ethSupportsNetwork(1)).toBe(true);
+ expect(await info.ethSupportsSecureTransfer()).toBe(false);
+ expect(info.ethSupportsNativeShapeShift()).toBe(false);
+ expect(await info.ethSupportsEIP1559()).toBe(true);
+ expect(await info.supportsOfflineSigning()).toBe(false);
+ expect(await info.supportsBroadcast()).toBe(true);
+ });
+});
+
+describe("PhantomHDWallet", () => {
+ let wallet: PhantomHDWallet;
+ beforeEach(() => {
+ wallet = new PhantomHDWallet(core.untouchable("PhantomHDWallet:provider"));
+ wallet.ethAddress = "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8";
+ });
+
+ it("should match the metadata", async () => {
+ expect(wallet.getVendor()).toBe("Phantom");
+ expect(wallet.hasOnDevicePinEntry()).toBe(false);
+ expect(wallet.hasOnDevicePassphrase()).toBe(true);
+ expect(wallet.hasOnDeviceDisplay()).toBe(true);
+ expect(wallet.hasOnDeviceRecovery()).toBe(true);
+ expect(await wallet.ethSupportsNetwork(1)).toBe(true);
+ expect(await wallet.ethSupportsSecureTransfer()).toBe(false);
+ expect(wallet.ethSupportsNativeShapeShift()).toBe(false);
+ expect(await wallet.ethSupportsEIP1559()).toBe(true);
+ expect(await wallet.supportsOfflineSigning()).toBe(false);
+ expect(wallet.supportsBip44Accounts()).toBe(false);
+ expect(await wallet.supportsBroadcast()).toBe(true);
+ });
+
+ it("should test ethSignMessage", async () => {
+ wallet.provider = {
+ request: jest.fn().mockReturnValue(
+ `Object {
+ "address": "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
+ "signature": "0x05f51140905ffa33ffdc57f46b0b8d8fbb1d2a99f8cd843ca27893c01c31351c08b76d83dce412731c846e3b50649724415deb522d00950fbf4f2c1459c2b70b1b",
+ }`
+ ),
+ };
+ const msg = "0x737570657220736563726574206d657373616765"; // super secret message
+ expect(
+ await wallet.ethSignMessage({
+ addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
+ message: msg,
+ })
+ ).toMatchInlineSnapshot(`
+ Object {
+ "address": "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
+ "signature": "Object {
+ \\"address\\": \\"0x73d0385F4d8E00C5e6504C6030F47BF6212736A8\\",
+ \\"signature\\": \\"0x05f51140905ffa33ffdc57f46b0b8d8fbb1d2a99f8cd843ca27893c01c31351c08b76d83dce412731c846e3b50649724415deb522d00950fbf4f2c1459c2b70b1b\\",
+ }",
+ }
+ `);
+ });
+
+ it("ethSignMessage returns null on error", async () => {
+ wallet.provider = {
+ request: jest.fn().mockRejectedValue(new Error("An Error has occurred")),
+ };
+
+ const msg = "0x737570657220736563726574206d657373616765"; // super secret message
+ const sig = await wallet.ethSignMessage({
+ addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
+ message: msg,
+ });
+
+ expect(sig).toBe(null);
+ });
+
+ it("ethGetAddress returns a valid address", async () => {
+ wallet.provider = {
+ request: jest.fn().mockReturnValue(["0x73d0385F4d8E00C5e6504C6030F47BF6212736A8"]),
+ };
+
+ const msg = "0x737570657220736563726574206d657373616765"; // super secret message
+ const sig = await wallet.ethSignMessage({
+ addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
+ message: msg,
+ });
+
+ expect(sig).toMatchObject({
+ address: "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
+ signature: ["0x73d0385F4d8E00C5e6504C6030F47BF6212736A8"],
+ });
+ });
+ it("ethSendTx returns a valid hash", async () => {
+ wallet.provider = {
+ request: jest.fn().mockReturnValue("0x123"),
+ };
+
+ const hash = await wallet.ethSendTx({
+ addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
+ nonce: "0xDEADBEEF",
+ gasPrice: "0xDEADBEEF",
+ gasLimit: "0xDEADBEEF",
+ to: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ value: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ data: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ chainId: 1,
+ });
+ expect(wallet.provider.request).toHaveBeenCalled();
+ expect(hash).toMatchObject({ hash: "0x123" });
+ });
+ it("ethSendTx returns a valid hash if maxFeePerGas is present in msg", async () => {
+ wallet.provider = {
+ request: jest.fn().mockReturnValue("0x123"),
+ };
+
+ const hash = await wallet.ethSendTx({
+ addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
+ nonce: "0xDEADBEEF",
+ gasLimit: "0xDEADBEEF",
+ maxFeePerGas: "0xDEADBEEF",
+ to: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ value: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ data: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ chainId: 1,
+ });
+ expect(wallet.provider.request).toHaveBeenCalled();
+ expect(hash).toMatchObject({ hash: "0x123" });
+ });
+ it("ethSendTx returns null on error", async () => {
+ wallet.provider = {
+ request: jest.fn().mockRejectedValue(new Error("An Error has occurred")),
+ };
+
+ const hash = await wallet.ethSendTx({
+ addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
+ nonce: "0xDEADBEEF",
+ gasPrice: "0xDEADBEEF",
+ gasLimit: "0xDEADBEEF",
+ to: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ value: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ data: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
+ chainId: 1,
+ });
+ expect(wallet.provider.request).toHaveBeenCalled();
+ expect(hash).toBe(null);
+ });
+ it("ethVerifyMessage returns null as its not implemented", async () => {
+ wallet.provider = {
+ request: jest.fn().mockReturnValue("0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8"),
+ };
+ expect(
+ await wallet.ethVerifyMessage({
+ address: "0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8",
+ message: "hello world",
+ signature:
+ "0x29f7212ecc1c76cea81174af267b67506f754ea8c73f144afa900a0d85b24b21319621aeb062903e856352f38305710190869c3ce5a1425d65ef4fa558d0fc251b",
+ })
+ ).toEqual(null);
+ });
+});
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
new file mode 100644
index 000000000..00c9866a3
--- /dev/null
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -0,0 +1,363 @@
+import * as core from "@shapeshiftoss/hdwallet-core";
+import { AddEthereumChainParameter } from "@shapeshiftoss/hdwallet-core";
+import { ethErrors, serializeError } from "eth-rpc-errors";
+import _ from "lodash";
+
+import * as eth from "./ethereum";
+
+export function isPhantom(wallet: core.HDWallet): wallet is PhantomHDWallet {
+ return _.isObject(wallet) && (wallet as any)._isPhantom;
+}
+
+export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInfo {
+ readonly _supportsBTCInfo = false;
+ readonly _supportsETHInfo = true;
+ readonly _supportsCosmosInfo = false;
+ readonly _supportsBinanceInfo = false;
+ readonly _supportsRippleInfo = false;
+ readonly _supportsEosInfo = false;
+ readonly _supportsFioInfo = false;
+ readonly _supportsThorchainInfo = false;
+ readonly _supportsSecretInfo = false;
+ readonly _supportsKavaInfo = false;
+ readonly _supportsTerraInfo = false;
+
+ public getVendor(): string {
+ return "Phantom";
+ }
+
+ public hasOnDevicePinEntry(): boolean {
+ return false;
+ }
+
+ public hasOnDevicePassphrase(): boolean {
+ return true;
+ }
+
+ public hasOnDeviceDisplay(): boolean {
+ return true;
+ }
+
+ public hasOnDeviceRecovery(): boolean {
+ return true;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public hasNativeShapeShift(srcCoin: core.Coin, dstCoin: core.Coin): boolean {
+ return false;
+ }
+
+ public supportsBip44Accounts(): boolean {
+ return false;
+ }
+
+ public supportsOfflineSigning(): boolean {
+ return false;
+ }
+
+ public supportsBroadcast(): boolean {
+ return true;
+ }
+
+ public describePath(msg: core.DescribePath): core.PathDescription {
+ switch (msg.coin) {
+ case "Ethereum":
+ return eth.describeETHPath(msg.path);
+ default:
+ throw new Error("Unsupported path");
+ }
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public ethNextAccountPath(msg: core.ETHAccountPath): core.ETHAccountPath | undefined {
+ // TODO: What do we do here?
+ return undefined;
+ }
+
+ public async ethSupportsNetwork(chainId: number): Promise {
+ return chainId === 1;
+ }
+
+ public async ethSupportsSecureTransfer(): Promise {
+ return false;
+ }
+
+ public ethSupportsNativeShapeShift(): boolean {
+ return false;
+ }
+
+ public async ethSupportsEIP1559(): Promise {
+ return true;
+ }
+
+ public ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
+ return eth.ethGetAccountPaths(msg);
+ }
+}
+
+export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
+ readonly _supportsETH = true;
+ readonly _supportsETHInfo = true;
+ readonly _supportsBTCInfo = false;
+ readonly _supportsBTC = false;
+ readonly _supportsCosmosInfo = false;
+ readonly _supportsCosmos = false;
+ readonly _supportsEthSwitchChain = true;
+ readonly _supportsAvalanche = true;
+ readonly _supportsOptimism = true;
+ readonly _supportsBSC = true;
+ readonly _supportsPolygon = true;
+ readonly _supportsGnosis = true;
+ readonly _supportsArbitrum = true;
+ readonly _supportsArbitrumNova = true;
+ readonly _supportsBase = true;
+ readonly _supportsOsmosisInfo = false;
+ readonly _supportsOsmosis = false;
+ readonly _supportsBinanceInfo = false;
+ readonly _supportsBinance = false;
+ readonly _supportsDebugLink = false;
+ readonly _isPortis = false;
+ readonly _isPhantom = true;
+ readonly _supportsRippleInfo = false;
+ readonly _supportsRipple = false;
+ readonly _supportsEosInfo = false;
+ readonly _supportsEos = false;
+ readonly _supportsFioInfo = false;
+ readonly _supportsFio = false;
+ readonly _supportsThorchainInfo = false;
+ readonly _supportsThorchain = false;
+ readonly _supportsSecretInfo = false;
+ readonly _supportsSecret = false;
+ readonly _supportsKava = false;
+ readonly _supportsKavaInfo = false;
+ readonly _supportsTerra = false;
+ readonly _supportsTerraInfo = false;
+
+ info: PhantomHDWalletInfo & core.HDWalletInfo;
+ ethAddress?: string | null;
+ provider: any;
+
+ constructor(provider: unknown) {
+ this.info = new PhantomHDWalletInfo();
+ this.provider = provider;
+ }
+
+ async getFeatures(): Promise> {
+ return {};
+ }
+
+ public async isLocked(): Promise {
+ return !this.provider._phantom.isUnlocked();
+ }
+
+ public getVendor(): string {
+ return "Phantom";
+ }
+
+ public async getModel(): Promise {
+ return "Phantom";
+ }
+
+ public async getLabel(): Promise {
+ return "Phantom";
+ }
+
+ public async initialize(): Promise {
+ // nothing to initialize
+ }
+
+ public hasOnDevicePinEntry(): boolean {
+ return this.info.hasOnDevicePinEntry();
+ }
+
+ public hasOnDevicePassphrase(): boolean {
+ return this.info.hasOnDevicePassphrase();
+ }
+
+ public hasOnDeviceDisplay(): boolean {
+ return this.info.hasOnDeviceDisplay();
+ }
+
+ public hasOnDeviceRecovery(): boolean {
+ return this.info.hasOnDeviceRecovery();
+ }
+
+ public hasNativeShapeShift(srcCoin: core.Coin, dstCoin: core.Coin): boolean {
+ return this.info.hasNativeShapeShift(srcCoin, dstCoin);
+ }
+
+ public supportsBip44Accounts(): boolean {
+ return this.info.supportsBip44Accounts();
+ }
+
+ public supportsOfflineSigning(): boolean {
+ return false;
+ }
+
+ public supportsBroadcast(): boolean {
+ return true;
+ }
+
+ public async clearSession(): Promise {
+ // TODO: Can we lock Phantom from here?
+ }
+
+ public async ping(msg: core.Ping): Promise {
+ // no ping function for Phantom, so just returning Core.Pong
+ return { msg: msg.msg };
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async sendPin(pin: string): Promise {
+ // no concept of pin in Phantom
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async sendPassphrase(passphrase: string): Promise {
+ // cannot send passphrase to Phantom. Could show the widget?
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async sendCharacter(charater: string): Promise {
+ // no concept of sendCharacter in Phantom
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async sendWord(word: string): Promise {
+ // no concept of sendWord in Phantom
+ }
+
+ public async cancel(): Promise {
+ // no concept of cancel in Phantom
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
+ public async wipe(): Promise {}
+
+ // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
+ public async reset(msg: core.ResetDevice): Promise {}
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async recover(msg: core.RecoverDevice): Promise {
+ // no concept of recover in Phantom
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async loadDevice(msg: core.LoadDevice): Promise {
+ // TODO: Does Phantom allow this to be done programatically?
+ }
+
+ public describePath(msg: core.DescribePath): core.PathDescription {
+ return this.info.describePath(msg);
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async getPublicKeys(msg: Array): Promise> {
+ // Ethereum public keys are not exposed by the RPC API
+ return [];
+ }
+
+ public async isInitialized(): Promise {
+ return true;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
+ public async disconnect(): Promise {}
+
+ public async ethSupportsNetwork(chainId = 1): Promise {
+ return chainId === 1;
+ }
+
+ public async ethGetChainId(): Promise {
+ try {
+ // chainId as hex string
+ const chainId: string = await this.provider.request({ method: "eth_chainId" });
+ return parseInt(chainId, 16);
+ } catch (e) {
+ console.error(e);
+ return null;
+ }
+ }
+
+ public async ethSwitchChain(params: AddEthereumChainParameter): Promise {
+ try {
+ // at this point, we know that we're in the context of a valid Phantom provider
+ await this.provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: params.chainId }] });
+ } catch (e: any) {
+ const error = serializeError(e);
+
+ if (error.code === 4001) {
+ throw ethErrors.provider.userRejectedRequest();
+ }
+
+ throw (error.data as any).originalError as {
+ code: number;
+ message: string;
+ stack: string;
+ };
+ }
+ }
+
+ public async ethSupportsSecureTransfer(): Promise {
+ return false;
+ }
+
+ public ethSupportsNativeShapeShift(): boolean {
+ return false;
+ }
+
+ public async ethSupportsEIP1559(): Promise {
+ return true;
+ }
+
+ public ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
+ return eth.ethGetAccountPaths(msg);
+ }
+
+ public ethNextAccountPath(msg: core.ETHAccountPath): core.ETHAccountPath | undefined {
+ return this.info.ethNextAccountPath(msg);
+ }
+
+ // TODO: Respect msg.addressNList!
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async ethGetAddress(msg: core.ETHGetAddress): Promise {
+ if (this.ethAddress) {
+ return this.ethAddress;
+ }
+ const address = await eth.ethGetAddress(this.provider);
+ if (address) {
+ this.ethAddress = address;
+ return address;
+ } else {
+ this.ethAddress = null;
+ return null;
+ }
+ }
+
+ public async ethSignTx(msg: core.ETHSignTx): Promise {
+ const address = await this.ethGetAddress(this.provider);
+ return address ? eth.ethSignTx(msg, this.provider, address) : null;
+ }
+
+ public async ethSendTx(msg: core.ETHSignTx): Promise {
+ const address = await this.ethGetAddress(this.provider);
+ return address ? eth.ethSendTx(msg, this.provider, address) : null;
+ }
+
+ public async ethSignMessage(msg: core.ETHSignMessage): Promise {
+ const address = await this.ethGetAddress(this.provider);
+ return address ? eth.ethSignMessage(msg, this.provider, address) : null;
+ }
+
+ public async ethVerifyMessage(msg: core.ETHVerifyMessage): Promise {
+ return eth.ethVerifyMessage(msg, this.provider);
+ }
+
+ public async getDeviceID(): Promise {
+ return "phantom:" + (await this.ethGetAddress(this.provider));
+ }
+
+ public async getFirmwareVersion(): Promise {
+ return "phantom";
+ }
+}
diff --git a/packages/hdwallet-phantom/tsconfig.json b/packages/hdwallet-phantom/tsconfig.json
new file mode 100644
index 000000000..0c82f8910
--- /dev/null
+++ b/packages/hdwallet-phantom/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist", "**/*.test.ts"],
+ "references": [{ "path": "../hdwallet-core" }]
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index e92968f5c..1060ad06e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -45,6 +45,7 @@
{ "path": "./packages/hdwallet-ledger-webusb" },
{ "path": "./packages/hdwallet-metamask" },
{ "path": "./packages/hdwallet-metamask-shapeshift-multichain" },
+ { "path": "./packages/hdwallet-phantom" },
{ "path": "./packages/hdwallet-coinbase" },
{ "path": "./packages/hdwallet-native" },
{ "path": "./packages/hdwallet-portis" },
From f516a17c03ff916b6d893f7a67a3c2e2764ba5fe Mon Sep 17 00:00:00 2001
From: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
Date: Fri, 6 Sep 2024 11:12:11 +0200
Subject: [PATCH 02/52] feat: update supports
---
packages/hdwallet-phantom/src/phantom.ts | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 00c9866a3..7265997c3 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -99,18 +99,18 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
readonly _supportsETH = true;
readonly _supportsETHInfo = true;
readonly _supportsBTCInfo = false;
- readonly _supportsBTC = false;
+ readonly _supportsBTC = true;
readonly _supportsCosmosInfo = false;
readonly _supportsCosmos = false;
- readonly _supportsEthSwitchChain = true;
- readonly _supportsAvalanche = true;
- readonly _supportsOptimism = true;
- readonly _supportsBSC = true;
+ readonly _supportsEthSwitchChain = false;
+ readonly _supportsAvalanche = false;
+ readonly _supportsOptimism = false;
+ readonly _supportsBSC = false;
readonly _supportsPolygon = true;
- readonly _supportsGnosis = true;
- readonly _supportsArbitrum = true;
- readonly _supportsArbitrumNova = true;
- readonly _supportsBase = true;
+ readonly _supportsGnosis = false;
+ readonly _supportsArbitrum = false;
+ readonly _supportsArbitrumNova = false;
+ readonly _supportsBase = false;
readonly _supportsOsmosisInfo = false;
readonly _supportsOsmosis = false;
readonly _supportsBinanceInfo = false;
From 617ea6cb57081d4822bf1e9459d2ee9850aed9b4 Mon Sep 17 00:00:00 2001
From: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
Date: Mon, 9 Sep 2024 11:24:01 +0200
Subject: [PATCH 03/52] feat: add btc supprot
---
packages/hdwallet-phantom/src/adapter.ts | 12 +-
packages/hdwallet-phantom/src/bitcoin.ts | 180 ++++++++++++++++++
packages/hdwallet-phantom/src/phantom.test.ts | 25 +--
packages/hdwallet-phantom/src/phantom.ts | 145 ++++++++++----
4 files changed, 314 insertions(+), 48 deletions(-)
create mode 100644 packages/hdwallet-phantom/src/bitcoin.ts
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 58d01661b..ee050b16f 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -7,6 +7,7 @@ declare global {
interface Window {
phantom?: {
ethereum?: providers.ExternalProvider;
+ bitcoin?: providers.ExternalProvider;
};
}
}
@@ -27,17 +28,18 @@ export class PhantomAdapter {
}
public async pairDevice(): Promise {
- const provider = window.phantom?.ethereum;
+ const evmProvider = window.phantom?.ethereum;
+ const bitcoinProvider = window.phantom?.bitcoin;
- if (!provider) {
+ if (!evmProvider || !bitcoinProvider) {
window.open("https://phantom.app/", "_blank");
console.error("Please install Phantom!");
throw new Error("Phantom provider not found");
}
try {
- await provider.request?.({ method: "eth_requestAccounts" }).catch(() =>
- provider.request?.({
+ await evmProvider.request?.({ method: "eth_requestAccounts" }).catch(() =>
+ evmProvider.request?.({
method: "wallet_requestPermissions",
params: [{ eth_accounts: {} }],
})
@@ -46,7 +48,7 @@ export class PhantomAdapter {
console.error("Could not get Phantom accounts. ");
throw error;
}
- const wallet = new PhantomHDWallet(provider);
+ const wallet = new PhantomHDWallet(evmProvider, bitcoinProvider);
await wallet.initialize();
const deviceID = await wallet.getDeviceID();
this.keyring.add(wallet, deviceID);
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
new file mode 100644
index 000000000..f37bef40e
--- /dev/null
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -0,0 +1,180 @@
+import * as bitcoin from "@shapeshiftoss/bitcoinjs-lib";
+import * as core from "@shapeshiftoss/hdwallet-core";
+
+type BtcAccount = {
+ address: string;
+ addressType: "p2tr" | "p2wpkh" | "p2sh" | "p2pkh";
+ publicKey: string;
+ purpose: "payment" | "ordinals";
+};
+
+function getNetwork(coin: string): bitcoin.networks.Network {
+ switch (coin.toLowerCase()) {
+ case "bitcoin":
+ return bitcoin.networks.bitcoin;
+ case "testnet":
+ return bitcoin.networks.testnet;
+ default:
+ throw new Error(`Unsupported coin: ${coin}`);
+ }
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export function bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
+ // Only support one account for now (like portis).
+ return undefined;
+}
+
+export async function bitcoinGetPublicKeys(msg: core.BTCGetAddress, provider: any): Promise {
+ const accounts = await provider.requestAccounts();
+ const paymentPublicKey = accounts.find((account: BtcAccount) => account.purpose === "payment")?.publicKey;
+
+ return [paymentPublicKey];
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export async function bitcoinGetAddress(msg: core.BTCGetAddress, provider: any): Promise {
+ const accounts = await provider.requestAccounts();
+ const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
+
+ return paymentAddress;
+}
+
+async function addInput(
+ wallet: core.BTCWallet,
+ psbt: bitcoin.Psbt,
+ input: core.BTCSignTxInput,
+ coin: string,
+ network: bitcoin.networks.Network
+): Promise {
+ const inputData: bitcoin.PsbtTxInput & {
+ nonWitnessUtxo?: Buffer;
+ witnessUtxo?: { script: Buffer; value: number };
+ } = {
+ hash: Buffer.from(input.txid, "hex"),
+ index: input.vout,
+ };
+
+ if (input.sequence !== undefined) {
+ inputData.sequence = input.sequence;
+ }
+
+ if (input.scriptType) {
+ switch (input.scriptType) {
+ case "p2pkh":
+ inputData.nonWitnessUtxo = Buffer.from(input.hex, "hex");
+ break;
+ case "p2sh-p2wpkh":
+ case "p2wpkh": {
+ const inputAddress = await wallet.btcGetAddress({ addressNList: input.addressNList, coin, showDisplay: false });
+
+ if (!inputAddress) throw new Error("Could not get address from wallet");
+
+ inputData.witnessUtxo = {
+ script: bitcoin.address.toOutputScript(inputAddress, network),
+ value: parseInt(input.amount),
+ };
+ break;
+ }
+ default:
+ throw new Error(`Unsupported script type: ${input.scriptType}`);
+ }
+ }
+
+ psbt.addInput(inputData);
+}
+
+async function addOutput(
+ wallet: core.BTCWallet,
+ psbt: bitcoin.Psbt,
+ output: core.BTCSignTxOutput,
+ coin: string
+): Promise {
+ if ("address" in output && output.address) {
+ psbt.addOutput({
+ address: output.address,
+ value: parseInt(output.amount),
+ });
+ } else if ("addressNList" in output && output.addressNList) {
+ const outputAddress = await wallet.btcGetAddress({ addressNList: output.addressNList, coin, showDisplay: false });
+
+ if (!outputAddress) throw new Error("Could not get address from wallet");
+
+ psbt.addOutput({
+ address: outputAddress,
+ value: parseInt(output.amount),
+ });
+ } else if ("opReturnData" in output && output.opReturnData) {
+ const data = Buffer.from(output.opReturnData.toString(), "hex");
+ const embed = bitcoin.payments.embed({ data: [data] });
+ psbt.addOutput({
+ script: embed.output!,
+ value: 0,
+ });
+ }
+}
+
+export async function bitcoinSignTx(
+ wallet: core.BTCWallet,
+ msg: core.BTCSignTx,
+ provider: any
+): Promise {
+ if (!msg.inputs.length || !msg.outputs.length) {
+ throw new Error("Invalid input: Empty inputs or outputs");
+ }
+
+ const network = getNetwork(msg.coin);
+
+ const psbt = new bitcoin.Psbt({ network });
+
+ psbt.setVersion(msg.version ?? 2);
+ if (msg.locktime) {
+ psbt.setLocktime(msg.locktime);
+ }
+
+ for (const input of msg.inputs) {
+ await addInput(wallet, psbt, input, msg.coin, network);
+ }
+
+ for (const output of msg.outputs) {
+ await addOutput(wallet, psbt, output, msg.coin);
+ }
+
+ const inputsToSign = await Promise.all(
+ msg.inputs.map(async (input, index) => {
+ const address = await wallet.btcGetAddress({
+ addressNList: input.addressNList,
+ coin: msg.coin,
+ showDisplay: false,
+ });
+
+ return {
+ address,
+ signingIndexes: [index],
+ sigHash: bitcoin.Transaction.SIGHASH_ALL,
+ };
+ })
+ );
+
+ const fromHexString = (hexString: string) => {
+ const bytes = hexString.match(/.{1,2}/g);
+ if (!bytes) throw new Error("Invalid hex string");
+
+ return Uint8Array.from(bytes.map((byte) => parseInt(byte, 16)));
+ };
+ const signedPsbtHex = await provider.signPSBT(fromHexString(psbt.toHex()), { inputsToSign });
+
+ const signedPsbt = bitcoin.Psbt.fromHex(signedPsbtHex, { network });
+
+ signedPsbt.finalizeAllInputs();
+ const tx = signedPsbt.extractTransaction();
+
+ const signatures = signedPsbt.data.inputs.map((input) =>
+ input.partialSig ? input.partialSig[0].signature.toString("hex") : ""
+ );
+
+ return {
+ signatures,
+ serializedTx: tx.toHex(),
+ };
+}
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index c363f60a7..4a325e3e5 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -23,7 +23,10 @@ describe("HDWalletInfo", () => {
describe("PhantomHDWallet", () => {
let wallet: PhantomHDWallet;
beforeEach(() => {
- wallet = new PhantomHDWallet(core.untouchable("PhantomHDWallet:provider"));
+ wallet = new PhantomHDWallet(
+ core.untouchable("PhantomHDWallet:provider"),
+ core.untouchable("PhantomHDWallet:provider")
+ );
wallet.ethAddress = "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8";
});
@@ -43,7 +46,7 @@ describe("PhantomHDWallet", () => {
});
it("should test ethSignMessage", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockReturnValue(
`Object {
"address": "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
@@ -69,7 +72,7 @@ describe("PhantomHDWallet", () => {
});
it("ethSignMessage returns null on error", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockRejectedValue(new Error("An Error has occurred")),
};
@@ -83,7 +86,7 @@ describe("PhantomHDWallet", () => {
});
it("ethGetAddress returns a valid address", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockReturnValue(["0x73d0385F4d8E00C5e6504C6030F47BF6212736A8"]),
};
@@ -99,7 +102,7 @@ describe("PhantomHDWallet", () => {
});
});
it("ethSendTx returns a valid hash", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockReturnValue("0x123"),
};
@@ -113,11 +116,11 @@ describe("PhantomHDWallet", () => {
data: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
chainId: 1,
});
- expect(wallet.provider.request).toHaveBeenCalled();
+ expect(wallet.evmProvider.request).toHaveBeenCalled();
expect(hash).toMatchObject({ hash: "0x123" });
});
it("ethSendTx returns a valid hash if maxFeePerGas is present in msg", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockReturnValue("0x123"),
};
@@ -131,11 +134,11 @@ describe("PhantomHDWallet", () => {
data: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
chainId: 1,
});
- expect(wallet.provider.request).toHaveBeenCalled();
+ expect(wallet.evmProvider.request).toHaveBeenCalled();
expect(hash).toMatchObject({ hash: "0x123" });
});
it("ethSendTx returns null on error", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockRejectedValue(new Error("An Error has occurred")),
};
@@ -149,11 +152,11 @@ describe("PhantomHDWallet", () => {
data: "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
chainId: 1,
});
- expect(wallet.provider.request).toHaveBeenCalled();
+ expect(wallet.evmProvider.request).toHaveBeenCalled();
expect(hash).toBe(null);
});
it("ethVerifyMessage returns null as its not implemented", async () => {
- wallet.provider = {
+ wallet.evmProvider = {
request: jest.fn().mockReturnValue("0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8"),
};
expect(
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 7265997c3..ecc397b54 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -1,8 +1,8 @@
import * as core from "@shapeshiftoss/hdwallet-core";
import { AddEthereumChainParameter } from "@shapeshiftoss/hdwallet-core";
-import { ethErrors, serializeError } from "eth-rpc-errors";
import _ from "lodash";
+import * as Btc from "./bitcoin";
import * as eth from "./ethereum";
export function isPhantom(wallet: core.HDWallet): wallet is PhantomHDWallet {
@@ -22,6 +22,9 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
readonly _supportsKavaInfo = false;
readonly _supportsTerraInfo = false;
+ bitcoinAddress?: string | null;
+ ethAddress?: string | null;
+
public getVendor(): string {
return "Phantom";
}
@@ -135,11 +138,13 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
info: PhantomHDWalletInfo & core.HDWalletInfo;
ethAddress?: string | null;
- provider: any;
+ evmProvider: any;
+ bitcoinProvider: any;
- constructor(provider: unknown) {
+ constructor(evmProvider: unknown, bitcoinProvider: unknown) {
this.info = new PhantomHDWalletInfo();
- this.provider = provider;
+ this.evmProvider = evmProvider;
+ this.bitcoinProvider = bitcoinProvider;
}
async getFeatures(): Promise> {
@@ -147,7 +152,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public async isLocked(): Promise {
- return !this.provider._phantom.isUnlocked();
+ return !this.evmProvider._phantom.isUnlocked();
}
public getVendor(): string {
@@ -248,7 +253,19 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public describePath(msg: core.DescribePath): core.PathDescription {
- return this.info.describePath(msg);
+ switch (msg.coin) {
+ case "bitcoin": {
+ const unknown = core.unknownUTXOPath(msg.path, msg.coin, msg.scriptType);
+
+ if (!msg.scriptType) return unknown;
+
+ return core.describeUTXOPath(msg.path, msg.coin, msg.scriptType);
+ }
+ case "ethereum":
+ return core.describeETHPath(msg.path);
+ default:
+ throw new Error("Unsupported path");
+ }
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -271,7 +288,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
public async ethGetChainId(): Promise {
try {
// chainId as hex string
- const chainId: string = await this.provider.request({ method: "eth_chainId" });
+ const chainId: string = await this.evmProvider.request({ method: "eth_chainId" });
return parseInt(chainId, 16);
} catch (e) {
console.error(e);
@@ -279,23 +296,9 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
}
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
public async ethSwitchChain(params: AddEthereumChainParameter): Promise {
- try {
- // at this point, we know that we're in the context of a valid Phantom provider
- await this.provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: params.chainId }] });
- } catch (e: any) {
- const error = serializeError(e);
-
- if (error.code === 4001) {
- throw ethErrors.provider.userRejectedRequest();
- }
-
- throw (error.data as any).originalError as {
- code: number;
- message: string;
- stack: string;
- };
- }
+ // no concept of switch chain in phantom
}
public async ethSupportsSecureTransfer(): Promise {
@@ -324,7 +327,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
if (this.ethAddress) {
return this.ethAddress;
}
- const address = await eth.ethGetAddress(this.provider);
+ const address = await eth.ethGetAddress(this.evmProvider);
if (address) {
this.ethAddress = address;
return address;
@@ -335,29 +338,107 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public async ethSignTx(msg: core.ETHSignTx): Promise {
- const address = await this.ethGetAddress(this.provider);
- return address ? eth.ethSignTx(msg, this.provider, address) : null;
+ const address = await this.ethGetAddress(this.evmProvider);
+ return address ? eth.ethSignTx(msg, this.evmProvider, address) : null;
}
public async ethSendTx(msg: core.ETHSignTx): Promise {
- const address = await this.ethGetAddress(this.provider);
- return address ? eth.ethSendTx(msg, this.provider, address) : null;
+ const address = await this.ethGetAddress(this.evmProvider);
+ return address ? eth.ethSendTx(msg, this.evmProvider, address) : null;
}
public async ethSignMessage(msg: core.ETHSignMessage): Promise {
- const address = await this.ethGetAddress(this.provider);
- return address ? eth.ethSignMessage(msg, this.provider, address) : null;
+ const address = await this.ethGetAddress(this.evmProvider);
+ return address ? eth.ethSignMessage(msg, this.evmProvider, address) : null;
}
public async ethVerifyMessage(msg: core.ETHVerifyMessage): Promise {
- return eth.ethVerifyMessage(msg, this.provider);
+ return eth.ethVerifyMessage(msg, this.evmProvider);
}
public async getDeviceID(): Promise {
- return "phantom:" + (await this.ethGetAddress(this.provider));
+ return "phantom:" + (await this.ethGetAddress(this.evmProvider));
}
public async getFirmwareVersion(): Promise {
return "phantom";
}
+
+ /** BITCOIN */
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
+ // TODO: What do we do here?
+ return undefined;
+ }
+
+ public async btcSupportsSecureTransfer(): Promise {
+ return false;
+ }
+
+ public btcSupportsNativeShapeShift(): boolean {
+ return false;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public btcGetAccountPaths(msg: core.BTCGetAccountPaths): Array {
+ throw new Error("Method not implemented.");
+ }
+
+ public btcNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
+ return this.bitcoinNextAccountPath(msg);
+ }
+
+ addressCache: Map = new Map();
+ public async btcGetAddress(msg: core.BTCGetAddress): Promise {
+ const key = JSON.stringify(msg);
+ const maybeCachedAddress = this.addressCache.get(key);
+ if (maybeCachedAddress) return maybeCachedAddress;
+ const value = await (async () => {
+ switch (msg.coin) {
+ case "Bitcoin":
+ return Btc.bitcoinGetAddress(msg, this.bitcoinProvider);
+ default:
+ return null;
+ }
+ })();
+ if (!value || typeof value !== "string") return null;
+
+ this.addressCache.set(key, value);
+ return value;
+ }
+
+ public async btcSignTx(msg: core.BTCSignTx): Promise {
+ const { coin } = msg;
+ switch (coin) {
+ case "Bitcoin":
+ return Btc.bitcoinSignTx(this, msg, this.bitcoinProvider);
+ default:
+ return null;
+ }
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async btcSignMessage(msg: core.BTCSignMessage): Promise {
+ throw new Error("Method not implemented.");
+ }
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async btcVerifyMessage(msg: core.BTCVerifyMessage): Promise {
+ throw new Error("Method not implemented.");
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async btcSupportsScriptType(coin: string, scriptType?: core.BTCInputScriptType | undefined): Promise {
+ throw new Error("Method not implemented.");
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public async btcSupportsCoin(coin: core.Coin): Promise {
+ throw new Error("Method not implemented.");
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public btcIsSameAccount(msg: core.BTCAccountPath[]): boolean {
+ throw new Error("Method not implemented.");
+ }
}
From 014913ded232d74491e908b941e761932701d4dc Mon Sep 17 00:00:00 2001
From: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
Date: Mon, 9 Sep 2024 11:42:10 +0200
Subject: [PATCH 04/52] feat: lint
---
examples/sandbox/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/sandbox/index.ts b/examples/sandbox/index.ts
index 0065fddfc..02f89017b 100644
--- a/examples/sandbox/index.ts
+++ b/examples/sandbox/index.ts
@@ -11,8 +11,8 @@ import * as keplr from "@shapeshiftoss/hdwallet-keplr";
import * as ledgerWebHID from "@shapeshiftoss/hdwallet-ledger-webhid";
import * as ledgerWebUSB from "@shapeshiftoss/hdwallet-ledger-webusb";
import * as metaMask from "@shapeshiftoss/hdwallet-metamask";
-import * as phantom from "@shapeshiftoss/hdwallet-phantom";
import * as native from "@shapeshiftoss/hdwallet-native";
+import * as phantom from "@shapeshiftoss/hdwallet-phantom";
import * as portis from "@shapeshiftoss/hdwallet-portis";
import * as tallyHo from "@shapeshiftoss/hdwallet-tallyho";
import * as trezorConnect from "@shapeshiftoss/hdwallet-trezor-connect";
From 69d8892b29448b489a0cf1eaf09824f4dff32025 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 00:01:16 +0200
Subject: [PATCH 05/52] feat: cleanup
---
packages/hdwallet-phantom/package.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/hdwallet-phantom/package.json b/packages/hdwallet-phantom/package.json
index 4adbd0b1c..5a5b2ff37 100644
--- a/packages/hdwallet-phantom/package.json
+++ b/packages/hdwallet-phantom/package.json
@@ -15,7 +15,6 @@
},
"dependencies": {
"@shapeshiftoss/hdwallet-core": "1.54.2",
- "eth-rpc-errors": "^4.0.3",
"lodash": "^4.17.21"
},
"devDependencies": {
From b55e957480c903fd1f4b4e18b5e821b284c39b15 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 00:04:04 +0200
Subject: [PATCH 06/52] feat: revert me
---
tsconfig.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tsconfig.json b/tsconfig.json
index 1060ad06e..a48be222c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,8 +3,8 @@
// tsc is insanely drunk with internal resolutions currently, this at least silences it so we can ship things
// the installed versions are still the same as before, but the bumped tsc version might have made it stricter
"skipLibCheck": true,
- "target": "ES2016",
- "module": "commonjs",
+ "target": "ESNext",
+ "module": "ESNext",
"lib": ["es2020", "dom", "es5"],
"declaration": true,
"declarationMap": true,
From d622b47df797d6c405d0858cc46c61d5d939f876 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 12:40:46 +0200
Subject: [PATCH 07/52] feat: wip window.solana
---
packages/hdwallet-phantom/src/adapter.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index ee050b16f..3a37151a6 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -8,6 +8,9 @@ declare global {
phantom?: {
ethereum?: providers.ExternalProvider;
bitcoin?: providers.ExternalProvider;
+ // TODO: update with proper types once implemented
+ // https://github.com/anza-xyz/wallet-adapter/blob/3761cd8cc867da39da7c0b070bbf8779402cff36/packages/wallets/phantom/src/adapter.ts#L36
+ solana?: any;
};
}
}
From af83e76c2f17ad34451b78e5b6b7c1c128ed7b38 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 12:43:12 +0200
Subject: [PATCH 08/52] feat: fromHexString outside of fn scope
---
packages/hdwallet-phantom/src/bitcoin.ts | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index f37bef40e..2ff543f93 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -8,6 +8,13 @@ type BtcAccount = {
purpose: "payment" | "ordinals";
};
+const fromHexString = (hexString: string) => {
+ const bytes = hexString.match(/.{1,2}/g);
+ if (!bytes) throw new Error("Invalid hex string");
+
+ return Uint8Array.from(bytes.map((byte) => parseInt(byte, 16)));
+};
+
function getNetwork(coin: string): bitcoin.networks.Network {
switch (coin.toLowerCase()) {
case "bitcoin":
@@ -156,12 +163,6 @@ export async function bitcoinSignTx(
})
);
- const fromHexString = (hexString: string) => {
- const bytes = hexString.match(/.{1,2}/g);
- if (!bytes) throw new Error("Invalid hex string");
-
- return Uint8Array.from(bytes.map((byte) => parseInt(byte, 16)));
- };
const signedPsbtHex = await provider.signPSBT(fromHexString(psbt.toHex()), { inputsToSign });
const signedPsbt = bitcoin.Psbt.fromHex(signedPsbtHex, { network });
From 0ff0419a111951cd1769a17eee647e4437ec95d4 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 12:44:17 +0200
Subject: [PATCH 09/52] feat: rm testnet support
---
packages/hdwallet-phantom/src/bitcoin.ts | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 2ff543f93..b0ee3903c 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -15,16 +15,14 @@ const fromHexString = (hexString: string) => {
return Uint8Array.from(bytes.map((byte) => parseInt(byte, 16)));
};
-function getNetwork(coin: string): bitcoin.networks.Network {
+const getNetwork = (coin: string): bitcoin.networks.Network => {
switch (coin.toLowerCase()) {
case "bitcoin":
return bitcoin.networks.bitcoin;
- case "testnet":
- return bitcoin.networks.testnet;
default:
throw new Error(`Unsupported coin: ${coin}`);
}
-}
+};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
From 14fa1807ff395c7f29d9265366af17c64cd00ee8 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 12:44:55 +0200
Subject: [PATCH 10/52] feat: rm useless fn
---
packages/hdwallet-phantom/src/bitcoin.ts | 7 -------
1 file changed, 7 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index b0ee3903c..62b598a30 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -30,13 +30,6 @@ export function bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccoun
return undefined;
}
-export async function bitcoinGetPublicKeys(msg: core.BTCGetAddress, provider: any): Promise {
- const accounts = await provider.requestAccounts();
- const paymentPublicKey = accounts.find((account: BtcAccount) => account.purpose === "payment")?.publicKey;
-
- return [paymentPublicKey];
-}
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function bitcoinGetAddress(msg: core.BTCGetAddress, provider: any): Promise {
const accounts = await provider.requestAccounts();
From bde4f7a8cef4dd79e73995515bc544b75a6edf3b Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 12:46:46 +0200
Subject: [PATCH 11/52] feat: cleanup
---
packages/hdwallet-phantom/src/bitcoin.ts | 6 ------
packages/hdwallet-phantom/src/phantom.ts | 7 +++++--
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 62b598a30..2ee0d9291 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -24,12 +24,6 @@ const getNetwork = (coin: string): bitcoin.networks.Network => {
}
};
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export function bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
- // Only support one account for now (like portis).
- return undefined;
-}
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function bitcoinGetAddress(msg: core.BTCGetAddress, provider: any): Promise {
const accounts = await provider.requestAccounts();
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index ecc397b54..46bfae7a2 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -382,11 +382,14 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public btcGetAccountPaths(msg: core.BTCGetAccountPaths): Array {
+ // Phantom doesn't support BIP44 paths
throw new Error("Method not implemented.");
}
- public btcNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
- return this.bitcoinNextAccountPath(msg);
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public btcNextAccountPath(_msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
+ // Phantom doesn't support BIP44 paths
+ throw new Error("Method not implemented.");
}
addressCache: Map = new Map();
From 65c70ff020b66c0f99466f6668fb5ba70f60dd71 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:03:57 +0200
Subject: [PATCH 12/52] fix: isUnlocked
---
packages/hdwallet-phantom/src/adapter.ts | 3 ++-
packages/hdwallet-phantom/src/bitcoin.ts | 4 ++--
packages/hdwallet-phantom/src/phantom.ts | 20 ++++++++++++++------
packages/hdwallet-phantom/src/types.ts | 7 +++++++
4 files changed, 25 insertions(+), 9 deletions(-)
create mode 100644 packages/hdwallet-phantom/src/types.ts
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 3a37151a6..1d195bd7f 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -2,11 +2,12 @@ import * as core from "@shapeshiftoss/hdwallet-core";
import { providers } from "ethers";
import { PhantomHDWallet } from "./phantom";
+import { PhantomEvmProvider } from "./types";
declare global {
interface Window {
phantom?: {
- ethereum?: providers.ExternalProvider;
+ ethereum?: PhantomEvmProvider;
bitcoin?: providers.ExternalProvider;
// TODO: update with proper types once implemented
// https://github.com/anza-xyz/wallet-adapter/blob/3761cd8cc867da39da7c0b070bbf8779402cff36/packages/wallets/phantom/src/adapter.ts#L36
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 2ee0d9291..3ac64fc14 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -1,7 +1,7 @@
import * as bitcoin from "@shapeshiftoss/bitcoinjs-lib";
import * as core from "@shapeshiftoss/hdwallet-core";
-type BtcAccount = {
+export type BtcAccount = {
address: string;
addressType: "p2tr" | "p2wpkh" | "p2sh" | "p2pkh";
publicKey: string;
@@ -25,7 +25,7 @@ const getNetwork = (coin: string): bitcoin.networks.Network => {
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export async function bitcoinGetAddress(msg: core.BTCGetAddress, provider: any): Promise {
+export async function bitcoinGetAddress(_msg: core.BTCGetAddress, provider: any): Promise {
const accounts = await provider.requestAccounts();
const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 46bfae7a2..3ece27462 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -1,9 +1,12 @@
import * as core from "@shapeshiftoss/hdwallet-core";
import { AddEthereumChainParameter } from "@shapeshiftoss/hdwallet-core";
+import { providers } from "ethers";
import _ from "lodash";
import * as Btc from "./bitcoin";
+import { BtcAccount } from "./bitcoin";
import * as eth from "./ethereum";
+import { PhantomEvmProvider } from "./types";
export function isPhantom(wallet: core.HDWallet): wallet is PhantomHDWallet {
return _.isObject(wallet) && (wallet as any)._isPhantom;
@@ -138,10 +141,10 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
info: PhantomHDWalletInfo & core.HDWalletInfo;
ethAddress?: string | null;
- evmProvider: any;
- bitcoinProvider: any;
+ evmProvider: PhantomEvmProvider;
+ bitcoinProvider: providers.ExternalProvider;
- constructor(evmProvider: unknown, bitcoinProvider: unknown) {
+ constructor(evmProvider: PhantomEvmProvider, bitcoinProvider: providers.ExternalProvider) {
this.info = new PhantomHDWalletInfo();
this.evmProvider = evmProvider;
this.bitcoinProvider = bitcoinProvider;
@@ -152,7 +155,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public async isLocked(): Promise {
- return !this.evmProvider._phantom.isUnlocked();
+ return !this.evmProvider._metamask.isUnlocked();
}
public getVendor(): string {
@@ -287,6 +290,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
public async ethGetChainId(): Promise {
try {
+ if (!this.evmProvider.request) throw new Error("Provider does not support ethereum.request");
// chainId as hex string
const chainId: string = await this.evmProvider.request({ method: "eth_chainId" });
return parseInt(chainId, 16);
@@ -399,8 +403,12 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
if (maybeCachedAddress) return maybeCachedAddress;
const value = await (async () => {
switch (msg.coin) {
- case "Bitcoin":
- return Btc.bitcoinGetAddress(msg, this.bitcoinProvider);
+ case "Bitcoin": {
+ const accounts = await this.bitcoinProvider.requestAccounts();
+ const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
+
+ return paymentAddress;
+ }
default:
return null;
}
diff --git a/packages/hdwallet-phantom/src/types.ts b/packages/hdwallet-phantom/src/types.ts
new file mode 100644
index 000000000..e95bbe4eb
--- /dev/null
+++ b/packages/hdwallet-phantom/src/types.ts
@@ -0,0 +1,7 @@
+import { providers } from "ethers";
+
+export type PhantomEvmProvider = providers.ExternalProvider & {
+ _metamask: {
+ isUnlocked: () => boolean;
+ };
+};
From 2e6c32c5cf5d896dcc029613a2be2bbb255605de Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:06:19 +0200
Subject: [PATCH 13/52] feat: more cleanunp
---
packages/hdwallet-coinbase/src/coinbase.ts | 1 -
packages/hdwallet-metamask/src/metamask.ts | 3 +--
packages/hdwallet-phantom/src/phantom.ts | 12 +++++-------
3 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/packages/hdwallet-coinbase/src/coinbase.ts b/packages/hdwallet-coinbase/src/coinbase.ts
index 2e148c75c..aca7b9431 100644
--- a/packages/hdwallet-coinbase/src/coinbase.ts
+++ b/packages/hdwallet-coinbase/src/coinbase.ts
@@ -344,7 +344,6 @@ export class CoinbaseHDWallet implements core.HDWallet, core.ETHWallet {
return this.info.ethNextAccountPath(msg);
}
- // TODO: Respect msg.addressNList!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async ethGetAddress(msg: core.ETHGetAddress): Promise {
if (this.ethAddress) {
diff --git a/packages/hdwallet-metamask/src/metamask.ts b/packages/hdwallet-metamask/src/metamask.ts
index d305e7285..3592388e2 100644
--- a/packages/hdwallet-metamask/src/metamask.ts
+++ b/packages/hdwallet-metamask/src/metamask.ts
@@ -345,9 +345,8 @@ export class MetaMaskHDWallet implements core.HDWallet, core.ETHWallet {
return this.info.ethNextAccountPath(msg);
}
- // TODO: Respect msg.addressNList!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async ethGetAddress(msg: core.ETHGetAddress): Promise {
+ public async ethGetAddress(_msg: core.ETHGetAddress): Promise {
if (this.ethAddress) {
return this.ethAddress;
}
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 3ece27462..b5d987fe3 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -325,9 +325,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
return this.info.ethNextAccountPath(msg);
}
- // TODO: Respect msg.addressNList!
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async ethGetAddress(msg: core.ETHGetAddress): Promise {
+ public async ethGetAddress(): Promise {
if (this.ethAddress) {
return this.ethAddress;
}
@@ -342,17 +340,17 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public async ethSignTx(msg: core.ETHSignTx): Promise {
- const address = await this.ethGetAddress(this.evmProvider);
+ const address = await this.ethGetAddress();
return address ? eth.ethSignTx(msg, this.evmProvider, address) : null;
}
public async ethSendTx(msg: core.ETHSignTx): Promise {
- const address = await this.ethGetAddress(this.evmProvider);
+ const address = await this.ethGetAddress();
return address ? eth.ethSendTx(msg, this.evmProvider, address) : null;
}
public async ethSignMessage(msg: core.ETHSignMessage): Promise {
- const address = await this.ethGetAddress(this.evmProvider);
+ const address = await this.ethGetAddress();
return address ? eth.ethSignMessage(msg, this.evmProvider, address) : null;
}
@@ -361,7 +359,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public async getDeviceID(): Promise {
- return "phantom:" + (await this.ethGetAddress(this.evmProvider));
+ return "phantom:" + (await this.ethGetAddress());
}
public async getFirmwareVersion(): Promise {
From 9357bdcb325f12130a429ccda4f8b5bb959eed2f Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:18:47 +0200
Subject: [PATCH 14/52] fix: describePath
---
packages/hdwallet-phantom/src/phantom.ts | 25 ++++++++++--------------
1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index b5d987fe3..37cf66896 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -67,8 +67,15 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
public describePath(msg: core.DescribePath): core.PathDescription {
switch (msg.coin) {
- case "Ethereum":
- return eth.describeETHPath(msg.path);
+ case "bitcoin": {
+ const unknown = core.unknownUTXOPath(msg.path, msg.coin, msg.scriptType);
+
+ if (!msg.scriptType) return unknown;
+
+ return core.describeUTXOPath(msg.path, msg.coin, msg.scriptType);
+ }
+ case "ethereum":
+ return core.describeETHPath(msg.path);
default:
throw new Error("Unsupported path");
}
@@ -256,19 +263,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public describePath(msg: core.DescribePath): core.PathDescription {
- switch (msg.coin) {
- case "bitcoin": {
- const unknown = core.unknownUTXOPath(msg.path, msg.coin, msg.scriptType);
-
- if (!msg.scriptType) return unknown;
-
- return core.describeUTXOPath(msg.path, msg.coin, msg.scriptType);
- }
- case "ethereum":
- return core.describeETHPath(msg.path);
- default:
- throw new Error("Unsupported path");
- }
+ return this.info.describePath(msg);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
From 29f33c85023678af065c7d9fcdc384a54b907cf6 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:21:20 +0200
Subject: [PATCH 15/52] fix: btcSupportsCoin
---
packages/hdwallet-phantom/src/phantom.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 37cf66896..03a294530 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -438,7 +438,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcSupportsCoin(coin: core.Coin): Promise {
- throw new Error("Method not implemented.");
+ return coin === "bitcoin";
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
From 23fa8375a62caf51e75ca2bf86135af21b5318aa Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:30:58 +0200
Subject: [PATCH 16/52] feat: make it compile
---
packages/hdwallet-phantom/src/phantom.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 03a294530..543f28abd 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -397,7 +397,8 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
const value = await (async () => {
switch (msg.coin) {
case "Bitcoin": {
- const accounts = await this.bitcoinProvider.requestAccounts();
+ // TODO(gomes): type this
+ const accounts = await (this.bitcoinProvider as any).requestAccounts();
const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
return paymentAddress;
From a5b92966838dccc973a749f01f7e549baad6a8da Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:49:48 +0200
Subject: [PATCH 17/52] feat: btcSignMessage
---
packages/hdwallet-phantom/src/phantom.ts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 543f28abd..c5b95dd4c 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -425,7 +425,12 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcSignMessage(msg: core.BTCSignMessage): Promise {
- throw new Error("Method not implemented.");
+ const address = await this.btcGetAddress({ coin: "Bitcoin" } as core.BTCGetAddress);
+ const message = new TextEncoder().encode(msg.message);
+
+ // TODO(gomes): type bitcoinpovider
+ const result = await (this.bitcoinProvider as any).signMessage(address, message);
+ return result;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcVerifyMessage(msg: core.BTCVerifyMessage): Promise {
From e5b646ad530c74dce8c967eb4b57418f2981c79b Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:51:37 +0200
Subject: [PATCH 18/52] feat: bitcoin requestAccounts()
---
packages/hdwallet-phantom/src/adapter.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 1d195bd7f..909e73c2f 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -48,6 +48,8 @@ export class PhantomAdapter {
params: [{ eth_accounts: {} }],
})
);
+ // TODO(gomes): type bitcoinprovider
+ await (bitcoinProvider as any).requestAccounts();
} catch (error) {
console.error("Could not get Phantom accounts. ");
throw error;
From 2d1645dbacd48504f91e1cf860c073fe6bdd2280 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:55:01 +0200
Subject: [PATCH 19/52] feat: safety
---
packages/hdwallet-phantom/src/phantom.ts | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index c5b95dd4c..e2752f4d3 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -426,11 +426,12 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcSignMessage(msg: core.BTCSignMessage): Promise {
const address = await this.btcGetAddress({ coin: "Bitcoin" } as core.BTCGetAddress);
+ if (!address) throw new Error("Could not get Bitcoin address");
const message = new TextEncoder().encode(msg.message);
// TODO(gomes): type bitcoinpovider
- const result = await (this.bitcoinProvider as any).signMessage(address, message);
- return result;
+ const { signature } = await (this.bitcoinProvider as any).signMessage(address, message);
+ return { signature, address };
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcVerifyMessage(msg: core.BTCVerifyMessage): Promise {
From 76a77d611185a4348600006d84ac9a784c8929ad Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 15:05:56 +0200
Subject: [PATCH 20/52] Revert "feat: bitcoin requestAccounts()"
This reverts commit e5b646ad530c74dce8c967eb4b57418f2981c79b.
---
packages/hdwallet-phantom/src/adapter.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 909e73c2f..1d195bd7f 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -48,8 +48,6 @@ export class PhantomAdapter {
params: [{ eth_accounts: {} }],
})
);
- // TODO(gomes): type bitcoinprovider
- await (bitcoinProvider as any).requestAccounts();
} catch (error) {
console.error("Could not get Phantom accounts. ");
throw error;
From a80e1e1497a22b2b893db02d206d5efbf873cf67 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 15:14:03 +0200
Subject: [PATCH 21/52] feat: only p2wpkh effectively supported
---
packages/hdwallet-phantom/src/bitcoin.ts | 17 +++++++++++------
packages/hdwallet-phantom/src/phantom.ts | 1 +
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 3ac64fc14..436ea49a5 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -1,9 +1,12 @@
import * as bitcoin from "@shapeshiftoss/bitcoinjs-lib";
import * as core from "@shapeshiftoss/hdwallet-core";
+import { BTCInputScriptType } from "@shapeshiftoss/hdwallet-core";
export type BtcAccount = {
address: string;
- addressType: "p2tr" | "p2wpkh" | "p2sh" | "p2pkh";
+ // Phantom supposedly supports more scriptTypes but in effect, doesn't (currently)
+ // https://github.com/orgs/phantom/discussions/173
+ addressType: BTCInputScriptType.SpendWitness;
publicKey: string;
purpose: "payment" | "ordinals";
};
@@ -53,11 +56,13 @@ async function addInput(
if (input.scriptType) {
switch (input.scriptType) {
- case "p2pkh":
- inputData.nonWitnessUtxo = Buffer.from(input.hex, "hex");
- break;
- case "p2sh-p2wpkh":
- case "p2wpkh": {
+ // Phantom supposedly supports more scriptTypes but in effect, doesn't (currently)
+ // https://github.com/orgs/phantom/discussions/173
+ // case "p2pkh":
+ // inputData.nonWitnessUtxo = Buffer.from(input.hex, "hex");
+ // break;
+ // case "p2sh-p2wpkh":
+ case BTCInputScriptType.SpendWitness: {
const inputAddress = await wallet.btcGetAddress({ addressNList: input.addressNList, coin, showDisplay: false });
if (!inputAddress) throw new Error("Could not get address from wallet");
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index e2752f4d3..14f3ff948 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -399,6 +399,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
case "Bitcoin": {
// TODO(gomes): type this
const accounts = await (this.bitcoinProvider as any).requestAccounts();
+ console.log({ accounts });
const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
return paymentAddress;
From e8633087b2acb984f73835f6f5e9a53e5bbf1053 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 16:21:53 +0200
Subject: [PATCH 22/52] feat: getPublicKeys
---
packages/hdwallet-phantom/src/phantom.ts | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 14f3ff948..e92cccb18 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -1,5 +1,5 @@
import * as core from "@shapeshiftoss/hdwallet-core";
-import { AddEthereumChainParameter } from "@shapeshiftoss/hdwallet-core";
+import { AddEthereumChainParameter, BTCInputScriptType } from "@shapeshiftoss/hdwallet-core";
import { providers } from "ethers";
import _ from "lodash";
@@ -268,8 +268,14 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async getPublicKeys(msg: Array): Promise> {
+ // Only p2wpkh effectively supported for now
+ if (msg[0].scriptType !== BTCInputScriptType.SpendWitness) return [];
+
+ // Note this is a pubKey, not an xpub
+ const pubKey = await this.btcGetAddress({ coin: "Bitcoin" } as core.BTCGetAddress);
+ if (!pubKey) return [];
// Ethereum public keys are not exposed by the RPC API
- return [];
+ return [{ xpub: pubKey }];
}
public async isInitialized(): Promise {
@@ -399,7 +405,6 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
case "Bitcoin": {
// TODO(gomes): type this
const accounts = await (this.bitcoinProvider as any).requestAccounts();
- console.log({ accounts });
const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
return paymentAddress;
From d14e51959d7247904e8ef708dd389346e596df95 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 16:50:19 +0200
Subject: [PATCH 23/52] feat: Bitcoin coin only
---
packages/hdwallet-phantom/src/phantom.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index e92cccb18..4e6aa6480 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -269,6 +269,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async getPublicKeys(msg: Array): Promise> {
// Only p2wpkh effectively supported for now
+ if (msg[0].coin !== "Bitcoin") return [];
if (msg[0].scriptType !== BTCInputScriptType.SpendWitness) return [];
// Note this is a pubKey, not an xpub
From d227432f20a7285ff6f4e665425fda56b46599b9 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 17:36:51 +0200
Subject: [PATCH 24/52] fix: gasLimit over gas
---
packages/hdwallet-phantom/src/ethereum.ts | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
index 3f910a826..2e59d5647 100644
--- a/packages/hdwallet-phantom/src/ethereum.ts
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -65,11 +65,7 @@ export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string
value: msg.value,
chainId: msg.chainId,
data: msg.data && msg.data !== "" ? msg.data : undefined,
- // Phantom, like other Web3 libraries, derives its transaction schema from Ethereum's official JSON-RPC API specification
- // (https://github.com/ethereum/execution-apis/blob/d63d2a02bcd2a8cef54ae2fc5bbff8b4fac944eb/src/schemas/transaction.json).
- // That schema defines the use of the label `gas` to set the transaction's gas limit and not `gasLimit` as used in other
- // libraries and as stated in the official yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf).
- gas: msg.gasLimit,
+ gasLimit: msg.gasLimit,
};
const utx = msg.maxFeePerGas
From 2094a1f8c1a50c14a32c6b8c4d17e539edf24e69 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 18:42:34 +0200
Subject: [PATCH 25/52] feat: add gasPrice
---
packages/hdwallet-phantom/src/ethereum.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
index 2e59d5647..7f49839f5 100644
--- a/packages/hdwallet-phantom/src/ethereum.ts
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -66,6 +66,7 @@ export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string
chainId: msg.chainId,
data: msg.data && msg.data !== "" ? msg.data : undefined,
gasLimit: msg.gasLimit,
+ gasPrice: msg.gasPrice,
};
const utx = msg.maxFeePerGas
@@ -76,6 +77,7 @@ export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string
}
: { ...utxBase, gasPrice: msg.gasPrice };
+ console.log({ utx });
const signedTx = await ethereum.request({
method: "eth_sendTransaction",
params: [utx],
From df0d141322fe3f836b50e977cf2aeb5a0edffb6f Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:45:17 +0200
Subject: [PATCH 26/52] fix: psbt
---
packages/hdwallet-phantom/src/bitcoin.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 436ea49a5..796e3d6b7 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -42,11 +42,13 @@ async function addInput(
coin: string,
network: bitcoin.networks.Network
): Promise {
- const inputData: bitcoin.PsbtTxInput & {
+ const inputData: Omit & {
nonWitnessUtxo?: Buffer;
witnessUtxo?: { script: Buffer; value: number };
+ hash: string | Buffer;
} = {
- hash: Buffer.from(input.txid, "hex"),
+ nonWitnessUtxo: input.hex ? Buffer.from(input.hex, "hex") : undefined,
+ hash: input.txid,
index: input.vout,
};
From 860373cdbc6e650549c7f509b97f1ed49090cc7e Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:49:50 +0200
Subject: [PATCH 27/52] feat: cleanup
---
packages/hdwallet-phantom/src/ethereum.ts | 7 -------
packages/hdwallet-phantom/src/phantom.ts | 4 ++--
2 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
index 7f49839f5..15907ab1c 100644
--- a/packages/hdwallet-phantom/src/ethereum.ts
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -51,12 +51,6 @@ export function ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
- console.error("Method ethSignTx unsupported for Phantom wallet!");
- return null;
-}
-
export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string): Promise {
try {
const utxBase = {
@@ -77,7 +71,6 @@ export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string
}
: { ...utxBase, gasPrice: msg.gasPrice };
- console.log({ utx });
const signedTx = await ethereum.request({
method: "eth_sendTransaction",
params: [utx],
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 4e6aa6480..6e2a9ed54 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -341,9 +341,9 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
}
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
public async ethSignTx(msg: core.ETHSignTx): Promise {
- const address = await this.ethGetAddress();
- return address ? eth.ethSignTx(msg, this.evmProvider, address) : null;
+ throw new Error("unimplemented");
}
public async ethSendTx(msg: core.ETHSignTx): Promise {
From f620a165254797b76a712d06f03d930c5b516b25 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:52:07 +0200
Subject: [PATCH 28/52] feat: more cleanup
---
packages/hdwallet-phantom/src/ethereum.ts | 30 +++++++++++++++--------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
index 15907ab1c..0c9beef3a 100644
--- a/packages/hdwallet-phantom/src/ethereum.ts
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -2,6 +2,8 @@ import * as core from "@shapeshiftoss/hdwallet-core";
import { ETHSignedMessage } from "@shapeshiftoss/hdwallet-core";
import { isHexString } from "ethers/lib/utils";
+import { PhantomEvmProvider } from "./types";
+
export function describeETHPath(path: core.BIP32Path): core.PathDescription {
const pathStr = core.addressNListToBIP32(path);
const unknown: core.PathDescription = {
@@ -32,9 +34,13 @@ export function describeETHPath(path: core.BIP32Path): core.PathDescription {
};
}
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export async function ethVerifyMessage(msg: core.ETHVerifyMessage, ethereum: any): Promise {
- console.error("Method ethVerifyMessage unsupported for Phantom wallet!");
+export async function ethVerifyMessage(
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ msg: core.ETHVerifyMessage,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ phantom: PhantomEvmProvider
+): Promise {
+ console.error("Unimplemented");
return null;
}
@@ -51,7 +57,11 @@ export function ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
+export async function ethSendTx(
+ msg: core.ETHSignTx,
+ phantom: PhantomEvmProvider,
+ from: string
+): Promise {
try {
const utxBase = {
from: from,
@@ -71,7 +81,7 @@ export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string
}
: { ...utxBase, gasPrice: msg.gasPrice };
- const signedTx = await ethereum.request({
+ const signedTx = await phantom.request?.({
method: "eth_sendTransaction",
params: [utx],
});
@@ -87,12 +97,12 @@ export async function ethSendTx(msg: core.ETHSignTx, ethereum: any, from: string
export async function ethSignMessage(
msg: core.ETHSignMessage,
- ethereum: any,
+ phantom: PhantomEvmProvider,
address: string
): Promise {
try {
if (!isHexString(msg.message)) throw new Error("data is not an hex string");
- const signedMsg = await ethereum.request({
+ const signedMsg = await phantom.request?.({
method: "personal_sign",
params: [msg.message, address],
});
@@ -107,12 +117,12 @@ export async function ethSignMessage(
}
}
-export async function ethGetAddress(ethereum: any): Promise {
- if (!(ethereum && ethereum.request)) {
+export async function ethGetAddress(phantom: PhantomEvmProvider): Promise {
+ if (!(phantom && phantom.request)) {
return null;
}
try {
- const ethAccounts = await ethereum.request({
+ const ethAccounts = await phantom.request({
method: "eth_accounts",
});
return ethAccounts[0];
From 6193e58c3e93077a374987794fd6f682d35e3149 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:53:03 +0200
Subject: [PATCH 29/52] feat: more more cleanup
---
packages/hdwallet-phantom/src/phantom.ts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 6e2a9ed54..ce2cabfae 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -83,8 +83,7 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public ethNextAccountPath(msg: core.ETHAccountPath): core.ETHAccountPath | undefined {
- // TODO: What do we do here?
- return undefined;
+ throw new Error("Unimplemented");
}
public async ethSupportsNetwork(chainId: number): Promise {
From b82d05073a424e072406e2f3882029762e8605ab Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:53:37 +0200
Subject: [PATCH 30/52] feat: more more more cleanup
---
packages/hdwallet-phantom/src/phantom.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index ce2cabfae..8295e90d2 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -87,7 +87,7 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
}
public async ethSupportsNetwork(chainId: number): Promise {
- return chainId === 1;
+ return chainId === 1 || chainId === 137;
}
public async ethSupportsSecureTransfer(): Promise {
From d6e3e9668fbf628b447f6a21a92a51a1d8a8cfde Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:54:47 +0200
Subject: [PATCH 31/52] feat: more more more more cleanup
---
packages/hdwallet-phantom/src/ethereum.ts | 10 ----------
packages/hdwallet-phantom/src/phantom.ts | 3 ++-
2 files changed, 2 insertions(+), 11 deletions(-)
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
index 0c9beef3a..15286f2ba 100644
--- a/packages/hdwallet-phantom/src/ethereum.ts
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -34,16 +34,6 @@ export function describeETHPath(path: core.BIP32Path): core.PathDescription {
};
}
-export async function ethVerifyMessage(
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- msg: core.ETHVerifyMessage,
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- phantom: PhantomEvmProvider
-): Promise {
- console.error("Unimplemented");
- return null;
-}
-
export function ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
const slip44 = core.slip44ByCoin(msg.coin);
if (slip44 === undefined) return [];
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 8295e90d2..e960d07d7 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -355,8 +355,9 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
return address ? eth.ethSignMessage(msg, this.evmProvider, address) : null;
}
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
public async ethVerifyMessage(msg: core.ETHVerifyMessage): Promise {
- return eth.ethVerifyMessage(msg, this.evmProvider);
+ throw new Error("Method not implemented.");
}
public async getDeviceID(): Promise {
From 128b40787f93e5c4710adb1d742f85730d28c1ac Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:55:14 +0200
Subject: [PATCH 32/52] feat: more more more more more cleanup
---
packages/hdwallet-phantom/src/phantom.ts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index e960d07d7..7ba809d77 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -372,8 +372,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
- // TODO: What do we do here?
- return undefined;
+ throw new Error("Method not implemented.");
}
public async btcSupportsSecureTransfer(): Promise {
From e810ac00b2ac95739fe3ba73546074c0524a7994 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 23:42:30 +0200
Subject: [PATCH 33/52] feat: rm address cache
---
packages/hdwallet-phantom/src/phantom.ts | 5 -----
1 file changed, 5 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 7ba809d77..b1814e551 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -395,11 +395,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
throw new Error("Method not implemented.");
}
- addressCache: Map = new Map();
public async btcGetAddress(msg: core.BTCGetAddress): Promise {
- const key = JSON.stringify(msg);
- const maybeCachedAddress = this.addressCache.get(key);
- if (maybeCachedAddress) return maybeCachedAddress;
const value = await (async () => {
switch (msg.coin) {
case "Bitcoin": {
@@ -415,7 +411,6 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
})();
if (!value || typeof value !== "string") return null;
- this.addressCache.set(key, value);
return value;
}
From de602be9c59ff9f91895915feb0b715f70ad0429 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 23:47:41 +0200
Subject: [PATCH 34/52] fix: tests types
---
packages/hdwallet-phantom/src/phantom.test.ts | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index 4a325e3e5..4c50a422a 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -47,6 +47,9 @@ describe("PhantomHDWallet", () => {
it("should test ethSignMessage", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockReturnValue(
`Object {
"address": "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
@@ -73,6 +76,9 @@ describe("PhantomHDWallet", () => {
it("ethSignMessage returns null on error", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockRejectedValue(new Error("An Error has occurred")),
};
@@ -87,6 +93,9 @@ describe("PhantomHDWallet", () => {
it("ethGetAddress returns a valid address", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockReturnValue(["0x73d0385F4d8E00C5e6504C6030F47BF6212736A8"]),
};
@@ -103,6 +112,9 @@ describe("PhantomHDWallet", () => {
});
it("ethSendTx returns a valid hash", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockReturnValue("0x123"),
};
@@ -121,6 +133,9 @@ describe("PhantomHDWallet", () => {
});
it("ethSendTx returns a valid hash if maxFeePerGas is present in msg", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockReturnValue("0x123"),
};
@@ -139,6 +154,9 @@ describe("PhantomHDWallet", () => {
});
it("ethSendTx returns null on error", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockRejectedValue(new Error("An Error has occurred")),
};
@@ -157,6 +175,9 @@ describe("PhantomHDWallet", () => {
});
it("ethVerifyMessage returns null as its not implemented", async () => {
wallet.evmProvider = {
+ _metamask: {
+ isUnlocked: () => true,
+ },
request: jest.fn().mockReturnValue("0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8"),
};
expect(
From 53a5cd0422a44e9db4c509a9cace177275bd3522 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Wed, 18 Sep 2024 23:53:47 +0200
Subject: [PATCH 35/52] fix: test
---
packages/hdwallet-phantom/src/phantom.test.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index 4c50a422a..7530cf3cc 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -173,7 +173,7 @@ describe("PhantomHDWallet", () => {
expect(wallet.evmProvider.request).toHaveBeenCalled();
expect(hash).toBe(null);
});
- it("ethVerifyMessage returns null as its not implemented", async () => {
+ it("ethVerifyMessage throws as its not implemented", async () => {
wallet.evmProvider = {
_metamask: {
isUnlocked: () => true,
@@ -187,6 +187,6 @@ describe("PhantomHDWallet", () => {
signature:
"0x29f7212ecc1c76cea81174af267b67506f754ea8c73f144afa900a0d85b24b21319621aeb062903e856352f38305710190869c3ce5a1425d65ef4fa558d0fc251b",
})
- ).toEqual(null);
+ ).toThrow();
});
});
From 8aee937000f7febf21365f3cec4217649f2f43c1 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 00:01:18 +0200
Subject: [PATCH 36/52] Revert "fix: test"
This reverts commit 53a5cd0422a44e9db4c509a9cace177275bd3522.
---
packages/hdwallet-phantom/src/phantom.test.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index 7530cf3cc..4c50a422a 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -173,7 +173,7 @@ describe("PhantomHDWallet", () => {
expect(wallet.evmProvider.request).toHaveBeenCalled();
expect(hash).toBe(null);
});
- it("ethVerifyMessage throws as its not implemented", async () => {
+ it("ethVerifyMessage returns null as its not implemented", async () => {
wallet.evmProvider = {
_metamask: {
isUnlocked: () => true,
@@ -187,6 +187,6 @@ describe("PhantomHDWallet", () => {
signature:
"0x29f7212ecc1c76cea81174af267b67506f754ea8c73f144afa900a0d85b24b21319621aeb062903e856352f38305710190869c3ce5a1425d65ef4fa558d0fc251b",
})
- ).toThrow();
+ ).toEqual(null);
});
});
From 5637977f02a822e4a2ce3e2863b82a282909eca3 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 00:01:36 +0200
Subject: [PATCH 37/52] fix: actually fix test
---
packages/hdwallet-phantom/src/phantom.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index b1814e551..a696ef398 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -357,7 +357,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async ethVerifyMessage(msg: core.ETHVerifyMessage): Promise {
- throw new Error("Method not implemented.");
+ return null;
}
public async getDeviceID(): Promise {
From a9d3035a76c3397a655b00506362ddcb0b7d895a Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 23:03:23 +0200
Subject: [PATCH 38/52] feat: add window.ethereum
---
packages/hdwallet-phantom/src/adapter.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 1d195bd7f..928367ee7 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -6,6 +6,7 @@ import { PhantomEvmProvider } from "./types";
declare global {
interface Window {
+ ethereum?: PhantomEvmProvider;
phantom?: {
ethereum?: PhantomEvmProvider;
bitcoin?: providers.ExternalProvider;
From 389d7e68f6ca9479c26fc60f5083c77275ae44a4 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 23:13:35 +0200
Subject: [PATCH 39/52] feat: cleanup
---
packages/hdwallet-phantom/src/phantom.ts | 3 ---
1 file changed, 3 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index a696ef398..2730939d1 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -25,9 +25,6 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
readonly _supportsKavaInfo = false;
readonly _supportsTerraInfo = false;
- bitcoinAddress?: string | null;
- ethAddress?: string | null;
-
public getVendor(): string {
return "Phantom";
}
From 8e1fff9d86217956cf3fffabaef7a689fe14486f Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 23:14:24 +0200
Subject: [PATCH 40/52] feat: more cleanup
---
packages/hdwallet-phantom/src/phantom.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 2730939d1..171f09540 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -209,9 +209,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
return true;
}
- public async clearSession(): Promise {
- // TODO: Can we lock Phantom from here?
- }
+ public async clearSession(): Promise {}
public async ping(msg: core.Ping): Promise {
// no ping function for Phantom, so just returning Core.Pong
From a5078c5fb5db4533fd47c61f3051e59aa863c65d Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 23:14:35 +0200
Subject: [PATCH 41/52] feat: more more cleaup
---
packages/hdwallet-phantom/src/phantom.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 171f09540..6e7f9799b 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -252,9 +252,7 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async loadDevice(msg: core.LoadDevice): Promise {
- // TODO: Does Phantom allow this to be done programatically?
- }
+ public async loadDevice(msg: core.LoadDevice): Promise {}
public describePath(msg: core.DescribePath): core.PathDescription {
return this.info.describePath(msg);
From 248372b06571c3e43336e441abef41608f80f967 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Thu, 19 Sep 2024 23:18:59 +0200
Subject: [PATCH 42/52] feat: more cleanup
---
packages/hdwallet-phantom/src/adapter.ts | 5 ++---
packages/hdwallet-phantom/src/phantom.ts | 18 +++++++-----------
packages/hdwallet-phantom/src/types.ts | 12 ++++++++++++
3 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 928367ee7..4f9d75fe9 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -1,15 +1,14 @@
import * as core from "@shapeshiftoss/hdwallet-core";
-import { providers } from "ethers";
import { PhantomHDWallet } from "./phantom";
-import { PhantomEvmProvider } from "./types";
+import { PhantomEvmProvider, PhantomUtxoProvider } from "./types";
declare global {
interface Window {
ethereum?: PhantomEvmProvider;
phantom?: {
ethereum?: PhantomEvmProvider;
- bitcoin?: providers.ExternalProvider;
+ bitcoin?: PhantomUtxoProvider;
// TODO: update with proper types once implemented
// https://github.com/anza-xyz/wallet-adapter/blob/3761cd8cc867da39da7c0b070bbf8779402cff36/packages/wallets/phantom/src/adapter.ts#L36
solana?: any;
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 6e7f9799b..a62322ecf 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -1,12 +1,10 @@
import * as core from "@shapeshiftoss/hdwallet-core";
import { AddEthereumChainParameter, BTCInputScriptType } from "@shapeshiftoss/hdwallet-core";
-import { providers } from "ethers";
import _ from "lodash";
import * as Btc from "./bitcoin";
-import { BtcAccount } from "./bitcoin";
import * as eth from "./ethereum";
-import { PhantomEvmProvider } from "./types";
+import { PhantomEvmProvider, PhantomUtxoProvider } from "./types";
export function isPhantom(wallet: core.HDWallet): wallet is PhantomHDWallet {
return _.isObject(wallet) && (wallet as any)._isPhantom;
@@ -145,9 +143,9 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
info: PhantomHDWalletInfo & core.HDWalletInfo;
ethAddress?: string | null;
evmProvider: PhantomEvmProvider;
- bitcoinProvider: providers.ExternalProvider;
+ bitcoinProvider: PhantomUtxoProvider;
- constructor(evmProvider: PhantomEvmProvider, bitcoinProvider: providers.ExternalProvider) {
+ constructor(evmProvider: PhantomEvmProvider, bitcoinProvider: PhantomUtxoProvider) {
this.info = new PhantomHDWalletInfo();
this.evmProvider = evmProvider;
this.bitcoinProvider = bitcoinProvider;
@@ -392,9 +390,8 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
const value = await (async () => {
switch (msg.coin) {
case "Bitcoin": {
- // TODO(gomes): type this
- const accounts = await (this.bitcoinProvider as any).requestAccounts();
- const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
+ const accounts = await this.bitcoinProvider.requestAccounts();
+ const paymentAddress = accounts.find((account) => account.purpose === "payment")?.address;
return paymentAddress;
}
@@ -423,9 +420,8 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
if (!address) throw new Error("Could not get Bitcoin address");
const message = new TextEncoder().encode(msg.message);
- // TODO(gomes): type bitcoinpovider
- const { signature } = await (this.bitcoinProvider as any).signMessage(address, message);
- return { signature, address };
+ const { signature } = await this.bitcoinProvider.signMessage(address, message);
+ return { signature: core.toHexString(signature), address };
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcVerifyMessage(msg: core.BTCVerifyMessage): Promise {
diff --git a/packages/hdwallet-phantom/src/types.ts b/packages/hdwallet-phantom/src/types.ts
index e95bbe4eb..b823dbc51 100644
--- a/packages/hdwallet-phantom/src/types.ts
+++ b/packages/hdwallet-phantom/src/types.ts
@@ -1,7 +1,19 @@
import { providers } from "ethers";
+import { BtcAccount } from "./bitcoin";
+
export type PhantomEvmProvider = providers.ExternalProvider & {
_metamask: {
isUnlocked: () => boolean;
};
};
+
+export type PhantomUtxoProvider = providers.ExternalProvider & {
+ requestAccounts: () => Promise;
+ signMessage: (
+ address: string,
+ message: Uint8Array
+ ) => Promise<{
+ signature: Uint8Array;
+ }>;
+};
From e149db1ddc0ca05da76c717cc6eac6ddf6144aa6 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Fri, 20 Sep 2024 16:53:15 +0200
Subject: [PATCH 43/52] fix: OP_RETURN_DATA :fridaydog:
---
packages/hdwallet-phantom/src/bitcoin.ts | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 796e3d6b7..39b1ad98d 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -103,13 +103,6 @@ async function addOutput(
address: outputAddress,
value: parseInt(output.amount),
});
- } else if ("opReturnData" in output && output.opReturnData) {
- const data = Buffer.from(output.opReturnData.toString(), "hex");
- const embed = bitcoin.payments.embed({ data: [data] });
- psbt.addOutput({
- script: embed.output!,
- value: 0,
- });
}
}
@@ -139,6 +132,15 @@ export async function bitcoinSignTx(
await addOutput(wallet, psbt, output, msg.coin);
}
+ if (msg.opReturnData) {
+ const data = Buffer.from(msg.opReturnData, "utf-8");
+ const embed = bitcoin.payments.embed({ data: [data] });
+ psbt.addOutput({
+ script: embed.output!,
+ value: 0,
+ });
+ }
+
const inputsToSign = await Promise.all(
msg.inputs.map(async (input, index) => {
const address = await wallet.btcGetAddress({
From f528f10610e0a30f9573268b9f74f5849db6619a Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Fri, 20 Sep 2024 17:26:18 +0200
Subject: [PATCH 44/52] feat: more cleanupy
---
packages/hdwallet-phantom/src/phantom.ts | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index a62322ecf..689199d46 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -141,7 +141,6 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
readonly _supportsTerraInfo = false;
info: PhantomHDWalletInfo & core.HDWalletInfo;
- ethAddress?: string | null;
evmProvider: PhantomEvmProvider;
bitcoinProvider: PhantomUtxoProvider;
@@ -318,17 +317,8 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
}
public async ethGetAddress(): Promise {
- if (this.ethAddress) {
- return this.ethAddress;
- }
const address = await eth.ethGetAddress(this.evmProvider);
- if (address) {
- this.ethAddress = address;
- return address;
- } else {
- this.ethAddress = null;
- return null;
- }
+ return address;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
From 66b2348fa2aacccc0a51c0ab9069c09bb8c709c5 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Fri, 20 Sep 2024 17:43:33 +0200
Subject: [PATCH 45/52] feat: saner tests
---
packages/hdwallet-phantom/src/phantom.test.ts | 46 +++++++++++--------
1 file changed, 28 insertions(+), 18 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index 4c50a422a..6882ddd8b 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -1,6 +1,7 @@
import * as core from "@shapeshiftoss/hdwallet-core";
import { PhantomHDWallet, PhantomHDWalletInfo } from ".";
+import { PhantomUtxoProvider } from "./types";
describe("HDWalletInfo", () => {
const info = new PhantomHDWalletInfo();
@@ -27,7 +28,6 @@ describe("PhantomHDWallet", () => {
core.untouchable("PhantomHDWallet:provider"),
core.untouchable("PhantomHDWallet:provider")
);
- wallet.ethAddress = "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8";
});
it("should match the metadata", async () => {
@@ -64,14 +64,14 @@ describe("PhantomHDWallet", () => {
message: msg,
})
).toMatchInlineSnapshot(`
- Object {
- "address": "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
- "signature": "Object {
- \\"address\\": \\"0x73d0385F4d8E00C5e6504C6030F47BF6212736A8\\",
- \\"signature\\": \\"0x05f51140905ffa33ffdc57f46b0b8d8fbb1d2a99f8cd843ca27893c01c31351c08b76d83dce412731c846e3b50649724415deb522d00950fbf4f2c1459c2b70b1b\\",
- }",
- }
- `);
+ Object {
+ "address": "O",
+ "signature": "Object {
+ \\"address\\": \\"0x73d0385F4d8E00C5e6504C6030F47BF6212736A8\\",
+ \\"signature\\": \\"0x05f51140905ffa33ffdc57f46b0b8d8fbb1d2a99f8cd843ca27893c01c31351c08b76d83dce412731c846e3b50649724415deb522d00950fbf4f2c1459c2b70b1b\\",
+ }",
+ }
+ `);
});
it("ethSignMessage returns null on error", async () => {
@@ -99,17 +99,27 @@ describe("PhantomHDWallet", () => {
request: jest.fn().mockReturnValue(["0x73d0385F4d8E00C5e6504C6030F47BF6212736A8"]),
};
- const msg = "0x737570657220736563726574206d657373616765"; // super secret message
- const sig = await wallet.ethSignMessage({
- addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
- message: msg,
- });
+ const address = await wallet.ethGetAddress();
- expect(sig).toMatchObject({
- address: "0x73d0385F4d8E00C5e6504C6030F47BF6212736A8",
- signature: ["0x73d0385F4d8E00C5e6504C6030F47BF6212736A8"],
- });
+ expect(address).toEqual("0x73d0385F4d8E00C5e6504C6030F47BF6212736A8");
});
+ it("btcGetAddress returns a valid address", async () => {
+ wallet.bitcoinProvider = {
+ requestAccounts: jest.fn().mockReturnValue([
+ {
+ purpose: "payment",
+ address: "bc1q9sjm947kn2hz84syykmem7dshvevm8xm5dkrpg",
+ },
+ ]),
+ } as unknown as PhantomUtxoProvider;
+
+ const address = await wallet.btcGetAddress({
+ coin: "Bitcoin",
+ } as core.BTCGetAddress);
+
+ expect(address).toEqual("bc1q9sjm947kn2hz84syykmem7dshvevm8xm5dkrpg");
+ });
+
it("ethSendTx returns a valid hash", async () => {
wallet.evmProvider = {
_metamask: {
From 0f648fd73ec0f9f3f41a66ffda4d64e9b09d859e Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Fri, 20 Sep 2024 18:30:05 +0200
Subject: [PATCH 46/52] feat: up-to-date hdwallet deps
---
packages/hdwallet-phantom/package.json | 2 +-
yarn.lock | 12 ------------
2 files changed, 1 insertion(+), 13 deletions(-)
diff --git a/packages/hdwallet-phantom/package.json b/packages/hdwallet-phantom/package.json
index 5a5b2ff37..7345023fd 100644
--- a/packages/hdwallet-phantom/package.json
+++ b/packages/hdwallet-phantom/package.json
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.54.2",
+ "@shapeshiftoss/hdwallet-core": "1.55.4",
"lodash": "^4.17.21"
},
"devDependencies": {
diff --git a/yarn.lock b/yarn.lock
index 19f5ca127..d032ca968 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4646,18 +4646,6 @@
web-encoding "^1.1.0"
wif "^2.0.6"
-"@shapeshiftoss/hdwallet-core@1.54.2":
- version "1.54.2"
- resolved "https://registry.yarnpkg.com/@shapeshiftoss/hdwallet-core/-/hdwallet-core-1.54.2.tgz#0bcc9fe56bd869b7942ffd36735190d5692bb97d"
- integrity sha512-bJx0vgpudvq+k1ZRG5+xGx7w5w7sJDyDQcdHtoILhB9htgt36ILjsmCJSrpc+0LSIwP2P/LLw3cg88beqahVNw==
- dependencies:
- "@shapeshiftoss/proto-tx-builder" "^0.8.0"
- eip-712 "^1.0.0"
- eventemitter2 "^5.0.1"
- lodash "^4.17.21"
- rxjs "^6.4.0"
- type-assertions "^1.1.0"
-
"@shapeshiftoss/hdwallet-core@latest":
version "1.55.2"
resolved "https://registry.yarnpkg.com/@shapeshiftoss/hdwallet-core/-/hdwallet-core-1.55.2.tgz#1b153d3a1edaf4f38ea7295ff9363a76f02c2f43"
From dd5b0f17479255e6cbdac0974ecf52d64dd1ec77 Mon Sep 17 00:00:00 2001
From: kaladinlight <35275952+kaladinlight@users.noreply.github.com>
Date: Fri, 20 Sep 2024 13:14:18 -0600
Subject: [PATCH 47/52] cleanup
---
.../ethereum/OpenSea-ethSignTypedDataV4.json | 2 +-
examples/sandbox/json/ethereum/ethTx.json | 3 +-
examples/sandbox/package.json | 2 +-
packages/hdwallet-core/package.json | 1 +
packages/hdwallet-core/src/ethereum.ts | 14 +
.../src/crypto/isolation/adapters/ethereum.ts | 3 +-
packages/hdwallet-native/src/ethereum.ts | 3 +-
packages/hdwallet-native/src/util.ts | 14 -
packages/hdwallet-phantom/package.json | 4 +-
packages/hdwallet-phantom/src/bitcoin.ts | 22 +-
packages/hdwallet-phantom/src/ethereum.ts | 58 ++-
packages/hdwallet-phantom/src/phantom.test.ts | 25 +-
packages/hdwallet-phantom/src/phantom.ts | 370 +++++++-----------
13 files changed, 213 insertions(+), 308 deletions(-)
diff --git a/examples/sandbox/json/ethereum/OpenSea-ethSignTypedDataV4.json b/examples/sandbox/json/ethereum/OpenSea-ethSignTypedDataV4.json
index 44b3a7400..bd20f0def 100644
--- a/examples/sandbox/json/ethereum/OpenSea-ethSignTypedDataV4.json
+++ b/examples/sandbox/json/ethereum/OpenSea-ethSignTypedDataV4.json
@@ -118,7 +118,7 @@
"domain": {
"name": "Seaport",
"version": "1.5",
- "chainId": 137,
+ "chainId": 1,
"verifyingContract": "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC"
},
"message": {
diff --git a/examples/sandbox/json/ethereum/ethTx.json b/examples/sandbox/json/ethereum/ethTx.json
index c43243e07..7420ccdd6 100644
--- a/examples/sandbox/json/ethereum/ethTx.json
+++ b/examples/sandbox/json/ethereum/ethTx.json
@@ -156,7 +156,8 @@
"verifyingContract": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chainId": 1
},
- "primaryType": "EIP712Domain"
+ "primaryType": "EIP712Domain",
+ "message": {}
}
}
},
diff --git a/examples/sandbox/package.json b/examples/sandbox/package.json
index c33cdd541..e46ebeef8 100644
--- a/examples/sandbox/package.json
+++ b/examples/sandbox/package.json
@@ -22,7 +22,7 @@
"@shapeshiftoss/hdwallet-ledger-webhid": "1.55.5",
"@shapeshiftoss/hdwallet-ledger-webusb": "1.55.5",
"@shapeshiftoss/hdwallet-metamask": "1.55.5",
- "@shapeshiftoss/hdwallet-phantom": "1.55.4",
+ "@shapeshiftoss/hdwallet-phantom": "1.55.5",
"@shapeshiftoss/hdwallet-native": "1.55.5",
"@shapeshiftoss/hdwallet-portis": "1.55.5",
"@shapeshiftoss/hdwallet-tallyho": "1.55.5",
diff --git a/packages/hdwallet-core/package.json b/packages/hdwallet-core/package.json
index 0655e3ae6..3e73592dc 100644
--- a/packages/hdwallet-core/package.json
+++ b/packages/hdwallet-core/package.json
@@ -16,6 +16,7 @@
"dependencies": {
"@shapeshiftoss/proto-tx-builder": "^0.8.0",
"eip-712": "^1.0.0",
+ "ethers": "5.7.2",
"eventemitter2": "^5.0.1",
"lodash": "^4.17.21",
"rxjs": "^6.4.0",
diff --git a/packages/hdwallet-core/src/ethereum.ts b/packages/hdwallet-core/src/ethereum.ts
index 16d15a465..22bf307f2 100644
--- a/packages/hdwallet-core/src/ethereum.ts
+++ b/packages/hdwallet-core/src/ethereum.ts
@@ -1,5 +1,6 @@
import { Bytes } from "@ethersproject/bytes";
import { TypedData } from "eip-712";
+import { ethers } from "ethers";
import { addressNListToBIP32, slip44ByCoin } from "./utils";
import { BIP32Path, HDWallet, HDWalletInfo, PathDescription } from "./wallet";
@@ -240,3 +241,16 @@ export function describeETHPath(path: BIP32Path): PathDescription {
isPrefork: false,
};
}
+
+export function buildMessage(message: ethers.utils.BytesLike): Uint8Array {
+ const messageBytes =
+ typeof message === "string" && !ethers.utils.isHexString(message)
+ ? ethers.utils.toUtf8Bytes(message)
+ : ethers.utils.arrayify(message);
+
+ return ethers.utils.concat([
+ ethers.utils.toUtf8Bytes("\x19Ethereum Signed Message:\n"),
+ ethers.utils.toUtf8Bytes(String(messageBytes.length)),
+ messageBytes,
+ ]);
+}
diff --git a/packages/hdwallet-native/src/crypto/isolation/adapters/ethereum.ts b/packages/hdwallet-native/src/crypto/isolation/adapters/ethereum.ts
index f6e4c284a..e547ea1c7 100644
--- a/packages/hdwallet-native/src/crypto/isolation/adapters/ethereum.ts
+++ b/packages/hdwallet-native/src/crypto/isolation/adapters/ethereum.ts
@@ -12,7 +12,6 @@ import {
splitSignature,
} from "ethers/lib/utils.js";
-import { buildMessage } from "../../../util";
import { Isolation } from "../..";
import { SecP256K1 } from "../core";
@@ -80,7 +79,7 @@ export class SignerAdapter {
}
async signMessage(messageData: BytesLike, addressNList: core.BIP32Path): Promise {
- const messageBuf = buildMessage(messageData);
+ const messageBuf = core.buildMessage(messageData);
const nodeAdapter = await this.nodeAdapter.derivePath(core.addressNListToBIP32(addressNList));
const rawSig = await SecP256K1.RecoverableSignature.signCanonically(nodeAdapter.node, "keccak256", messageBuf);
return joinSignature(ethSigFromRecoverableSig(rawSig));
diff --git a/packages/hdwallet-native/src/ethereum.ts b/packages/hdwallet-native/src/ethereum.ts
index ff35ea5ff..f70a5b18b 100644
--- a/packages/hdwallet-native/src/ethereum.ts
+++ b/packages/hdwallet-native/src/ethereum.ts
@@ -4,7 +4,6 @@ import { keccak256, parseTransaction, recoverAddress } from "ethers/lib/utils.js
import * as Isolation from "./crypto/isolation";
import SignerAdapter from "./crypto/isolation/adapters/ethereum";
import { NativeHDWalletBase } from "./native";
-import { buildMessage } from "./util";
export function MixinNativeETHWalletInfo>(Base: TBase) {
// eslint-disable-next-line @typescript-eslint/no-shadow
@@ -142,7 +141,7 @@ export function MixinNativeETHWallet {
if (!signature.startsWith("0x")) signature = `0x${signature}`;
- const digest = keccak256(buildMessage(message));
+ const digest = keccak256(core.buildMessage(message));
return recoverAddress(digest, signature) === address;
}
};
diff --git a/packages/hdwallet-native/src/util.ts b/packages/hdwallet-native/src/util.ts
index 1a7c7862f..a6a0c4e46 100644
--- a/packages/hdwallet-native/src/util.ts
+++ b/packages/hdwallet-native/src/util.ts
@@ -1,5 +1,4 @@
import * as core from "@shapeshiftoss/hdwallet-core";
-import { ethers } from "ethers";
import { BTCScriptType } from "./bitcoin";
import * as Isolation from "./crypto/isolation";
@@ -16,16 +15,3 @@ export async function getKeyPair(
const path = core.addressNListToBIP32(addressNList);
return await wallet.derivePath(path);
}
-
-export function buildMessage(message: ethers.utils.BytesLike): Uint8Array {
- const messageBytes =
- typeof message === "string" && !ethers.utils.isHexString(message)
- ? ethers.utils.toUtf8Bytes(message)
- : ethers.utils.arrayify(message);
-
- return ethers.utils.concat([
- ethers.utils.toUtf8Bytes("\x19Ethereum Signed Message:\n"),
- ethers.utils.toUtf8Bytes(String(messageBytes.length)),
- messageBytes,
- ]);
-}
diff --git a/packages/hdwallet-phantom/package.json b/packages/hdwallet-phantom/package.json
index 2804f6d7f..460f07687 100644
--- a/packages/hdwallet-phantom/package.json
+++ b/packages/hdwallet-phantom/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-phantom",
- "version": "1.55.4",
+ "version": "1.55.5",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,6 +15,8 @@
},
"dependencies": {
"@shapeshiftoss/hdwallet-core": "1.55.5",
+ "base64-js": "^1.5.1",
+ "bitcoinjs-message": "^2.0.0",
"lodash": "^4.17.21"
},
"devDependencies": {
diff --git a/packages/hdwallet-phantom/src/bitcoin.ts b/packages/hdwallet-phantom/src/bitcoin.ts
index 39b1ad98d..aa03ed6d7 100644
--- a/packages/hdwallet-phantom/src/bitcoin.ts
+++ b/packages/hdwallet-phantom/src/bitcoin.ts
@@ -27,7 +27,27 @@ const getNetwork = (coin: string): bitcoin.networks.Network => {
}
};
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export const btcGetAccountPaths = (msg: core.BTCGetAccountPaths): Array => {
+ const slip44 = core.slip44ByCoin(msg.coin);
+ if (slip44 === undefined) return [];
+
+ const bip84 = core.segwitNativeAccount(msg.coin, slip44, msg.accountIdx);
+
+ const coinPaths = {
+ bitcoin: [bip84],
+ } as Partial>>;
+
+ let paths: Array = coinPaths[msg.coin.toLowerCase()] || [];
+
+ if (msg.scriptType !== undefined) {
+ paths = paths.filter((path) => {
+ return path.scriptType === msg.scriptType;
+ });
+ }
+
+ return paths;
+};
+
export async function bitcoinGetAddress(_msg: core.BTCGetAddress, provider: any): Promise {
const accounts = await provider.requestAccounts();
const paymentAddress = accounts.find((account: BtcAccount) => account.purpose === "payment")?.address;
diff --git a/packages/hdwallet-phantom/src/ethereum.ts b/packages/hdwallet-phantom/src/ethereum.ts
index 15286f2ba..ee483f872 100644
--- a/packages/hdwallet-phantom/src/ethereum.ts
+++ b/packages/hdwallet-phantom/src/ethereum.ts
@@ -4,36 +4,6 @@ import { isHexString } from "ethers/lib/utils";
import { PhantomEvmProvider } from "./types";
-export function describeETHPath(path: core.BIP32Path): core.PathDescription {
- const pathStr = core.addressNListToBIP32(path);
- const unknown: core.PathDescription = {
- verbose: pathStr,
- coin: "Ethereum",
- isKnown: false,
- };
-
- if (path.length !== 5) return unknown;
-
- if (path[0] !== 0x80000000 + 44) return unknown;
-
- if (path[1] !== 0x80000000 + core.slip44ByCoin("Ethereum")) return unknown;
-
- if ((path[2] & 0x80000000) >>> 0 !== 0x80000000) return unknown;
-
- if (path[3] !== 0) return unknown;
-
- if (path[4] !== 0) return unknown;
-
- const index = path[2] & 0x7fffffff;
- return {
- verbose: `Ethereum Account #${index}`,
- accountIdx: index,
- wholeAccount: true,
- coin: "Ethereum",
- isKnown: true,
- };
-}
-
export function ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
const slip44 = core.slip44ByCoin(msg.coin);
if (slip44 === undefined) return [];
@@ -58,9 +28,8 @@ export async function ethSendTx(
to: msg.to,
value: msg.value,
chainId: msg.chainId,
- data: msg.data && msg.data !== "" ? msg.data : undefined,
+ data: msg.data,
gasLimit: msg.gasLimit,
- gasPrice: msg.gasPrice,
};
const utx = msg.maxFeePerGas
@@ -76,9 +45,7 @@ export async function ethSendTx(
params: [utx],
});
- return {
- hash: signedTx,
- } as core.ETHTxHash;
+ return { hash: signedTx } as core.ETHTxHash;
} catch (error) {
console.error(error);
return null;
@@ -107,6 +74,27 @@ export async function ethSignMessage(
}
}
+export async function ethSignTypedData(
+ msg: core.ETHSignTypedData,
+ phantom: PhantomEvmProvider,
+ address: string
+): Promise {
+ try {
+ const signedMsg = await phantom.request?.({
+ method: "eth_signTypedData_v4",
+ params: [address, JSON.stringify(msg.typedData)],
+ });
+
+ return {
+ address: address,
+ signature: signedMsg,
+ } as ETHSignedMessage;
+ } catch (error) {
+ console.error(error);
+ return null;
+ }
+}
+
export async function ethGetAddress(phantom: PhantomEvmProvider): Promise {
if (!(phantom && phantom.request)) {
return null;
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index 6882ddd8b..ed089165f 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -1,28 +1,11 @@
import * as core from "@shapeshiftoss/hdwallet-core";
-import { PhantomHDWallet, PhantomHDWalletInfo } from ".";
+import { PhantomHDWallet } from ".";
import { PhantomUtxoProvider } from "./types";
-describe("HDWalletInfo", () => {
- const info = new PhantomHDWalletInfo();
-
- it("should have correct metadata", async () => {
- expect(info.getVendor()).toBe("Phantom");
- expect(info.hasOnDevicePinEntry()).toBe(false);
- expect(info.hasOnDevicePassphrase()).toBe(true);
- expect(info.hasOnDeviceDisplay()).toBe(true);
- expect(info.hasOnDeviceRecovery()).toBe(true);
- expect(await info.ethSupportsNetwork(1)).toBe(true);
- expect(await info.ethSupportsSecureTransfer()).toBe(false);
- expect(info.ethSupportsNativeShapeShift()).toBe(false);
- expect(await info.ethSupportsEIP1559()).toBe(true);
- expect(await info.supportsOfflineSigning()).toBe(false);
- expect(await info.supportsBroadcast()).toBe(true);
- });
-});
-
describe("PhantomHDWallet", () => {
let wallet: PhantomHDWallet;
+
beforeEach(() => {
wallet = new PhantomHDWallet(
core.untouchable("PhantomHDWallet:provider"),
@@ -40,9 +23,9 @@ describe("PhantomHDWallet", () => {
expect(await wallet.ethSupportsSecureTransfer()).toBe(false);
expect(wallet.ethSupportsNativeShapeShift()).toBe(false);
expect(await wallet.ethSupportsEIP1559()).toBe(true);
- expect(await wallet.supportsOfflineSigning()).toBe(false);
+ expect(wallet.supportsOfflineSigning()).toBe(false);
expect(wallet.supportsBip44Accounts()).toBe(false);
- expect(await wallet.supportsBroadcast()).toBe(true);
+ expect(wallet.supportsBroadcast()).toBe(true);
});
it("should test ethSignMessage", async () => {
diff --git a/packages/hdwallet-phantom/src/phantom.ts b/packages/hdwallet-phantom/src/phantom.ts
index 689199d46..30c001106 100644
--- a/packages/hdwallet-phantom/src/phantom.ts
+++ b/packages/hdwallet-phantom/src/phantom.ts
@@ -1,8 +1,11 @@
import * as core from "@shapeshiftoss/hdwallet-core";
-import { AddEthereumChainParameter, BTCInputScriptType } from "@shapeshiftoss/hdwallet-core";
+import { BTCInputScriptType } from "@shapeshiftoss/hdwallet-core";
+import Base64 from "base64-js";
+import * as bitcoinMsg from "bitcoinjs-message";
+import { keccak256, recoverAddress } from "ethers/lib/utils.js";
import _ from "lodash";
-import * as Btc from "./bitcoin";
+import * as btc from "./bitcoin";
import * as eth from "./ethereum";
import { PhantomEvmProvider, PhantomUtxoProvider } from "./types";
@@ -10,18 +13,15 @@ export function isPhantom(wallet: core.HDWallet): wallet is PhantomHDWallet {
return _.isObject(wallet) && (wallet as any)._isPhantom;
}
-export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInfo {
- readonly _supportsBTCInfo = false;
+export class PhantomHDWalletInfo implements core.HDWalletInfo, core.BTCWalletInfo, core.ETHWalletInfo {
+ readonly _supportsBTCInfo = true;
readonly _supportsETHInfo = true;
- readonly _supportsCosmosInfo = false;
- readonly _supportsBinanceInfo = false;
- readonly _supportsRippleInfo = false;
- readonly _supportsEosInfo = false;
- readonly _supportsFioInfo = false;
- readonly _supportsThorchainInfo = false;
- readonly _supportsSecretInfo = false;
- readonly _supportsKavaInfo = false;
- readonly _supportsTerraInfo = false;
+
+ evmProvider: PhantomEvmProvider;
+
+ constructor(evmProvider: PhantomEvmProvider) {
+ this.evmProvider = evmProvider;
+ }
public getVendor(): string {
return "Phantom";
@@ -61,11 +61,13 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
}
public describePath(msg: core.DescribePath): core.PathDescription {
- switch (msg.coin) {
+ switch (msg.coin.toLowerCase()) {
case "bitcoin": {
const unknown = core.unknownUTXOPath(msg.path, msg.coin, msg.scriptType);
if (!msg.scriptType) return unknown;
+ if (!this.btcSupportsCoin(msg.coin)) return unknown;
+ if (!this.btcSupportsScriptType(msg.coin, msg.scriptType)) return unknown;
return core.describeUTXOPath(msg.path, msg.coin, msg.scriptType);
}
@@ -76,13 +78,22 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
}
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public ethNextAccountPath(msg: core.ETHAccountPath): core.ETHAccountPath | undefined {
- throw new Error("Unimplemented");
- }
+ /** Ethereum */
public async ethSupportsNetwork(chainId: number): Promise {
- return chainId === 1 || chainId === 137;
+ return chainId === 1;
+ }
+
+ public async ethGetChainId(): Promise {
+ try {
+ if (!this.evmProvider.request) throw new Error("Provider does not support ethereum.request");
+ // chainId as hex string
+ const chainId: string = await this.evmProvider.request({ method: "eth_chainId" });
+ return parseInt(chainId, 16);
+ } catch (e) {
+ console.error(e);
+ return null;
+ }
}
public async ethSupportsSecureTransfer(): Promise {
@@ -100,66 +111,86 @@ export class PhantomHDWalletInfo implements core.HDWalletInfo, core.ETHWalletInf
public ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
return eth.ethGetAccountPaths(msg);
}
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public ethNextAccountPath(msg: core.ETHAccountPath): core.ETHAccountPath | undefined {
+ throw new Error("Method not implemented");
+ }
+
+ /** Bitcoin */
+
+ public async btcSupportsCoin(coin: core.Coin): Promise {
+ return coin === "bitcoin";
+ }
+
+ public async btcSupportsScriptType(coin: string, scriptType?: core.BTCInputScriptType | undefined): Promise {
+ if (!this.btcSupportsCoin(coin)) return false;
+
+ switch (scriptType) {
+ case core.BTCInputScriptType.SpendWitness:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public async btcSupportsSecureTransfer(): Promise {
+ return false;
+ }
+
+ public btcSupportsNativeShapeShift(): boolean {
+ return false;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public btcGetAccountPaths(msg: core.BTCGetAccountPaths): Array {
+ return btc.btcGetAccountPaths(msg);
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public btcIsSameAccount(msg: core.BTCAccountPath[]): boolean {
+ throw new Error("Method not implemented.");
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public btcNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
+ throw new Error("Method not implemented");
+ }
}
-export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
- readonly _supportsETH = true;
- readonly _supportsETHInfo = true;
- readonly _supportsBTCInfo = false;
+export class PhantomHDWallet extends PhantomHDWalletInfo implements core.HDWallet, core.BTCWallet, core.ETHWallet {
readonly _supportsBTC = true;
- readonly _supportsCosmosInfo = false;
- readonly _supportsCosmos = false;
+ readonly _supportsETH = true;
readonly _supportsEthSwitchChain = false;
readonly _supportsAvalanche = false;
readonly _supportsOptimism = false;
- readonly _supportsBSC = false;
readonly _supportsPolygon = true;
readonly _supportsGnosis = false;
readonly _supportsArbitrum = false;
readonly _supportsArbitrumNova = false;
readonly _supportsBase = false;
- readonly _supportsOsmosisInfo = false;
- readonly _supportsOsmosis = false;
- readonly _supportsBinanceInfo = false;
- readonly _supportsBinance = false;
- readonly _supportsDebugLink = false;
- readonly _isPortis = false;
+ readonly _supportsBSC = false;
readonly _isPhantom = true;
- readonly _supportsRippleInfo = false;
- readonly _supportsRipple = false;
- readonly _supportsEosInfo = false;
- readonly _supportsEos = false;
- readonly _supportsFioInfo = false;
- readonly _supportsFio = false;
- readonly _supportsThorchainInfo = false;
- readonly _supportsThorchain = false;
- readonly _supportsSecretInfo = false;
- readonly _supportsSecret = false;
- readonly _supportsKava = false;
- readonly _supportsKavaInfo = false;
- readonly _supportsTerra = false;
- readonly _supportsTerraInfo = false;
-
- info: PhantomHDWalletInfo & core.HDWalletInfo;
+
evmProvider: PhantomEvmProvider;
bitcoinProvider: PhantomUtxoProvider;
constructor(evmProvider: PhantomEvmProvider, bitcoinProvider: PhantomUtxoProvider) {
- this.info = new PhantomHDWalletInfo();
+ super(evmProvider);
this.evmProvider = evmProvider;
this.bitcoinProvider = bitcoinProvider;
}
- async getFeatures(): Promise> {
- return {};
+ public async getDeviceID(): Promise {
+ return "phantom:" + (await this.ethGetAddress());
}
- public async isLocked(): Promise {
- return !this.evmProvider._metamask.isUnlocked();
+ async getFeatures(): Promise> {
+ return {};
}
- public getVendor(): string {
- return "Phantom";
+ public async getFirmwareVersion(): Promise {
+ return "phantom";
}
public async getModel(): Promise {
@@ -170,160 +201,76 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
return "Phantom";
}
- public async initialize(): Promise {
- // nothing to initialize
- }
-
- public hasOnDevicePinEntry(): boolean {
- return this.info.hasOnDevicePinEntry();
- }
-
- public hasOnDevicePassphrase(): boolean {
- return this.info.hasOnDevicePassphrase();
- }
-
- public hasOnDeviceDisplay(): boolean {
- return this.info.hasOnDeviceDisplay();
- }
-
- public hasOnDeviceRecovery(): boolean {
- return this.info.hasOnDeviceRecovery();
- }
-
- public hasNativeShapeShift(srcCoin: core.Coin, dstCoin: core.Coin): boolean {
- return this.info.hasNativeShapeShift(srcCoin, dstCoin);
- }
-
- public supportsBip44Accounts(): boolean {
- return this.info.supportsBip44Accounts();
- }
-
- public supportsOfflineSigning(): boolean {
- return false;
+ public async isInitialized(): Promise {
+ return true;
}
- public supportsBroadcast(): boolean {
- return true;
+ public async isLocked(): Promise {
+ return !this.evmProvider._metamask.isUnlocked();
}
public async clearSession(): Promise {}
+ public async initialize(): Promise {}
+
public async ping(msg: core.Ping): Promise {
- // no ping function for Phantom, so just returning Core.Pong
return { msg: msg.msg };
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async sendPin(pin: string): Promise {
- // no concept of pin in Phantom
- }
+ public async sendPin(pin: string): Promise {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async sendPassphrase(passphrase: string): Promise {
- // cannot send passphrase to Phantom. Could show the widget?
- }
+ public async sendPassphrase(passphrase: string): Promise {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async sendCharacter(charater: string): Promise {
- // no concept of sendCharacter in Phantom
- }
+ public async sendCharacter(charater: string): Promise {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async sendWord(word: string): Promise {
- // no concept of sendWord in Phantom
- }
+ public async sendWord(word: string): Promise {}
- public async cancel(): Promise {
- // no concept of cancel in Phantom
- }
+ public async cancel(): Promise {}
- // eslint-disable-next-line @typescript-eslint/no-empty-function
public async wipe(): Promise {}
- // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
public async reset(msg: core.ResetDevice): Promise {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async recover(msg: core.RecoverDevice): Promise {
- // no concept of recover in Phantom
- }
+ public async recover(msg: core.RecoverDevice): Promise {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async loadDevice(msg: core.LoadDevice): Promise {}
- public describePath(msg: core.DescribePath): core.PathDescription {
- return this.info.describePath(msg);
- }
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async getPublicKeys(msg: Array): Promise> {
- // Only p2wpkh effectively supported for now
- if (msg[0].coin !== "Bitcoin") return [];
- if (msg[0].scriptType !== BTCInputScriptType.SpendWitness) return [];
-
- // Note this is a pubKey, not an xpub
- const pubKey = await this.btcGetAddress({ coin: "Bitcoin" } as core.BTCGetAddress);
- if (!pubKey) return [];
- // Ethereum public keys are not exposed by the RPC API
- return [{ xpub: pubKey }];
- }
-
- public async isInitialized(): Promise {
- return true;
- }
-
- // eslint-disable-next-line @typescript-eslint/no-empty-function
public async disconnect(): Promise {}
- public async ethSupportsNetwork(chainId = 1): Promise {
- return chainId === 1;
- }
-
- public async ethGetChainId(): Promise {
- try {
- if (!this.evmProvider.request) throw new Error("Provider does not support ethereum.request");
- // chainId as hex string
- const chainId: string = await this.evmProvider.request({ method: "eth_chainId" });
- return parseInt(chainId, 16);
- } catch (e) {
- console.error(e);
- return null;
- }
- }
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async ethSwitchChain(params: AddEthereumChainParameter): Promise {
- // no concept of switch chain in phantom
- }
-
- public async ethSupportsSecureTransfer(): Promise {
- return false;
- }
-
- public ethSupportsNativeShapeShift(): boolean {
- return false;
- }
-
- public async ethSupportsEIP1559(): Promise {
- return true;
- }
+ public async getPublicKeys(msg: Array): Promise> {
+ return await Promise.all(
+ msg.map(async (getPublicKey) => {
+ const { coin, scriptType } = getPublicKey;
+
+ // Only p2wpkh effectively supported for now
+ if (coin === "Bitcoin" && scriptType === BTCInputScriptType.SpendWitness) {
+ // Note this is a pubKey, not an xpub, however phantom does not support utxo derivation,
+ // so this functions as an account (xpub) for all intents and purposes
+ const pubKey = await this.btcGetAddress({ coin: "Bitcoin" } as core.BTCGetAddress);
+ return { xpub: pubKey } as core.PublicKey;
+ }
- public ethGetAccountPaths(msg: core.ETHGetAccountPath): Array {
- return eth.ethGetAccountPaths(msg);
+ return null;
+ })
+ );
}
- public ethNextAccountPath(msg: core.ETHAccountPath): core.ETHAccountPath | undefined {
- return this.info.ethNextAccountPath(msg);
- }
+ /** Ethereum */
public async ethGetAddress(): Promise {
- const address = await eth.ethGetAddress(this.evmProvider);
- return address;
+ return eth.ethGetAddress(this.evmProvider);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async ethSignTx(msg: core.ETHSignTx): Promise {
- throw new Error("unimplemented");
+ throw new Error("Method not implemented");
}
public async ethSendTx(msg: core.ETHSignTx): Promise {
@@ -336,45 +283,18 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
return address ? eth.ethSignMessage(msg, this.evmProvider, address) : null;
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async ethVerifyMessage(msg: core.ETHVerifyMessage): Promise {
- return null;
- }
-
- public async getDeviceID(): Promise {
- return "phantom:" + (await this.ethGetAddress());
- }
-
- public async getFirmwareVersion(): Promise {
- return "phantom";
- }
-
- /** BITCOIN */
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public bitcoinNextAccountPath(msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
- throw new Error("Method not implemented.");
- }
-
- public async btcSupportsSecureTransfer(): Promise {
- return false;
+ async ethSignTypedData(msg: core.ETHSignTypedData): Promise {
+ const address = await this.ethGetAddress();
+ return address ? eth.ethSignTypedData(msg, this.evmProvider, address) : null;
}
- public btcSupportsNativeShapeShift(): boolean {
- return false;
+ public async ethVerifyMessage(msg: core.ETHVerifyMessage): Promise {
+ if (!msg.signature.startsWith("0x")) msg.signature = `0x${msg.signature}`;
+ const digest = keccak256(core.buildMessage(msg.message));
+ return recoverAddress(digest, msg.signature) === msg.address;
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public btcGetAccountPaths(msg: core.BTCGetAccountPaths): Array {
- // Phantom doesn't support BIP44 paths
- throw new Error("Method not implemented.");
- }
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public btcNextAccountPath(_msg: core.BTCAccountPath): core.BTCAccountPath | undefined {
- // Phantom doesn't support BIP44 paths
- throw new Error("Method not implemented.");
- }
+ /** Bitcoin */
public async btcGetAddress(msg: core.BTCGetAddress): Promise {
const value = await (async () => {
@@ -398,38 +318,30 @@ export class PhantomHDWallet implements core.HDWallet, core.ETHWallet {
const { coin } = msg;
switch (coin) {
case "Bitcoin":
- return Btc.bitcoinSignTx(this, msg, this.bitcoinProvider);
+ return btc.bitcoinSignTx(this, msg, this.bitcoinProvider);
default:
return null;
}
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
public async btcSignMessage(msg: core.BTCSignMessage): Promise {
- const address = await this.btcGetAddress({ coin: "Bitcoin" } as core.BTCGetAddress);
- if (!address) throw new Error("Could not get Bitcoin address");
- const message = new TextEncoder().encode(msg.message);
-
- const { signature } = await this.bitcoinProvider.signMessage(address, message);
- return { signature: core.toHexString(signature), address };
- }
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async btcVerifyMessage(msg: core.BTCVerifyMessage): Promise {
- throw new Error("Method not implemented.");
- }
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async btcSupportsScriptType(coin: string, scriptType?: core.BTCInputScriptType | undefined): Promise {
- throw new Error("Method not implemented.");
- }
+ const { coin } = msg;
+ switch (coin) {
+ case "Bitcoin": {
+ const address = await this.btcGetAddress({ coin } as core.BTCGetAddress);
+ if (!address) throw new Error(`Could not get ${coin} address`);
+ const message = new TextEncoder().encode(msg.message);
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public async btcSupportsCoin(coin: core.Coin): Promise {
- return coin === "bitcoin";
+ const { signature } = await this.bitcoinProvider.signMessage(address, message);
+ return { signature: core.toHexString(signature), address };
+ }
+ default:
+ return null;
+ }
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- public btcIsSameAccount(msg: core.BTCAccountPath[]): boolean {
- throw new Error("Method not implemented.");
+ public async btcVerifyMessage(msg: core.BTCVerifyMessage): Promise {
+ const signature = Base64.fromByteArray(core.fromHexString(msg.signature));
+ return bitcoinMsg.verify(msg.message, msg.address, signature);
}
}
From 6b89f946af61820787a9d2d6afe9b34d4901ab8a Mon Sep 17 00:00:00 2001
From: kaladinlight <35275952+kaladinlight@users.noreply.github.com>
Date: Fri, 20 Sep 2024 13:29:47 -0600
Subject: [PATCH 48/52] fix test
---
packages/hdwallet-phantom/src/phantom.test.ts | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/packages/hdwallet-phantom/src/phantom.test.ts b/packages/hdwallet-phantom/src/phantom.test.ts
index ed089165f..202df1f20 100644
--- a/packages/hdwallet-phantom/src/phantom.test.ts
+++ b/packages/hdwallet-phantom/src/phantom.test.ts
@@ -166,20 +166,14 @@ describe("PhantomHDWallet", () => {
expect(wallet.evmProvider.request).toHaveBeenCalled();
expect(hash).toBe(null);
});
- it("ethVerifyMessage returns null as its not implemented", async () => {
- wallet.evmProvider = {
- _metamask: {
- isUnlocked: () => true,
- },
- request: jest.fn().mockReturnValue("0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8"),
- };
+ it("ethVerifyMessage returns true for a valid signature", async () => {
expect(
await wallet.ethVerifyMessage({
- address: "0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8",
- message: "hello world",
+ address: "0x2068dD92B6690255553141Dfcf00dF308281f763",
+ message: "Hello World",
signature:
- "0x29f7212ecc1c76cea81174af267b67506f754ea8c73f144afa900a0d85b24b21319621aeb062903e856352f38305710190869c3ce5a1425d65ef4fa558d0fc251b",
+ "0x61f1dda82e9c3800e960894396c9ce8164fd1526fccb136c71b88442405f7d09721725629915d10bc7cecfca2818fe76bc5816ed96a1b0cebee9b03b052980131b",
})
- ).toEqual(null);
+ ).toEqual(true);
});
});
From 7cb54cb86958e170586ad6fb3337af07a04cffff Mon Sep 17 00:00:00 2001
From: kaladinlight <35275952+kaladinlight@users.noreply.github.com>
Date: Fri, 20 Sep 2024 14:54:15 -0600
Subject: [PATCH 49/52] cleanup bitcoin
---
packages/hdwallet-core/package.json | 1 +
packages/hdwallet-core/src/bitcoin.ts | 48 ++++++++++
packages/hdwallet-native/src/bitcoin.ts | 49 +---------
packages/hdwallet-phantom/package.json | 1 +
packages/hdwallet-phantom/src/bitcoin.ts | 110 +++++++++--------------
packages/hdwallet-phantom/src/types.ts | 4 +
6 files changed, 97 insertions(+), 116 deletions(-)
diff --git a/packages/hdwallet-core/package.json b/packages/hdwallet-core/package.json
index 3e73592dc..08eb9e6f2 100644
--- a/packages/hdwallet-core/package.json
+++ b/packages/hdwallet-core/package.json
@@ -14,6 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
+ "@shapeshiftoss/bitcoinjs-lib": "5.2.0-shapeshift.2",
"@shapeshiftoss/proto-tx-builder": "^0.8.0",
"eip-712": "^1.0.0",
"ethers": "5.7.2",
diff --git a/packages/hdwallet-core/src/bitcoin.ts b/packages/hdwallet-core/src/bitcoin.ts
index 49c9971fb..5725d42a5 100644
--- a/packages/hdwallet-core/src/bitcoin.ts
+++ b/packages/hdwallet-core/src/bitcoin.ts
@@ -1,3 +1,4 @@
+import * as bitcoin from "@shapeshiftoss/bitcoinjs-lib";
import * as ta from "type-assertions";
import { addressNListToBIP32, slip44ByCoin } from "./utils";
@@ -488,3 +489,50 @@ export function segwitNativeAccount(coin: Coin, slip44: number, accountIdx: numb
addressNList: [0x80000000 + 84, 0x80000000 + slip44, 0x80000000 + accountIdx],
};
}
+
+export function validateVoutOrdering(msg: BTCSignTxNative, tx: bitcoin.Transaction): boolean {
+ // From THORChain specification:
+ /* ignoreTx checks if we can already ignore a tx according to preset rules
+
+ we expect array of "vout" for a BTC to have this format
+ OP_RETURN is mandatory only on inbound tx
+ vout:0 is our vault
+ vout:1 is any any change back to themselves
+ vout:2 is OP_RETURN (first 80 bytes)
+ vout:3 is OP_RETURN (next 80 bytes)
+
+ Rules to ignore a tx are:
+ - vout:0 doesn't have coins (value)
+ - vout:0 doesn't have address
+ - count vouts > 4
+ - count vouts with coins (value) > 2
+ */
+
+ // Check that vout:0 contains the vault address
+ if (bitcoin.address.fromOutputScript(tx.outs[0].script) != msg.vaultAddress) {
+ console.error("Vout:0 does not contain vault address.");
+ return false;
+ }
+
+ // TODO: Can we check and make sure vout:1 is our address?
+
+ // Check and make sure vout:2 exists
+ if (tx.outs.length < 3) {
+ console.error("Not enough outputs found in transaction.", msg);
+ return false;
+ }
+ // Check and make sure vout:2 has OP_RETURN data
+ const opcode = bitcoin.script.decompile(tx.outs[2].script)?.[0];
+ if (Object.keys(bitcoin.script.OPS).find((k) => bitcoin.script.OPS[k] === opcode) != "OP_RETURN") {
+ console.error("OP_RETURN output not found for transaction.");
+ return false;
+ }
+
+ // Make sure vout:3 does not exist
+ if (tx.outs[3]) {
+ console.error("Illegal second op_return output found.");
+ return false;
+ }
+
+ return true;
+}
diff --git a/packages/hdwallet-native/src/bitcoin.ts b/packages/hdwallet-native/src/bitcoin.ts
index 182ea6bbd..7275d9af4 100644
--- a/packages/hdwallet-native/src/bitcoin.ts
+++ b/packages/hdwallet-native/src/bitcoin.ts
@@ -171,53 +171,6 @@ export function MixinNativeBTCWallet 4
- - count vouts with coins (value) > 2
- */
-
- // Check that vout:0 contains the vault address
- if (bitcoin.address.fromOutputScript(tx.outs[0].script) != msg.vaultAddress) {
- console.error("Vout:0 does not contain vault address.");
- return false;
- }
-
- // TODO: Can we check and make sure vout:1 is our address?
-
- // Check and make sure vout:2 exists
- if (tx.outs.length < 3) {
- console.error("Not enough outputs found in transaction.", msg);
- return false;
- }
- // Check and make sure vout:2 has OP_RETURN data
- const opcode = bitcoin.script.decompile(tx.outs[2].script)?.[0];
- if (Object.keys(bitcoin.script.OPS).find((k) => bitcoin.script.OPS[k] === opcode) != "OP_RETURN") {
- console.error("OP_RETURN output not found for transaction.");
- return false;
- }
-
- // Make sure vout:3 does not exist
- if (tx.outs[3]) {
- console.error("Illegal second op_return output found.");
- return false;
- }
-
- return true;
- }
-
async buildInput(coin: core.Coin, input: core.BTCSignTxInputNative): Promise {
return this.needsMnemonic(!!this.#masterKey, async () => {
const { addressNList, amount, hex, scriptType } = input;
@@ -355,7 +308,7 @@ export function MixinNativeBTCWallet {
- const inputData: Omit & {
- nonWitnessUtxo?: Buffer;
- witnessUtxo?: { script: Buffer; value: number };
- hash: string | Buffer;
- } = {
- nonWitnessUtxo: input.hex ? Buffer.from(input.hex, "hex") : undefined,
- hash: input.txid,
- index: input.vout,
- };
-
- if (input.sequence !== undefined) {
- inputData.sequence = input.sequence;
- }
+async function addInput(psbt: bitcoin.Psbt, input: core.BTCSignTxInput): Promise {
+ switch (input.scriptType) {
+ // Phantom supposedly supports more scriptTypes but in effect, doesn't (currently)
+ // https://github.com/orgs/phantom/discussions/173
+ case BTCInputScriptType.SpendWitness: {
+ psbt.addInput({
+ hash: input.txid,
+ index: input.vout,
+ nonWitnessUtxo: Buffer.from(input.hex, "hex"),
+ });
- if (input.scriptType) {
- switch (input.scriptType) {
- // Phantom supposedly supports more scriptTypes but in effect, doesn't (currently)
- // https://github.com/orgs/phantom/discussions/173
- // case "p2pkh":
- // inputData.nonWitnessUtxo = Buffer.from(input.hex, "hex");
- // break;
- // case "p2sh-p2wpkh":
- case BTCInputScriptType.SpendWitness: {
- const inputAddress = await wallet.btcGetAddress({ addressNList: input.addressNList, coin, showDisplay: false });
-
- if (!inputAddress) throw new Error("Could not get address from wallet");
-
- inputData.witnessUtxo = {
- script: bitcoin.address.toOutputScript(inputAddress, network),
- value: parseInt(input.amount),
- };
- break;
- }
- default:
- throw new Error(`Unsupported script type: ${input.scriptType}`);
+ break;
}
+ default:
+ throw new Error(`Unsupported script type: ${input.scriptType}`);
}
-
- psbt.addInput(inputData);
}
async function addOutput(
@@ -109,32 +81,28 @@ async function addOutput(
output: core.BTCSignTxOutput,
coin: string
): Promise {
- if ("address" in output && output.address) {
- psbt.addOutput({
- address: output.address,
- value: parseInt(output.amount),
- });
- } else if ("addressNList" in output && output.addressNList) {
- const outputAddress = await wallet.btcGetAddress({ addressNList: output.addressNList, coin, showDisplay: false });
+ if (!output.amount) throw new Error("Invalid output - missing amount.");
- if (!outputAddress) throw new Error("Could not get address from wallet");
+ const address = await (async () => {
+ if (output.address) return output.address;
- psbt.addOutput({
- address: outputAddress,
- value: parseInt(output.amount),
- });
- }
+ if (output.addressNList) {
+ const outputAddress = await wallet.btcGetAddress({ addressNList: output.addressNList, coin, showDisplay: false });
+ if (!outputAddress) throw new Error("Could not get address from wallet");
+ return outputAddress;
+ }
+ })();
+
+ if (!address) throw new Error("Invalid output - no address");
+
+ psbt.addOutput({ address, value: parseInt(output.amount) });
}
export async function bitcoinSignTx(
wallet: core.BTCWallet,
msg: core.BTCSignTx,
- provider: any
+ provider: PhantomUtxoProvider
): Promise {
- if (!msg.inputs.length || !msg.outputs.length) {
- throw new Error("Invalid input: Empty inputs or outputs");
- }
-
const network = getNetwork(msg.coin);
const psbt = new bitcoin.Psbt({ network });
@@ -145,7 +113,7 @@ export async function bitcoinSignTx(
}
for (const input of msg.inputs) {
- await addInput(wallet, psbt, input, msg.coin, network);
+ await addInput(psbt, input);
}
for (const output of msg.outputs) {
@@ -155,10 +123,9 @@ export async function bitcoinSignTx(
if (msg.opReturnData) {
const data = Buffer.from(msg.opReturnData, "utf-8");
const embed = bitcoin.payments.embed({ data: [data] });
- psbt.addOutput({
- script: embed.output!,
- value: 0,
- });
+ const script = embed.output;
+ if (!script) throw new Error("unable to build OP_RETURN script");
+ psbt.addOutput({ script, value: 0 });
}
const inputsToSign = await Promise.all(
@@ -169,6 +136,8 @@ export async function bitcoinSignTx(
showDisplay: false,
});
+ if (!address) throw new Error("Could not get address from wallet");
+
return {
address,
signingIndexes: [index],
@@ -178,12 +147,17 @@ export async function bitcoinSignTx(
);
const signedPsbtHex = await provider.signPSBT(fromHexString(psbt.toHex()), { inputsToSign });
-
- const signedPsbt = bitcoin.Psbt.fromHex(signedPsbtHex, { network });
+ const signedPsbt = bitcoin.Psbt.fromBuffer(Buffer.from(signedPsbtHex), { network });
signedPsbt.finalizeAllInputs();
+
const tx = signedPsbt.extractTransaction();
+ // If this is a THORChain transaction, validate the vout ordering
+ if (msg.vaultAddress && !core.validateVoutOrdering(msg, tx)) {
+ throw new Error("Improper vout ordering for BTC Thorchain transaction");
+ }
+
const signatures = signedPsbt.data.inputs.map((input) =>
input.partialSig ? input.partialSig[0].signature.toString("hex") : ""
);
diff --git a/packages/hdwallet-phantom/src/types.ts b/packages/hdwallet-phantom/src/types.ts
index b823dbc51..ceaa936f9 100644
--- a/packages/hdwallet-phantom/src/types.ts
+++ b/packages/hdwallet-phantom/src/types.ts
@@ -16,4 +16,8 @@ export type PhantomUtxoProvider = providers.ExternalProvider & {
) => Promise<{
signature: Uint8Array;
}>;
+ signPSBT(
+ psbt: Uint8Array,
+ options: { inputsToSign: { sigHash?: number | undefined; address: string; signingIndexes: number[] }[] }
+ ): Promise;
};
From 1107098f0ac7fa609cde99b57cb7bce18d405652 Mon Sep 17 00:00:00 2001
From: kaladinlight <35275952+kaladinlight@users.noreply.github.com>
Date: Fri, 20 Sep 2024 15:34:47 -0600
Subject: [PATCH 50/52] fix test take 2
---
packages/hdwallet-phantom/src/adapter.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/hdwallet-phantom/src/adapter.ts b/packages/hdwallet-phantom/src/adapter.ts
index 4f9d75fe9..1a65a5480 100644
--- a/packages/hdwallet-phantom/src/adapter.ts
+++ b/packages/hdwallet-phantom/src/adapter.ts
@@ -5,7 +5,6 @@ import { PhantomEvmProvider, PhantomUtxoProvider } from "./types";
declare global {
interface Window {
- ethereum?: PhantomEvmProvider;
phantom?: {
ethereum?: PhantomEvmProvider;
bitcoin?: PhantomUtxoProvider;
From e18b090c33c6f8dc920140a64707c9efaf9aca05 Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Fri, 20 Sep 2024 23:56:02 +0200
Subject: [PATCH 51/52] feat: cleanup tsconfig.json
---
tsconfig.json | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/tsconfig.json b/tsconfig.json
index a48be222c..e92968f5c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,8 +3,8 @@
// tsc is insanely drunk with internal resolutions currently, this at least silences it so we can ship things
// the installed versions are still the same as before, but the bumped tsc version might have made it stricter
"skipLibCheck": true,
- "target": "ESNext",
- "module": "ESNext",
+ "target": "ES2016",
+ "module": "commonjs",
"lib": ["es2020", "dom", "es5"],
"declaration": true,
"declarationMap": true,
@@ -45,7 +45,6 @@
{ "path": "./packages/hdwallet-ledger-webusb" },
{ "path": "./packages/hdwallet-metamask" },
{ "path": "./packages/hdwallet-metamask-shapeshift-multichain" },
- { "path": "./packages/hdwallet-phantom" },
{ "path": "./packages/hdwallet-coinbase" },
{ "path": "./packages/hdwallet-native" },
{ "path": "./packages/hdwallet-portis" },
From 1e04575f773046f7778b7d1965f139b80a9aa7fd Mon Sep 17 00:00:00 2001
From: gomes <17035424+gomesalexandre@users.noreply.github.com>
Date: Fri, 20 Sep 2024 23:56:21 +0200
Subject: [PATCH 52/52] chore(release): publish 1.55.6
---
examples/sandbox/package.json | 40 +++++++++----------
integration/package.json | 20 +++++-----
lerna.json | 2 +-
packages/hdwallet-coinbase/package.json | 4 +-
packages/hdwallet-core/package.json | 2 +-
.../hdwallet-keepkey-chromeusb/package.json | 6 +--
.../hdwallet-keepkey-electron/package.json | 4 +-
.../hdwallet-keepkey-nodehid/package.json | 4 +-
.../hdwallet-keepkey-nodewebusb/package.json | 6 +--
packages/hdwallet-keepkey-tcp/package.json | 6 +--
packages/hdwallet-keepkey-webusb/package.json | 6 +--
packages/hdwallet-keepkey/package.json | 4 +-
packages/hdwallet-keplr/package.json | 4 +-
packages/hdwallet-ledger-webhid/package.json | 6 +--
packages/hdwallet-ledger-webusb/package.json | 6 +--
packages/hdwallet-ledger/package.json | 4 +-
.../package.json | 4 +-
packages/hdwallet-metamask/package.json | 4 +-
packages/hdwallet-native-vault/package.json | 4 +-
packages/hdwallet-native/package.json | 4 +-
packages/hdwallet-phantom/package.json | 4 +-
packages/hdwallet-portis/package.json | 4 +-
packages/hdwallet-tallyho/package.json | 4 +-
packages/hdwallet-trezor-connect/package.json | 6 +--
packages/hdwallet-trezor/package.json | 4 +-
packages/hdwallet-walletconnect/package.json | 4 +-
.../hdwallet-walletconnectV2/package.json | 4 +-
packages/hdwallet-xdefi/package.json | 4 +-
28 files changed, 87 insertions(+), 87 deletions(-)
diff --git a/examples/sandbox/package.json b/examples/sandbox/package.json
index e46ebeef8..ba5d2143e 100644
--- a/examples/sandbox/package.json
+++ b/examples/sandbox/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-sandbox",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"private": true,
"browserslist": "> 0.5%, last 2 versions, not dead",
@@ -12,25 +12,25 @@
"dependencies": {
"@esm2cjs/p-queue": "^7.3.0",
"@metamask/eth-sig-util": "^7.0.0",
- "@shapeshiftoss/hdwallet-coinbase": "1.55.5",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey-tcp": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey-webusb": "1.55.5",
- "@shapeshiftoss/hdwallet-keplr": "1.55.5",
- "@shapeshiftoss/hdwallet-ledger": "1.55.5",
- "@shapeshiftoss/hdwallet-ledger-webhid": "1.55.5",
- "@shapeshiftoss/hdwallet-ledger-webusb": "1.55.5",
- "@shapeshiftoss/hdwallet-metamask": "1.55.5",
- "@shapeshiftoss/hdwallet-phantom": "1.55.5",
- "@shapeshiftoss/hdwallet-native": "1.55.5",
- "@shapeshiftoss/hdwallet-portis": "1.55.5",
- "@shapeshiftoss/hdwallet-tallyho": "1.55.5",
- "@shapeshiftoss/hdwallet-trezor": "1.55.5",
- "@shapeshiftoss/hdwallet-trezor-connect": "1.55.5",
- "@shapeshiftoss/hdwallet-walletconnect": "1.55.5",
- "@shapeshiftoss/hdwallet-walletconnectv2": "1.55.5",
- "@shapeshiftoss/hdwallet-xdefi": "1.55.5",
+ "@shapeshiftoss/hdwallet-coinbase": "1.55.6",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey-tcp": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey-webusb": "1.55.6",
+ "@shapeshiftoss/hdwallet-keplr": "1.55.6",
+ "@shapeshiftoss/hdwallet-ledger": "1.55.6",
+ "@shapeshiftoss/hdwallet-ledger-webhid": "1.55.6",
+ "@shapeshiftoss/hdwallet-ledger-webusb": "1.55.6",
+ "@shapeshiftoss/hdwallet-metamask": "1.55.6",
+ "@shapeshiftoss/hdwallet-native": "1.55.6",
+ "@shapeshiftoss/hdwallet-phantom": "1.55.6",
+ "@shapeshiftoss/hdwallet-portis": "1.55.6",
+ "@shapeshiftoss/hdwallet-tallyho": "1.55.6",
+ "@shapeshiftoss/hdwallet-trezor": "1.55.6",
+ "@shapeshiftoss/hdwallet-trezor-connect": "1.55.6",
+ "@shapeshiftoss/hdwallet-walletconnect": "1.55.6",
+ "@shapeshiftoss/hdwallet-walletconnectv2": "1.55.6",
+ "@shapeshiftoss/hdwallet-xdefi": "1.55.6",
"bip32": "^2.0.4",
"eip-712": "^1.0.0",
"jquery": "^3.7.1",
diff --git a/integration/package.json b/integration/package.json
index 8a964fe63..5e1b8b031 100644
--- a/integration/package.json
+++ b/integration/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/integration",
- "version": "1.55.5",
+ "version": "1.55.6",
"main": "index.js",
"license": "MIT",
"private": true,
@@ -10,15 +10,15 @@
"dev": "lerna run test --scope integration --parallel --include-filtered-dependencies"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey-nodewebusb": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey-tcp": "1.55.5",
- "@shapeshiftoss/hdwallet-ledger": "1.55.5",
- "@shapeshiftoss/hdwallet-native": "1.55.5",
- "@shapeshiftoss/hdwallet-portis": "1.55.5",
- "@shapeshiftoss/hdwallet-trezor": "1.55.5",
- "@shapeshiftoss/hdwallet-xdefi": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey-nodewebusb": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey-tcp": "1.55.6",
+ "@shapeshiftoss/hdwallet-ledger": "1.55.6",
+ "@shapeshiftoss/hdwallet-native": "1.55.6",
+ "@shapeshiftoss/hdwallet-portis": "1.55.6",
+ "@shapeshiftoss/hdwallet-trezor": "1.55.6",
+ "@shapeshiftoss/hdwallet-xdefi": "1.55.6",
"fast-json-stable-stringify": "^2.1.0",
"msw": "^0.27.1",
"whatwg-fetch": "^3.6.2"
diff --git a/lerna.json b/lerna.json
index d474d95b4..6b41bc3e9 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,6 +1,6 @@
{
"lerna": "5.2.0",
- "version": "1.55.5",
+ "version": "1.55.6",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
diff --git a/packages/hdwallet-coinbase/package.json b/packages/hdwallet-coinbase/package.json
index f93eab7bd..baa8a2acb 100644
--- a/packages/hdwallet-coinbase/package.json
+++ b/packages/hdwallet-coinbase/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-coinbase",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,7 +15,7 @@
},
"dependencies": {
"@coinbase/wallet-sdk": "^3.6.6",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"eth-rpc-errors": "^4.0.3",
"lodash": "^4.17.21"
},
diff --git a/packages/hdwallet-core/package.json b/packages/hdwallet-core/package.json
index 08eb9e6f2..53c5a67e5 100644
--- a/packages/hdwallet-core/package.json
+++ b/packages/hdwallet-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-core",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
diff --git a/packages/hdwallet-keepkey-chromeusb/package.json b/packages/hdwallet-keepkey-chromeusb/package.json
index d7391cf82..52e79af52 100644
--- a/packages/hdwallet-keepkey-chromeusb/package.json
+++ b/packages/hdwallet-keepkey-chromeusb/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey-chromeusb",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5"
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6"
}
}
diff --git a/packages/hdwallet-keepkey-electron/package.json b/packages/hdwallet-keepkey-electron/package.json
index ac024a86a..27849cefe 100644
--- a/packages/hdwallet-keepkey-electron/package.json
+++ b/packages/hdwallet-keepkey-electron/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey-electron",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6",
"uuid": "^8.3.2"
},
"peerDependencies": {
diff --git a/packages/hdwallet-keepkey-nodehid/package.json b/packages/hdwallet-keepkey-nodehid/package.json
index 3d3b638e4..9ed6ce3e4 100644
--- a/packages/hdwallet-keepkey-nodehid/package.json
+++ b/packages/hdwallet-keepkey-nodehid/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey-nodehid",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5"
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6"
},
"peerDependencies": {
"node-hid": "^2.1.1"
diff --git a/packages/hdwallet-keepkey-nodewebusb/package.json b/packages/hdwallet-keepkey-nodewebusb/package.json
index 5b662d7bd..25822cb38 100644
--- a/packages/hdwallet-keepkey-nodewebusb/package.json
+++ b/packages/hdwallet-keepkey-nodewebusb/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey-nodewebusb",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,8 +14,8 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5"
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6"
},
"peerDependencies": {
"usb": "^2.3.1"
diff --git a/packages/hdwallet-keepkey-tcp/package.json b/packages/hdwallet-keepkey-tcp/package.json
index af259f49a..6e4d800f5 100644
--- a/packages/hdwallet-keepkey-tcp/package.json
+++ b/packages/hdwallet-keepkey-tcp/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey-tcp",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,8 +14,8 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6",
"axios": "^0.21.1"
}
}
diff --git a/packages/hdwallet-keepkey-webusb/package.json b/packages/hdwallet-keepkey-webusb/package.json
index 3fc429e7d..7c08eccc4 100644
--- a/packages/hdwallet-keepkey-webusb/package.json
+++ b/packages/hdwallet-keepkey-webusb/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey-webusb",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,8 +14,8 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-keepkey": "1.55.5"
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-keepkey": "1.55.6"
},
"devDependencies": {
"@types/w3c-web-usb": "^1.0.4"
diff --git a/packages/hdwallet-keepkey/package.json b/packages/hdwallet-keepkey/package.json
index f9fbb8722..ea0ca354f 100644
--- a/packages/hdwallet-keepkey/package.json
+++ b/packages/hdwallet-keepkey/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keepkey",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -20,7 +20,7 @@
"@keepkey/device-protocol": "^7.12.2",
"@metamask/eth-sig-util": "^7.0.0",
"@shapeshiftoss/bitcoinjs-lib": "5.2.0-shapeshift.2",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"@shapeshiftoss/proto-tx-builder": "^0.8.0",
"bignumber.js": "^9.0.1",
"bnb-javascript-sdk-nobroadcast": "^2.16.14",
diff --git a/packages/hdwallet-keplr/package.json b/packages/hdwallet-keplr/package.json
index 5867ef595..88b4a7434 100644
--- a/packages/hdwallet-keplr/package.json
+++ b/packages/hdwallet-keplr/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-keplr",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,7 +15,7 @@
},
"dependencies": {
"@shapeshiftoss/caip": "8.15.0",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"@shapeshiftoss/proto-tx-builder": "^0.8.0",
"@shapeshiftoss/types": "3.1.3",
"base64-js": "^1.5.1",
diff --git a/packages/hdwallet-ledger-webhid/package.json b/packages/hdwallet-ledger-webhid/package.json
index 9302ca9c3..b71ecd952 100644
--- a/packages/hdwallet-ledger-webhid/package.json
+++ b/packages/hdwallet-ledger-webhid/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-ledger-webhid",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -19,8 +19,8 @@
"@ledgerhq/hw-transport": "^6.31.2",
"@ledgerhq/hw-transport-webhid": "^6.29.2",
"@ledgerhq/live-common": "^21.8.2",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-ledger": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-ledger": "1.55.6",
"@types/w3c-web-hid": "^1.0.2"
},
"devDependencies": {
diff --git a/packages/hdwallet-ledger-webusb/package.json b/packages/hdwallet-ledger-webusb/package.json
index 1bb60f3b0..cb39bdbba 100644
--- a/packages/hdwallet-ledger-webusb/package.json
+++ b/packages/hdwallet-ledger-webusb/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-ledger-webusb",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -20,8 +20,8 @@
"@ledgerhq/hw-transport-webusb": "^6.29.2",
"@ledgerhq/live-common": "^21.8.2",
"@ledgerhq/logs": "^6.10.1",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-ledger": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-ledger": "1.55.6",
"@types/w3c-web-usb": "^1.0.4",
"p-queue": "^7.4.1"
},
diff --git a/packages/hdwallet-ledger/package.json b/packages/hdwallet-ledger/package.json
index bd838a6b7..fd547d79c 100644
--- a/packages/hdwallet-ledger/package.json
+++ b/packages/hdwallet-ledger/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-ledger",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -19,7 +19,7 @@
"@ethereumjs/tx": "^3.3.0",
"@ledgerhq/hw-app-cosmos": "^6.29.1",
"@shapeshiftoss/bitcoinjs-lib": "5.2.0-shapeshift.2",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"base64-js": "^1.5.1",
"bchaddrjs": "^0.4.4",
"bitcoinjs-message": "^2.0.0",
diff --git a/packages/hdwallet-metamask-shapeshift-multichain/package.json b/packages/hdwallet-metamask-shapeshift-multichain/package.json
index f16c724c3..66734796b 100644
--- a/packages/hdwallet-metamask-shapeshift-multichain/package.json
+++ b/packages/hdwallet-metamask-shapeshift-multichain/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-shapeshift-multichain",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -17,7 +17,7 @@
"@metamask/detect-provider": "^1.2.0",
"@metamask/onboarding": "^1.0.1",
"@shapeshiftoss/common-api": "^9.3.0",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"@shapeshiftoss/metamask-snaps-adapter": "^1.0.10",
"@shapeshiftoss/metamask-snaps-types": "^1.0.10",
"eth-rpc-errors": "^4.0.3",
diff --git a/packages/hdwallet-metamask/package.json b/packages/hdwallet-metamask/package.json
index 5927fc4e3..528a3d837 100644
--- a/packages/hdwallet-metamask/package.json
+++ b/packages/hdwallet-metamask/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-metamask",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -16,7 +16,7 @@
"dependencies": {
"@metamask/detect-provider": "^1.2.0",
"@metamask/onboarding": "^1.0.1",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"eth-rpc-errors": "^4.0.3",
"lodash": "^4.17.21"
},
diff --git a/packages/hdwallet-native-vault/package.json b/packages/hdwallet-native-vault/package.json
index 1bec662a3..67fe8c531 100644
--- a/packages/hdwallet-native-vault/package.json
+++ b/packages/hdwallet-native-vault/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-native-vault",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-native": "1.55.5",
+ "@shapeshiftoss/hdwallet-native": "1.55.6",
"bip39": "^3.0.4",
"hash-wasm": "^4.11.0",
"idb-keyval": "^6.0.3",
diff --git a/packages/hdwallet-native/package.json b/packages/hdwallet-native/package.json
index 7043d1b29..72d8c5677 100644
--- a/packages/hdwallet-native/package.json
+++ b/packages/hdwallet-native/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-native",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -16,7 +16,7 @@
"dependencies": {
"@shapeshiftoss/bitcoinjs-lib": "5.2.0-shapeshift.2",
"@shapeshiftoss/fiosdk": "1.2.1-shapeshift.6",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"@shapeshiftoss/proto-tx-builder": "^0.8.0",
"@zxing/text-encoding": "^0.9.0",
"bchaddrjs": "^0.4.9",
diff --git a/packages/hdwallet-phantom/package.json b/packages/hdwallet-phantom/package.json
index ba5fb4fae..238194a75 100644
--- a/packages/hdwallet-phantom/package.json
+++ b/packages/hdwallet-phantom/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-phantom",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,7 +15,7 @@
},
"dependencies": {
"@shapeshiftoss/bitcoinjs-lib": "5.2.0-shapeshift.2",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"base64-js": "^1.5.1",
"bitcoinjs-message": "^2.0.0",
"lodash": "^4.17.21"
diff --git a/packages/hdwallet-portis/package.json b/packages/hdwallet-portis/package.json
index 05429184e..08b422d30 100644
--- a/packages/hdwallet-portis/package.json
+++ b/packages/hdwallet-portis/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-portis",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,7 +15,7 @@
},
"dependencies": {
"@portis/web3": "3.0.10",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"base64-js": "^1.5.1",
"bip32": "^2.0.4",
"bitcoinjs-lib": "^5.1.6",
diff --git a/packages/hdwallet-tallyho/package.json b/packages/hdwallet-tallyho/package.json
index 4218e5c5c..6f2383f1b 100644
--- a/packages/hdwallet-tallyho/package.json
+++ b/packages/hdwallet-tallyho/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-tallyho",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"lodash": "^4.17.21",
"tallyho-onboarding": "^1.0.2"
},
diff --git a/packages/hdwallet-trezor-connect/package.json b/packages/hdwallet-trezor-connect/package.json
index 8ce6ca263..bc7d772a6 100644
--- a/packages/hdwallet-trezor-connect/package.json
+++ b/packages/hdwallet-trezor-connect/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-trezor-connect",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,8 +14,8 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
- "@shapeshiftoss/hdwallet-trezor": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
+ "@shapeshiftoss/hdwallet-trezor": "1.55.6",
"@trezor/rollout": "^1.2.0",
"trezor-connect": "^8.2.1"
}
diff --git a/packages/hdwallet-trezor/package.json b/packages/hdwallet-trezor/package.json
index 868635e0c..004e3575e 100644
--- a/packages/hdwallet-trezor/package.json
+++ b/packages/hdwallet-trezor/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-trezor",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -17,7 +17,7 @@
"dependencies": {
"@ethereumjs/common": "^2.4.0",
"@ethereumjs/tx": "^3.3.0",
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"base64-js": "^1.5.1",
"lodash": "^4.17.21"
},
diff --git a/packages/hdwallet-walletconnect/package.json b/packages/hdwallet-walletconnect/package.json
index b8ce276e2..7e62e6dcf 100644
--- a/packages/hdwallet-walletconnect/package.json
+++ b/packages/hdwallet-walletconnect/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-walletconnect",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,7 +15,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"@walletconnect/qrcode-modal": "^1.7.8",
"@walletconnect/web3-provider": "^1.7.8",
"ethers": "^5.6.5"
diff --git a/packages/hdwallet-walletconnectV2/package.json b/packages/hdwallet-walletconnectV2/package.json
index 20622130f..ccc929665 100644
--- a/packages/hdwallet-walletconnectV2/package.json
+++ b/packages/hdwallet-walletconnectV2/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-walletconnectv2",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -15,7 +15,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"@walletconnect/ethereum-provider": "^2.10.1",
"@walletconnect/modal": "^2.6.2",
"ethers": "^5.6.5"
diff --git a/packages/hdwallet-xdefi/package.json b/packages/hdwallet-xdefi/package.json
index 57f24e1fe..c1e9b06d8 100644
--- a/packages/hdwallet-xdefi/package.json
+++ b/packages/hdwallet-xdefi/package.json
@@ -1,6 +1,6 @@
{
"name": "@shapeshiftoss/hdwallet-xdefi",
- "version": "1.55.5",
+ "version": "1.55.6",
"license": "MIT",
"publishConfig": {
"access": "public"
@@ -14,7 +14,7 @@
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
- "@shapeshiftoss/hdwallet-core": "1.55.5",
+ "@shapeshiftoss/hdwallet-core": "1.55.6",
"lodash": "^4.17.21"
},
"devDependencies": {