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

dry out describe path functions #420

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 9 additions & 22 deletions integration/src/thorchain/thorchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,17 @@ export function thorchainTests(get: () => { wallet: core.HDWallet; info: core.HD
coin: "Thorchain",
});

// This is strange, and probably wrong, behavior... but it's what happens.
if (wallet.getVendor() === "KeepKey") {
// eslint-disable-next-line jest/no-conditional-expect
expect(out).toMatchInlineSnapshot(`
// eslint-disable-next-line jest/no-conditional-expect
expect(out).toMatchInlineSnapshot(`
Object {
"coin": "Thorchain",
"isKnown": false,
"scriptType": undefined,
"verbose": "m/44'/931'/0'/0/0",
"accountIdx": 0,
"coin": "Rune",
"isKnown": true,
"isPrefork": false,
"verbose": "THORChain Account #0",
"wholeAccount": true,
}
`);
} else {
// eslint-disable-next-line jest/no-conditional-expect
expect(out).toMatchInlineSnapshot(`
Object {
"accountIdx": 0,
"coin": "Thorchain",
"isKnown": true,
"isPrefork": false,
"verbose": "Thorchain Account #0",
"wholeAccount": true,
}
`);
}
`);
},
TIMEOUT
);
Expand Down
11 changes: 8 additions & 3 deletions integration/src/wallets/ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,15 @@ export function selfTest(get: () => core.HDWallet): void {
scriptType: core.BTCInputScriptType.SpendAddress,
})
).toEqual({
verbose: "m/44'/0'/7'/1/5",
accountIdx: 7,
addressIdx: 5,
verbose: "BitcoinCash Account #7, Change Address #5 (Prefork)",
coin: "BitcoinCash",
scriptType: core.BTCInputScriptType.SpendAddress,
isKnown: false,
isChange: true,
isKnown: true,
isPrefork: true,
wholeAccount: false,
});

expect(
Expand Down Expand Up @@ -450,7 +455,7 @@ export function selfTest(get: () => core.HDWallet): void {
coin: "Ethereum",
})
).toEqual({
verbose: "Ethereum Account #42",
verbose: "Ethereum Account #42 (Legacy)",
coin: "Ethereum",
isKnown: true,
wholeAccount: true,
Expand Down
2 changes: 2 additions & 0 deletions integration/src/wallets/metamask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export function selfTest(get: () => core.HDWallet): void {
verbose: "Ethereum Account #0",
coin: "Ethereum",
isKnown: true,
isPrefork: false,
accountIdx: 0,
wholeAccount: true,
});
Expand All @@ -126,6 +127,7 @@ export function selfTest(get: () => core.HDWallet): void {
verbose: "Ethereum Account #3",
coin: "Ethereum",
isKnown: true,
isPrefork: false,
accountIdx: 3,
wholeAccount: true,
});
Expand Down
2 changes: 1 addition & 1 deletion integration/src/wallets/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export function selfTest(get: () => core.HDWallet): void {
coin: "Litecoin",
isKnown: true,
scriptType: "p2wpkh",
verbose: "Litecoin Account #4 (Segwit)",
verbose: "Litecoin Account #4 (Segwit Native)",
wholeAccount: true,
isPrefork: false,
},
Expand Down
9 changes: 7 additions & 2 deletions integration/src/wallets/trezor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,15 @@ export function selfTest(get: () => core.HDWallet): void {
scriptType: core.BTCInputScriptType.SpendAddress,
})
).toEqual({
verbose: "m/44'/0'/7'/1/5",
accountIdx: 7,
addressIdx: 5,
verbose: "BitcoinCash Account #7, Change Address #5 (Prefork)",
coin: "BitcoinCash",
scriptType: core.BTCInputScriptType.SpendAddress,
isKnown: false,
isChange: true,
isKnown: true,
isPrefork: true,
wholeAccount: false,
});

expect(
Expand Down
26 changes: 16 additions & 10 deletions packages/hdwallet-core/src/bitcoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ export function unknownUTXOPath(path: BIP32Path, coin: Coin, scriptType?: BTCInp
};
}

