UNPKG

@vechain/connex-driver

Version:
186 lines 16.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TransactionType = exports.Driver = void 0; const driver_no_vendor_1 = require("./driver-no-vendor"); const thor_devkit_1 = require("thor-devkit"); const crypto_1 = require("crypto"); const bignumber_js_1 = __importDefault(require("bignumber.js")); /** class fully implements DriverInterface */ class Driver extends driver_no_vendor_1.DriverNoVendor { /** * create driver instance * it will fetch config(genesis, head) via net as construction params * @param net * @param wallet */ static connect(net, wallet) { return __awaiter(this, void 0, void 0, function* () { const genesis = yield net.http('GET', 'blocks/0'); const best = yield net.http('GET', 'blocks/best', { validateResponseHeader: headers => { const xgid = headers['x-genesis-id']; if (xgid && xgid !== genesis.id) { throw new Error(`responded 'x-genesis-id' not matched`); } } }); const head = { id: best.id, number: best.number, timestamp: best.timestamp, parentID: best.parentID, txsFeatures: best.txsFeatures, gasLimit: best.gasLimit, }; if (best.baseFeePerGas) { head.baseFeePerGas = best.baseFeePerGas; } return new Driver(net, genesis, head, wallet); }); } constructor(net, genesis, initialHead, wallet) { super(net, genesis, initialHead); this.wallet = wallet; /** params for tx construction */ this.txParams = { expiration: 18, gasPriceCoef: 0, maxPriorityFeePerGas: 0, txType: exports.TransactionType.DynamicFee }; } signTx(msg, options) { return __awaiter(this, void 0, void 0, function* () { options.onAccepted && options.onAccepted(); const key = this.findKey(options.signer); const clauses = msg.map(c => ({ to: c.to ? c.to.toLowerCase() : null, value: c.value.toString().toLowerCase(), data: (c.data || '0x').toLowerCase(), })); const gas = options.gas || (yield this.estimateGas(clauses, key.address)); // Base transaction body const baseTxBody = { chainTag: Number.parseInt(this.genesis.id.slice(-2), 16), blockRef: this.head.id.slice(0, 18), expiration: this.txParams.expiration, clauses, gas, dependsOn: options.dependsOn || null, nonce: '0x' + (0, crypto_1.randomBytes)(8).toString('hex') }; // Determine transaction type and create appropriate body let txType = this.txParams.txType; if (txType === exports.TransactionType.DynamicFee && !this.head.baseFeePerGas) { // If baseFeePerGas is not available, means dynamic fee is not enabled // in the current block, fallback to legacy transaction txType = exports.TransactionType.Legacy; } let txBody; if (txType === exports.TransactionType.DynamicFee) { // Dynamic fee transaction txBody = Object.assign(Object.assign({}, baseTxBody), { type: exports.TransactionType.DynamicFee, maxPriorityFeePerGas: this.txParams.maxPriorityFeePerGas.toString(), maxFeePerGas: new bignumber_js_1.default(this.txParams.maxPriorityFeePerGas).plus(this.head.baseFeePerGas).toString() }); } else { // Legacy transaction txBody = Object.assign(Object.assign({}, baseTxBody), { type: exports.TransactionType.Legacy, gasPriceCoef: this.txParams.gasPriceCoef }); } let tx; if (options.delegator) { const delegatedTx = new thor_devkit_1.Transaction(Object.assign(Object.assign({}, txBody), { reserved: { features: 1 /* vip191 */ } })); const originSig = yield key.sign(delegatedTx.signingHash()); const unsigned = { raw: '0x' + delegatedTx.encode().toString('hex'), origin: key.address }; try { const result = yield this.net.http('POST', options.delegator.url, { body: unsigned }); delegatedTx.signature = Buffer.concat([originSig, Buffer.from(result.signature.slice(2), 'hex')]); tx = delegatedTx; } catch (err) { // tslint:disable-next-line: no-console console.warn('tx delegation error: ', err); // fallback to non-vip191 tx } } if (!tx) { tx = new thor_devkit_1.Transaction(txBody); // eslint-disable-next-line @typescript-eslint/no-unsafe-call tx.signature = yield key.sign(tx.signingHash()); } // eslint-disable-next-line @typescript-eslint/no-unsafe-call const raw = `0x${tx.encode().toString('hex')}`; if (this.onTxCommit) { this.onTxCommit({ id: tx.id, raw, resend: () => __awaiter(this, void 0, void 0, function* () { yield this.sendTx(raw); }) }); } yield this.sendTx(raw); return { txid: tx.id, signer: key.address }; }); } signCert(msg, options) { return __awaiter(this, void 0, void 0, function* () { options.onAccepted && options.onAccepted(); const key = this.findKey(options.signer); const annex = { domain: 'localhost', timestamp: this.head.timestamp, signer: key.address }; const unsigned = thor_devkit_1.Certificate.encode(Object.assign(Object.assign({}, msg), annex)); const signature = yield key.sign((0, thor_devkit_1.blake2b256)(unsigned)); return { annex, signature: '0x' + signature.toString('hex') }; }); } findKey(addr) { if (this.wallet) { const keys = this.wallet.list; const key = addr ? keys.find(k => k.address === addr) : keys[0]; if (key) { return key; } } throw new Error('empty wallet'); } sendTx(raw) { return this.httpPost('transactions', { raw }); } estimateGas(clauses, caller) { return __awaiter(this, void 0, void 0, function* () { const outputs = yield this.explain({ clauses, caller, }, this.head.id); const execGas = outputs.reduce((sum, out) => sum + out.gasUsed, 0); const intrinsicGas = thor_devkit_1.Transaction.intrinsicGas(clauses); return intrinsicGas + (execGas ? (execGas + 15000) : 0); }); } } exports.Driver = Driver; exports.TransactionType = thor_devkit_1.Transaction.Type; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJpdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2RyaXZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFDQSx5REFBbUQ7QUFFbkQsNkNBQWtFO0FBQ2xFLG1DQUFvQztBQUNwQyxnRUFBb0M7QUFFcEMsNkNBQTZDO0FBQzdDLE1BQWEsTUFBTyxTQUFRLGlDQUFjO0lBQ3RDOzs7OztPQUtHO0lBQ0ksTUFBTSxDQUFPLE9BQU8sQ0FBQyxHQUFRLEVBQUUsTUFBZTs7WUFDakQsTUFBTSxPQUFPLEdBQXNCLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLENBQUE7WUFDcEUsTUFBTSxJQUFJLEdBQXNCLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsYUFBYSxFQUFFO2dCQUNqRSxzQkFBc0IsRUFBRSxPQUFPLENBQUMsRUFBRTtvQkFDOUIsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFBO29CQUNwQyxJQUFJLElBQUksSUFBSSxJQUFJLEtBQUssT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDO3dCQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLHNDQUFzQyxDQUFDLENBQUE7b0JBQzNELENBQUM7Z0JBQ0wsQ0FBQzthQUNKLENBQUMsQ0FBQTtZQUVGLE1BQU0sSUFBSSxHQUErQjtnQkFDckMsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO2dCQUNYLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtnQkFDbkIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO2dCQUN6QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7Z0JBQ3ZCLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztnQkFDN0IsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO2FBQzFCLENBQUE7WUFDRCxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDckIsSUFBSSxDQUFDLGFB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