import { TronWeb } from '../../tronweb.js'; import { Transaction, TransactionWrapper } from '../../types/Transaction.js'; import { txCheckWithArgs, txJsonToPb, txPbToTxID, txPbToRawDataHex } from '../../utils/transaction.js'; import { clonePlainData } from '../../utils/clone.js'; import { keccak256 } from '../../utils/ethersUtils.js'; import { hexStr2byteArray } from '../../utils/code.js'; import { ContractParamter, ContractType } from '../../types/Contract.js'; import { TriggerConstantContractOptions } from '../../types/TransactionBuilder.js'; export function fromUtf8(value: string) { return TronWeb.fromUtf8(value).replace(/^0x/, ''); } export function deepCopyJson(json: object): T { return JSON.parse(JSON.stringify(json)); } export function resultManager(transaction: TransactionWrapper, data: unknown, options: TriggerConstantContractOptions) { if (transaction.Error) throw new Error(transaction.Error); if (transaction.result && transaction.result.message) { throw new Error(TronWeb.toUtf8(transaction.result.message)); } const authResult = txCheckWithArgs(transaction, data, options); if (authResult) { return transaction; } throw new Error('Invalid transaction'); } /** * Deep-copies the options of `triggerSmartContract` into plain data. The copy keeps `Uint8Array` * values (`bytes` arguments in `parametersV2`); anything else that is not plain data (functions, * `Date`, circular references, ...) is rejected with `Invalid options provided: at `. */ export function cloneTriggerOptions(options: T): T { return clonePlainData(options, { root: 'options', bytes: true, invalid: (reason, path) => new Error(`Invalid options provided: ${reason} at ${path}`), }); } /** * Deep-copies the `parameters` of `triggerSmartContract` (`{ type, value }` entries) into plain * data. The copy keeps `Uint8Array` values (`bytes` arguments); anything else that is not plain * data is rejected with `Invalid parameters provided: at `. */ export function cloneParameters(parameters: T): T { return clonePlainData(parameters, { root: 'parameters', bytes: true, invalid: (reason, path) => new Error(`Invalid parameters provided: ${reason} at ${path}`), }); } export function resultManagerTriggerSmartContract( transaction: TransactionWrapper, data: unknown, options: TriggerConstantContractOptions ) { if (transaction.Error) throw new Error(transaction.Error); if (transaction.result && transaction.result.message) { throw new Error(TronWeb.toUtf8(transaction.result.message)); } if (!(options._isConstant || options.estimateEnergy)) { const authResult = txCheckWithArgs(transaction.transaction, data, options); if (authResult) { return transaction; } throw new Error('Invalid transaction'); } return transaction; } export function genContractAddress(ownerAddress: string, txID: string) { return ( '41' + keccak256(new Uint8Array(hexStr2byteArray(txID + ownerAddress))) .toString() .substring(2) .slice(24) ); } function checkBlockHeader(options = {} as Partial): boolean { if ( typeof options['ref_block_bytes'] === 'undefined' && typeof options['ref_block_hash'] === 'undefined' && typeof options['expiration'] === 'undefined' && typeof options['timestamp'] === 'undefined' ) { return false; } if (typeof options['ref_block_bytes'] !== 'string') { throw new Error('Invalid ref_block_bytes provided.'); } if (typeof options['ref_block_hash'] !== 'string') { throw new Error('Invalid ref_block_hash provided.'); } if (typeof options['expiration'] !== 'number') { throw new Error('Invalid expiration provided.'); } if (typeof options['timestamp'] !== 'number') { throw new Error('Invalid timestamp provided.'); } return true; } export async function createTransaction( tronWeb: TronWeb, type: ContractType, value: T, Permission_id?: number, options = {} as Partial> ): Promise> { const tx: Transaction = { visible: false, txID: '', raw_data_hex: '', raw_data: { contract: [ { parameter: { value, type_url: `type.googleapis.com/protocol.${type}`, }, type, }, ], ...(checkBlockHeader(options) ? ({} as Transaction['raw_data']) : await tronWeb.trx.getCurrentRefBlockParams()), ...options, }, }; if (Permission_id) { tx.raw_data.contract[0].Permission_id = Permission_id; } const pb = txJsonToPb(tx); tx.txID = txPbToTxID(pb).replace(/^0x/, ''); tx.raw_data_hex = txPbToRawDataHex(pb).toLowerCase(); return tx; } export function getTransactionOptions(options: { blockHeader?: Partial } = {}) { const ret = {} as Partial; if (checkBlockHeader(options.blockHeader)) { ret['ref_block_bytes'] = options.blockHeader!['ref_block_bytes']; ret['ref_block_hash'] = options.blockHeader!['ref_block_hash']; ret['expiration'] = options.blockHeader!['expiration']; ret['timestamp'] = options.blockHeader!['timestamp']; } return ret; }