export function describeUTXOPath(path: BIP32Path, coin: Coin, scriptType: BTCInputScriptType): PathDescription {
export function btcDescribePath(path: BIP32Path, coin: Coin, scriptType?: BTCInputScriptType): PathDescription {
const unknown = unknownUTXOPath(path, coin, scriptType);

if (path.length !== 3 && path.length !== 5) return unknown;
Expand All @@ -396,16 +396,22 @@ export function describeUTXOPath(path: BIP32Path, coin: Coin, scriptType: BTCInp

if (purpose === 49 && scriptType !== BTCInputScriptType.SpendP2SHWitness) return unknown;

if (purpose === 84 && !(scriptType === BTCInputScriptType.SpendWitness || scriptType === BTCInputScriptType.Bech32)) {
return unknown;
}

const wholeAccount = path.length === 3;

const script = (
{
[BTCInputScriptType.SpendAddress]: ["Legacy"],
[BTCInputScriptType.SpendP2SHWitness]: [],
[BTCInputScriptType.SpendWitness]: ["Segwit"],
[BTCInputScriptType.Bech32]: ["Segwit Native"],
} as Partial<Record<BTCInputScriptType, string[]>>
)[scriptType];
const script = scriptType
? (
{
[BTCInputScriptType.SpendAddress]: ["Legacy"],
[BTCInputScriptType.SpendP2SHWitness]: [],
[BTCInputScriptType.SpendWitness]: ["Segwit Native"],
[BTCInputScriptType.Bech32]: ["Segwit Native"],
} as Partial<Record<BTCInputScriptType, string[]>>
)[scriptType] ?? []
: [];

let isPrefork = false;
const slip44 = slip44ByCoin(coin);
Expand Down Expand Up @@ -438,7 +444,7 @@ export function describeUTXOPath(path: BIP32Path, coin: Coin, scriptType: BTCInp
case "Litecoin":
case "BitcoinGold":
case "Testnet": {
if (script) attributes = attributes.concat(script);
attributes = attributes.concat(script);
break;
}
default:
Expand Down
40 changes: 40 additions & 0 deletions packages/hdwallet-core/src/eos.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { addressNListToBIP32, PathDescription, slip44ByCoin } from ".";
import { BIP32Path, HDWallet, HDWalletInfo } from "./wallet";

export interface EosGetPublicKey {
Expand Down Expand Up @@ -93,3 +94,42 @@ export interface EosWallet extends EosWalletInfo, HDWallet {
eosGetPublicKey(msg: EosGetPublicKey): Promise<string | null>;
eosSignTx(msg: EosToSignTx): Promise<EosTxSigned | null>;
}

export function eosDescribePath(path: BIP32Path): PathDescription {
const pathStr = addressNListToBIP32(path);
const unknown: PathDescription = {
verbose: pathStr,
coin: "Eos",
isKnown: false,
};

if (path.length != 5) {
return unknown;
}

if (path[0] != 0x80000000 + 44) {
return unknown;
}

if (path[1] != 0x80000000 + slip44ByCoin("Eos")) {
return unknown;
}

if ((path[2] & 0x80000000) >>> 0 !== 0x80000000) {
return unknown;
}

if (path[3] !== 0 || path[4] !== 0) {
return unknown;
}

const index = path[2] & 0x7fffffff;
return {
verbose: `Eos Account #${index}`,
accountIdx: index,
wholeAccount: true,
coin: "Eos",
isKnown: true,
isPrefork: false,
};
}
132 changes: 132 additions & 0 deletions packages/hdwallet-core/src/ethereum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { bip32ToAddressNList } from ".";
import { ETHAddressDerivationScheme, ethDescribePath } from "./ethereum";

describe("ethDescribePath", () => {
it("works with BIP44 derivation", async () => {
const describePath = (x: string) =>
ethDescribePath(bip32ToAddressNList(x), ETHAddressDerivationScheme.BIP44).verbose;

expect(describePath("m/1/2/3")).toMatchInlineSnapshot(`"m/1/2/3"`);
expect(describePath("m/44'/123")).toMatchInlineSnapshot(`"m/44'/123"`);
expect(describePath("m/44'/123'")).toMatchInlineSnapshot(`"m/44'/123'"`);
expect(describePath("m/44'/123'/0")).toMatchInlineSnapshot(`"m/44'/123'/0"`);
expect(describePath("m/44'/123'/0'")).toMatchInlineSnapshot(`"m/44'/123'/0'"`);
expect(describePath("m/44'/123'/0'/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0"`);
expect(describePath("m/44'/123'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0/0"`);
expect(describePath("m/44'/0'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/0'/0'/0/0"`);

expect(describePath("m/44'/60'/0'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #0"`);
expect(describePath("m/44'/60'/1'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #1"`);
expect(describePath("m/44'/60'/2'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #2"`);
expect(describePath("m/44'/60'/3'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #3"`);

expect(describePath("m/44'/60'/0'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/1"`);
expect(describePath("m/44'/60'/0'/0/2")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/2"`);
expect(describePath("m/44'/60'/0'/0/3")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/3"`);

expect(describePath("m/44'/60'/1'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/1'/0/1"`);
expect(describePath("m/44'/60'/1'/2/3")).toMatchInlineSnapshot(`"m/44'/60'/1'/2/3"`);
expect(describePath("m/44'/60'/0'/0")).toMatchInlineSnapshot(`"m/44'/60'/0'/0"`);
expect(describePath("m/44'/60'/0'/1")).toMatchInlineSnapshot(`"m/44'/60'/0'/1"`);
expect(describePath("m/44'/60'/0'/2")).toMatchInlineSnapshot(`"m/44'/60'/0'/2"`);
expect(describePath("m/44'/60'/0'/3")).toMatchInlineSnapshot(`"m/44'/60'/0'/3"`);
expect(describePath("m/44'/60'/1'/0")).toMatchInlineSnapshot(`"m/44'/60'/1'/0"`);
expect(describePath("m/44'/60'/1'/2")).toMatchInlineSnapshot(`"m/44'/60'/1'/2"`);
});

it("works with Metamask derivation", async () => {
const describePath = (x: string) =>
ethDescribePath(bip32ToAddressNList(x), ETHAddressDerivationScheme.Metamask).verbose;

expect(describePath("m/1/2/3")).toMatchInlineSnapshot(`"m/1/2/3"`);
expect(describePath("m/44'/123")).toMatchInlineSnapshot(`"m/44'/123"`);
expect(describePath("m/44'/123'")).toMatchInlineSnapshot(`"m/44'/123'"`);
expect(describePath("m/44'/123'/0")).toMatchInlineSnapshot(`"m/44'/123'/0"`);
expect(describePath("m/44'/123'/0'")).toMatchInlineSnapshot(`"m/44'/123'/0'"`);
expect(describePath("m/44'/123'/0'/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0"`);
expect(describePath("m/44'/123'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0/0"`);
expect(describePath("m/44'/0'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/0'/0'/0/0"`);

expect(describePath("m/44'/60'/0'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #0"`);
expect(describePath("m/44'/60'/1'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/1'/0/0"`);
expect(describePath("m/44'/60'/2'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/2'/0/0"`);
expect(describePath("m/44'/60'/3'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/3'/0/0"`);

expect(describePath("m/44'/60'/0'/0/1")).toMatchInlineSnapshot(`"Ethereum Account #1"`);
expect(describePath("m/44'/60'/0'/0/2")).toMatchInlineSnapshot(`"Ethereum Account #2"`);
expect(describePath("m/44'/60'/0'/0/3")).toMatchInlineSnapshot(`"Ethereum Account #3"`);

expect(describePath("m/44'/60'/1'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/1'/0/1"`);
expect(describePath("m/44'/60'/1'/2/3")).toMatchInlineSnapshot(`"m/44'/60'/1'/2/3"`);
expect(describePath("m/44'/60'/0'/0")).toMatchInlineSnapshot(`"m/44'/60'/0'/0"`);
expect(describePath("m/44'/60'/0'/1")).toMatchInlineSnapshot(`"m/44'/60'/0'/1"`);
expect(describePath("m/44'/60'/0'/2")).toMatchInlineSnapshot(`"m/44'/60'/0'/2"`);
expect(describePath("m/44'/60'/0'/3")).toMatchInlineSnapshot(`"m/44'/60'/0'/3"`);
expect(describePath("m/44'/60'/1'/0")).toMatchInlineSnapshot(`"m/44'/60'/1'/0"`);
expect(describePath("m/44'/60'/1'/2")).toMatchInlineSnapshot(`"m/44'/60'/1'/2"`);
});

it("works with OldLedger derivation", async () => {
const describePath = (x: string) =>
ethDescribePath(bip32ToAddressNList(x), ETHAddressDerivationScheme.OldLedger).verbose;

expect(describePath("m/1/2/3")).toMatchInlineSnapshot(`"m/1/2/3"`);
expect(describePath("m/44'/123")).toMatchInlineSnapshot(`"m/44'/123"`);
expect(describePath("m/44'/123'")).toMatchInlineSnapshot(`"m/44'/123'"`);
expect(describePath("m/44'/123'/0")).toMatchInlineSnapshot(`"m/44'/123'/0"`);
expect(describePath("m/44'/123'/0'")).toMatchInlineSnapshot(`"m/44'/123'/0'"`);
expect(describePath("m/44'/123'/0'/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0"`);
expect(describePath("m/44'/123'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0/0"`);
expect(describePath("m/44'/0'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/0'/0'/0/0"`);

expect(describePath("m/44'/60'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/0"`);
expect(describePath("m/44'/60'/1'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/1'/0/0"`);
expect(describePath("m/44'/60'/2'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/2'/0/0"`);
expect(describePath("m/44'/60'/3'/0/0")).toMatchInlineSnapshot(`"m/44'/60'/3'/0/0"`);

expect(describePath("m/44'/60'/0'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/1"`);
expect(describePath("m/44'/60'/0'/0/2")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/2"`);
expect(describePath("m/44'/60'/0'/0/3")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/3"`);

expect(describePath("m/44'/60'/1'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/1'/0/1"`);
expect(describePath("m/44'/60'/1'/2/3")).toMatchInlineSnapshot(`"m/44'/60'/1'/2/3"`);
expect(describePath("m/44'/60'/0'/0")).toMatchInlineSnapshot(`"Ethereum Account #0"`);
expect(describePath("m/44'/60'/0'/1")).toMatchInlineSnapshot(`"Ethereum Account #1"`);
expect(describePath("m/44'/60'/0'/2")).toMatchInlineSnapshot(`"Ethereum Account #2"`);
expect(describePath("m/44'/60'/0'/3")).toMatchInlineSnapshot(`"Ethereum Account #3"`);
expect(describePath("m/44'/60'/1'/0")).toMatchInlineSnapshot(`"m/44'/60'/1'/0"`);
expect(describePath("m/44'/60'/1'/2")).toMatchInlineSnapshot(`"m/44'/60'/1'/2"`);
});

it("works with Ledger derivation", async () => {
const describePath = (x: string) =>
ethDescribePath(bip32ToAddressNList(x), ETHAddressDerivationScheme.Ledger).verbose;

expect(describePath("m/1/2/3")).toMatchInlineSnapshot(`"m/1/2/3"`);
expect(describePath("m/44'/123")).toMatchInlineSnapshot(`"m/44'/123"`);
expect(describePath("m/44'/123'")).toMatchInlineSnapshot(`"m/44'/123'"`);
expect(describePath("m/44'/123'/0")).toMatchInlineSnapshot(`"m/44'/123'/0"`);
expect(describePath("m/44'/123'/0'")).toMatchInlineSnapshot(`"m/44'/123'/0'"`);
expect(describePath("m/44'/123'/0'/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0"`);
expect(describePath("m/44'/123'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/123'/0'/0/0"`);
expect(describePath("m/44'/0'/0'/0/0")).toMatchInlineSnapshot(`"m/44'/0'/0'/0/0"`);

expect(describePath("m/44'/60'/0'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #0"`);
expect(describePath("m/44'/60'/1'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #1"`);
expect(describePath("m/44'/60'/2'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #2"`);
expect(describePath("m/44'/60'/3'/0/0")).toMatchInlineSnapshot(`"Ethereum Account #3"`);

expect(describePath("m/44'/60'/0'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/1"`);
expect(describePath("m/44'/60'/0'/0/2")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/2"`);
expect(describePath("m/44'/60'/0'/0/3")).toMatchInlineSnapshot(`"m/44'/60'/0'/0/3"`);

expect(describePath("m/44'/60'/1'/0/1")).toMatchInlineSnapshot(`"m/44'/60'/1'/0/1"`);
expect(describePath("m/44'/60'/1'/2/3")).toMatchInlineSnapshot(`"m/44'/60'/1'/2/3"`);
expect(describePath("m/44'/60'/0'/0")).toMatchInlineSnapshot(`"Ethereum Account #0 (Legacy)"`);
expect(describePath("m/44'/60'/0'/1")).toMatchInlineSnapshot(`"Ethereum Account #1 (Legacy)"`);
expect(describePath("m/44'/60'/0'/2")).toMatchInlineSnapshot(`"Ethereum Account #2 (Legacy)"`);
expect(describePath("m/44'/60'/0'/3")).toMatchInlineSnapshot(`"Ethereum Account #3 (Legacy)"`);
expect(describePath("m/44'/60'/1'/0")).toMatchInlineSnapshot(`"m/44'/60'/1'/0"`);
expect(describePath("m/44'/60'/1'/2")).toMatchInlineSnapshot(`"m/44'/60'/1'/2"`);
});
});
Loading