UNPKG

@pgchain/blockchain-libs

Version:
299 lines 13.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Provider = void 0; const abi_1 = require("@ethersproject/abi"); const address_1 = require("@ethersproject/address"); const bytes_1 = require("@ethersproject/bytes"); const keccak256_1 = require("@ethersproject/keccak256"); const transactions_1 = require("@ethersproject/transactions"); const eth_sig_util_1 = require("@metamask/eth-sig-util"); const js_sdk_1 = __importDefault(require("@onekeyfe/js-sdk")); const bignumber_js_1 = __importDefault(require("bignumber.js")); const ethUtil = __importStar(require("ethereumjs-util")); const bignumber_plus_1 = require("../../../basic/bignumber-plus"); const precondtion_1 = require("../../../basic/precondtion"); const abc_1 = require("../../abc"); const geth_1 = require("./geth"); const message_1 = require("./sdk/message"); class Provider extends abc_1.BaseProvider { get geth() { return this.clientSelector((i) => i instanceof geth_1.Geth); } get chainId() { var _a, _b; return Number((_b = (_a = this.chainInfo) === null || _a === void 0 ? void 0 : _a.implOptions) === null || _b === void 0 ? void 0 : _b.chainId); } verifyAddress(address) { let isValid = false; let checksumAddress = ''; try { checksumAddress = (0, address_1.getAddress)(address); isValid = checksumAddress.length === 42; } catch { // pass } return Promise.resolve({ normalizedAddress: checksumAddress.toLowerCase() || undefined, displayAddress: checksumAddress || undefined, isValid, }); } async pubkeyToAddress(verifier, encoding) { const pubkey = await verifier.getPubkey(false); return '0x' + (0, keccak256_1.keccak256)(pubkey.slice(-64)).slice(-40); } async buildUnsignedTx(unsignedTx) { const input = unsignedTx.inputs[0]; const output = unsignedTx.outputs[0]; const payload = unsignedTx.payload || {}; const nonce = unsignedTx.nonce; let feeLimit = unsignedTx.feeLimit; (0, precondtion_1.check)(typeof nonce === 'number' && nonce >= 0, 'nonce is required'); if (input && output) { const fromAddress = input.address; const tokenAddress = output.tokenAddress; let toAddress = output.address; let value = (0, bignumber_plus_1.toBigIntHex)(output.value); let data; if (tokenAddress) { data = '0xa9059cbb' + abi_1.defaultAbiCoder .encode(['address', 'uint256'], [toAddress, value]) .slice(2); // method_selector(transfer) + byte32_pad(address) + byte32_pad(value) value = '0x0'; toAddress = tokenAddress; } else { data = payload.data; } if (typeof data === 'string' && data) { payload.data = data; } if (!feeLimit) { const estimatedGasLimit = await this.geth.then((client) => client.estimateGasLimit(fromAddress, toAddress, value, data)); const estimatedGasLimitBN = (0, bignumber_plus_1.fromBigIntHex)(estimatedGasLimit); const multiplier = this.chainInfo.implOptions['contract_gaslimit_multiplier'] || 1.2; feeLimit = tokenAddress || ((await this.verifyAddress(toAddress)).isValid && (await this.geth.then((client) => client.isContract(toAddress)))) ? estimatedGasLimitBN.multipliedBy(multiplier).integerValue() : estimatedGasLimitBN; } } feeLimit = feeLimit || new bignumber_js_1.default(21000); let feePricePerUnit = unsignedTx.feePricePerUnit; if (!feePricePerUnit) { const feePrice = await this.geth.then((i) => i.getFeePricePerUnit()); const normal = feePrice.normal; feePricePerUnit = normal.price; if (normal.payload) { Object.assign(payload, normal.payload); } } return Object.assign(unsignedTx, { inputs: input ? [input] : [], outputs: output ? [output] : [], nonce, feeLimit, feePricePerUnit, payload, }); } async signTransaction(unsignedTx, signers) { var _a; const fromAddress = (_a = unsignedTx.inputs[0]) === null || _a === void 0 ? void 0 : _a.address; (0, precondtion_1.check)(fromAddress && signers[fromAddress], 'Signer not found'); const tx = this.buildEtherUnSignedTx(unsignedTx); const digest = (0, keccak256_1.keccak256)((0, transactions_1.serialize)(tx)); const [sig, recoveryParam] = await signers[fromAddress].sign(Buffer.from(digest.slice(2), 'hex')); const [r, s] = [sig.slice(0, 32), sig.slice(32)]; const signature = (0, bytes_1.splitSignature)({ recoveryParam: recoveryParam, r: (0, bytes_1.hexZeroPad)('0x' + r.toString('hex'), 32), s: (0, bytes_1.hexZeroPad)('0x' + s.toString('hex'), 32), }); const rawTx = (0, transactions_1.serialize)(tx, signature); const txid = (0, keccak256_1.keccak256)(rawTx); return { txid, rawTx }; } buildEtherUnSignedTx(unsignedTx) { var _a, _b, _c, _d; const output = unsignedTx.outputs[0]; const isERC20Transfer = !!output.tokenAddress; const toAddress = isERC20Transfer ? output.tokenAddress : output.address; const value = isERC20Transfer ? '0x0' : (0, bignumber_plus_1.toBigIntHex)(output.value); const baseTx = { to: toAddress || undefined, value, gasLimit: (0, bignumber_plus_1.toBigIntHex)((0, precondtion_1.checkIsDefined)(unsignedTx.feeLimit)), nonce: (0, precondtion_1.checkIsDefined)(unsignedTx.nonce), data: ((_a = unsignedTx.payload) === null || _a === void 0 ? void 0 : _a.data) || '0x', chainId: parseInt((0, precondtion_1.checkIsDefined)(this.chainInfo.implOptions.chainId)), }; if (((_b = unsignedTx.payload) === null || _b === void 0 ? void 0 : _b.EIP1559Enabled) === true) { Object.assign(baseTx, { type: 2, maxFeePerGas: (0, bignumber_plus_1.toBigIntHex)(new bignumber_js_1.default((0, precondtion_1.checkIsDefined)((_c = unsignedTx.payload) === null || _c === void 0 ? void 0 : _c.maxFeePerGas))), maxPriorityFeePerGas: (0, bignumber_plus_1.toBigIntHex)(new bignumber_js_1.default((0, precondtion_1.checkIsDefined)((_d = unsignedTx.payload) === null || _d === void 0 ? void 0 : _d.maxPriorityFeePerGas))), }); } else { Object.assign(baseTx, { gasPrice: (0, bignumber_plus_1.toBigIntHex)((0, precondtion_1.checkIsDefined)(unsignedTx.feePricePerUnit)), }); } return baseTx; } async signMessage(message, signer, address) { const messageHash = (0, message_1.hashMessage)(message.type, message.message); const [sig, recId] = await signer.sign(ethUtil.toBuffer(messageHash)); return ethUtil.addHexPrefix(Buffer.concat([sig, Buffer.from([recId + 27])]).toString('hex')); } async verifyMessage(address, message, signature) { const recoveredAddress = await this.ecRecover(message, signature); return address.toLowerCase() === recoveredAddress.toLowerCase(); } async ecRecover(message, signature) { const messageHash = (0, message_1.hashMessage)(message.type, message.message); const hashBuffer = ethUtil.toBuffer(messageHash); const sigBuffer = ethUtil.toBuffer(signature); (0, precondtion_1.check)(hashBuffer.length === 32, 'Invalid message hash length'); (0, precondtion_1.check)(sigBuffer.length === 65, 'Invalid signature length'); const [r, s, v] = [ sigBuffer.slice(0, 32), sigBuffer.slice(32, 64), sigBuffer[64], ]; const publicKey = ethUtil.ecrecover(hashBuffer, v, r, s); return ethUtil.addHexPrefix(ethUtil.pubToAddress(publicKey).toString('hex')); } // The below two mm- methods are very specific functions needed to mimic a // metamask provider. async mmDecrypt(serializedMessage, signer) { const encryptedData = JSON.parse(ethUtil.toBuffer(serializedMessage).toString()); return (0, eth_sig_util_1.decrypt)({ encryptedData, privateKey: (await signer.getPrvkey()).toString('hex'), }); } async mmGetPublicKey(signer) { return (0, eth_sig_util_1.getEncryptionPublicKey)((await signer.getPrvkey()).toString('hex')); } async hardwareGetXpubs(paths, showOnDevice) { const resp = await this.wrapHardwareCall(() => js_sdk_1.default.ethereumGetPublicKey({ bundle: paths.map((path) => ({ path, showOnTrezor: showOnDevice })), })); return resp.map((i) => ({ path: i.serializedPath, xpub: i.xpub, })); } async hardwareGetAddress(path, showOnDevice, addressToVerify) { const params = { path, showOnTrezor: showOnDevice, }; if (typeof addressToVerify === 'string') { Object.assign(params, { address: addressToVerify, }); } const { address } = await this.wrapHardwareCall(() => js_sdk_1.default.ethereumGetAddress(params)); return address; } async hardwareSignTransaction(unsignedTx, signers) { const { inputs: [{ address: fromAddress }], } = unsignedTx; const signer = signers[fromAddress]; (0, precondtion_1.check)(signer, 'Signer not found'); const tx = this.buildEtherUnSignedTx(unsignedTx); const { r, s, v } = await this.wrapHardwareCall(() => js_sdk_1.default.ethereumSignTransaction({ path: signer, transaction: { to: tx.to, value: tx.value, gasPrice: tx.gasPrice, gasLimit: tx.gasLimit, nonce: ethUtil.addHexPrefix( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion ethUtil.padToEven(tx.nonce.toString(16))), data: tx.data, chainId: tx.chainId, }, })); const signature = (0, bytes_1.splitSignature)({ v: Number(v), r, s, }); const rawTx = (0, transactions_1.serialize)(tx, signature); const txid = (0, keccak256_1.keccak256)(rawTx); return { txid, rawTx }; } async hardwareSignMessage(message, signer) { const { type: messageType, message: strMessage } = message; switch (messageType) { case message_1.MessageTypes.ETH_SIGN: throw new Error('eth_sign is not supported for hardware'); case message_1.MessageTypes.TYPE_DATA_V1: throw new Error('signTypedData_v1 is not supported for hardware'); case message_1.MessageTypes.PERSONAL_SIGN: { const { signature } = await this.wrapHardwareCall(() => js_sdk_1.default.ethereumSignMessage({ path: signer, message: strMessage, })); return ethUtil.addHexPrefix(signature); } case message_1.MessageTypes.TYPE_DATA_V3: case message_1.MessageTypes.TYPE_DATA_V4: { const { signature } = await this.wrapHardwareCall(() => // @ts-ignore js_sdk_1.default.ethereumSignMessageEIP712({ path: signer, version: messageType === message_1.MessageTypes.TYPE_DATA_V3 ? 'V3' : 'V4', data: JSON.parse(strMessage), })); return ethUtil.addHexPrefix(signature); } } throw new Error(`Not supported`); } async hardwareVerifyMessage(address, message, signature) { const { type: messageType, message: strMessage } = message; if (messageType === message_1.MessageTypes.PERSONAL_SIGN) { const { message: resp } = await this.wrapHardwareCall(() => js_sdk_1.default.ethereumVerifyMessage({ address, message: strMessage, signature, })); return resp === 'Message verified'; } throw new Error('Not supported'); } } exports.Provider = Provider; //# sourceMappingURL=provider.js.map