Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tally wallet #506

Merged
merged 78 commits into from
May 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
7781611
Add Tally HD wallet
0xzoz Apr 4, 2022
81166be
First pass - add tally as a hdwallet
0xzoz Apr 7, 2022
0ecada7
Modify tallyho-onboarding import
0xzoz Apr 7, 2022
8481ba8
Add tally to tsconfig
0xzoz Apr 8, 2022
948ce8b
Remove used type
0xzoz Apr 8, 2022
7d7e637
Remove Metamask references
0xzoz Apr 8, 2022
07cc87b
Reorder deps
0xzoz Apr 8, 2022
586fb9a
Make functions async
0xzoz Apr 8, 2022
0fcae1c
Fix package import
0xzoz Apr 8, 2022
5c4d9c8
Update packages/hdwallet-tally/tsconfig.json
0xzoz Apr 8, 2022
4e3a838
Update packages/hdwallet-tally/package.json
0xzoz Apr 8, 2022
0b0e667
Fix init function
0xzoz Apr 8, 2022
ed959f6
Merge branch 'add-tally-wallet' of https://github.com/0xzoz/hdwallet …
0xzoz Apr 8, 2022
4c5318c
Remove unneccesary functions and properties
0xzoz Apr 8, 2022
66a876a
Fix hdwallet-tally versioning
0xzoz Apr 8, 2022
273f353
Remove unneccesary properties
0xzoz Apr 8, 2022
8d12504
Remove TallyTransport function and references
0xzoz Apr 8, 2022
44c2ba6
Inject provider from adapter
0xzoz Apr 11, 2022
04a5333
Add adapter test
0xzoz Apr 12, 2022
b941445
Add ethereum test
0xzoz Apr 12, 2022
d599527
Add index test
0xzoz Apr 12, 2022
ba4518d
Fix isolated modules error
0xzoz Apr 12, 2022
e78237e
Fix isolated modules error
0xzoz Apr 12, 2022
56739fa
Fix tally test errors
0xzoz Apr 12, 2022
ddd480b
Fix tally test errors
0xzoz Apr 13, 2022
403a8bf
Fix Tally tests to pass
0xzoz Apr 14, 2022
97bd37a
Fix Tally tests to pass
0xzoz Apr 14, 2022
35a2712
Change error wording to match prod error
0xzoz Apr 15, 2022
399ebe1
Update packages/hdwallet-tally/src/tally.ts
0xzoz Apr 15, 2022
371d1df
Add test button in sandbox
0xzoz Apr 15, 2022
a3b9c7e
Merge branch 'add-tally-wallet' of https://github.com/0xzoz/hdwallet …
0xzoz Apr 15, 2022
1c32bf2
Fix name
0xzoz Apr 15, 2022
3e307a6
merge conflicts
0xzoz Apr 18, 2022
bcb5eae
Fix conflicts
0xzoz Apr 18, 2022
743c72b
Fix lint issues
0xzoz Apr 20, 2022
47e150a
Merge branch 'master' into add-tally-wallet
0xzoz Apr 20, 2022
0864019
Address merge issue with xDefi casing
0xzoz Apr 22, 2022
fa79588
Fix lockfile
0xzoz Apr 22, 2022
2390e4e
Merge branch 'shapeshift:master' into add-tally-wallet
0xzoz Apr 22, 2022
0c142aa
Downgrade typescript version
0xzoz Apr 25, 2022
1548023
Merge branch 'add-tally-wallet' of https://github.com/0xzoz/hdwallet …
0xzoz Apr 25, 2022
38d9522
Downgrade typescript version
0xzoz Apr 25, 2022
079901b
Fix typo
0xzoz Apr 25, 2022
dc92d5d
Fix yarn.lock
0xzoz Apr 25, 2022
3540db3
Fix yarn.lock
0xzoz Apr 25, 2022
468bb59
Fix typo
0xzoz Apr 25, 2022
4200e45
Fix xDEFI typo
0xzoz Apr 25, 2022
eac4450
Update tsconfig.json
0xzoz Apr 28, 2022
adb18b5
Update integration/src/wallets/tally.ts
0xzoz Apr 28, 2022
19ae7aa
Update package.json
0xzoz Apr 28, 2022
dd5d8da
Update packages/hdwallet-tally/src/adapter.ts
0xzoz Apr 28, 2022
132c06e
Update packages/hdwallet-tally/src/adapter.ts
0xzoz Apr 28, 2022
b52c472
Update packages/hdwallet-tally/src/adapter.ts
0xzoz Apr 28, 2022
66513b1
Update packages/hdwallet-tally/src/adapter.ts
0xzoz Apr 28, 2022
beb80dd
Update packages/hdwallet-tally/src/adapter.ts
0xzoz Apr 28, 2022
66f0e2e
Fix linting and testing issues after previous commits
0xzoz Apr 28, 2022
568ce3d
Update packages/hdwallet-tally/src/ethereum.ts
0xzoz Apr 28, 2022
cf85c7e
Update packages/hdwallet-tally/src/ethereum.ts
0xzoz Apr 28, 2022
7dccbd2
Update packages/hdwallet-tally/src/tally.ts
0xzoz Apr 28, 2022
08cc3dc
Update packages/hdwallet-tally/src/tally.ts
0xzoz Apr 28, 2022
8d2ab92
Update packages/hdwallet-tally/src/tally.ts
0xzoz Apr 28, 2022
1f88543
Update packages/hdwallet-tally/tsconfig.json
0xzoz Apr 28, 2022
9c47622
Update packages/hdwallet-xdefi/tsconfig.json
0xzoz Apr 28, 2022
812cfb1
Remove private from public var
0xzoz Apr 28, 2022
6599597
fix lint issue
0xzoz Apr 28, 2022
6d002fa
downgrade ts version
0xzoz May 10, 2022
53e1c79
Rename tally > tally ho due to branding change
0xzoz May 11, 2022
ae3a726
Fix build issue - name change
0xzoz May 11, 2022
70af112
Fix lint issues
0xzoz May 11, 2022
42d41cb
Rename folder to match package naming
0xzoz May 11, 2022
badf43c
Rename to match package naming
0xzoz May 11, 2022
06e8a32
Remove MM dependancies for Tally
0xzoz May 11, 2022
435ea5c
Remove noop
0xzoz May 11, 2022
d02c69f
Merge branch 'shapeshift:master' into add-tally-wallet
0xzoz May 12, 2022
2bad1a8
Add try/catch
0xzoz May 12, 2022
a261f6f
Merge branch 'add-tally-wallet' of https://github.com/0xzoz/hdwallet …
0xzoz May 12, 2022
904bde5
Make function private
0xzoz May 12, 2022
067ac70
Add commenting
0xzoz May 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/sandbox/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ <h4>Select</h4>
<button id="portis">Pair Portis</button>
<button id="native">Pair Native</button>
<button id="metaMask">Pair MetaMask</button>
<button id="xdefi">Pair XDEFI</button>
<button id="tallyHo">Pair Tally Ho</button>
<button id="xdefi">Pair XDeFi</button>

