Skip to content

Commit

Permalink
CU-86dtu8ra6 - NEON3 - Ledger - MultiAccount support
Browse files Browse the repository at this point in the history
  • Loading branch information
raulduartep committed Jul 11, 2024
1 parent 87ca6e9 commit ac4f5b6
Show file tree
Hide file tree
Showing 22 changed files with 377 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/blockchain-service",
"comment": "Adapt interfaces to support ledger multi account",
"type": "minor"
}
],
"packageName": "@cityofzion/blockchain-service"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-ethereum",
"comment": "Add support to ledger multi account",
"type": "minor"
}
],
"packageName": "@cityofzion/bs-ethereum"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-neo-legacy",
"comment": "Remove AccountWithDerivationPath type",
"type": "patch"
}
],
"packageName": "@cityofzion/bs-neo-legacy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-neo3",
"comment": "Add support to ledger multi account",
"type": "minor"
}
],
"packageName": "@cityofzion/bs-neo3"
}
8 changes: 4 additions & 4 deletions packages/blockchain-service/src/BSAggregator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AccountWithDerivationPath, BlockchainService, PartialNetwork } from './interfaces'
import { Account, BlockchainService, PartialNetwork } from './interfaces'

export class BSAggregator<
BSCustomName extends string = string,
Expand Down Expand Up @@ -55,12 +55,12 @@ export class BSAggregator<
async generateAccountFromMnemonicAllBlockchains(
mnemonic: string,
skippedAddresses?: string[]
): Promise<Map<BSCustomName, AccountWithDerivationPath[]>> {
const mnemonicAccounts = new Map<BSCustomName, AccountWithDerivationPath[]>()
): Promise<Map<BSCustomName, Account[]>> {
const mnemonicAccounts = new Map<BSCustomName, Account[]>()

const promises = this.#blockchainServices.map(async service => {
let index = 0
const accounts: AccountWithDerivationPath[] = []
const accounts: Account[] = []
let hasError = false

while (!hasError) {
Expand Down
11 changes: 5 additions & 6 deletions packages/blockchain-service/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ export type Account = {
key: string
type: 'wif' | 'privateKey' | 'publicKey'
address: string
derivationIndex?: number
}
export type AccountWithDerivationPath = Account & {
derivationPath: string
}

export interface Token {
symbol: string
name: string
Expand Down Expand Up @@ -52,7 +51,7 @@ export interface BlockchainService<BSCustomName extends string = string, BSAvail
tokens: Token[]
network: Network<BSAvailableNetworks>
setNetwork: (partialNetwork: PartialNetwork<BSAvailableNetworks>) => void
generateAccountFromMnemonic(mnemonic: string | string, index: number): AccountWithDerivationPath
generateAccountFromMnemonic(mnemonic: string | string, index: number): Account
generateAccountFromKey(key: string): Account
decrypt(keyOrJson: string, password: string): Promise<Account>
encrypt(key: string, password: string): Promise<string>
Expand Down Expand Up @@ -243,8 +242,8 @@ export type LedgerServiceEmitter = TypedEmitter<{
export interface LedgerService {
emitter: LedgerServiceEmitter
getLedgerTransport?: (account: Account) => Promise<Transport>
getAddress(transport: Transport): Promise<string>
getPublicKey(transport: Transport): Promise<string>
getAccounts(transport: Transport): Promise<Account[]>
getAccount(transport: Transport, index: number): Promise<Account>
}

export type SwapRoute = {
Expand Down
2 changes: 1 addition & 1 deletion packages/bs-ethereum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
],
"scripts": {
"build": "tsc --project tsconfig.build.json",
"test": "jest --config jest.config.ts",
"test": "jest --verbose --config jest.config.ts",
"lint": "eslint .",
"format": "eslint --fix"
},
Expand Down
56 changes: 22 additions & 34 deletions packages/bs-ethereum/src/BSEthereum.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
Account,
AccountWithDerivationPath,
BSCalculableFee,
BSWithLedger,
BSWithNameService,
Expand Down Expand Up @@ -58,7 +57,7 @@ export class BSEthereum<BSCustomName extends string = string>
getLedgerTransport?: (account: Account) => Promise<Transport>
) {
this.blockchainName = blockchainName
this.ledgerService = new LedgerServiceEthereum(getLedgerTransport)
this.ledgerService = new LedgerServiceEthereum(this.blockchainDataService, getLedgerTransport)
this.derivationPath = DERIVATION_PATH
this.tokens = [NATIVE_ASSET_BY_NETWORK_ID[network.id]]
this.feeToken = NATIVE_ASSET_BY_NETWORK_ID[network.id]
Expand Down Expand Up @@ -107,15 +106,15 @@ export class BSEthereum<BSCustomName extends string = string>
return true
}

generateAccountFromMnemonic(mnemonic: string[] | string, index: number): AccountWithDerivationPath {
generateAccountFromMnemonic(mnemonic: string[] | string, index: number): Account {
const path = this.derivationPath.replace('?', index.toString())
const wallet = ethers.Wallet.fromMnemonic(Array.isArray(mnemonic) ? mnemonic.join(' ') : mnemonic, path)

return {
address: wallet.address,
key: wallet.privateKey,
type: 'privateKey',
derivationPath: path,
derivationIndex: index,
}
}

Expand Down Expand Up @@ -153,22 +152,7 @@ export class BSEthereum<BSCustomName extends string = string>
}

async transfer(param: TransferParam): Promise<string> {
const provider = new ethers.providers.JsonRpcProvider(this.network.url)

let ledgerTransport: Transport | undefined

if (param.isLedger) {
if (!this.ledgerService.getLedgerTransport)
throw new Error('You must provide getLedgerTransport function to use Ledger')
ledgerTransport = await this.ledgerService.getLedgerTransport(param.senderAccount)
}

let signer: ethers.Signer
if (ledgerTransport) {
signer = new LedgerSigner(ledgerTransport, provider)
} else {
signer = new ethers.Wallet(param.senderAccount.key, provider)
}
const signer = await this.#generateSigner(param.senderAccount, param.isLedger)

const decimals = param.intent.tokenDecimals ?? 18
const amount = ethersBigNumber.parseFixed(param.intent.amount, decimals)
Expand Down Expand Up @@ -196,20 +180,7 @@ export class BSEthereum<BSCustomName extends string = string>
async calculateTransferFee(param: TransferParam): Promise<string> {
const provider = new ethers.providers.JsonRpcProvider(this.network.url)

let ledgerTransport: Transport | undefined

if (param.isLedger) {
if (!this.ledgerService.getLedgerTransport)
throw new Error('You must provide getLedgerTransport function to use Ledger')
ledgerTransport = await this.ledgerService.getLedgerTransport(param.senderAccount)
}

let signer: ethers.Signer
if (ledgerTransport) {
signer = new LedgerSigner(ledgerTransport, provider)
} else {
signer = new ethers.Wallet(param.senderAccount.key, provider)
}
const signer = await this.#generateSigner(param.senderAccount, param.isLedger)

const gasPrice = await provider.getGasPrice()

Expand Down Expand Up @@ -243,4 +214,21 @@ export class BSEthereum<BSCustomName extends string = string>
if (!address) throw new Error('No address found for domain name')
return address
}

async #generateSigner(account: Account, isLedger?: boolean): Promise<ethers.Signer> {
const provider = new ethers.providers.JsonRpcProvider(this.network.url)

if (isLedger) {
if (!this.ledgerService.getLedgerTransport)
throw new Error('You must provide getLedgerTransport function to use Ledger')

if (typeof account.derivationIndex !== 'number')
throw new Error('Your account must have derivationIndex to use Ledger')

const ledgerTransport = await this.ledgerService.getLedgerTransport(account)
return new LedgerSigner(ledgerTransport, account.derivationIndex, provider)
}

return new ethers.Wallet(account.key, provider)
}
}
Loading

0 comments on commit ac4f5b6

Please sign in to comment.