Skip to content

Commit

Permalink
Merge pull request #1095 from multiversx/MEX-316
Browse files Browse the repository at this point in the history
MEX-316: governance implementation
  • Loading branch information
dragos-rebegea authored Jul 14, 2023
2 parents 1b9d179 + 5618622 commit 8614afc
Show file tree
Hide file tree
Showing 17 changed files with 1,508 additions and 15 deletions.
775 changes: 775 additions & 0 deletions src/abis/governance-v2.abi.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,8 @@
"energyUpdate": "./src/abis/energy-update.abi.json",
"tokenUnstake": "./src/abis/token-unstake.abi.json",
"lockedTokenWrapper": "./src/abis/locked-token-wrapper.abi.json",
"escrow": "./src/abis/lkmex-transfer.abi.json"
"escrow": "./src/abis/lkmex-transfer.abi.json",
"governance": "./src/abis/governance-v2.abi.json"
},
"cron": {
"transactionCollectorMaxHyperblocks": 10,
Expand Down
8 changes: 7 additions & 1 deletion src/config/devnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@
"energyUpdate": "erd1qqqqqqqqqqqqqpgqqns0u3hw0e3j0km9h77emuear4xq7k7fd8ss0cwgja",
"tokenUnstake": "erd1qqqqqqqqqqqqqpgqnysvq99c2t4a9pvvv22elnl6p73el8vw0n4spyfv7p",
"lockedTokenWrapper": "erd1qqqqqqqqqqqqqpgq9ej9vcnr38l69rgkc735kgv0qlu2ptrsd8ssu9rwtu",
"escrow": "erd1qqqqqqqqqqqqqpgqz0wkk0j6y4h0mcxfxsg023j4x5sfgrmz0n4s4swp7a"
"escrow": "erd1qqqqqqqqqqqqqpgqz0wkk0j6y4h0mcxfxsg023j4x5sfgrmz0n4s4swp7a",
"governance": {
"energy": [
"erd1qqqqqqqqqqqqqpgqu5u5kgmjm067dhwdfe4l3flwmadm2nqlczfskufug3"
],
"token": []
}
},
"farms": {
"v1.2": [],
Expand Down
62 changes: 62 additions & 0 deletions src/modules/governance/governance.contract.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
import { GovernanceAbiService } from './services/governance.abi.service';
import { GovernanceContract } from './models/governance.contract.model';
import { GovernanceProposal } from './models/governance.proposal.model';

@Resolver(() => GovernanceContract)
export class GovernanceContractResolver {
constructor(
private readonly governanceAbi: GovernanceAbiService,
) {
}

@ResolveField()
async minEnergyForPropose(@Parent() governanceContract: GovernanceContract): Promise<string> {
return this.governanceAbi.minEnergyForPropose(governanceContract.address);
}

@ResolveField()
async minFeeForPropose(@Parent() governanceContract: GovernanceContract): Promise<string> {
return this.governanceAbi.minFeeForPropose(governanceContract.address);
}

@ResolveField()
async quorum(@Parent() governanceContract: GovernanceContract): Promise<string> {
return this.governanceAbi.quorum(governanceContract.address);
}

@ResolveField()
async votingDelayInBlocks(@Parent() governanceContract: GovernanceContract): Promise<number> {
return this.governanceAbi.votingDelayInBlocks(governanceContract.address);
}

@ResolveField()
async votingPeriodInBlocks(@Parent() governanceContract: GovernanceContract): Promise<number> {
return this.governanceAbi.votingPeriodInBlocks(governanceContract.address);
}

@ResolveField()
async feeTokenId(@Parent() governanceContract: GovernanceContract): Promise<string> {
return this.governanceAbi.feeTokenId(governanceContract.address);
}

@ResolveField()
async withdrawPercentageDefeated(@Parent() governanceContract: GovernanceContract): Promise<number> {
return this.governanceAbi.withdrawPercentageDefeated(governanceContract.address);
}

@ResolveField(() => [GovernanceProposal])
async proposals(@Parent() governanceContract: GovernanceContract): Promise<GovernanceProposal[]> {
return this.governanceAbi.proposals(governanceContract.address);
}

@ResolveField()
async feesCollectorAddress(@Parent() governanceContract: GovernanceContract): Promise<string> {
return this.governanceAbi.feesCollectorAddress(governanceContract.address);
}

@ResolveField()
async energyFactoryAddress(@Parent() governanceContract: GovernanceContract): Promise<string> {
return this.governanceAbi.energyFactoryAddress(governanceContract.address);
}
}
41 changes: 41 additions & 0 deletions src/modules/governance/governance.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Module } from '@nestjs/common';
import { CommonAppModule } from 'src/common.app.module';
import { CachingModule } from 'src/services/caching/cache.module';
import { ContextModule } from 'src/services/context/context.module';
import { MXCommunicationModule } from 'src/services/multiversx-communication/mx.communication.module';
import { TokenModule } from '../tokens/token.module';
import { EnergyModule } from '../energy/energy.module';
import { GovernanceAbiService } from './services/governance.abi.service';
import { GovernanceQueryResolver } from './governance.query.resolver';
import { GovernanceContractResolver } from './governance.contract.resolver';
import { GovernanceProposalResolver } from './governance.propose.resolver';
import { GovernanceService } from './services/governance.service';


