import type Transport from "@ledgerhq/hw-transport" ; import type { Transaction } from "@solana/web3.js" ; import { PublicKey } from "@solana/web3.js" ; const INS_GET_PUBKEY = 0x05 ; const INS_SIGN_MESSAGE = 0x06 ; const P1_NON_CONFIRM = 0x00 ; const P1_CONFIRM = 0x01 ; const P2_EXTEND = 0x01 ; const P2_MORE = 0x02 ; const MAX_PAYLOAD = 255 ; const LEDGER_CLA = 0xe0 ; async function ledgerSend ( transport , instruction , p1 , payload ) { let p2 = 0 ; let payloadOffset = 0 ; if ( payload . length > MAX_PAYLOAD ) { while ( payload . length - payloadOffset > MAX_PAYLOAD ) { const chunk = payload . slice ( payloadOffset , payloadOffset + MAX_PAYLOAD ) ; payloadOffset += MAX_PAYLOAD ; const reply = await transport . send ( LEDGER_CLA , instruction , p1 , p2 | P2_MORE , chunk ) ; if ( reply . length !== 2 ) { throw new Error ( "Received unexpected reply payload" ) ; } p2 |= P2_EXTEND ; } } const chunk = payload . slice ( payloadOffset ) ; const reply = await transport . send ( LEDGER_CLA , instruction , p1 , p2 , chunk ) ; return reply . slice ( 0 , reply . length - 2 ) ; } const BIP32_HARDENED_BIT = ( 1 << 31 ) >>> 0 ; function harden ( n = 0 ) { return ( n | BIP32_HARDENED_BIT ) >>> 0 ; } export function getSolanaDerivationPath ( account ? , change ? ) { let length ; if ( account !== undefined ) { if ( change !== undefined ) { length = 4 ; } else { length = 3 ; } } else { length = 2 ; } const derivationPath = Buffer . alloc ( 1 + length * 4 ) ; var offset = 0 ; offset = derivationPath . writeUInt8 ( length , offset ) ; offset = derivationPath . writeUInt32BE ( harden ( 44 ) , offset ) ; offset = derivationPath . writeUInt32BE ( harden ( 501 ) , offset ) ; if ( length > 2 ) { offset = derivationPath . writeUInt32BE ( harden ( account ) , offset ) ; if ( length === 4 ) { offset = derivationPath . writeUInt32BE ( harden ( change ) , offset ) ; } } return derivationPath ; } export async function signTransaction ( transport , transaction , derivationPath = getSolanaDerivationPath ( ) ) { const messageBytes = transaction . serializeMessage ( ) ; return signBytes ( transport , messageBytes , derivationPath ) ; } export async function signBytes ( transport , bytes , derivationPath = getSolanaDerivationPath ( ) ) { const numPaths = Buffer . alloc ( 1 ) ; numPaths . writeUInt8 ( 1 , 0 ) ; const payload = Buffer . concat ( [ numPaths , derivationPath , bytes ] ) ; return ledgerSend ( transport , INS_SIGN_MESSAGE , P1_CONFIRM , payload ) ; } export async function getPublicKey ( transport , derivationPath = getSolanaDerivationPath ( ) ) { const publicKeyBytes = await ledgerSend ( transport , INS_GET_PUBKEY , P1_NON_CONFIRM , derivationPath ) ; return new PublicKey ( publicKeyBytes ) ; }