@tronlink/core
Version:
The library serves as a core module within TronLink Extension, which provides low-level wallet functionality for both Tron and Ethereum networks, primary features includes account generation and transaction signing
127 lines • 5.43 kB
JavaScript
// @ts-ignore
import bip39 from 'bip39';
import { HDKey } from 'ethereum-cryptography/hdkey';
import { bufferToHex, isValidAddress, privateToPublic, publicToAddress, stripHexPrefix, toChecksumAddress, bigIntToBuffer, ecsign, ecrecover, fromRpcSig, hashPersonalMessage, } from '@ethereumjs/util';
import { ethers } from 'ethers';
import { TransactionFactory } from '@ethereumjs/tx';
import { Chain, Common, Hardfork } from '@ethereumjs/common';
import { signTypedData_v4 } from 'eth-sig-util';
import { BaseWallet } from '../base_wallet';
import { CoinType } from '../base_wallet/constants';
import { msgHexToText } from './util';
import { checkSignParams } from '../utils';
import { InvalidParameterError, SignError } from '../base_wallet/error';
export class EvmWallet extends BaseWallet {
getCoinType() {
return CoinType.ETHER;
}
derivePrivateKey(params) {
const seed = bip39.mnemonicToSeed(params.mnemonic);
const hdWallet = HDKey.fromMasterSeed(seed);
const wallet = hdWallet.derive(params.path);
const privateKey = stripHexPrefix(bufferToHex(Buffer.from(wallet.privateKey)));
return privateKey;
}
getAddressBy(params) {
const strippedHexPrivateKey = stripHexPrefix(params.privateKey);
const evmPrivateKey = Buffer.from(strippedHexPrivateKey, 'hex');
const publicKey = privateToPublic(evmPrivateKey);
const evmAddress = toChecksumAddress(bufferToHex(publicToAddress(Buffer.from(publicKey), true)));
return evmAddress;
}
validateAddress(params) {
if (!params.address) {
return false;
}
return isValidAddress(params.address);
}
async sign(params) {
try {
checkSignParams(params);
const { data } = params;
if (typeof data === 'string') {
return this.signMessage(params);
}
else if (typeof data === 'object' && data.domain && data.types && data.message) {
return this.signTypedData(params);
}
else if (typeof data === 'object' && !Array.isArray(data)) {
return this.signTransaction(params);
}
else {
throw new InvalidParameterError();
}
}
catch (error) {
throw new SignError(error.message);
}
}
async signMessage(param) {
if (typeof param.data !== 'string') {
throw new SignError('The "data" parameter of the function "signMessage" must be passed in string type');
}
const textMessage = msgHexToText(param.data);
const signature = ecsign(hashPersonalMessage(Buffer.from(textMessage)), Buffer.from(param.privateKey, 'hex'));
const rawMsgSign = this.signedConvertRSVtoHex({
r: signature.r,
s: signature.s,
v: signature.v,
});
return rawMsgSign;
}
async signTransaction(params) {
const tx = TransactionFactory.fromTxData(params.data.unSignedTransaction, {
common: params.data.common,
});
const hexPrivateKey = Buffer.from(params.privateKey, 'hex');
const signedTX = tx.sign(hexPrivateKey);
return signedTX;
}
verifyEthMessageSign(signature, message, expectAddress) {
const { r, s, v } = fromRpcSig(signature);
const publicKey = ecrecover(hashPersonalMessage(Buffer.from(msgHexToText(message))), v, r, s);
const address = publicToAddress(publicKey, true);
return `${address.toString('hex').toLowerCase()}` === expectAddress.slice(2).toLowerCase();
}
verifyEthTransactionSign(rawTransaction, rsvSignature, expectAddress) {
const serializedTransaction = ethers.utils.serializeTransaction(rawTransaction);
const txHash = ethers.utils.keccak256(serializedTransaction);
const recoveredAddress = ethers.utils.recoverAddress(txHash, rsvSignature);
return expectAddress.toLowerCase() === recoveredAddress.toLowerCase();
}
async signTypedData(params) {
if (typeof params.data === 'string') {
throw new SignError('The "data" parameter of the function "signTypedData" must be passed in type of a specific structure');
}
return signTypedData_v4(Buffer.from(params.privateKey, 'hex'), { data: params.data });
}
signedConvertRSVtoHex({ r, s, v }) {
const vBuffer = bigIntToBuffer(v);
const rHex = r.toString('hex');
const sHex = s.toString('hex');
const vHex = vBuffer.toString('hex');
const rPadded = rHex.padStart(64, '0');
const sPadded = sHex.padStart(64, '0');
const vPadded = vHex;
return `0x${rPadded}${sPadded}${vPadded}`;
}
getCommonConfiguration({ isSupportsEIP1559, chain, chainId, chainName, }) {
const hardfork = isSupportsEIP1559 ? Hardfork.London : Hardfork.Berlin;
if (chain && [Chain.Sepolia, Chain.Goerli, Chain.Mainnet].includes(chain)) {
return new Common({
chain,
hardfork,
});
}
else {
return Common.custom({
name: chainName,
chainId: parseInt(chainId, 16),
networkId: parseInt(chainId, 16),
// @ts-ignore
hardfork,
});
}
}
}
//# sourceMappingURL=EvmWallet.js.map