@Module({
imports: [
CommonAppModule,
CachingModule,
MXCommunicationModule,
ContextModule,
TokenModule,
EnergyModule
],
providers: [
GovernanceService,
GovernanceAbiService,
// GovernanceSetterService,
// GovernanceComputeService,
// GovernanceTransactionService,
GovernanceQueryResolver,
GovernanceContractResolver,
GovernanceProposalResolver,
],
exports: [
GovernanceAbiService,
// GovernanceSetterService,
// GovernanceComputeService,
GovernanceService,
],
})
export class GovernanceModule {}
37 changes: 37 additions & 0 deletions src/modules/governance/governance.propose.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
import { GovernanceAbiService } from './services/governance.abi.service';
import { GovernanceProposal, GovernanceProposalStatus } from './models/governance.proposal.model';
import { ProposalVotes } from './models/proposal.votes.model';
import { GovernanceService } from './services/governance.service';
import { UseGuards } from '@nestjs/common';
import { JwtOrNativeAuthGuard } from '../auth/jwt.or.native.auth.guard';
import { UserAuthResult } from '../auth/user.auth.result';
import { AuthUser } from '../auth/auth.user';

@Resolver(() => GovernanceProposal)
export class GovernanceProposalResolver {
constructor(
private readonly governanceAbi: GovernanceAbiService,
private readonly governanceService: GovernanceService,
) {
}

@ResolveField()
async status(@Parent() governanceProposal: GovernanceProposal): Promise<GovernanceProposalStatus> {
return this.governanceAbi.proposalStatus(governanceProposal.contractAddress, governanceProposal.proposalId);
}

@ResolveField()
async votes(@Parent() governanceProposal: GovernanceProposal): Promise<ProposalVotes> {
return this.governanceAbi.proposalVotes(governanceProposal.contractAddress, governanceProposal.proposalId);
}

@UseGuards(JwtOrNativeAuthGuard)
@ResolveField()
async hasVoted(
@AuthUser() user: UserAuthResult,
@Parent() governanceProposal: GovernanceProposal
): Promise<boolean> {
return this.governanceService.hasUserVoted(governanceProposal.contractAddress, governanceProposal.proposalId, user.address);
}
}
19 changes: 19 additions & 0 deletions src/modules/governance/governance.query.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Args, Query, Resolver } from '@nestjs/graphql';
import { GovernanceContractsFiltersArgs } from './models/contracts.filter.args';
import { GovernanceService } from './services/governance.service';
import { GovernanceContract } from './models/governance.contract.model';

@Resolver()
export class GovernanceQueryResolver {
constructor(
private readonly governanceService: GovernanceService,
) {
}

@Query(() => [GovernanceContract])
async governanceContracts(
@Args() filters: GovernanceContractsFiltersArgs
): Promise<GovernanceContract[]> {
return this.governanceService.getGovernanceContracts(filters);
}
}
11 changes: 11 additions & 0 deletions src/modules/governance/models/contracts.filter.args.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ArgsType, Field } from '@nestjs/graphql';