<select id="keyring" style="height: 100px" size="4"></select>
</div>
Expand Down
23 changes: 23 additions & 0 deletions examples/sandbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as ledgerWebUSB from "@shapeshiftoss/hdwallet-ledger-webusb";
import * as metaMask from "@shapeshiftoss/hdwallet-metamask";
import * as native from "@shapeshiftoss/hdwallet-native";
import * as portis from "@shapeshiftoss/hdwallet-portis";
import * as tallyHo from "@shapeshiftoss/hdwallet-tallyho";
import * as trezorConnect from "@shapeshiftoss/hdwallet-trezor-connect";
import * as xdefi from "@shapeshiftoss/hdwallet-xdefi";
import $ from "jquery";
Expand Down Expand Up @@ -64,6 +65,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 tallyHoAdapter = tallyHo.TallyHoAdapter.useKeyring(keyring);
const xdefiAdapter = xdefi.XDEFIAdapter.useKeyring(keyring);
const nativeAdapter = native.NativeAdapter.useKeyring(keyring, {
mnemonic,
Expand Down Expand Up @@ -95,6 +97,7 @@ const $ledgerwebhid = $("#ledgerwebhid");
const $portis = $("#portis");
const $native = $("#native");
const $metaMask = $("#metaMask");
const $tallyHo = $("#tallyHo");
const $xdefi = $("#xdefi");
const $keyring = $("#keyring");

Expand Down Expand Up @@ -181,6 +184,20 @@ $metaMask.on("click", async (e) => {
console.error(error);
}
});

$tallyHo.on("click", async (e) => {
e.preventDefault();
wallet = await tallyHoAdapter.pairDevice();
window["wallet"] = wallet;
let deviceID = "nothing";
try {
deviceID = await wallet.getDeviceID();
$("#keyring select").val(deviceID);
} catch (error) {
console.error(error);
}
});

$xdefi.on("click", async (e) => {
e.preventDefault();
wallet = await xdefiAdapter.pairDevice("testid");
Expand Down Expand Up @@ -275,6 +292,12 @@ async function deviceConnected(deviceId) {
console.error("Could not initialize MetaMaskAdapter", e);
}

try {
await tallyHoAdapter.initialize();
} catch (e) {
console.error("Could not initialize TallyHoAdapter", e);
}

for (const deviceID of Object.keys(keyring.wallets)) {
await deviceConnected(deviceID);
}
Expand Down
2 changes: 2 additions & 0 deletions integration/src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as ledger from "@shapeshiftoss/hdwallet-ledger";
import * as metamask from "@shapeshiftoss/hdwallet-metamask";
import * as native from "@shapeshiftoss/hdwallet-native";
import * as portis from "@shapeshiftoss/hdwallet-portis";
import * as tallyHo from "@shapeshiftoss/hdwallet-tallyho";
import * as trezor from "@shapeshiftoss/hdwallet-trezor";
import * as xdefi from "@shapeshiftoss/hdwallet-xdefi";

Expand Down Expand Up @@ -54,6 +55,7 @@ export function integration(suite: WalletSuite): void {
(portis.isPortis(wallet) ? 1 : 0) +
(native.isNative(wallet) ? 1 : 0) +
(metamask.isMetaMask(wallet) ? 1 : 0) +
(tallyHo.isTallyHo(wallet) ? 1 : 0) +
(xdefi.isXDEFI(wallet) ? 1 : 0)
).toEqual(1);
});
Expand Down
166 changes: 166 additions & 0 deletions integration/src/wallets/tallyho.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import * as core from "@shapeshiftoss/hdwallet-core";
import * as tallyHo from "@shapeshiftoss/hdwallet-tallyho";

export function name(): string {
return "Tally Ho";
}

export function createInfo(): core.HDWalletInfo {
return new tallyHo.TallyHoHDWalletInfo();
}

export async function createWallet(): Promise<core.HDWallet> {
const provider = {
request: jest.fn(({ method, params }: any) => {
switch (method) {
case "eth_accounts":
return ["0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8"];
case "personal_sign": {
const [message] = params;

if (message === "48656c6c6f20576f726c64")
return "0x29f7212ecc1c76cea81174af267b67506f754ea8c73f144afa900a0d85b24b21319621aeb062903e856352f38305710190869c3ce5a1425d65ef4fa558d0fc251b";

throw new Error("unknown message");
}
case "eth_sendTransaction": {
const [{ to }] = params;

return `txHash-${to}`;
}
default:
throw new Error(`ethereum: Unknown method ${method}`);
}
}),
};
const wallet = new tallyHo.TallyHoHDWallet(provider);
await wallet.initialize();
return wallet;
}

export function selfTest(get: () => core.HDWallet): void {
let wallet: tallyHo.TallyHoHDWallet;

beforeAll(async () => {
const w = get() as tallyHo.TallyHoHDWallet;

if (tallyHo.isTallyHo(w) && !core.supportsBTC(w) && core.supportsETH(w)) {
wallet = w;
} else {
throw "Wallet is not a Tally";
}
});

it("supports Ethereum mainnet", async () => {
if (!wallet) return;
expect(await wallet.ethSupportsNetwork()).toEqual(true);
});

it("does not support BTC", async () => {
if (!wallet) return;
expect(core.supportsBTC(wallet)).toBe(false);
});

it("does not support Native ShapeShift", async () => {
if (!wallet) return;
expect(wallet.ethSupportsNativeShapeShift()).toEqual(false);
});

it("does support EIP1559", async () => {
if (!wallet) return;
expect(await wallet.ethSupportsEIP1559()).toEqual(true);
});

it("does not support Secure Transfer", async () => {
if (!wallet) return;
expect(await wallet.ethSupportsSecureTransfer()).toEqual(false);
});

it("uses correct eth bip44 paths", () => {
if (!wallet) return;
[0, 1, 3, 27].forEach((account) => {
const paths = wallet.ethGetAccountPaths({
coin: "Ethereum",
accountIdx: account,
});
expect(paths).toEqual([
{
addressNList: core.bip32ToAddressNList(`m/44'/60'/${account}'/0/0`),
hardenedPath: core.bip32ToAddressNList(`m/44'/60'/${account}'`),
relPath: [0, 0],
description: "TallyHo",
},
]);
paths.forEach((path) => {
expect(
wallet.describePath({
coin: "Ethereum",
path: path.addressNList,
}).isKnown
).toBeTruthy();
});
});
});

it("can describe ETH paths", () => {
if (!wallet) return;
expect(
wallet.describePath({
path: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
coin: "Ethereum",
})
).toEqual({
verbose: "Ethereum Account #0",
coin: "Ethereum",
isKnown: true,
accountIdx: 0,
wholeAccount: true,
});

expect(
wallet.describePath({
path: core.bip32ToAddressNList("m/44'/60'/3'/0/0"),
coin: "Ethereum",
})
).toEqual({
verbose: "Ethereum Account #3",
coin: "Ethereum",
isKnown: true,
accountIdx: 3,
wholeAccount: true,
});

expect(
wallet.describePath({
path: core.bip32ToAddressNList("m/44'/60'/0'/0/3"),
coin: "Ethereum",
})
).toEqual({
verbose: "m/44'/60'/0'/0/3",
coin: "Ethereum",
isKnown: false,
});
});

it("should return a valid ETH address", async () => {
if (!wallet) return;
expect(
await wallet.ethGetAddress({
addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
showDisplay: false,
})
).toEqual("0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8");
});

it("should sign a message", async () => {
if (!wallet) return;
const res = await wallet.ethSignMessage({
addressNList: core.bip32ToAddressNList("m/44'/60'/0'/0/0"),
message: "Hello World",
});
expect(res?.address).toEqual("0x3f2329C9ADFbcCd9A84f52c906E936A42dA18CB8");
expect(res?.signature).toEqual(
"0x29f7212ecc1c76cea81174af267b67506f754ea8c73f144afa900a0d85b24b21319621aeb062903e856352f38305710190869c3ce5a1425d65ef4fa558d0fc251b"
);
});
}
25 changes: 25 additions & 0 deletions packages/hdwallet-tallyho/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@shapeshiftoss/hdwallet-tallyho",
"version": "1.19.0",
"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 tsconfig.tsbuildinfo",
"prepublishOnly": "yarn clean && yarn build"
},
"dependencies": {
"@shapeshiftoss/hdwallet-core": "1.19.0",
0xzoz marked this conversation as resolved.
Show resolved Hide resolved
"lodash": "^4.17.21",
"tallyho-onboarding": "^1.0.2"
},
"devDependencies": {
"@types/lodash": "^4.14.168",
"typescript": "^4.3.2"
}
}
11 changes: 11 additions & 0 deletions packages/hdwallet-tallyho/src/adapter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as core from "@shapeshiftoss/hdwallet-core";

