lisk-framework
Version:
Lisk blockchain application platform
130 lines • 6.88 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeeModule = void 0;
const lisk_utils_1 = require("@liskhq/lisk-utils");
const lisk_validator_1 = require("@liskhq/lisk-validator");
const lisk_cryptography_1 = require("@liskhq/lisk-cryptography");
const constants_1 = require("./constants");
const state_machine_1 = require("../../state_machine");
const method_1 = require("./method");
const endpoint_1 = require("./endpoint");
const schemas_1 = require("./schemas");
const generator_fee_processed_1 = require("./events/generator_fee_processed");
const relayer_fee_processed_1 = require("./events/relayer_fee_processed");
const insufficient_fee_1 = require("./events/insufficient_fee");
const cc_method_1 = require("./cc_method");
const base_interoperable_module_1 = require("../interoperability/base_interoperable_module");
class FeeModule extends base_interoperable_module_1.BaseInteroperableModule {
constructor() {
super();
this.method = new method_1.FeeMethod(this.stores, this.events);
this.crossChainMethod = new cc_method_1.FeeInteroperableMethod(this.stores, this.events, this.name);
this.configSchema = schemas_1.configSchema;
this.endpoint = new endpoint_1.FeeEndpoint(this.stores, this.offchainStores);
this.events.register(generator_fee_processed_1.GeneratorFeeProcessedEvent, new generator_fee_processed_1.GeneratorFeeProcessedEvent(this.name));
this.events.register(relayer_fee_processed_1.RelayerFeeProcessedEvent, new relayer_fee_processed_1.RelayerFeeProcessedEvent(this.name));
this.events.register(insufficient_fee_1.InsufficientFeeEvent, new insufficient_fee_1.InsufficientFeeEvent(this.name));
}
addDependencies(tokenMethod, interopMethod) {
this._tokenMethod = tokenMethod;
this.crossChainMethod.addDependencies(interopMethod, tokenMethod);
}
metadata() {
return {
...this.baseMetadata(),
endpoints: [
{
name: this.endpoint.getMinFeePerByte.name,
response: schemas_1.getMinFeePerByteResponseSchema,
},
{
name: this.endpoint.getFeeTokenID.name,
response: schemas_1.getFeeTokenIDResponseSchema,
},
],
};
}
async init(args) {
const defaultFeeTokenID = `${args.genesisConfig.chainID}${Buffer.alloc(4).toString('hex')}`;
const config = lisk_utils_1.objects.mergeDeep({}, { ...constants_1.defaultConfig, feeTokenID: defaultFeeTokenID }, args.moduleConfig);
lisk_validator_1.validator.validate(schemas_1.configSchema, config);
const moduleConfig = {
...config,
feeTokenID: Buffer.from(config.feeTokenID, 'hex'),
feePoolAddress: config.feePoolAddress
? lisk_cryptography_1.address.getAddressFromLisk32Address(config.feePoolAddress)
: undefined,
};
this.method.init(moduleConfig);
this.endpoint.init(moduleConfig);
this.crossChainMethod.init(moduleConfig);
this._tokenID = moduleConfig.feeTokenID;
this._minFeePerByte = moduleConfig.minFeePerByte;
this._maxBlockHeightZeroFeePerByte = moduleConfig.maxBlockHeightZeroFeePerByte;
this._feePoolAddress = moduleConfig.feePoolAddress;
}
async verifyTransaction(context) {
const { getMethodContext, transaction, header } = context;
const minFee = this._getMinFee(header.height, transaction.getBytes().length);
if (transaction.fee < minFee) {
throw new Error(`Insufficient transaction fee. Minimum required fee is ${minFee}.`);
}
const balance = await this._tokenMethod.getAvailableBalance(getMethodContext(), transaction.senderAddress, this._tokenID);
if (transaction.fee > balance) {
throw new Error(`Insufficient balance.`);
}
return { status: state_machine_1.VerifyStatus.OK };
}
async beforeCommandExecute(context) {
const { transaction, header } = context;
const minFee = this._getMinFee(header.height, transaction.getBytes().length);
const availableFee = transaction.fee - minFee;
if (availableFee < 0) {
throw new Error(`Insufficient transaction fee. Minimum required fee is ${minFee}.`);
}
const methodContext = context.getMethodContext();
await this._tokenMethod.lock(methodContext, transaction.senderAddress, this.name, this._tokenID, transaction.fee);
context.contextStore.set(constants_1.CONTEXT_STORE_KEY_AVAILABLE_FEE, availableFee);
}
async afterCommandExecute(context) {
const { header, transaction } = context;
await this._tokenMethod.unlock(context.getMethodContext(), transaction.senderAddress, this.name, this._tokenID, transaction.fee);
let availableFee = (0, state_machine_1.getContextStoreBigInt)(context.contextStore, constants_1.CONTEXT_STORE_KEY_AVAILABLE_FEE);
const userSubstoreGeneratorExists = await this._tokenMethod.userSubstoreExists(context, header.generatorAddress, this._tokenID);
if (userSubstoreGeneratorExists) {
await this._tokenMethod.transfer(context.getMethodContext(), transaction.senderAddress, header.generatorAddress, this._tokenID, availableFee);
}
else {
availableFee = BigInt(0);
}
let burnConsumedFee = true;
if (this._feePoolAddress) {
const userSubstoreFeePoolExists = await this._tokenMethod.userSubstoreExists(context, this._feePoolAddress, this._tokenID);
if (userSubstoreFeePoolExists) {
burnConsumedFee = false;
}
}
const minFee = transaction.fee - availableFee;
if (burnConsumedFee) {
await this._tokenMethod.burn(context.getMethodContext(), transaction.senderAddress, this._tokenID, minFee);
}
else {
await this._tokenMethod.transfer(context.getMethodContext(), transaction.senderAddress, this._feePoolAddress, this._tokenID, minFee);
}
this.events.get(generator_fee_processed_1.GeneratorFeeProcessedEvent).log(context, {
burntAmount: transaction.fee - availableFee,
generatorAddress: header.generatorAddress,
generatorAmount: availableFee,
senderAddress: transaction.senderAddress,
});
context.contextStore.delete(constants_1.CONTEXT_STORE_KEY_AVAILABLE_FEE);
}
_getMinFee(blockHeight, transactionByteLength) {
if (blockHeight < this._maxBlockHeightZeroFeePerByte) {
return BigInt(0);
}
return BigInt(this._minFeePerByte) * BigInt(transactionByteLength);
}
}
exports.FeeModule = FeeModule;
//# sourceMappingURL=module.js.map