-
Notifications
You must be signed in to change notification settings - Fork 0
Implement voteOnProposal command #220
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ | ||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ | ||
/* eslint-disable @typescript-eslint/no-misused-promises */ | ||
/* eslint-disable @typescript-eslint/no-floating-promises */ | ||
/* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
|
||
/* | ||
* Copyright © 2022 Lisk Foundation | ||
* | ||
* See the LICENSE file at the top-level directory of this distribution | ||
* for licensing information. | ||
* | ||
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, | ||
* no part of this software, including this file, may be copied, modified, | ||
* propagated, or distributed except according to the terms contained in the | ||
* LICENSE file. | ||
* | ||
* Removal or modification of this copyright notice is prohibited. | ||
*/ | ||
|
||
import { | ||
BaseCommand, | ||
CommandExecuteContext, | ||
CommandVerifyContext, | ||
VerificationResult, | ||
VerifyStatus, | ||
} from 'lisk-sdk'; | ||
|
||
import { PoSEndpoint } from 'lisk-framework/dist-node/modules/pos/endpoint'; | ||
import { PrefixedStateReadWriter } from 'lisk-framework/dist-node/state_machine/prefixed_state_read_writer'; | ||
import { | ||
createTransientModuleEndpointContext, | ||
InMemoryPrefixedStateDB, | ||
} from 'lisk-framework/dist-node/testing'; | ||
import { MIN_SINT32 } from '@liskhq/lisk-validator'; | ||
import { MethodContext } from 'lisk-framework/dist-node/state_machine/method_context'; | ||
import { ProposalsStore, VotesStore } from '../stores'; | ||
import { sha256 } from '../../dexRewards/constants'; | ||
|
||
import { numberToQ96, q96ToBytes } from '../../dex/utils/q96'; | ||
import { ProposalVotedEvent } from '../events'; | ||
import { | ||
COMMAND_ID_VOTE_ON_PORPOSAL, | ||
LENGTH_ADDRESS, | ||
MAX_NUM_RECORDED_VOTES, | ||
PROPOSAL_STATUS_ACTIVE, | ||
} from '../constants'; | ||
import { Vote, voteOnProposalParamsData } from '../types'; | ||
import { addVotes } from '../utils/auxiliaryFunctions'; | ||
|
||
export class VoteOnPorposalCommand extends BaseCommand { | ||
public id = COMMAND_ID_VOTE_ON_PORPOSAL; | ||
private _posEndpoint!: PoSEndpoint; | ||
private _methodContext!: MethodContext; | ||
|
||
public init({ posEndpoint, methodContext }): void { | ||
this._posEndpoint = posEndpoint; | ||
this._methodContext = methodContext; | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/require-await | ||
public async verify( | ||
ctx: CommandVerifyContext<voteOnProposalParamsData>, | ||
): Promise<VerificationResult> { | ||
const proposalStoreInfo = this.stores.get(ProposalsStore); | ||
|
||
const result = Buffer.alloc(4); | ||
result.writeUInt32BE(ctx.params.proposalIndex, 0); | ||
const proposalsStoreDate = await proposalStoreInfo.get(this._methodContext, result); | ||
|
||
if (!proposalsStoreDate) { | ||
return { | ||
status: VerifyStatus.FAIL, | ||
error: new Error('Proposal does not exist'), | ||
}; | ||
} | ||
if (ctx.params.decision > 2) { | ||
return { | ||
status: VerifyStatus.FAIL, | ||
error: new Error('Decision does not exist'), | ||
}; | ||
} | ||
if ( | ||
(await proposalStoreInfo.get(this._methodContext, result)).status !== PROPOSAL_STATUS_ACTIVE | ||
) { | ||
return { | ||
status: VerifyStatus.FAIL, | ||
error: new Error('Proposal does not exist'), | ||
}; | ||
} | ||
return { | ||
status: VerifyStatus.OK, | ||
}; | ||
} | ||
|
||
public async execute(ctx: CommandExecuteContext<voteOnProposalParamsData>): Promise<void> { | ||
const stateStore = new PrefixedStateReadWriter(new InMemoryPrefixedStateDB()); | ||
const methodContext = ctx.getMethodContext(); | ||
const votesStoreInfo: VotesStore = this.stores.get(VotesStore); | ||
let smallestproposalIndex = 0; | ||
let smallestproposalValue = MIN_SINT32; | ||
let previousSavedStorescheck = false; | ||
const senderAddress = sha256(ctx.transaction.senderPublicKey.toString()).slice( | ||
0, | ||
LENGTH_ADDRESS, | ||
); | ||
|
||
const moduleEndpointContext = createTransientModuleEndpointContext({ | ||
stateStore, | ||
params: { address: senderAddress }, | ||
}); | ||
|
||
const index = ctx.params.proposalIndex; | ||
|
||
const stakedAmount = (await this._posEndpoint.getLockedStakedAmount(moduleEndpointContext)) | ||
.amount; | ||
|
||
if (!(await votesStoreInfo.get(methodContext, senderAddress))) { | ||
votesStoreInfo.set(methodContext, senderAddress, { voteInfos: [] }); | ||
} | ||
|
||
const newVoteInfo: Vote = { | ||
voteInfos: [ | ||
{ | ||
proposalIndex: index, | ||
decision: ctx.params.decision, | ||
amount: BigInt(stakedAmount), | ||
}, | ||
], | ||
}; | ||
const { voteInfos } = await votesStoreInfo.get(methodContext, senderAddress); | ||
|
||
for (let itr = 0; itr < voteInfos.length; itr += 1) { | ||
if (voteInfos[itr]?.proposalIndex === index) { | ||
addVotes( | ||
methodContext, | ||
this.stores.get(ProposalsStore), | ||
index, | ||
voteInfos[itr]!.amount, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sergeyshemyakov true replaces this line with: |
||
voteInfos[itr]!.decision, | ||
); | ||
votesStoreInfo.setKey(methodContext, [senderAddress], newVoteInfo); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand the code correctly, there is an error here. I think you set the votes store entry to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sergeyshemyakov |
||
previousSavedStorescheck = true; | ||
} | ||
if (smallestproposalValue > voteInfos[itr]!.proposalIndex) { | ||
smallestproposalValue = voteInfos[itr]!.proposalIndex; | ||
smallestproposalIndex = itr; | ||
} | ||
} | ||
|
||
if ( | ||
!previousSavedStorescheck && | ||
(await votesStoreInfo.get(methodContext, senderAddress)).voteInfos.length < | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a small suggestion: you could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sergeyshemyakov updated it to your recommendation. |
||
MAX_NUM_RECORDED_VOTES | ||
) { | ||
(await votesStoreInfo.getKey(methodContext, [senderAddress])).voteInfos.push( | ||
newVoteInfo.voteInfos[0], | ||
); | ||
} else if (!previousSavedStorescheck) { | ||
[(await votesStoreInfo.get(methodContext, senderAddress)).voteInfos[smallestproposalIndex]] = | ||
newVoteInfo.voteInfos; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sergeyshemyakov agree and that is why changed it to: |
||
} | ||
|
||
addVotes( | ||
methodContext, | ||
this.stores.get(ProposalsStore), | ||
index, | ||
BigInt(stakedAmount), | ||
ctx.params.decision, | ||
); | ||
this.events.get(ProposalVotedEvent).add( | ||
methodContext, | ||
{ | ||
index, | ||
voterAddress: senderAddress, | ||
decision: ctx.params.decision, | ||
amount: BigInt(stakedAmount), | ||
}, | ||
[senderAddress, q96ToBytes(numberToQ96(BigInt(index)))], | ||
true, | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,3 +51,5 @@ export const DECISION_NO = 1; // Code for the vote decision "No". | |
export const DECISION_PASS = 2; // Code for the vote decision "Pass". | ||
|
||
export const defaultConfig = {}; | ||
|
||
export const COMMAND_ID_VOTE_ON_PORPOSAL = Buffer.from('0002', 'hex'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't have command IDs anymore, instead we have command names:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sergeyshemyakov chnaged it to:
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,7 +38,7 @@ export const ProposalVotedEventSchema = { | |
}, | ||
voterAddress: { | ||
dataType: 'bytes', | ||
length: LENGTH_ADDRESS, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The address of the voter should be exactly 20 bytes (i.e. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sergeyshemyakov if change it to length it gives a schema validator error |
||
maxLength: LENGTH_ADDRESS, | ||
fieldNumber: 2, | ||
}, | ||
decision: { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,19 @@ | |
* Removal or modification of this copyright notice is prohibited. | ||
*/ | ||
|
||
import { BaseCommand, BaseModule, ModuleMetadata, PoSMethod, TokenMethod } from 'lisk-sdk'; | ||
import { PoSEndpoint } from 'lisk-framework/dist-node/modules/pos/endpoint'; | ||
import { | ||
BaseCommand, | ||
BaseModule, | ||
ModuleInitArgs, | ||
ModuleMetadata, | ||
PoSMethod, | ||
TokenMethod, | ||
utils, | ||
} from 'lisk-sdk'; | ||
import { ModuleConfig } from '../dex/types'; | ||
import { VoteOnPorposalCommand } from './commands/voteOnPorposal'; | ||
import { defaultConfig } from './constants'; | ||
|
||
import { DexGovernanceEndpoint } from './endpoint'; | ||
import { | ||
|
@@ -41,8 +53,16 @@ export class DexGovernanceModule extends BaseModule { | |
public method = new DexGovernanceMethod(this.stores, this.events); | ||
public _tokenMethod!: TokenMethod; | ||
public _posMethod!: PoSMethod; | ||
public _moduleConfig!: ModuleConfig; | ||
public _posEndpoint!: PoSEndpoint; | ||
public _methodContext!: PoSEndpoint; | ||
|
||
private readonly __createvoteOnPorposalCommand = new VoteOnPorposalCommand( | ||
this.stores, | ||
this.events, | ||
); | ||
|
||
public commands = []; | ||
public commands = [this.__createvoteOnPorposalCommand]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please fix the typos to "Proposal" and add proper caps/names where needed, for example this would be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes it was not aligned with command name so change it to |
||
|
||
public constructor() { | ||
super(); | ||
|
@@ -104,4 +124,15 @@ export class DexGovernanceModule extends BaseModule { | |
this._tokenMethod = tokenMethod; | ||
this._posMethod = posMethod; | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/require-await | ||
public async init(args: ModuleInitArgs) { | ||
const { moduleConfig } = args; | ||
this._moduleConfig = utils.objects.mergeDeep({}, defaultConfig, moduleConfig) as ModuleConfig; | ||
|
||
this.__createvoteOnPorposalCommand.init({ | ||
posEndpoint: this._posEndpoint, | ||
methodContext: this._methodContext, | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems it was already added as a method here, I think it would make more sense to use that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emiliolisk I think I am already using the method you mentioned here. I have an import at the top of file as well:
import { PoSEndpoint } from 'lisk-framework/dist-node/modules/pos/endpoint';
Can you please give a look again. Thanks