| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.Method = void 0;
- const tslib_1 = require("tslib");
- /* eslint-disable no-control-regex */
- const index_js_1 = tslib_1.__importDefault(require("../../utils/index.js"));
- const abi_js_1 = require("../../utils/abi.js");
- const crypto_js_1 = require("../../utils/crypto.js");
- const getFunctionSelector = (abi) => {
- if ('stateMutability' in abi) {
- abi.stateMutability = abi.stateMutability ? abi.stateMutability.toLowerCase() : 'nonpayable';
- }
- abi.type = abi.type ? abi.type.toLowerCase() : '';
- if (abi.type === 'fallback' || abi.type === 'receive')
- return '0x';
- const iface = new index_js_1.default.ethersUtils.Interface([abi]);
- let obj;
- if (abi.type === 'event') {
- obj = iface.getEvent(abi.name);
- }
- else {
- obj = iface.getFunction(abi.name);
- }
- if (obj) {
- return obj.format('sighash');
- }
- throw new Error('unknown function');
- };
- const decodeOutput = (abi, output) => {
- return (0, abi_js_1.decodeParamsV2ByABI)(abi, output);
- };
- class Method {
- tronWeb;
- contract;
- abi;
- name;
- inputs;
- outputs;
- functionSelector;
- signature;
- defaultOptions;
- constructor(contract, abi) {
- this.tronWeb = contract.tronWeb;
- this.contract = contract;
- this.abi = abi;
- this.name = abi.name || abi.type;
- this.inputs = abi.inputs || [];
- this.outputs = [];
- if ('outputs' in abi && abi.outputs) {
- this.outputs = abi.outputs;
- }
- this.functionSelector = getFunctionSelector(abi);
- this.signature = (0, crypto_js_1.sha3)(this.functionSelector, false).slice(0, 8);
- this.defaultOptions = {
- feeLimit: this.tronWeb.feeLimit,
- callValue: 0,
- userFeePercentage: 100,
- shouldPollResponse: false, // Only used for sign()
- };
- }
- decodeInput(data) {
- const abi = JSON.parse(JSON.stringify(this.abi));
- abi.outputs = abi.inputs;
- return decodeOutput(abi, '0x' + data);
- }
- onMethod(...args) {
- let rawParameter = '';
- if (this.abi && !/event/i.test(this.abi.type)) {
- rawParameter = (0, abi_js_1.encodeParamsV2ByABI)(this.abi, args);
- }
- return {
- call: async (options = {}) => {
- options = {
- ...options,
- rawParameter,
- };
- return await this._call([], [], options);
- },
- send: async (options = {}, privateKey = this.tronWeb.defaultPrivateKey) => {
- options = {
- ...options,
- rawParameter,
- };
- return await this._send([], [], options, privateKey);
- },
- };
- }
- async _call(types, args, options = {}) {
- if (types.length !== args.length) {
- throw new Error('Invalid argument count provided');
- }
- if (!this.contract.address) {
- throw new Error('Smart contract is missing address');
- }
- if (!this.contract.deployed) {
- throw new Error('Calling smart contracts requires you to load the contract first');
- }
- if ('stateMutability' in this.abi) {
- const { stateMutability } = this.abi;
- if (stateMutability && !['pure', 'view'].includes(stateMutability.toLowerCase())) {
- throw new Error(`Methods with state mutability "${stateMutability}" must use send()`);
- }
- }
- options = {
- ...this.defaultOptions,
- from: this.tronWeb.defaultAddress.hex,
- ...options,
- _isConstant: true,
- };
- const parameters = args.map((value, index) => ({
- type: types[index],
- value,
- }));
- const transaction = await this.tronWeb.transactionBuilder.triggerSmartContract(this.contract.address, this.functionSelector, options, parameters, options.from ? this.tronWeb.address.toHex(options.from) : undefined);
- if (!index_js_1.default.hasProperty(transaction, 'constant_result')) {
- throw new Error('Failed to execute');
- }
- const len = transaction.constant_result[0].length;
- if (len === 0 || len % 64 === 8) {
- let msg = 'The call has been reverted or has thrown an error.';
- if (len !== 0) {
- msg += ' Error message: ';
- let msg2 = '';
- const chunk = transaction.constant_result[0].substring(8);
- for (let i = 0; i < len - 8; i += 64) {
- msg2 += this.tronWeb.toUtf8(chunk.substring(i, i + 64));
- }
- msg += msg2
- .replace(/(\u0000|\u000b|\f)+/g, ' ')
- .replace(/ +/g, ' ')
- .replace(/\s+$/g, '');
- }
- throw new Error(msg);
- }
- let output = decodeOutput(this.abi, '0x' + transaction.constant_result[0]);
- if (output.length === 1 && Object.keys(output).length === 1) {
- output = output[0];
- }
- return output;
- }
- async _send(types, args, options = {}, privateKey = this.tronWeb.defaultPrivateKey) {
- if (types.length !== args.length) {
- throw new Error('Invalid argument count provided');
- }
- if (!this.contract.address) {
- throw new Error('Smart contract is missing address');
- }
- if (!this.contract.deployed) {
- throw new Error('Calling smart contracts requires you to load the contract first');
- }
- const { stateMutability } = this.abi;
- if (['pure', 'view'].includes(stateMutability.toLowerCase())) {
- throw new Error(`Methods with state mutability "${stateMutability}" must use call()`);
- }
- // If a function isn't payable, dont provide a callValue.
- if (!['payable'].includes(stateMutability.toLowerCase())) {
- options.callValue = 0;
- }
- options = {
- ...this.defaultOptions,
- from: this.tronWeb.defaultAddress.hex,
- ...options,
- };
- const parameters = args.map((value, index) => ({
- type: types[index],
- value,
- }));
- const address = privateKey ? this.tronWeb.address.fromPrivateKey(privateKey) : this.tronWeb.defaultAddress.base58;
- const transaction = await this.tronWeb.transactionBuilder.triggerSmartContract(this.contract.address, this.functionSelector, options, parameters, this.tronWeb.address.toHex(address));
- if (!transaction.result || !transaction.result.result) {
- throw new Error('Unknown error: ' + JSON.stringify(transaction, null, 2));
- }
- // If privateKey is false, this won't be signed here. We assume sign functionality will be replaced.
- const signedTransaction = await this.tronWeb.trx.sign(transaction.transaction, privateKey);
- if (!signedTransaction.signature) {
- if (!privateKey) {
- throw new Error('Transaction was not signed properly');
- }
- throw new Error('Invalid private key provided');
- }
- const broadcast = await this.tronWeb.trx.sendRawTransaction(signedTransaction);
- if (broadcast.code) {
- const err = {
- error: broadcast.code,
- message: broadcast.code,
- };
- if (broadcast.message)
- err.message = this.tronWeb.toUtf8(broadcast.message);
- const error = new Error(err.message);
- error.error = broadcast.code;
- throw error;
- }
- if (!options.shouldPollResponse) {
- return signedTransaction.txID;
- }
- const checkResult = async (index) => {
- if (index === (options.pollTimes || 20)) {
- const error = new Error('Cannot find result in solidity node');
- error.error = 'Cannot find result in solidity node';
- error.transaction = signedTransaction;
- throw error;
- }
- const output = await this.tronWeb.trx.getTransactionInfo(signedTransaction.txID);
- if (!Object.keys(output).length) {
- await new Promise((r) => setTimeout(r, 3000));
- return checkResult(index + 1);
- }
- if (output.result && output.result === 'FAILED') {
- const error = new Error(this.tronWeb.toUtf8(output.resMessage));
- error.error = this.tronWeb.toUtf8(output.resMessage);
- error.transaction = signedTransaction;
- error.output = output;
- throw error;
- }
- if (!index_js_1.default.hasProperty(output, 'contractResult')) {
- const error = new Error('Failed to execute: ' + JSON.stringify(output, null, 2));
- error.error = 'Failed to execute: ' + JSON.stringify(output, null, 2);
- error.transaction = signedTransaction;
- error.output = output;
- throw error;
- }
- if (options.rawResponse) {
- return output;
- }
- let decoded = decodeOutput(this.abi, '0x' + output.contractResult[0]);
- if (decoded.length === 1 && Object.keys(decoded).length === 1) {
- decoded = decoded[0];
- }
- if (options.keepTxID) {
- return [signedTransaction.txID, decoded];
- }
- return decoded;
- };
- return checkResult(0);
- }
- }
- exports.Method = Method;
- //# sourceMappingURL=method.js.map
|