UNPKG

@okxweb3/coin-ethereum

Version:

An Ethereum SDK for building Web3 wallets and applications.

391 lines 15.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EthWallet = void 0; const coin_base_1 = require("@okxweb3/coin-base"); const coin_base_2 = require("@okxweb3/coin-base"); const coin_base_3 = require("@okxweb3/coin-base"); const eth = __importStar(require("./index")); const ethereumjs_util_1 = require("./lib/sdk/ethereumjs-util"); const index_1 = require("./index"); const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb'; class EthWallet extends coin_base_1.BaseWallet { async getDerivedPath(param) { return `m/44'/60'/0'/0/${param.index}`; } async getNewAddress(param) { let pri = param.privateKey; let ok = eth.validPrivateKey(pri); if (!ok) { throw new Error('invalid key'); } try { const privateKey = coin_base_2.base.fromHex(pri.toLowerCase()); (0, coin_base_1.assertBufferLength)(privateKey, 32); return Promise.resolve(eth.getNewAddress(pri.toLowerCase())); } catch (e) { } return Promise.reject(coin_base_1.NewAddressError); } async validPrivateKey(param) { let isValid = eth.validPrivateKey(param.privateKey); const data = { isValid: isValid, privateKey: param.privateKey, }; return Promise.resolve(data); } async validAddress(param) { try { return Promise.resolve(eth.validAddress(param.address)); } catch (e) { return Promise.resolve({ isValid: false, }); } } convert2HexString(data) { let n; if (coin_base_2.BigNumber.isBigNumber(data)) { n = data; } else { n = new coin_base_2.BigNumber(data); } return coin_base_2.base.toBigIntHex(n); } convert2TxParam(data) { const param = { to: data.to, value: this.convert2HexString(data.value || 0), nonce: this.convert2HexString(data.nonce), contractAddress: data.contractAddress, gasPrice: this.convert2HexString(data.gasPrice || 0), gasLimit: this.convert2HexString(data.gasLimit || 0), data: data.data, chainId: this.convert2HexString(data.chainId || 1), type: data.type || 0, maxPriorityFeePerGas: this.convert2HexString(data.maxPriorityFeePerGas || 0), maxFeePerGas: this.convert2HexString(data.maxFeePerGas || 0), authorizationList: data.authorizationList || [], useValue: data.useValue || false, }; return param; } async signTransaction(param) { try { const privateKey = param.privateKey; if (privateKey) { (0, coin_base_1.assertBufferLength)(coin_base_2.base.fromHex(privateKey), 32); } const txParams = this.convert2TxParam(param.data); if (txParams.to) { const validation = await this.validAddress({ address: txParams.to, }); if (!validation.isValid) { return Promise.reject(coin_base_1.ValidAddressError); } } if (txParams.contractAddress) { const validation = await this.validAddress({ address: txParams.contractAddress, }); if (!validation.isValid) { return Promise.reject(coin_base_1.ValidAddressError); } } const chainId = txParams.chainId; const nonce = txParams.nonce; const type = txParams.type; if (type === 0 || type === 1) { const gasPrice = txParams.gasPrice; const tokenAddress = txParams.contractAddress; let toAddress = txParams.to; let value = txParams.value; let data; if (tokenAddress) { data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map .call(coin_base_3.abi.RawEncode(['address', 'uint256'], [toAddress, value]), (x) => `00${x.toString(16)}`.slice(-2)) .join(''); if (!txParams.useValue) { value = '0x0'; } toAddress = tokenAddress; } else { data = txParams.data; } const txData = { nonce: nonce, gasPrice: gasPrice, gasLimit: txParams.gasLimit, to: toAddress, value: value, data: data, chainId: chainId, type: type, }; return Promise.resolve(eth.signTransaction(privateKey, txData)); } else if (type === 2) { const tokenAddress = txParams.contractAddress; let toAddress = txParams.to; let value = txParams.value; let data; if (tokenAddress) { data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map .call(coin_base_3.abi.RawEncode(['address', 'uint256'], [toAddress, value]), (x) => `00${x.toString(16)}`.slice(-2)) .join(''); value = '0x0'; toAddress = tokenAddress; } else { data = txParams.data; } const txData = { nonce: nonce, gasLimit: txParams.gasLimit, to: toAddress, value: value, data: data, chainId: chainId, type: type, maxPriorityFeePerGas: txParams.maxPriorityFeePerGas, maxFeePerGas: txParams.maxFeePerGas, }; return Promise.resolve(eth.signTransaction(privateKey, txData)); } else if (type === 4) { const tokenAddress = txParams.contractAddress; let toAddress = txParams.to; let value = txParams.value; let data; if (tokenAddress) { data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map .call(coin_base_3.abi.RawEncode(['address', 'uint256'], [toAddress, value]), (x) => `00${x.toString(16)}`.slice(-2)) .join(''); value = '0x0'; toAddress = tokenAddress; } else { data = txParams.data; } const txData = { nonce: nonce, gasLimit: txParams.gasLimit, to: toAddress, value: value, data: data, chainId: chainId, type: type, maxPriorityFeePerGas: txParams.maxPriorityFeePerGas, maxFeePerGas: txParams.maxFeePerGas, authorizationList: txParams.authorizationList, }; return Promise.resolve(eth.signTransaction(privateKey, txData)); } return Promise.reject(coin_base_1.SignTxError); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } async signAuthorizationListItem(param) { if (!param.privateKey) { throw Error('privateKey is invalid'); } const privateKey = coin_base_2.base.fromHex(param.privateKey); (0, coin_base_1.assertBufferLength)(coin_base_2.base.fromHex(param.privateKey), 32); const { chainId, nonce, address } = param.data; const chainIdBytes = eth.unpadBytes(eth.hexToBytes(chainId)); const nonceBytes = nonce !== undefined ? eth.unpadBytes(eth.hexToBytes(nonce)) : new Uint8Array(); const addressBytes = eth.hexToBytes(address); const rlpdMsg = ethereumjs_util_1.rlp.encode([chainIdBytes, addressBytes, nonceBytes]); const msgToSign = eth.keccak256((0, ethereumjs_util_1.concatBytes)(new Uint8Array([5]), rlpdMsg)); const signed = eth.ecdsaSign(msgToSign, privateKey); const auth = { chainId: (0, index_1.bytesToHex)(chainIdBytes), address: address, nonce: (0, index_1.bytesToHex)(nonceBytes), yParity: signed.v - 27 === 0 ? '0x' : '0x1', r: coin_base_2.base.toHex((0, index_1.unpadBuffer)(signed.r), true), s: coin_base_2.base.toHex((0, index_1.unpadBuffer)(signed.s), true), }; return auth; } async signAuthorizationListItemForRPC(param) { const auth = await this.signAuthorizationListItem(param); return this.toRpcAuth(auth); } toRpcAuth(auth) { const keys = ['chainId', 'nonce', 'yParity', 'r', 's']; const ret = { ...auth }; for (const key of keys) { ret[key] = this.toRpcHex(ret[key]); } return ret; } toRpcHex(hex) { const body = hex.slice(2); const trimmedBody = body.replace(/^0+/, '') || '0'; return '0x' + trimmedBody; } async signMessage(param) { if (!param.privateKey) { return Promise.reject(`${coin_base_1.InvalidPrivateKeyError}: cannot be empty`); } return this.signMessage0(param); } async signMessage0(param) { let privateKey; if (param.privateKey) { try { (0, coin_base_1.assertBufferLength)(coin_base_2.base.fromHex(param.privateKey), 32); } catch (e) { return Promise.reject(`${coin_base_1.InvalidPrivateKeyError}: ${e.message}`); } privateKey = coin_base_2.base.fromHex(param.privateKey); } const data = param.data; const t = data.type; const result = eth.signMessage(t, data.message, privateKey); return Promise.resolve(result); } async verifyMessage(param) { const d = param.data; const r = await this.ecRecover(d, param.signature); const address = param.address || ''; return Promise.resolve(address.toLowerCase() === r.toLowerCase()); } async ecRecover(message, signature) { const t = message.type; const publicKey = eth.verifyMessage(t, message.message, coin_base_2.base.fromHex(signature)); const address = coin_base_2.base.toHex(eth.publicToAddress(publicKey), true); return Promise.resolve(address); } async encrypt(publicKey, data, version) { return Promise.resolve(eth.sigUtil.encrypt({ publicKey: publicKey, data: data, version: version, })); } async decrypt(encryptedData, privateKey) { return Promise.resolve(eth.sigUtil.decrypt({ encryptedData: encryptedData, privateKey: coin_base_2.base.stripHexPrefix(privateKey), })); } async getEncryptionPublicKey(privateKey) { return Promise.resolve(eth.sigUtil.getEncryptionPublicKey(coin_base_2.base.stripHexPrefix(privateKey))); } getAddressByPublicKey(param) { return Promise.resolve(coin_base_2.base.toHex(eth.publicToAddress(coin_base_2.base.fromHex(param.publicKey), true), true)); } async getMPCRawTransaction(param) { try { const mpcRaw = await this.signTransaction(param); return Promise.resolve({ raw: mpcRaw.raw, hash: mpcRaw.hash, }); } catch (e) { return Promise.reject(coin_base_1.GetMpcRawTransactionError); } } async getMPCTransaction(param) { try { const signedTx = eth.getMPCTransaction(param.raw, param.sigs, param.publicKey); return Promise.resolve(signedTx); } catch (e) { return Promise.reject(coin_base_1.GetMpcTransactionError); } } async getMPCRawMessage(param) { try { const msgHash = await this.signMessage0(param); return Promise.resolve({ hash: msgHash }); } catch (e) { return Promise.reject(coin_base_1.GetMpcRawTransactionError); } } async getMPCSignedMessage(param) { try { return Promise.resolve(eth.getMPCSignedMessage(param.hash, param.sigs, param.publicKey)); } catch (e) { return Promise.reject(coin_base_1.GetMpcTransactionError); } } async getHardWareRawTransaction(param) { try { const rawTx = await this.signTransaction(param); return Promise.resolve(rawTx.serializeRaw); } catch (e) { return Promise.reject(coin_base_1.GetHardwareRawTransactionError); } } async getHardWareSignedTransaction(param) { try { return eth.getSignedTransaction(param.raw, param.r, param.s, param.v); } catch (e) { return Promise.reject(coin_base_1.GetHardwareSignedTransactionError); } } async calcTxHash(param) { const serializedData = coin_base_2.base.fromHex(param.data); const signedTx = eth.TransactionFactory.fromSerializedData(serializedData); return Promise.resolve(coin_base_2.base.toHex(signedTx.hash(), true)); } async validSignedTransaction(param) { try { const chainId = param.data ? param.data.chainId : undefined; const publicKey = param.data ? param.data.publicKey : undefined; const ret = eth.validSignedTransaction(param.tx, chainId, publicKey); return Promise.resolve((0, coin_base_1.jsonStringifyUniform)(ret)); } catch (e) { return Promise.reject(coin_base_1.validSignedTransactionError); } } } exports.EthWallet = EthWallet; //# sourceMappingURL=EthWallet.js.map