UNPKG

@swaptoshi/governance-module

Version:

Klayr governance on-chain module

170 lines 9.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DelegatedVote = void 0; const cryptography = require("@klayr/cryptography"); const utils = require("@klayr/utils"); const base_1 = require("./base"); const utils_1 = require("@swaptoshi/utils"); const delegated_vote_1 = require("../delegated_vote"); const vote_delegated_1 = require("../../events/vote_delegated"); const delegated_vote_revoked_1 = require("../../events/delegated_vote_revoked"); const vote_score_1 = require("../vote_score"); const casted_vote_1 = require("../casted_vote"); const boosted_account_1 = require("../boosted_account"); class DelegatedVote extends base_1.BaseInstance { constructor(stores, events, config, genesisConfig, moduleName, delegatedVote, address) { super(delegated_vote_1.DelegatedVoteStore, stores, events, config, genesisConfig, moduleName, address); this.outgoingDelegation = Buffer.alloc(0); this.incomingDelegation = []; Object.assign(this, utils.objects.cloneDeep(delegatedVote)); this.castedVoteStore = stores.get(casted_vote_1.CastedVoteStore); this.boostedAccountStore = stores.get(boosted_account_1.BoostedAccountStore); this.voteScoreStore = stores.get(vote_score_1.VoteScoreStore); } toJSON() { return utils.objects.cloneDeep(utils_1.object.serializer({ outgoingDelegation: this.outgoingDelegation, incomingDelegation: this.incomingDelegation, })); } toObject() { return utils.objects.cloneDeep({ outgoingDelegation: this.outgoingDelegation, incomingDelegation: this.incomingDelegation, }); } async verifyDelegateVote(params) { this._checkImmutableDependencies(); utils_1.verify.verifyAddress('params.delegateeAddress', params.delegateeAddress); if (Buffer.compare(this.outgoingDelegation, Buffer.alloc(0)) !== 0) { throw new Error(`sender already delegate their vote, revoke it first!`); } const delegateeAccount = await this.instanceStore.getOrDefault(this.immutableContext.context, params.delegateeAddress); const index = delegateeAccount.incomingDelegation.findIndex(buf => buf.equals(this.immutableContext.senderAddress)); if (index !== -1) { throw new Error(`sender already exists on ${cryptography.address.getKlayr32AddressFromAddress(params.delegateeAddress)} incoming delegation`); } const circularDelegationPath = await this._isCircularDelegation(params.delegateeAddress); if (circularDelegationPath.length > 0) { throw new Error(`circular delegation detected: ${circularDelegationPath.map(addr => cryptography.address.getKlayr32AddressFromAddress(addr)).join(' => ')}`); } } async delegateVote(params, verify = true) { this._checkMutableDependencies(); if (verify) await this.verifyDelegateVote(params); await this._removeSenderVoteAndDelegatedVoteFromProposal(); this.outgoingDelegation = params.delegateeAddress; await this._saveStore(); const delegateeAccount = await this.instanceStore.getOrDefault(this.mutableContext.context, params.delegateeAddress); delegateeAccount.incomingDelegation.push(this.mutableContext.senderAddress); await this.instanceStore.set(this.mutableContext.context, params.delegateeAddress, delegateeAccount); await this._addDelegatedSenderVoteToProposal(); const events = this.events.get(vote_delegated_1.VoteDelegatedEvent); events.add(this.mutableContext.context, { delegatorAddress: this.mutableContext.senderAddress, delegateeAddress: params.delegateeAddress, }, [this.mutableContext.senderAddress, params.delegateeAddress]); } async verifyRevokeDelegatedVote(_params) { this._checkImmutableDependencies(); if (Buffer.compare(this.outgoingDelegation, Buffer.alloc(0)) === 0) { throw new Error(`sender is not delegating their vote!`); } } async revokeDelegatedVote(_params, verify = true) { this._checkMutableDependencies(); if (verify) await this.verifyRevokeDelegatedVote(_params); await this._removeSenderVoteAndDelegatedVoteFromProposal(); const delegateeAccount = await this.instanceStore.getOrDefault(this.mutableContext.context, this.outgoingDelegation); const indexToRemove = delegateeAccount.incomingDelegation.findIndex(buf => buf.equals(this.mutableContext.senderAddress)); if (indexToRemove !== -1) delegateeAccount.incomingDelegation.splice(indexToRemove, 1); await this.instanceStore.set(this.mutableContext.context, this.outgoingDelegation, delegateeAccount); const events = this.events.get(delegated_vote_revoked_1.DelegatedVoteRevokedEvent); events.add(this.mutableContext.context, { delegatorAddress: this.mutableContext.senderAddress, delegateeAddress: this.outgoingDelegation, }, [this.mutableContext.senderAddress, this.outgoingDelegation]); this.outgoingDelegation = Buffer.alloc(0); await this._saveStore(); } async getIncomingDelegationVoteScore() { return this._getIncomingDelegationVoteScore(this.key); } async _getIncomingDelegationVoteScore(address) { this._checkImmutableDependencies(); const voteScoreArray = []; const delegatedVote = await this.instanceStore.getOrDefault(this.immutableContext.context, address); for (const incomingDelegation of delegatedVote.incomingDelegation) { const incomingDelegationState = await this.instanceStore.getOrDefault(this.immutableContext.context, incomingDelegation); if (incomingDelegationState.incomingDelegation.length > 0) { voteScoreArray.push(...(await this._getIncomingDelegationVoteScore(incomingDelegation))); } else { const voteScore = await this.voteScoreStore.getVoteScore(this.immutableContext.context, incomingDelegation); const boostingHeight = await this.boostedAccountStore.getOrDefault(this.immutableContext.context, incomingDelegation); voteScoreArray.push({ voteScore, boostingHeight: boostingHeight.targetHeight }); } } return voteScoreArray; } async _isCircularDelegation(delegateeAddress) { this._checkImmutableDependencies(); const visited = new Set(); const path = []; visited.add(delegateeAddress.toString('hex')); path.push(delegateeAddress); return this._checkForCycles(this.immutableContext.senderAddress, visited, path); } async _checkForCycles(address, visited, path) { const addressHex = address.toString('hex'); if (visited.has(addressHex)) { path.push(address); const cycleStartIndex = path.findIndex(addr => addr.equals(address)); if (cycleStartIndex !== -1) { return path.slice(cycleStartIndex); } return []; } visited.add(addressHex); path.push(address); const delegatedVote = await this.instanceStore.getOrDefault(this.immutableContext.context, address); if (delegatedVote.incomingDelegation.length === 0) { path.pop(); visited.delete(addressHex); return []; } for (const incomingDelegation of delegatedVote.incomingDelegation) { const circularRoute = await this._checkForCycles(incomingDelegation, visited, path); if (circularRoute.length > 0) { return circularRoute; } } path.pop(); visited.delete(addressHex); return []; } async _removeSenderVoteAndDelegatedVoteFromProposal() { this._checkMutableDependencies(); if (!this.internalMethod) throw new Error(`delegatedVote instance is created without internalMethod dependencies`); const voteScore = await this.voteScoreStore.getVoteScore(this.mutableContext.context, this.mutableContext.senderAddress); await this.internalMethod.updateProposalVoteSummaryByVoter(this.mutableContext.context, this.mutableContext.senderAddress, BigInt(0), voteScore); const incomingDelegationVoteScore = await this._getIncomingDelegationVoteScore(this.mutableContext.senderAddress); await this.internalMethod.updateProposalVoteSummaryByVoter(this.mutableContext.context, this.mutableContext.senderAddress, BigInt(0), incomingDelegationVoteScore); await this.castedVoteStore.removeAllCastedVote(this.mutableContext.context, this.mutableContext.senderAddress); } async _addDelegatedSenderVoteToProposal() { this._checkMutableDependencies(); if (!this.internalMethod) throw new Error(`delegatedVote instance is created without internalMethod dependencies`); const voteScore = await this.voteScoreStore.getVoteScore(this.mutableContext.context, this.mutableContext.senderAddress); await this.internalMethod.updateProposalVoteSummaryByVoter(this.mutableContext.context, this.mutableContext.senderAddress, voteScore, BigInt(0)); const incomingDelegationVoteScore = await this._getIncomingDelegationVoteScore(this.mutableContext.senderAddress); await this.internalMethod.updateProposalVoteSummaryByVoter(this.mutableContext.context, this.mutableContext.senderAddress, incomingDelegationVoteScore, BigInt(0)); } } exports.DelegatedVote = DelegatedVote; //# sourceMappingURL=delegated_vote.js.map