@ArgsType()
export class GovernanceContractsFiltersArgs {
@Field(() => [String], { nullable: true })
identifiers: string;
@Field(() => [String], { nullable: true })
contracts: string;
@Field({ nullable: true })
type: string;
}
17 changes: 17 additions & 0 deletions src/modules/governance/models/governance.action.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Field, Int, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class GovernanceAction {
@Field(() => Int)
gasLimit: number;
@Field()
destAddress: string;
@Field()
functionName: string;
@Field( () => [String])
arguments: string[];

constructor(init?: Partial<GovernanceAction>) {
Object.assign(this, init);
}
}
37 changes: 37 additions & 0 deletions src/modules/governance/models/governance.contract.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { GovernanceProposal } from './governance.proposal.model';

export enum GovernanceType {
ENERGY = 'energy',
TOKEN = 'token',
}

@ObjectType()
export class GovernanceContract {
@Field()
address: string;
@Field()
minEnergyForPropose: string;
@Field()
minFeeForPropose: string;
@Field()
quorum: string;
@Field(() => Int)
votingDelayInBlocks: number;
@Field(() => Int)
votingPeriodInBlocks: number;
@Field()
feeTokenId: string;
@Field(() => Int)
withdrawPercentageDefeated: number;
@Field(() => [GovernanceProposal])
proposals: GovernanceProposal[];
@Field()
feesCollectorAddress: string;
@Field()
energyFactoryAddress: string;

constructor(init: Partial<GovernanceContract>) {
Object.assign(this, init);
}
}
67 changes: 67 additions & 0 deletions src/modules/governance/models/governance.proposal.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Field, Int, ObjectType, registerEnumType } from '@nestjs/graphql';
import { GovernanceAction } from './governance.action.model';
import { EsdtTokenPaymentModel } from '../../tokens/models/esdt.token.payment.model';
import { ProposalVotes } from './proposal.votes.model'; //Assuming you will create GovernanceAction model separately

export enum GovernanceProposalStatus {
None ='None',
Pending ='Pending',
Active ='Active',
Defeated ='Defeated',
DefeatedWithVeto ='DefeatedWithVeto',
Succeeded ='Succeeded',
}

registerEnumType(GovernanceProposalStatus, { name: 'GovernanceProposalStatus' });

@ObjectType()
export class Description {
@Field()
title: string;
@Field()
hash: string;
@Field(() => Int)
strapiId: number;

constructor(init: Partial<Description>) {
Object.assign(this, init);
}
}

@ObjectType()
export class GovernanceProposal {
@Field()
contractAddress: string;
@Field()
proposalId: number;
@Field()
proposer: string;
@Field(() => [GovernanceAction])
actions: GovernanceAction[];
@Field( () => Description)
description: Description;
@Field(() => EsdtTokenPaymentModel)
feePayment: EsdtTokenPaymentModel;
@Field()
minimumQuorum: string;
@Field(() => Int)
votingDelayInBlocks: number;
@Field(() => Int)
votingPeriodInBlocks: number;
@Field(() => Int)
withdrawPercentageDefeated: number;
@Field()
totalEnergy: string;
@Field(() => Int)
proposalStartBlock: number;
@Field()
status: GovernanceProposalStatus;
@Field( () => ProposalVotes )
votes: ProposalVotes;
@Field()
hasVoted?: boolean;

constructor(init: Partial<GovernanceProposal>) {
Object.assign(this, init);
}
}
29 changes: 29 additions & 0 deletions src/modules/governance/models/proposal.votes.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Field, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class ProposalVotes {
@Field()
upVotes: string;
@Field()
downVotes: string;
@Field()
downVetoVotes: string;
@Field()
abstainVotes: string;
@Field()
quorum: string;

constructor(init?: Partial<ProposalVotes>) {
Object.assign(this, init);
}

static default(): ProposalVotes {
return new ProposalVotes({
upVotes: '0',
downVotes: '0',
downVetoVotes: '0',
abstainVotes: '0',
quorum: '0',
});
}
}
Loading

0 comments on commit 8614afc

Please sign in to comment.