import crypto from 'crypto' ; import { coin as COIN , Transport , utils , config , apdu , tx } from '@coolwallet/core' ; const bip32 = require ( 'bip32' ) ; const elliptic = require ( 'elliptic' ) ; const ec = new elliptic . ec ( 'secp256k1' ) ; const createKeccakHash = require ( 'keccak' ) ; const rlp = require ( 'rlp' ) ; import { Transaction , handleHex , getRawTx } from './utils' ; export default class Template implements COIN . Coin { getPublicKey = async ( transport , appPrivateKey , appId , addressIndex ) : Promise < string > => { const path = utils . getFullPath ( { pathType : config . PathType . BIP32 , pathString : "44'/60'/0'" , } ) ; const accExtKey = await COIN . getPublicKeyByPath ( transport , appId , appPrivateKey , path ) ; const accExtKeyBuf = Buffer . from ( accExtKey , 'hex' ) ; const accPublicKey = accExtKeyBuf . slice ( 0 , 33 ) ; const accChainCode = accExtKeyBuf . slice ( 33 ) ; const accNode = bip32 . fromPublicKey ( accPublicKey , accChainCode ) ; const changeNode = accNode . derive ( 0 ) ; const addressNode = changeNode . derive ( addressIndex ) ; const publicKey = addressNode . publicKey . toString ( 'hex' ) ; return publicKey ; } ; getAddress = async ( transport , appPrivateKey , appId , addressIndex ) : Promise < string > => { const publicKey = await this . getPublicKey ( transport , appPrivateKey , appId , addressIndex ) ; const uncompressedKey = ec . keyFromPublic ( publicKey , "hex" ) . getPublic ( false , 'hex' ) ; const keyBuffer = Buffer . from ( uncompressedKey . substr ( 2 ) , 'hex' ) ; const keyHash = createKeccakHash ( 'keccak256' ) . update ( keyBuffer ) . digest ( 'hex' ) ; const address = "0x" . concat ( keyHash . substr ( - 40 ) ) ; return address ; } ; signTransaction = async ( transport , appPrivateKey , appId , addressIndex , transaction ) : Promise < string > => { const script = '03000601C707000000003CCC07C002F800C2ACD70032FFF8C2ACD7001EFFF6C2ACD70028FFF6CC071094CAA02700C2A2D700FFF6C2AC97003CCC0E1001C2E09700CC07C0028080C37097C002DC07C003455448D207C005534d415254D207CC05065052455353425554546f4e' ; const scriptSig = '3046022100EC9BC856CEC733451CF4063C60DE27F9E920F7423122CCA19DC47B82E694799C0221008F754911B9C966EF430ED8919A58333D9800E8EBF4FB98B06C797E991DA03697' ; await apdu . tx . sendScript ( transport , script + scriptSig ) ; const path = await utils . getFullPath ( { pathType : config . PathType . BIP32 , pathString : "44'/60'/0'/0/0" , } ) ; console . log ( 'path :' , path ) ; const argument = '15' + path + handleHex ( transaction . to ) + handleHex ( transaction . value ) . padStart ( 20 , "0" ) + handleHex ( transaction . gasPrice ) . padStart ( 20 , "0" ) + handleHex ( transaction . gasLimit ) . padStart ( 20 , "0" ) + handleHex ( transaction . nonce ) . padStart ( 16 , "0" ) + handleHex ( transaction . chainId . toString ( 16 ) ) . padStart ( 4 , "0" ) + handleHex ( transaction . data ) ; const encryptedSig = await apdu . tx . executeScript ( transport , appId , appPrivateKey , argument ) ; await apdu . tx . finishPrepare ( transport ) ; await apdu . tx . getTxDetail ( transport ) ; const decryptingKey = await apdu . tx . getSignatureKey ( transport ) ; await apdu . tx . clearTransaction ( transport ) ; await apdu . mcu . control . powerOff ( transport ) ; const sig = tx . util . decryptSignatureFromSE ( encryptedSig ! , decryptingKey ) ; const { signedTx } = await apdu . tx . getSignedHex ( transport ) ; const rawTx = getRawTx ( transaction ) ; const rawData = rlp . encode ( rawTx ) ; if ( rawData . toString ( 'hex' ) !== signedTx ) { throw new Error ( 'unexpected transaction format!' ) ; } const hash = createKeccakHash ( 'keccak256' ) . update ( rawData ) . digest ( 'hex' ) ; const data = Buffer . from ( handleHex ( hash ) , 'hex' ) ; const publicKey = await this . getPublicKey ( transport , appPrivateKey , appId , addressIndex ) ; const keyPair = ec . keyFromPublic ( publicKey , 'hex' ) ; const recoveryParam = ec . getKeyRecoveryParam ( data , sig , keyPair . pub ) ; const v = recoveryParam + 27 ; const { r , s } = sig as { r : string ; s : string ; } ; const vValue = v + transaction . chainId * 2 + 8 ; const signedTransaction = rawTx . slice ( 0 , 6 ) ; signedTransaction . push ( Buffer . from ( [ vValue ] ) , Buffer . from ( r , 'hex' ) , Buffer . from ( s , 'hex' ) ) ; const serializedTx = rlp . encode ( signedTransaction ) ; return `0x${ serializedTx . toString ( 'hex' ) }` ; } ; }