Skip to content

Commit

Permalink
feat: refactor trezor wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
billyjacoby committed Oct 15, 2024
1 parent d9ac8c9 commit 9807132
Show file tree
Hide file tree
Showing 14 changed files with 8,502 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/wallets/wallet-strategy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@injectivelabs/wallet-evm": "^0.0.1",
"@injectivelabs/wallet-ledger": "^0.0.1",
"@injectivelabs/wallet-keplr": "^0.0.1",
"@injectivelabs/wallet-trezor": "^0.0.1",
"alchemy-sdk": "^2.6.3",
"eip1193-provider": "^1.0.1",
"eth-sig-util": "^3.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { KeplrStrategy } from '@injectivelabs/wallet-keplr'
import { EvmWalletStrategy } from '@injectivelabs/wallet-evm'
import { BaseWalletStrategy } from '@injectivelabs/wallet-core'
import { TrezorWalletStrategy } from '@injectivelabs/wallet-trezor'

const ethereumWalletsDisabled = (args: WalletStrategyArguments) => {
const { ethereumOptions } = args
Expand Down Expand Up @@ -63,10 +64,8 @@ const createStrategy = ({
return new LedgerLegacyStrategy(ethWalletArgs)
// case Wallet.TrustWallet:
// return new TrustWallet(ethWalletArgs)
// case Wallet.Trezor:
// return new Trezor(ethWalletArgs)
// case Wallet.Torus:
// return new Torus(ethWalletArgs)
case Wallet.Trezor:
return new TrezorWalletStrategy(ethWalletArgs)
case Wallet.Phantom:
return new EvmWalletStrategy({
...ethWalletArgs,
Expand Down
60 changes: 60 additions & 0 deletions packages/wallets/wallet-trezor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 🌟 Injective Protocol - Ledger Wallet Strategy

<!-- TODO -->

[![downloads](https://img.shields.io/npm/dm/@injectivelabs/wallet-ts.svg)](https://www.npmjs.com/package/@injectivelabs/wallet-ts)
[![npm-version](https://img.shields.io/npm/v/@injectivelabs/wallet-ts.svg)](https://www.npmjs.com/package/@injectivelabs/wallet-ts)
[![license](https://img.shields.io/npm/l/express.svg)]()

_Package to use Ledger Wallets on Injective via the wallet strategy._

---

## 📚 Installation

```bash
yarn add @injectivelabs/wallet-ledger
```

---

## 📖 Documentation

<!-- TODO -->

Read more and find example usages on our [WalletStrategy Docs](https://docs.ts.injective.network/wallet/wallet-wallet-strategy)

---

## 📜 Contribution

**Contribution guides and practices will be available once there is a stable foundation of the whole package set within the `injective-ts` repo.**

---

## ⛑ Support

Reach out to us at one of the following places!

- Website at <a href="https://injective.com" target="_blank">`injective.com`</a>
- Twitter at <a href="https://twitter.com/Injective_" target="_blank">`@Injective`</a>
- Discord at <a href="https://discord.com/invite/NK4qdbv" target="_blank">`Discord`</a>
- Telegram at <a href="https://t.me/joininjective" target="_blank">`Telegram`</a>

---

## 🔓 License

Copyright © 2021 - 2022 Injective Labs Inc. (https://injectivelabs.org/)

<a href="https://iili.io/mNneZN.md.png"><img src="https://iili.io/mNneZN.md.png" style="width: 300px; max-width: 100%; height: auto" />

Originally released by Injective Labs Inc. under: <br />
Apache License <br />
Version 2.0, January 2004 <br />
http://www.apache.org/licenses/

<p>&nbsp;</p>
<div align="center">
<sub><em>Powering the future of decentralized finance.</em></sub>
</div>
65 changes: 65 additions & 0 deletions packages/wallets/wallet-trezor/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "@injectivelabs/wallet-trezor",
"description": "Trezor wallet strategy for use with @injectivelabs/wallet-core.",
"version": "0.0.1",
"sideEffects": false,
"author": {
"name": "InjectiveLabs",
"email": "admin@injectivelabs.org"
},
"license": "Apache-2.0",
"types": "dist/cjs/index.d.ts",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"files": [
"dist"
],
"_moduleAliases": {
"~wallet-trezor": "dist"
},
"scripts": {
"postinstall": "link-module-alias",
"build:cjs": "BUILD_MODE=cjs tsc --build tsconfig.build.json",
"build:esm": "BUILD_MODE=esm tsc --build tsconfig.build.esm.json",
"build": "yarn build:esm && yarn build:cjs && yarn build:post && link-module-alias",
"build:watch": "tsc --build -w tsconfig.build.json && tsc -w --build tsconfig.build.esm.json && yarn build:post && link-module-alias",
"build:post": "shx cp ../../../etc/stub/package.json.stub dist/cjs/package.json && shx cp ../../../etc/stub/package.esm.json.stub dist/esm/package.json",
"clean": "tsc --build tsconfig.build.json --clean && tsc --build tsconfig.build.esm.json --clean && shx rm -rf coverage *.log junit.xml dist && jest --clearCache && shx mkdir -p dist",
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --coverage --ci --reporters='jest-junit'",
"coverage": "jest --coverage",
"coverage:show": "live-server coverage",
"dev": "ts-node -r tsconfig-paths/register src/index.ts",
"start": "node dist/index.js"
},
"dependencies": {
"@ethereumjs/common": "^3.1.1",
"@ethereumjs/tx": "^4.1.1",
"@injectivelabs/exceptions": "^1.14.14",
"@injectivelabs/networks": "^1.14.15-beta.0",
"@injectivelabs/sdk-ts": "^1.14.15-beta.9",
"@injectivelabs/ts-types": "^1.14.14",
"@injectivelabs/utils": "^1.14.14",
"@injectivelabs/wallet-base": "^0.0.1",
"alchemy-sdk": "^2.6.3",
"eip1193-provider": "^1.0.1",
"eth-sig-util": "^3.0.1",
"ethereumjs-util": "^7.1.0",
"ethers": "^6.5.1",
"hdkey": "^2.0.1",
"@trezor/connect-web": "9.2.1",
"link-module-alias": "^1.2.0",
"long": "^5.2.1",
"shx": "^0.3.3"
},
"devDependencies": {
"@types/eth-sig-util": "^2.1.1",
"@types/ethereumjs-util": "^6.1.0",
"@types/hdkey": "^2.0.1"
},
"resolutions": {
"**/libsodium": "npm:@bangjelkoski/noop",
"**/libsodium-wrappers": "npm:@bangjelkoski/noop"
}
}
3 changes: 3 additions & 0 deletions packages/wallets/wallet-trezor/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { TrezorWallet as TrezorWalletStrategy } from './strategy/strategy'

export * from './types'
108 changes: 108 additions & 0 deletions packages/wallets/wallet-trezor/src/strategy/hw/AccountManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* eslint-disable class-methods-use-this */
import { AccountAddress } from '@injectivelabs/ts-types'
import HDNode from 'hdkey'
import { addHexPrefix, publicToAddress } from 'ethereumjs-util'
import { TrezorWalletInfo } from '../../types'
import {
DEFAULT_NUM_ADDRESSES_TO_FETCH,
DEFAULT_BASE_DERIVATION_PATH,
} from '@injectivelabs/wallet-base'

const addressOfHDKey = (hdKey: HDNode): string => {
const shouldSanitizePublicKey = true
const derivedPublicKey = hdKey.publicKey
const ethereumAddressWithoutPrefix = publicToAddress(
derivedPublicKey,
shouldSanitizePublicKey,
).toString('hex')
const address = addHexPrefix(ethereumAddressWithoutPrefix)

return address
}

export default class AccountManager {
private wallets: TrezorWalletInfo[] = []

private hdKey: HDNode

constructor(hdKey: HDNode) {
this.wallets = []
this.hdKey = hdKey
}

async getWallets(): Promise<TrezorWalletInfo[]> {
const { start, end } = this.getOffset()

/**
* 1. Wallets are not yet fetched at all,
* 2. Wallets are not yet fetched for that offset
*/
if (!this.hasWallets() || !this.hasWalletsInOffset(start)) {
await this.getWalletsBasedOnIndex({
start,
end,
})
}

return this.wallets.slice(start, end)
}

private async getWalletsBasedOnIndex({
start,
end,
}: {
start: number
end: number
}) {
for (let index = start; index < end; index += 1) {
const path = `m/${index}`
const hdKey = this.hdKey.derive(path)
const address = addressOfHDKey(hdKey)

this.wallets.push({
hdKey,
address: address.toLowerCase(),
derivationPath: `${DEFAULT_BASE_DERIVATION_PATH}/0'/0/${index}`,
})
}
}

private hasWallets(): boolean {
return this.wallets.length > 0
}

private hasWalletsInOffset(offset: number): boolean {
return this.wallets.length > offset
}

private getOffset(): { start: number; end: number } {
const totalWallets = this.wallets.length
const nextBatchStart = totalWallets
const nextBatchEnd = totalWallets + DEFAULT_NUM_ADDRESSES_TO_FETCH

return {
start: nextBatchStart,
end: nextBatchEnd,
}
}

hasWalletForAddress(address: AccountAddress): boolean {
return (
this.wallets.find(
(wallet) => wallet.address.toLowerCase() === address.toLowerCase(),
) !== undefined
)
}

async getWalletForAddress(
address: AccountAddress,
): Promise<TrezorWalletInfo | undefined> {
return this.wallets.find(
(wallet) => wallet.address.toLowerCase() === address.toLowerCase(),
)
}

reset() {
this.wallets = []
}
}
74 changes: 74 additions & 0 deletions packages/wallets/wallet-trezor/src/strategy/hw/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import TrezorConnect from '@trezor/connect-web'
import HDNode from 'hdkey'
import { DEFAULT_BASE_DERIVATION_PATH } from '@injectivelabs/wallet-base'
import AccountManager from './AccountManager'

// @ts-ignore
const trezorConnect = TrezorConnect.default || TrezorConnect

const TREZOR_CONNECT_MANIFEST = {
email: 'contact@injectivelabs.org',
appUrl: 'https://injectivelabs.org',
}

export default class TrezorTransport {
private accountManager: AccountManager | null = null

private hdKey: HDNode = new HDNode()

constructor() {
trezorConnect.init({ lazyLoad: true, manifest: TREZOR_CONNECT_MANIFEST })
}

async connect() {
await this.init()
}

async getAccountManager(): Promise<AccountManager> {
if (!this.accountManager) {
this.accountManager = new AccountManager(this.hdKey)
}

return this.accountManager
}

private isUnlocked() {
return Boolean(this.hdKey && this.hdKey.publicKey)
}

private async init() {
if (this.isUnlocked()) {
return Promise.resolve()
}

return new Promise((resolve, reject) => {
TrezorConnect.getPublicKey({
path: `${DEFAULT_BASE_DERIVATION_PATH}/0'/0`,
coin: 'ETH',
})
.then((response: any) => {
if (!response.success) {
return reject(
new Error(
(response.payload && response.payload.error) ||
'Please make sure your Trezor is connected and unlocked',
),
)
}

this.hdKey.publicKey = Buffer.from(response.payload.publicKey, 'hex')
this.hdKey.chainCode = Buffer.from(response.payload.chainCode, 'hex')

return resolve(TrezorConnect)
})
.catch((e: any) => {
reject(
new Error(
(e && e.toString()) ||
'Please make sure your Trezor is connected and unlocked',
),
)
})
})
}
}
Loading

0 comments on commit 9807132

Please sign in to comment.