UNPKG

@swaptoshi/liquid-pos-module

Version:

Klayr liquid PoS on-chain module

106 lines 5.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InternalLiquidPosMethod = void 0; const klayr_framework_1 = require("klayr-framework"); const codec_1 = require("@klayr/codec"); const validator = require("@klayr/validator"); const schemas_1 = require("klayr-framework/dist-node/modules/pos/schemas"); const bignumber_js_1 = require("bignumber.js"); const constants_1 = require("./constants"); const schema_1 = require("./schema"); const lst_mint_1 = require("./events/lst_mint"); const lst_burn_1 = require("./events/lst_burn"); const config_1 = require("./config"); bignumber_js_1.default.config({ ROUNDING_MODE: bignumber_js_1.default.ROUND_FLOOR }); class InternalLiquidPosMethod extends klayr_framework_1.Modules.BaseMethod { async init(moduleConfig, genesisConfig) { this._chainID = Buffer.from(genesisConfig.chainID, 'hex'); await this._assignLstTokenID(moduleConfig); } addDependencies(tokenMethod) { this._tokenMethod = tokenMethod; this._config = this.stores.get(config_1.LiquidPosGovernableConfig); } getLstTokenID() { return this._lstTokenID; } async handleInitGenesisState(context) { this.checkDependencies(); const isTokenIDAvailable = await this._tokenMethod.isTokenIDAvailable(context, this._lstTokenID); if (!isTokenIDAvailable) { const assetBytes = context.assets.getAsset(constants_1.POS_MODULE_NAME); if (!assetBytes) return; const genesisStore = codec_1.codec.decode(schemas_1.genesisStoreSchema, assetBytes); validator.validator.validate(schemas_1.genesisStoreSchema, genesisStore); const totalPosStaked = genesisStore.stakers.reduce((accumulator, stakerSubstore) => accumulator + stakerSubstore.stakes.reduce((stakerAccumulator, stakes) => stakerAccumulator + stakes.amount, BigInt(0)), BigInt(0)); const totalSupply = await this._tokenMethod.getTotalSupply(context); const lstTotalSupply = totalSupply.totalSupply.find(t => t.tokenID.equals(this._lstTokenID)).totalSupply; const computedLstTotalSupply = await this._multiplyByRatio(context, totalPosStaked); if (computedLstTotalSupply !== lstTotalSupply) throw new Error('lstTokenID supply doesnt match computed totalPosStaked'); } } async handleAfterCommandExecute(context) { this.checkDependencies(); if (context.transaction.module === constants_1.POS_MODULE_NAME && context.transaction.command === constants_1.POS_STAKE_COMMAND_NAME) { let totalStake = BigInt(0); const stakeParams = codec_1.codec.decode(schema_1.stakeCommandParamsSchema, context.transaction.params); for (const stakes of stakeParams.stakes) totalStake += stakes.amount; if (totalStake > BigInt(0)) { await this.mint(context, context.transaction.senderAddress, totalStake); } else if (totalStake < BigInt(0)) { await this.burn(context, context.transaction.senderAddress, totalStake * BigInt(-1)); } } } async mint(context, address, baseAmount) { this.checkDependencies(); if (baseAmount < BigInt(0)) throw new Error("baseAmount minted can't be negative"); const isTokenIDAvailable = await this._tokenMethod.isTokenIDAvailable(context, this._lstTokenID); if (isTokenIDAvailable) await this._tokenMethod.initializeToken(context, this._lstTokenID); const mintedAmount = await this._multiplyByRatio(context, baseAmount); await this._tokenMethod.mint(context, address, this._lstTokenID, mintedAmount); const events = this.events.get(lst_mint_1.LiquidStakingTokenMintEvent); events.add(context, { address, tokenID: this._lstTokenID, amount: mintedAmount }, [address]); } async burn(context, address, baseBurned) { this.checkDependencies(); if (baseBurned < BigInt(0)) throw new Error("baseBurned burned can't be negative"); const isTokenIDAvailable = await this._tokenMethod.isTokenIDAvailable(context, this._lstTokenID); if (isTokenIDAvailable) await this._tokenMethod.initializeToken(context, this._lstTokenID); const burnedAmount = await this._multiplyByRatio(context, baseBurned); await this._tokenMethod.burn(context, address, this._lstTokenID, burnedAmount); const events = this.events.get(lst_burn_1.LiquidStakingTokenBurnEvent); events.add(context, { address, tokenID: this._lstTokenID, amount: burnedAmount }, [address]); } checkDependencies() { if (!this._chainID || !this._tokenMethod || !this._lstTokenID || !this._config) { throw new Error('liquid_pos module dependencies is not configured, make sure LiquidPos.addDependencies() is called before module registration'); } } async _assignLstTokenID(config) { const { tokenID } = config; const chainID = this._chainID; if (tokenID.length === 16) { this._lstTokenID = Buffer.from(tokenID, 'hex'); } else if (tokenID.length === 8) { const buff = Buffer.from(tokenID, 'hex'); this._lstTokenID = Buffer.concat([chainID, buff]); } } async _multiplyByRatio(context, amount) { this.checkDependencies(); const config = await this._config.getConfig(context); return BigInt(new bignumber_js_1.default(amount.toString()).multipliedBy(config.ratio).toFixed(0)); } } exports.InternalLiquidPosMethod = InternalLiquidPosMethod; //# sourceMappingURL=internal_method.js.map