@broxus/js-core
Version:
MobX-based JavaScript Core library
254 lines (253 loc) • 9.56 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { debounce, throwException } from '@broxus/js-utils';
import { action, computed, makeObservable } from 'mobx';
import { SmartContractModel } from '../../core';
import { CONFIG_ABI, PRICES_PARAM_ABI } from '../../models/master-chain-config/constants';
import { contractStateChangeDebugMessage, isAddressesEquals, subscribeDebugMessage, syncErrorMessage, unsubscribeDebugMessage, unsubscribeErrorMessage, } from '../../utils';
export class MasterChainConfig extends SmartContractModel {
_connection;
options;
_contract;
/**
* @param {ProviderRpcClient} _connection Standalone RPC client that doesn't require connection to the TVM wallet provider
* @param {Address | string} address MasterChainConfig root address
* @param {Readonly<MasterChainConfigCtorOptions>} [options] (optional) MasterChainConfig Smart Contract Model options
*/
constructor(_connection, address, options) {
super(_connection, address);
this._connection = _connection;
this.options = options;
this._contract = new this._connection.Contract(CONFIG_ABI, this.address);
makeObservable(this);
}
/**
* @param {ProviderRpcClient} connection Standalone RPC client that doesn't require connection to the TVM wallet provider
* @param {Address | string} address MasterChainConfig root address
* @param {Readonly<MasterChainCreateOptions>} [options] (optional) MasterChainConfig Smart Contract Model options
*/
static async create(connection, address, options) {
const { sync = true, watch, watchCallback, ...restOptions } = { ...options };
const config = new MasterChainConfig(connection, address, restOptions);
if (sync) {
await config.sync({ force: false });
}
if (watch) {
await config.watch(watchCallback);
}
return config;
}
async sync(options) {
if (!options?.force && this.isSyncing) {
return;
}
try {
this.setState('isSyncing', !options?.silent);
await this.syncContractState({ force: options?.force || !this.contractState });
if (!this.isDeployed) {
throwException(`${this.constructor.name} is not deployed`);
}
await this.syncParams();
}
catch (e) {
if (process.env.NODE_ENV !== 'production') {
syncErrorMessage(this.constructor.name, this.address, e);
}
}
finally {
this.setState('isSyncing', false);
}
}
async watch(callback) {
try {
this.contractSubscriber = new this._connection.Subscriber();
await this.contractSubscriber.states(this.address).delayed(stream => {
if (process.env.NODE_ENV !== 'production') {
subscribeDebugMessage(this.constructor.name, this.address);
}
return stream.on(debounce(async (event) => {
if (process.env.NODE_ENV !== 'production') {
contractStateChangeDebugMessage(this.constructor.name, this.address, event);
}
if (isAddressesEquals(event.address, this.address)) {
await this.sync({ force: !this.isSyncing, silent: true });
callback?.();
return;
}
await this.unwatch();
}, this.options?.watchDebounceDelay ?? 3000));
});
return this.contractSubscriber;
}
catch (e) {
await this.unwatch();
throw e;
}
}
async unwatch() {
if (this.contractSubscriber === undefined) {
return;
}
try {
await this.contractSubscriber?.unsubscribe();
this.contractSubscriber = undefined;
if (process.env.NODE_ENV !== 'production') {
unsubscribeDebugMessage(this.constructor.name, this.address);
}
}
catch (e) {
if (process.env.NODE_ENV !== 'production') {
unsubscribeErrorMessage(this.constructor.name, this.address, e);
}
}
}
async syncParams() {
const { fields } = await this._contract.getFields({ allowPartial: true, cachedState: this.contractState });
if (fields == null) {
throw new Error('Config contract state not found');
}
const { boc: nonEmptyMap } = await this._connection.packIntoCell({
abiVersion: '2.2',
data: {
flag: true,
root: fields.paramsRoot,
},
structure: [
{ name: 'flag', type: 'bool' },
{ name: 'root', type: 'cell' },
],
});
const { data: { params: rawParams } } = await this._connection.unpackFromCell({
abiVersion: '2.2',
allowPartial: true,
boc: nonEmptyMap,
structure: [{ name: 'params', type: 'map(uint32,cell)' }],
});
const params = new Map();
for (const [id, value] of rawParams) {
params.set(parseInt(id, 10), value);
}
const param = params.get(20);
if (!param) {
throw new Error('Param state not found');
}
const { data: { value: prices } } = await this._connection.unpackFromCell({
abiVersion: '2.2',
allowPartial: true,
boc: param,
structure: PRICES_PARAM_ABI,
});
this.setData({ ...prices });
}
get gasPrice() {
return this._data.gasPrice;
}
get gasLimit() {
return this._data.gasLimit;
}
get tag2() {
return this._data.tag2;
}
get specialGasLimit() {
return this._data.specialGasLimit;
}
get gasCredit() {
return this._data.gasCredit;
}
get blockGasLimit() {
return this._data.blockGasLimit;
}
get freezeDueLimit() {
return this._data.freezeDueLimit;
}
get deleteDueLimit() {
return this._data.deleteDueLimit;
}
get flatGasLimit() {
return this._data.flatGasLimit;
}
get flatGasPrice() {
return this._data.flatGasPrice;
}
}
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], MasterChainConfig.prototype, "sync", null);
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Function]),
__metadata("design:returntype", Promise)
], MasterChainConfig.prototype, "watch", null);
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], MasterChainConfig.prototype, "unwatch", null);
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], MasterChainConfig.prototype, "syncParams", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "gasPrice", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "gasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "tag2", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "specialGasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "gasCredit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "blockGasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "freezeDueLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "deleteDueLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "flatGasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], MasterChainConfig.prototype, "flatGasPrice", null);