import { TallyHoAdapter } from "./adapter";

describe("TallyHoAdapter", () => {
it("throws error if provider is not preset", async () => {
const keyring = new core.Keyring();
const adapter = TallyHoAdapter.useKeyring(keyring);
await expect(async () => await adapter.pairDevice()).rejects.toThrowError("Could not get Tally Ho accounts.");
});
});
99 changes: 99 additions & 0 deletions packages/hdwallet-tallyho/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import * as core from "@shapeshiftoss/hdwallet-core";
import TallyHoOnboarding from "tallyho-onboarding";

import { TallyHoHDWallet } from "./tallyho";

interface TallyHoEthereumProvider {
isTally?: boolean;
}

interface Window {
ethereum?: TallyHoEthereumProvider;
}

export class TallyHoAdapter {
keyring: core.Keyring;

private constructor(keyring: core.Keyring) {
this.keyring = keyring;
}

public static useKeyring(keyring: core.Keyring) {
return new TallyHoAdapter(keyring);
}

public async pairDevice(): Promise<TallyHoHDWallet> {
let provider: any;
// eslint-disable-next-line no-useless-catch
try {
provider = await this.detectTallyProvider();
} catch (error) {
throw error;
}
if (!provider) {
const onboarding = new TallyHoOnboarding();
onboarding.startOnboarding();
console.error("Please install Tally Ho!");
}
if (provider === null) {
throw new Error("Could not get Tally Ho accounts.");
}

// eslint-disable-next-line no-useless-catch
try {
await provider.request({ method: "eth_requestAccounts" });
} catch (error) {
throw error;
}
const wallet = new TallyHoHDWallet(provider);
const deviceID = await wallet.getDeviceID();
this.keyring.add(wallet, deviceID);
this.keyring.emit(["Tally Ho", deviceID, core.Events.CONNECT], deviceID);

return wallet;
}

/*
* Tally works the same way as metamask.
* This code is copied from the @metamask/detect-provider package
* @see https://www.npmjs.com/package/@metamask/detect-provider
*/
private async detectTallyProvider(): Promise<TallyHoEthereumProvider | null> {
let handled = false;

return new Promise((resolve) => {
0xzoz marked this conversation as resolved.
Show resolved Hide resolved
if ((window as Window).ethereum) {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
handleEthereum();
} else {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
window.addEventListener("ethereum#initialized", handleEthereum, { once: true });

setTimeout(() => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
handleEthereum();
}, 3000);
}

function handleEthereum() {
if (handled) {
return;
}
handled = true;

window.removeEventListener("ethereum#initialized", handleEthereum);

const { ethereum } = window as Window;

if (ethereum && ethereum.isTally) {
resolve(ethereum as unknown as TallyHoEthereumProvider);
} else {
const message = ethereum ? "Non-TallyHo window.ethereum detected." : "Unable to detect window.ethereum.";

console.error("hdwallet-tallyho: ", message);
resolve(null);
}
}
});
}
}
Loading