@swaptoshi/governance-module
Version:
Klayr governance on-chain module
179 lines • 10.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.GovernanceInternalMethod = void 0;
const klayr_framework_1 = require("klayr-framework");
const codec_1 = require("@klayr/codec");
const cryptography = require("@klayr/cryptography");
const constants_1 = require("./constants");
const treasury_mint_1 = require("./events/treasury_mint");
const treasury_block_reward_tax_1 = require("./events/treasury_block_reward_tax");
const config_1 = require("./config");
const context_1 = require("./stores/context");
const queue_1 = require("./stores/queue");
const schema_1 = require("./schema");
const delegated_vote_1 = require("./stores/delegated_vote");
const casted_vote_1 = require("./stores/casted_vote");
const proposal_1 = require("./stores/proposal");
const vote_score_1 = require("./stores/vote_score");
const boosted_account_1 = require("./stores/boosted_account");
const utils_1 = require("./utils");
class GovernanceInternalMethod extends klayr_framework_1.Modules.BaseMethod {
addDependencies(token) {
this._tokenMethod = token;
}
async updateVoteScoreAfterStake(context) {
if (context.transaction.module === constants_1.POS_MODULE_NAME && context.transaction.command === constants_1.POS_STAKE_COMMAND_NAME) {
let totalAddedStake = BigInt(0);
let totalSubtractedStake = BigInt(0);
const stakeParams = codec_1.codec.decode(schema_1.stakeCommandParamsSchema, context.transaction.params);
for (const stakes of stakeParams.stakes)
if (stakes.amount > BigInt(0))
totalAddedStake += stakes.amount;
else
totalSubtractedStake += stakes.amount * BigInt(-1);
await this.updateProposalVoteSummaryByVoter(context, context.transaction.senderAddress, totalAddedStake, totalSubtractedStake);
await this.stores.get(vote_score_1.VoteScoreStore).addVoteScore(context, context.transaction.senderAddress, totalAddedStake - totalSubtractedStake);
}
}
async updateProposalVoteSummaryByVoter(context, voter, addedVote = BigInt(0), subtractedVote = BigInt(0), boostingHeight) {
const delegatedVoteStore = this.stores.get(delegated_vote_1.DelegatedVoteStore);
const boostedAccountStore = this.stores.get(boosted_account_1.BoostedAccountStore);
const voterBoostingState = await boostedAccountStore.getOrDefault(context, voter);
const voterBoostingHeight = voterBoostingState.targetHeight;
const delegatedVote = await delegatedVoteStore.getOrDefault(context, voter);
if (!delegatedVote.outgoingDelegation.equals(Buffer.alloc(0))) {
await this.updateProposalVoteSummaryByVoter(context, delegatedVote.outgoingDelegation, addedVote, subtractedVote, boostingHeight !== null && boostingHeight !== void 0 ? boostingHeight : voterBoostingHeight);
return;
}
const castedVoteStore = this.stores.get(casted_vote_1.CastedVoteStore);
const proposalStore = this.stores.get(proposal_1.ProposalStore);
const ctx = (0, context_1.methodGovernanceContext)(context, Buffer.alloc(0), 0);
const castedVote = await castedVoteStore.getOrDefault(context, voter);
for (const vote of castedVote.activeVote) {
if (typeof addedVote === 'bigint' && addedVote > BigInt(0)) {
await (await proposalStore.getMutableProposal(ctx, vote.proposalId)).addVote(addedVote, vote.decision, boostingHeight !== null && boostingHeight !== void 0 ? boostingHeight : voterBoostingHeight);
}
if (Array.isArray(addedVote)) {
for (const addedVoteItem of addedVote) {
if (addedVoteItem.voteScore > BigInt(0)) {
await (await proposalStore.getMutableProposal(ctx, vote.proposalId)).addVote(addedVoteItem.voteScore, vote.decision, addedVoteItem.boostingHeight);
}
}
}
if (typeof subtractedVote === 'bigint' && subtractedVote > BigInt(0)) {
await (await proposalStore.getMutableProposal(ctx, vote.proposalId)).subtractVote(subtractedVote, vote.decision, boostingHeight !== null && boostingHeight !== void 0 ? boostingHeight : voterBoostingHeight);
}
if (Array.isArray(subtractedVote)) {
for (const subtractedVoteItem of subtractedVote) {
if (subtractedVoteItem.voteScore > BigInt(0)) {
await (await proposalStore.getMutableProposal(ctx, vote.proposalId)).subtractVote(subtractedVoteItem.voteScore, vote.decision, subtractedVoteItem.boostingHeight);
}
}
}
}
}
async executeQueuedProposal(context) {
const proposalQueueStore = this.stores.get(queue_1.ProposalQueueStore);
const ctx = (0, context_1.mutableBlockHookGovernanceContext)(context);
const queue = await proposalQueueStore.getInstance(ctx);
await queue.executeQueue();
}
async addTreasuryReward(context) {
if (!this._tokenMethod)
throw new Error('GovernanceInternalMethod dependencies is not configured');
const config = await this._getGovernanceConfig(context);
const dynamicReward = this._getRewardDeduction(context);
const treasuryAddress = cryptography.address.getAddressFromKlayr32Address(config.treasuryAddress);
const mintedTreasury = await this._getMintBracket(context, dynamicReward, context.header.height);
if (mintedTreasury > BigInt(0)) {
await this._tokenMethod.mint(context, treasuryAddress, Buffer.from(config.treasuryReward.tokenID, 'hex'), mintedTreasury);
const events = this.events.get(treasury_mint_1.TreasuryMintEvent);
events.add(context, { amount: mintedTreasury }, [treasuryAddress]);
}
const taxedBlockRewardForTreasury = await this._getBlockRewardTaxBracket(context, dynamicReward, context.header.height);
if (taxedBlockRewardForTreasury > BigInt(0)) {
if (!this.isThisModulePriority()) {
throw new Error('Taxing block reward requires governance module to be registered before dynamicReward module');
}
await this._tokenMethod.mint(context, treasuryAddress, Buffer.from(config.treasuryReward.tokenID, 'hex'), taxedBlockRewardForTreasury);
this._setRewardContext(context, dynamicReward.blockReward - taxedBlockRewardForTreasury);
const events = this.events.get(treasury_block_reward_tax_1.TreasuryBlockRewardTaxEvent);
events.add(context, {
amount: taxedBlockRewardForTreasury,
generatorAddress: context.header.generatorAddress,
}, [treasuryAddress, context.header.generatorAddress]);
}
}
setModulePriorityStatus(context) {
if (this._modulePriorityStatus === undefined) {
const blockReward = this._getDynamicBlockRewardContext(context);
const reduction = this._getDynamicBlockReductionContext(context);
if (blockReward !== undefined && reduction !== undefined) {
this._modulePriorityStatus = false;
}
else {
this._modulePriorityStatus = true;
}
}
}
isThisModulePriority() {
return !!this._modulePriorityStatus;
}
isAppRunning() {
return this._modulePriorityStatus !== undefined;
}
async _getMintBracket(context, reward, height) {
const config = await this._getGovernanceConfig(context);
const bracket = await this._getBracket(context, config.treasuryReward.mintBracket, height);
if (bracket === '0' || bracket === '0%')
return BigInt(0);
return (0, utils_1.parseBigintOrPercentage)(bracket, reward.blockReward);
}
async _getBlockRewardTaxBracket(context, reward, height) {
const config = await this._getGovernanceConfig(context);
const bracket = await this._getBracket(context, config.treasuryReward.blockRewardTaxBracket, height);
if (bracket === '0' || bracket === '0%')
return BigInt(0);
return (0, utils_1.parseBigintOrPercentage)(bracket, reward.blockReward);
}
_getDynamicBlockRewardContext(context) {
return context.contextStore.get(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REWARD);
}
_getDynamicBlockReductionContext(context) {
return context.contextStore.get(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REDUCTION);
}
_getRewardDeduction(context) {
const blockReward = this._getDynamicBlockRewardContext(context);
const reduction = this._getDynamicBlockReductionContext(context);
return {
blockReward: blockReward === undefined ? BigInt(0) : blockReward,
reduction: reduction === undefined ? 0 : reduction,
};
}
_setRewardContext(context, updatedReward) {
context.contextStore.set(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REWARD, updatedReward);
}
async _getBracketLocation(context, height) {
const config = await this._getGovernanceConfig(context);
if (height < config.treasuryReward.offset) {
return 0;
}
const rewardDistance = Math.floor(config.treasuryReward.distance);
const location = Math.trunc((height - config.treasuryReward.offset) / rewardDistance);
return location;
}
async _getBracket(context, brackets, height) {
if (brackets.length === 0)
return '0';
const location = await this._getBracketLocation(context, height);
const lastBracket = brackets[brackets.length - 1];
const bracket = location > brackets.length - 1 ? brackets.lastIndexOf(lastBracket) : location;
return brackets[bracket];
}
async _getGovernanceConfig(context) {
const configStore = this.stores.get(config_1.GovernanceGovernableConfig);
return configStore.getConfig(context);
}
}
exports.GovernanceInternalMethod = GovernanceInternalMethod;
//# sourceMappingURL=internal_method.js.map