Skip to content

Commit

Permalink
v2.7.1 (#575)
Browse files Browse the repository at this point in the history
* bumps dependencies

* update integration test

* bump node in test

* revert eip712 `v` change

* bumps node version to 18

* update getMessageToSign to latest ethers version

* adds iteration index and test

* update iteration

* remove eslint

* remove unused imports

* updates snapshot

* bumps upload artifacts

* fix parse derivation path (#568)

* fix parse derivation path

* fix eslint errors with hardened values in strings

* exports parseDerivationPath

* bumps to v2.7.0 (#570)

* remove extra test files

* fixes issue with fetching addrs by derivation path (#572)

* fixes issue with fetching addrs by derivation path

* fix unit tests

* bump to 2.7.1

* Merge branch 'main' into dev

* bumps dependencies

* update integration test

* bump node in test

* revert eip712 `v` change

* bumps node version to 18

* update getMessageToSign to latest ethers version

* adds iteration index and test

* update iteration

* remove eslint

* remove unused imports

* updates snapshot

* bumps upload artifacts

* fix parse derivation path (#568)

* fix parse derivation path

* fix eslint errors with hardened values in strings

* exports parseDerivationPath

* bumps to v2.7.0 (#570)

* remove extra test files
  • Loading branch information
netbonus authored Oct 9, 2024
1 parent 4ed7445 commit 02dd5a1
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 33 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gridplus-sdk",
"version": "2.7.0",
"version": "2.7.1",
"description": "SDK to interact with GridPlus Lattice1 device",
"scripts": {
"build": "NODE_ENV=production tsc -p tsconfig.json",
Expand Down
11 changes: 11 additions & 0 deletions src/__test__/e2e/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ describe('API', () => {
addresses.forEach((address) => expect(address).toBeTruthy());
});

test('fetch solana addresses with wildcard in middle of path', async () => {
const addresses = await fetchAddressesByDerivationPath(
"44'/501'/X'/0'",
{
n: 1,
},
);
expect(addresses).toHaveLength(1);
addresses.forEach((address) => expect(address).toBeTruthy());
});

test('error on invalid derivation path', async () => {
await expect(
fetchAddressesByDerivationPath('invalid/path'),
Expand Down
43 changes: 24 additions & 19 deletions src/api/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {
MAX_ADDR,
SOLANA_DERIVATION,
} from '../constants';
import { getStartPath, parseDerivationPath, queue } from './utilities';
import {
getStartPath,
parseDerivationPathComponents,
queue,
getFlagFromPath,
} from './utilities';

type FetchAddressesParams = {
n?: number;
Expand Down Expand Up @@ -160,12 +165,10 @@ export const fetchLedgerLegacyAddresses = async (
return Promise.all(addresses);
};

export const fetchBip44ChangeAddresses = async (
{ n, startPathIndex }: FetchAddressesParams = {
n: MAX_ADDR,
startPathIndex: 0,
},
) => {
export const fetchBip44ChangeAddresses = async ({
n = MAX_ADDR,
startPathIndex = 0,
}: FetchAddressesParams = {}) => {
const addresses = [];
for (let i = 0; i < n; i++) {
addresses.push(
Expand Down Expand Up @@ -193,31 +196,33 @@ export async function fetchAddressesByDerivationPath(
path: string,
{ n = 1, startPathIndex = 0 }: FetchAddressesParams = {},
): Promise<string[]> {
const parsedPath = parseDerivationPath(path);
const hasWildcard = path.toLowerCase().includes('x');
const components = path.split('/').filter(Boolean);
const parsedPath = parseDerivationPathComponents(components);
const flag = getFlagFromPath(parsedPath);
const wildcardIndex = components.findIndex((part) =>
part.toLowerCase().includes('x'),
);

if (!hasWildcard) {
if (wildcardIndex === -1) {
return queue((client) =>
client.getAddresses({
startPath: parsedPath,
n: 1,
flag,
n,
}),
);
}

const wildcardIndex = parsedPath.findIndex((part) => part === 0);
const basePath = parsedPath.slice(0, wildcardIndex);

const addresses: string[] = [];
for (let i = 0; i < n; i++) {
const currentPath = [
...basePath,
startPathIndex + i,
...parsedPath.slice(wildcardIndex + 1),
];
const currentPath = [...parsedPath];
currentPath[wildcardIndex] =
currentPath[wildcardIndex] + startPathIndex + i;

const result = await queue((client) =>
client.getAddresses({
startPath: currentPath,
flag,
n: 1,
}),
);
Expand Down
38 changes: 25 additions & 13 deletions src/api/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
saveClient,
setFunctionQueue,
} from './state';
import { EXTERNAL, HARDENED_OFFSET } from '../constants';

/**
* `queue` is a function that wraps all functional API calls. It limits the number of concurrent
Expand Down Expand Up @@ -91,17 +92,28 @@ export const isEIP712Payload = (payload: any) =>

export function parseDerivationPath(path: string): number[] {
if (!path) return [];
return path
.split('/')
.filter(Boolean)
.map((part) => {
if (part.toLowerCase() === 'x') return 0;
if (part.toLowerCase() === "x'") return 0x80000000; // Hardened zero
if (part.endsWith("'")) return parseInt(part.slice(0, -1)) + 0x80000000;
const val = parseInt(part);
if (isNaN(val)) {
throw new Error(`Invalid part in derivation path: ${part}`);
}
return val;
});
const components = path.split('/').filter(Boolean);
return parseDerivationPathComponents(components);
}

export function parseDerivationPathComponents(components: string[]): number[] {
return components.map((part) => {
const lowerPart = part.toLowerCase();
if (lowerPart === 'x') return 0; // Wildcard
if (lowerPart === "x'") return HARDENED_OFFSET; // Hardened wildcard
if (part.endsWith("'"))
return parseInt(part.slice(0, -1)) + HARDENED_OFFSET;
const val = parseInt(part);
if (isNaN(val)) {
throw new Error(`Invalid part in derivation path: ${part}`);
}
return val;
});
}

export function getFlagFromPath(path: number[]): number | undefined {
if (path.length >= 2 && path[1] === 501 + HARDENED_OFFSET) {
return EXTERNAL.GET_ADDR_FLAGS.ED25519_PUB; // SOLANA
}
return undefined;
}

0 comments on commit 02dd5a1

Please sign in to comment.