web3-codegen
Библиотека, предоставляющая удобный доступ к методам смарт контрактов в сети TRON.
Использование
Создание и инициализация
- Импорт папки библиотеки
const Contracts = require('pathToLib');
- Получение инстанса класса путем передачи в конструктор обекта адресов. Ключи объекта адресов должны соответствовать названиям папок в 'lib/contracts'
const contracts = {
TestContract1: 'tronAddress1', //<--
TestContract2: 'tronAddress2', //<--
}
let contracts = new Contracts()
- Получение инстанса класса путем заполнения файла конфига 'lib/config.js'. Ключи объекта адресов должны соответствовать названиям папок в 'lib/contracts', при генерации устанавливаются автоматически
const config = {
contracts: {
TestContract1: 'tronAddress1', //<--
TestContract2: 'tronAddress2', //<--
},
sleepTime: {
waitRet: 500,
waitTrInfo: 1500
}
}
module.exports = config
let contracts = new Contracts()
- Инициализация инстанса объектом TronWeb. На фронте объект TronWeb получается из кошелька пользователя.
let pk = 'privateKey';
const fullNode = 'https://api.nileex.io';
const solidityNode = 'https://api.nileex.io';
const eventServer = 'https://event.nileex.io';
const TronWeb = require('tronweb');
const tronWeb = new TronWeb(fullNode, solidityNode, eventServer, pk);
await contracts.init(tronWeb); //<--
Ввзов методов контрактов
Вызов методов контракта происходит следующим образом:
let result = await contracts.contractName.contractMethodName(
contractParam1,
contractParam1,
__txParams__,
__requestParams__
);
Все методы контрактов асинхронные, возвращают Promise
Посмотреть все возможные методы для работы с контрактом можно по пути 'lib/currentContractName/currentContractName.js'.
Метод 'init' не относится к контракту и является внутренним методом библиотеки.
const _Contract = require('../_Contract.js');
const _ContractData = require('../contractData.js');
const _TriggerHandler = require('../triggerHandler.js');
const _Events = require('./BTTEvents.js');
const path = require('path');
const fs = require("fs-extra");
class BTT extends _Contract {
constructor(address) {
super(address);
this.events = null;
let abiObjPath = path.join(__dirname, 'abiObj.json');
let abiObj = JSON.parse(fs.readFileSync(abiObjPath));
this.contractData = new _ContractData(abiObj);
}
async init(tronWebInstance) {
await super.init(tronWebInstance);
this.events = new _Events(this._tw);
this.triggerHandler = new _TriggerHandler(this._tw);
return this;
}
async name() { //<--
const functionData = this.contractData.getFunctionData('name')
const triggerResult = await this._call('name');
let innerConvert = async (triggerResult) => {
return await this._convert.output(triggerResult, functionData.outputs)
}
return await this.triggerHandler.handle('_call', triggerResult, innerConvert)
}
async approve(guy,sad, __txParams__, __requestParams__) { //<--
const functionData = this.contractData.getFunctionData('approve')
const triggerResult = await this._send('approve', [guy,sad], __txParams__);
if(__requestParams__ !== undefined) {
if (__requestParams__?.idOnly === true) return triggerResult;
};
let innerConvert = async (triggerResult) => {
return await this._convert.output(triggerResult, functionData.outputs)
}
return await this.triggerHandler.handle('_send', triggerResult, innerConvert)
}
}
module.exports = BTT;
Методы контрактов, в логике работы библиотеки, делятся на 2 типа вызова:
- call - обрабатывают 'pure' и 'view' методы контрактов
- send - обрабатывают 'payable' и 'nonpayable' методы контрактов
В данном примере есть два метода: 'name' и 'approve'. У 'name' тип вызова call, у 'approve' тип вызова send
Определить тип вызова можно по первому параметру в вызываемой в конце функции.
- Если первый параметр
_call
то тип вызова call
async name() {
const functionData = this.contractData.getFunctionData('name')
const triggerResult = await this._call('name');
let innerConvert = async (triggerResult) => {
return await this._convert.output(triggerResult, functionData.outputs)
}
return await this.triggerHandler.handle('_call', triggerResult, innerConvert) //<--
}
методы с типом вызова call принимают на вход те же параметры, что и методы самого контракта. В результате ожидания промиса вернется объект вида:
{
triggerType: 'call',
transactionId: 'transactionId',
isSuccess: Boolean,
result: Array
}
В 'result' всегда будет массив возвращенных значений контракта. Если метод ничего не возвращает, в 'result' будет пустой массив
- Если первый параметр
_send
то тип вызова send
async approve(guy,sad, __txParams__, __requestParams__) {
const functionData = this.contractData.getFunctionData('approve')
const triggerResult = await this._send('approve', [guy,sad], __txParams__);
if(__requestParams__ !== undefined) {
if (__requestParams__?.idOnly === true) return triggerResult;
};
let innerConvert = async (triggerResult) => {
return await this._convert.output(triggerResult, functionData.outputs)
}
return await this.triggerHandler.handle('_send', triggerResult, innerConvert) //<--
}
методы с типом вызова send принимают на вход те же параметры, что и методы самого контракта и 2 объекта с настройками __txParams__
и __requestParams__
.
Превым идет __txParams__
, это стандартный объект с настройками вызова из TronWeb. Подробнее почитать про него можно в документации к TronWeb
Превым идет __requestParams__
, это объект настроек самой библиотеки. {workMode:'режим работы', waitTrInfo: bool}
Есть 3 режима работы:
-
{workMode:'idOnly'}
в результате вернет строку с transactionId. -
{workMode:'idPromise'}
режим работы по умолчанию, в результате вернет объект вида:
{
triggerType: 'send',
transactionId: 'transactionId',
isSuccess: Boolean,
result: Promise
}
-
{workMode:'idResult'}
в результате вернет объект вида:
{
triggerType: 'send',
transactionId: 'transactionId',
isSuccess: Boolean,
result: Result
}
При работе в режимах idPromise
(после ожидания промиса) и idResult
в result
будет лежать объект следующего вида:
{
transactionId: 'transactionId',
blockTimeStamp: Number,
blockNumber: Number,
events: Array, //Массив ивентов, которые были записаны в процессе исполнения метода
revertMessage: String, // Расшифрованное сообщение revert, если во время испонения метода что-то не прошло проверку в контракте
xStatus: String //Статус выполнения метода контракта
};
При значении waitTrInfo
: false вне зависимости от workMode некоторые значения в result
будут содержать в себе промис. Это сделано для того, чтобы сократить время до получения статуса транзакции. Ожидание любого из них вернет значение поля, которое ожидалось, а так же изменит объект результата так, что все промисы заменятся их значениями.
Поля, которые затрагивает эта настройка:
{
triggerType: 'send',
isSuccess: false,
result: {
transactionId: '152cc12b9033495cb95c52c9b1b449a74adb3b49d5a2adff1b12bfbff7f29e4b',
blockTimeStamp: Promise { <pending> }, //<---
blockNumber: Promise { <pending> }, //<---
events: Promise { <pending> }, //<---
revertMessage: Promise { <pending> }, //<---
xStatus: 'REVERT'
},
transactionId: '152cc12b9033495cb95c52c9b1b449a74adb3b49d5a2adff1b12bfbff7f29e4b'
}
После ожидания любого из них:
{
triggerType: 'send',
isSuccess: false,
result: {
transactionId: '152cc12b9033495cb95c52c9b1b449a74adb3b49d5a2adff1b12bfbff7f29e4b',
blockTimeStamp: 1658350602000, //<---
blockNumber: 26132987, //<---
events: [], //<---
revertMessage: 'IDK revert', //<---
xStatus: 'REVERT'
},
transactionId: '152cc12b9033495cb95c52c9b1b449a74adb3b49d5a2adff1b12bfbff7f29e4b'
}
xStatus
может быть следующим:
DEFAULT = 0;
SUCCESS = 1;
REVERT = 2;
BAD_JUMP_DESTINATION = 3;
OUT_OF_MEMORY = 4;
PRECOMPILED_CONTRACT = 5;
STACK_TOO_SMALL = 6;
STACK_TOO_LARGE = 7;
ILLEGAL_OPERATION = 8;
STACK_OVERFLOW = 9;
OUT_OF_ENERGY = 10;
OUT_OF_TIME = 11;
JVM_STACK_OVER_FLOW = 12;
UNKNOWN = 13;
Метод исполнился корректно, если xStatus
равен 'SUCCESS'
Если происходит ошибка на уровне TronWeb, то в result
будет лежать объект следующего вида:
{
error: 'Тип ошибки',
message: 'Сообщение'
}
Если во время , то в result
будет лежать объект следующего вида:
{
error: 'Тип ошибки',
message: 'Сообщение'
}