-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat @celo/viem-accounts/ledger (#344)
<!-- start pr-codex --> ## PR-Codex overview This PR introduces the `@celo/viem-account-ledger` library, facilitating interactions between Ledger devices and the `viem` framework. It includes type definitions, configurations, and initial implementations for ledger account management. ### Detailed summary - Added `Hex` type definition in `src/types.ts`. - Created initial release notes in `CHANGELOG.md`. - Configured ESLint and TypeScript settings. - Implemented `ledgerToAccount` function in `src/ledger-to-account.ts`. - Added utility functions in `src/utils.ts`. - Created test files for ledger interactions. - Updated `README.md` with installation and usage instructions. > The following files were skipped due to too many changes: `yarn.lock` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
- Loading branch information
1 parent
d3b88fd
commit 6bba5e3
Showing
21 changed files
with
2,114 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@celo/viem-account-ledger': major | ||
--- | ||
|
||
Initial release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
extends: '../../.eslintrc.js', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
lib/ | ||
tmp/ | ||
.tmp/ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/.devchain/ | ||
/.devchain.tar.gz | ||
/coverage/ | ||
/node_modules/ | ||
/src/ | ||
/tmp/ | ||
/.tmp/ | ||
|
||
/tsconfig.* | ||
/jest.config.* | ||
*.tgz | ||
|
||
/src | ||
|
||
/lib/**/*.test.* | ||
/lib/test-utils |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# @celo/viem-account-ledger | ||
|
||
This library aims to ease the usage of a ledger device with (viem)[https://viem.sh/]. | ||
|
||
## Installation | ||
|
||
```bash | ||
npm install @celo/viem-account-ledger viem@2 @ledgerhq/[email protected] | ||
# or yarn or bun or ... | ||
``` | ||
|
||
> [!IMPORTANT] > `viem` is a peer dependency and MUST be installed alongside this library. | ||
> `@ledgerhq/transport-node-hid` is a peer dependency and MUST be installed alongside this library. | ||
## Usage | ||
|
||
```ts | ||
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid' | ||
import { createWalletClient } from 'viem' | ||
import { celo, celoAlfajores } from 'viem/chains' | ||
import { ledgerToAccount } from '@celo/viem-account-ledger' | ||
|
||
async function main() => { | ||
const account = await ledgerToAccount({ | ||
transport: await TransportNodeHid.open(''), | ||
}) | ||
const client = createWalletClient({ | ||
account, | ||
chain: celo, | ||
transport: http() | ||
}); | ||
await client.sendTransaction({ | ||
to: '0x123...', | ||
value: 10n, | ||
feeCurrency: '0x123...' | ||
}); | ||
} | ||
``` | ||
|
||
You can also use the `account` directly eg: | ||
|
||
```ts | ||
const account = await ledgerToAccount({ | ||
transport: await TransportNodeHid.open(''), | ||
}) | ||
account.signTransaction({ | ||
to: '0x123...', | ||
value: 123n, | ||
chainId: celoAlfajores.id, | ||
nonce: 42, | ||
maxFeePerGas: 100n, | ||
maxPriorityFeePerGas: 100n, | ||
feeCurrency: '0x123...', | ||
}) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"extends": "./tsconfig.json", | ||
"exclude": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{ | ||
"name": "@celo/viem-account-ledger", | ||
"version": "0.0.1", | ||
"description": "Helper library to make ledger<->viem interactions easier", | ||
"type": "module", | ||
"exports": { | ||
".": "./lib/index.js" | ||
}, | ||
"types": "./lib/index.d.ts", | ||
"author": "cLabs", | ||
"license": "Apache-2.0", | ||
"homepage": "https://docs.celo.org/developer/tools", | ||
"repository": "https://github.com/celo-org/developer-tooling/tree/master/packages/viem-account-ledger", | ||
"keywords": [ | ||
"celo", | ||
"blockchain", | ||
"viem", | ||
"ledger" | ||
], | ||
"scripts": { | ||
"build": "yarn run --top-level tsc -b .", | ||
"clean": "yarn run --top-level tsc -b . --clean", | ||
"docs": "yarn run --top-level typedoc", | ||
"test": "yarn run vitest", | ||
"lint": "yarn run --top-level eslint -c .eslintrc.cjs ", | ||
"prepublishOnly": "yarn build" | ||
}, | ||
"peerDependencies": { | ||
"@ledgerhq/hw-transport-node-hid": "^6.x", | ||
"viem": "2.x" | ||
}, | ||
"dependencies": { | ||
"@celo/base": "^6.1.0", | ||
"@celo/ledger-token-signer": "^0.4.0", | ||
"@ledgerhq/errors": "^6.16.4", | ||
"@ledgerhq/hw-app-eth": "git+https://github.com:celo-org/ledgerjs-hw-app-eth.git", | ||
"semver": "^7.6.0" | ||
}, | ||
"devDependencies": { | ||
"@celo/typescript": "workspace:^", | ||
"@celo/utils": "workspace:^", | ||
"@celo/wallet-base": "workspace:^", | ||
"@celo/wallet-remote": "workspace:^", | ||
"@ethereumjs/util": "8.0.5", | ||
"@ledgerhq/hw-transport-node-hid": "^6.29.5", | ||
"@vitest/coverage-v8": "2.1.2", | ||
"dotenv": "^8.2.0", | ||
"viem": "^2.21.14", | ||
"vitest": "^2.1.2" | ||
}, | ||
"engines": { | ||
"node": ">=18" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// export default 'AAAAaARDRUxPRx7ON1DaI3+TuOM5xTaYm4l4pDgAAAASAACk7DBFAiEA5rECRg94+fCoIvoG9/5qWh62zl2C6Y+aFuuZrFe4CtcCIEJbRrkL3gqwT/Jj+7L3neazgpVCCTZZ3HX9JXXg5vleAAAAaARjVVNEdl3oFoRYYedaJfyhIrtomLixKCoAAAASAACk7DBFAiEApwQFHNBKXp+V2jq8BMD2y/5AwC9bhPQ2H4hT/vMl/B4CIFalOVtBFGREUKMU/F5vDlJLeQrTn6GQeDertpB2FpMvAAAAaARjRVVS2HY8uidqNzjm3oW0s79f3tbWynMAAAASAACk7DBFAiEAh2UeP1+SI2Ed5SiAjpJF6MkMrVa94gUwjJztyBlzhWMCIHfaOrEsxdxAGx+P+hxuSNO4zcw6KRLfJkkuic1V/CrHAAAAagZiIENFTE/dyb5X9VP+dXUtYWBrlMvX4CZO+AAAABIAAPNwMEUCIQCi62KsBfuNcfX0MriiRZ7a5DKERhtIz7sZ1SqBT7ruhgIgVrfmavyWzxzDW4AQeHn++A4qPjB1pQKoHvNXo8Hf1SMAAABpBmIgY1VTRGJJKmRKWI/ZBCcL7QatUrmr/qGuAAAAEgAA83AwRAIgGDYx4oB/gkYUqLeXqvEZXx9nOxVHzTe2ajyd2wnehxgCICQBe/rBPcXiaQJj3pdoXxroct/hV6r3G2G7y79EOEAPAAAAaQZiIGNFVVL57OMBJHrSziGJSUGDCiRw9Od0ygAAABIAAPNwMEQCIEdcFWP+HxEUoF1sCGVd34QGS0hL5cVUdrWdqVm3bYTgAiBCMA+Rg3Ubc3xla/35wzZesPlbeSMEPcr4uqL+8PeydwAAAGoGYSBDRUxP8ZSv31CwPmm9fQV8GqnhDJlU5MkAAAASAACu8zBFAiEAk/o0FBus2/QCrunFGEyoneQIRaMRC+y5L6Dvar8MU/kCIByJt2ziRhDG3AAbyXBIuJfZQujSHFcSJL3xF0xIlcPdAAAAaQZhIGNVU0SHQGn6HrFtRNYi8uDKJe6hcjabwQAAABIAAK7zMEQCIClrH2xgE3WMbD+hgQ7t5SiAcVG5WiUZ655voqCszKEoAiA/cO8UVgNY891MNJ5yeDk8w47WO0E1DQecrK71LR8g8gAAAGoGYSBjRVVSEMiSpuxDpT5F0LkWtLfTg7G3jA8AAAASAACu8zBFAiEAgpktbB1ZxyAwMJwKTSbZ30n8zgRuW0twbXoZxlsUAswCIHek4l4CIbjVMG2HVr0Ml9/8kA4F9dr69JBMaoSUkdKl' | ||
|
||
// This was signed by Marek Olszewski on Wed 18 June 2024 | ||
export default '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' | ||
|
||
// How did we get this? By following these steps: | ||
// 1 - get pubkey from https://github.com/blooo-io/app-celo-spender/pull/7/files#diff-e0cf5b28d9b6b600f0af2bc78e8fd30ec675fd731a5da86f0c4283ffc0e40176L75-L83 | ||
// 2 - now you've got to trust me | ||
// 3 - run `ASN1_PREFIX=3056301006072a8648ce3d020106052b8104000a034200` | ||
// 4 - remove spaces, colons, 0xs from the pubkey of step 1, I've done that for you :) | ||
// 5 - and store it in key `KEY=04b06cf5d8f7ed71d8bd9b9dc37944a1c6d240f69bb0be3621dddbb6ac0eccd1508bcc2ea46227e43b941e2c6f1b1cd0ae68e54b185e2cabef3455580604bd45b8` | ||
// 5 - finally run `echo $ASN1_PREFIX$KEY | xxd -r -p - | openssl ec -inform der -pubin -pubout` | ||
// 6 - enjoy | ||
export const legacyLedgerPublicKeyHex = [ | ||
`-----BEGIN PUBLIC KEY-----`, | ||
`MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEsGz12Pftcdi9m53DeUShxtJA9puwvjYh`, | ||
`3du2rA7M0VCLzC6kYifkO5QeLG8bHNCuaOVLGF4sq+80VVgGBL1FuA==`, | ||
`-----END PUBLIC KEY-----`, | ||
].join('\n') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export { | ||
CELO_BASE_DERIVATION_PATH, | ||
DEFAULT_DERIVATION_PATH, | ||
ledgerToAccount, | ||
} from './ledger-to-account.js' |
100 changes: 100 additions & 0 deletions
100
packages/viem-account-ledger/src/ledger-to-account.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid' | ||
import { describe, expect, it, test, vi } from 'vitest' | ||
import { ledgerToAccount } from './ledger-to-account.js' | ||
import { mockLedger, TEST_CHAIN_ID } from './test-utils.js' | ||
|
||
vi.mock('./utils.js', async () => { | ||
const module = await vi.importActual('./utils.js') | ||
|
||
return { | ||
...module, | ||
generateLedger: vi.fn(() => Promise.resolve(mockLedger())), | ||
} | ||
}) | ||
|
||
const transport = | ||
process.env.USE_PHYSICAL_LEDGER === 'true' | ||
? TransportNodeHid.open('') | ||
: Promise.resolve(undefined as unknown as TransportNodeHid) | ||
|
||
describe('ledgerToAccount', () => { | ||
it('can be setup', async () => { | ||
await expect( | ||
ledgerToAccount({ | ||
transport: await transport, | ||
}) | ||
).resolves.not.toBe(undefined) | ||
// expect((generateLedger as ReturnType<(typeof jest)['fn']>).mock.calls.length).toBe(1) | ||
}) | ||
|
||
describe('signs txs', () => { | ||
const txData = { | ||
to: '0x1234567890123456789012345678901234567890', | ||
value: BigInt(123), | ||
chainId: TEST_CHAIN_ID, | ||
nonce: 42, | ||
maxFeePerGas: BigInt(100), | ||
maxPriorityFeePerGas: BigInt(100), | ||
} as const | ||
|
||
test('eip1559', async () => { | ||
const account = await ledgerToAccount({ | ||
transport: await transport, | ||
}) | ||
await expect(account.signTransaction(txData)).resolves.toMatchInlineSnapshot( | ||
`"0x02f86282aef32a6464809412345678901234567890123456789012345678907b80c080a05e130d8edb38e3ee8ab283af7c03a2579598b9a77807d7d796060358787d4707a07219dd22fe3bf3fe57682041d8f80dc9909cd70d903163b077d19625c4cd6e67"` | ||
) | ||
}) | ||
|
||
test('cip64', async () => { | ||
const account = await ledgerToAccount({ | ||
transport: await transport, | ||
}) | ||
const cUSDa = '0x874069fa1eb16d44d622f2e0ca25eea172369bc1' | ||
await expect( | ||
account.signTransaction({ | ||
...txData, | ||
|
||
feeCurrency: cUSDa, | ||
}) | ||
).resolves.toMatchInlineSnapshot( | ||
`"0x7bf87782aef32a6464809412345678901234567890123456789012345678907b80c094874069fa1eb16d44d622f2e0ca25eea172369bc180a017d8df83b40dc645b60142280613467ca92438ff5aa0811a6ceff399fe66d661a02efe4eea14146f41d4f776bec1ededc486ddee37cea8304d297a69dbf27c4089"` | ||
) | ||
}) | ||
}) | ||
|
||
it('signs messages', async () => { | ||
const account = await ledgerToAccount({ | ||
transport: await transport, | ||
}) | ||
await expect(account.signMessage({ message: 'Hello World' })).resolves.toMatchInlineSnapshot( | ||
`"0x2f9a547e69592e98114263c08c6f7a6e6cd2f991fc29f442947179419233fe9641c8e4c86975a2722b54313e47768d2ffe2608c497ff9fe7f8c61b12e6257e571c"` | ||
) | ||
}) | ||
|
||
it('signs typed data', async () => { | ||
const account = await ledgerToAccount({ | ||
transport: await transport, | ||
}) | ||
|
||
await expect( | ||
account.signTypedData({ | ||
domain: { | ||
name: 'foo', | ||
version: '0.0.0', | ||
chainId: BigInt(42), | ||
verifyingContract: '0x123', | ||
}, | ||
primaryType: 'EIP712Domain', | ||
types: { | ||
EIP712Domain: [ | ||
{ name: 'name', type: 'string' }, | ||
{ name: 'version', type: 'string' }, | ||
{ name: 'chainId', type: 'uint256' }, | ||
{ name: 'verifyingContract', type: 'address' }, | ||
], | ||
}, | ||
}) | ||
).rejects.toMatchInlineSnapshot(`[Error: Not implemented as of this release.]`) | ||
}, 20_000) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { CELO_DERIVATION_PATH_BASE, trimLeading0x } from '@celo/base' | ||
import { ensureLeading0x } from '@celo/base/lib/address.js' | ||
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid' | ||
import { hashMessage, serializeSignature } from 'viem' | ||
import { LocalAccount, toAccount } from 'viem/accounts' | ||
import { CeloTransactionSerializable, serializeTransaction } from 'viem/celo' | ||
|
||
import { checkForKnownToken, generateLedger } from './utils.js' | ||
|
||
type LedgerAccount = LocalAccount<'ledger'> | ||
|
||
export const ETH_DERIVATION_PATH_BASE = "m/44'/60'/0'" as const | ||
export const CELO_BASE_DERIVATION_PATH = `${CELO_DERIVATION_PATH_BASE.slice(2)}/0` | ||
export const DEFAULT_DERIVATION_PATH = `${ETH_DERIVATION_PATH_BASE.slice(2)}/0` | ||
|
||
export async function ledgerToAccount({ | ||
transport, | ||
derivationPathIndex = 0, | ||
baseDerivationPath = DEFAULT_DERIVATION_PATH, | ||
}: { | ||
transport: TransportNodeHid.default | ||
derivationPathIndex?: number | string | ||
baseDerivationPath?: string | ||
}): Promise<LedgerAccount> { | ||
const derivationPath = `${baseDerivationPath}/${derivationPathIndex}` | ||
const ledger = await generateLedger(transport) | ||
const { address, publicKey } = await ledger.getAddress(derivationPath, true) | ||
|
||
const account = toAccount({ | ||
address: ensureLeading0x(address), | ||
|
||
async signTransaction(transaction: CeloTransactionSerializable) { | ||
await checkForKnownToken(ledger, { | ||
to: transaction.to!, | ||
chainId: transaction.chainId!, | ||
feeCurrency: transaction.feeCurrency, | ||
}) | ||
|
||
const hash = serializeTransaction(transaction) | ||
const { r, s, v } = await ledger!.signTransaction(derivationPath, trimLeading0x(hash), null) | ||
return serializeTransaction(transaction, { | ||
r: ensureLeading0x(r), | ||
s: ensureLeading0x(s), | ||
v: BigInt(ensureLeading0x(v)), | ||
}) | ||
}, | ||
|
||
async signMessage({ message }) { | ||
const hash = hashMessage(message) | ||
const { r, s, v } = await ledger!.signPersonalMessage(derivationPath, trimLeading0x(hash)) | ||
return serializeSignature({ | ||
r: ensureLeading0x(r), | ||
s: ensureLeading0x(s), | ||
v: BigInt(v), | ||
}) | ||
}, | ||
|
||
async signTypedData(_parameters) { | ||
throw new Error('Not implemented as of this release.') | ||
}, | ||
}) | ||
|
||
return { | ||
...account, | ||
publicKey: ensureLeading0x(publicKey), | ||
source: 'ledger', | ||
} | ||
} |
Oops, something went wrong.