@broxus/js-core
Version:
MobX-based JavaScript Core library
339 lines (338 loc) • 12.8 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 { SECONDS_IN_HOUR } from '../../constants';
import { SmartContractModel } from '../../core';
import { CONFIG_ABI, FORWARD_FEE_PRICES_PARAM_ABI, PRICES_PARAM_ABI } from '../../models/network-config/constants';
import { areAddressesEqual, contractStateChangeDebugMessage, subscribeDebugMessage, syncErrorMessage, unsubscribeDebugMessage, unsubscribeErrorMessage, } from '../../utils';
export class ShardChainConfig 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
* ShardChainConfig root address
* @param {Readonly<ShardChainConfigCtorOptions>} [options]
* (optional) ShardChainConfig 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
* ShardChainConfig root address
* @param {Readonly<ShardChainCreateOptions>} [options]
* (optional) ShardChainConfig Smart Contract Model options
*/
static async create(connection, address, options) {
const { sync = true, watch, watchCallback, ...restOptions } = { ...options };
const config = new ShardChainConfig(connection, address, restOptions);
if (sync) {
await config.sync({ force: false, ttl: options?.ttl });
}
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,
ttl: options?.ttl || SECONDS_IN_HOUR * 1000,
});
if (!this.isDeployed) {
throwException(`${this.constructor.name} is not deployed`);
}
await this.syncParams();
}
catch (e) {
if (process.env.NODE_ENV !== 'production') {
const state = await this._connection.getProviderState();
syncErrorMessage(this.constructor.name, this.address, e, state.networkId.toString());
}
}
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') {
const state = await this._connection.getProviderState();
contractStateChangeDebugMessage(this.constructor.name, this.address, event, state.networkId.toString());
}
if (areAddressesEqual(event.address, this.address)) {
await this.sync({ force: !this.isSyncing, silent: true });
callback?.(...this.toJSON(true));
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') {
const state = await this._connection.getProviderState();
unsubscribeErrorMessage(this.constructor.name, this.address, e, state.networkId.toString());
}
}
}
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);
}
// Base workchain gas limits and prices.
// https://github.com/broxus/everscale-types/blob/master/src/models/config/mod.rs#L1033
const param21 = params.get(21);
// Message forwarding prices for base workchain.
// https://github.com/broxus/everscale-types/blob/master/src/models/config/mod.rs#L1057
const param25 = params.get(25);
if (!param21) {
throw new Error('Param (21) state not found');
}
if (!param25) {
throw new Error('Param (25) state not found');
}
const [data21, data25] = await Promise.all([
this._connection.unpackFromCell({
abiVersion: '2.2',
allowPartial: true,
boc: param21,
structure: PRICES_PARAM_ABI,
}),
this._connection.unpackFromCell({
abiVersion: '2.2',
allowPartial: true,
boc: param25,
structure: FORWARD_FEE_PRICES_PARAM_ABI,
}),
]);
this.setData({
bitPrice: data25.data.value.bitPrice,
blockGasLimit: data21.data.value.blockGasLimit,
cellPrice: data25.data.value.cellPrice,
deleteDueLimit: data21.data.value.deleteDueLimit,
firstFrac: data25.data.value.firstFrac,
flatGasLimit: data21.data.value.flatGasLimit,
flatGasPrice: data21.data.value.flatGasPrice,
freezeDueLimit: data21.data.value.freezeDueLimit,
gasCredit: data21.data.value.gasCredit,
gasLimit: data21.data.value.gasLimit,
gasPrice: data21.data.value.gasPrice,
ihrPriceFactor: data25.data.value.ihrPriceFactor,
lumpPrice: data25.data.value.lumpPrice,
nextFrac: data25.data.value.nextFrac,
specialGasLimit: data21.data.value.specialGasLimit,
});
}
get bitPrice() {
return this._data.bitPrice;
}
get blockGasLimit() {
return this._data.blockGasLimit;
}
get cellPrice() {
return this._data.cellPrice;
}
get deleteDueLimit() {
return this._data.deleteDueLimit;
}
get firstFrac() {
return this._data.firstFrac;
}
get flatGasLimit() {
return this._data.flatGasLimit;
}
get flatGasPrice() {
return this._data.flatGasPrice;
}
get freezeDueLimit() {
return this._data.freezeDueLimit;
}
get gasCredit() {
return this._data.gasCredit;
}
get gasLimit() {
return this._data.gasLimit;
}
get gasPrice() {
return this._data.gasPrice;
}
get ihrPriceFactor() {
return this._data.ihrPriceFactor;
}
get lumpPrice() {
return this._data.lumpPrice;
}
get nextFrac() {
return this._data.nextFrac;
}
get specialGasLimit() {
return this._data.specialGasLimit;
}
}
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], ShardChainConfig.prototype, "sync", null);
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Function]),
__metadata("design:returntype", Promise)
], ShardChainConfig.prototype, "watch", null);
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], ShardChainConfig.prototype, "unwatch", null);
__decorate([
action.bound,
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], ShardChainConfig.prototype, "syncParams", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "bitPrice", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "blockGasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "cellPrice", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "deleteDueLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "firstFrac", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "flatGasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "flatGasPrice", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "freezeDueLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "gasCredit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "gasLimit", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "gasPrice", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "ihrPriceFactor", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "lumpPrice", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "nextFrac", null);
__decorate([
computed,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], ShardChainConfig.prototype, "specialGasLimit", null);