Skip to content

Commit

Permalink
Merge pull request #5123 from thesan/luxor/vested-wg-spending-qn
Browse files Browse the repository at this point in the history
Add vested budget spending tests and mappings
  • Loading branch information
kdembler authored Apr 8, 2024
2 parents 0d97754 + 8b00d54 commit 713d105
Show file tree
Hide file tree
Showing 10 changed files with 243 additions and 15 deletions.
19 changes: 19 additions & 0 deletions query-node/manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ typegen:
- storageWorkingGroup.WorkerRewardAmountUpdated
- storageWorkingGroup.StatusTextChanged
- storageWorkingGroup.BudgetSpending
- storageWorkingGroup.VestedBudgetSpending
- storageWorkingGroup.RewardPaid
- storageWorkingGroup.NewMissedRewardLevelReached
- storageWorkingGroup.LeadRemarked
Expand Down Expand Up @@ -289,6 +290,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: storageWorkingGroup.BudgetSpending
handler: workingGroups_BudgetSpending
- event: storageWorkingGroup.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: storageWorkingGroup.RewardPaid
handler: workingGroups_RewardPaid
- event: storageWorkingGroup.NewMissedRewardLevelReached
Expand Down Expand Up @@ -336,6 +339,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: forumWorkingGroup.BudgetSpending
handler: workingGroups_BudgetSpending
- event: forumWorkingGroup.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: forumWorkingGroup.RewardPaid
handler: workingGroups_RewardPaid
- event: forumWorkingGroup.NewMissedRewardLevelReached
Expand Down Expand Up @@ -387,6 +392,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: membershipWorkingGroup.BudgetSpending
handler: workingGroups_BudgetSpending
- event: membershipWorkingGroup.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: membershipWorkingGroup.RewardPaid
handler: workingGroups_RewardPaid
- event: membershipWorkingGroup.NewMissedRewardLevelReached
Expand Down Expand Up @@ -438,6 +445,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: contentWorkingGroup.BudgetSpending
handler: workingGroups_BudgetSpending
- event: contentWorkingGroup.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: contentWorkingGroup.RewardPaid
handler: workingGroups_RewardPaid
- event: contentWorkingGroup.NewMissedRewardLevelReached
Expand Down Expand Up @@ -485,6 +494,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: operationsWorkingGroupAlpha.BudgetSpending
handler: workingGroups_BudgetSpending
- event: operationsWorkingGroupAlpha.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: operationsWorkingGroupAlpha.RewardPaid
handler: workingGroups_RewardPaid
- event: operationsWorkingGroupAlpha.NewMissedRewardLevelReached
Expand Down Expand Up @@ -532,6 +543,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: operationsWorkingGroupBeta.BudgetSpending
handler: workingGroups_BudgetSpending
- event: operationsWorkingGroupBeta.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: operationsWorkingGroupBeta.RewardPaid
handler: workingGroups_RewardPaid
- event: operationsWorkingGroupBeta.NewMissedRewardLevelReached
Expand Down Expand Up @@ -579,6 +592,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: operationsWorkingGroupGamma.BudgetSpending
handler: workingGroups_BudgetSpending
- event: operationsWorkingGroupGamma.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: operationsWorkingGroupGamma.RewardPaid
handler: workingGroups_RewardPaid
- event: operationsWorkingGroupGamma.NewMissedRewardLevelReached
Expand Down Expand Up @@ -626,6 +641,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: distributionWorkingGroup.BudgetSpending
handler: workingGroups_BudgetSpending
- event: distributionWorkingGroup.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: distributionWorkingGroup.RewardPaid
handler: workingGroups_RewardPaid
- event: distributionWorkingGroup.NewMissedRewardLevelReached
Expand Down Expand Up @@ -673,6 +690,8 @@ mappings:
handler: workingGroups_StatusTextChanged
- event: appWorkingGroup.BudgetSpending
handler: workingGroups_BudgetSpending
- event: appWorkingGroup.VestedBudgetSpending
handler: workingGroups_VestedBudgetSpending
- event: appWorkingGroup.RewardPaid
handler: workingGroups_RewardPaid
- event: appWorkingGroup.NewMissedRewardLevelReached
Expand Down
28 changes: 26 additions & 2 deletions query-node/mappings/src/workingGroups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
BudgetFundedEvent,
BudgetSetEvent,
BudgetSpendingEvent,
VestedBudgetSpendingEvent,
ForumPost,
InvalidActionMetadata,
LeaderSetEvent,
Expand Down Expand Up @@ -83,6 +84,7 @@ import {
StorageWorkingGroup_ApplicationWithdrawnEvent_V1001 as WorkingGroup_ApplicationWithdrawnEvent_V1001,
StorageWorkingGroup_AppliedOnOpeningEvent_V1001 as WorkingGroup_AppliedOnOpeningEvent_V1001,
StorageWorkingGroup_BudgetSpendingEvent_V1001 as WorkingGroup_BudgetSpendingEvent_V1001,
StorageWorkingGroup_VestedBudgetSpendingEvent_V2003 as WorkingGroup_VestedBudgetSpendingEvent_V2003,
StorageWorkingGroup_LeadRemarkedEvent_V1001 as WorkingGroup_LeadRemarkedEvent_V1001,
StorageWorkingGroup_NewMissedRewardLevelReachedEvent_V1001 as WorkingGroup_NewMissedRewardLevelReachedEvent_V1001,
StorageWorkingGroup_OpeningAddedEvent_V1001 as WorkingGroup_OpeningAddedEvent_V1001,
Expand Down Expand Up @@ -1020,14 +1022,14 @@ export async function workingGroups_BudgetSet({ store, event }: EventContext & S
}

export async function workingGroups_BudgetSpending({ store, event }: EventContext & StoreContext): Promise<void> {
const [reciever, amount, optRationale] = new WorkingGroup_BudgetSpendingEvent_V1001(event).params
const [receiver, amount, optRationale] = new WorkingGroup_BudgetSpendingEvent_V1001(event).params
const group = await getWorkingGroupOrFail(store, event)

const budgetSpendingEvent = new BudgetSpendingEvent({
...genericEventFields(event),
group,
amount,
reciever: reciever.toString(),
receiver: receiver.toString(),
rationale: optRationale.isSome ? bytesToString(optRationale.unwrap()) : undefined,
})

Expand All @@ -1038,6 +1040,28 @@ export async function workingGroups_BudgetSpending({ store, event }: EventContex
await store.save<WorkingGroup>(group)
}

export async function workingGroups_VestedBudgetSpending({ store, event }: EventContext & StoreContext): Promise<void> {
const [receiver, vestingSchedule, rationale] = new WorkingGroup_VestedBudgetSpendingEvent_V2003(event).params
const amount = vestingSchedule.locked
const group = await getWorkingGroupOrFail(store, event)

const vestedBudgetSpendingEvent = new VestedBudgetSpendingEvent({
...genericEventFields(event),
group,
amount,
perBlock: vestingSchedule.perBlock,
startingBlock: vestingSchedule.startingBlock.toNumber(),
receiver: receiver.toString(),
rationale: rationale.isSome ? bytesToString(rationale.unwrap()) : undefined,
})

await store.save<VestedBudgetSpendingEvent>(vestedBudgetSpendingEvent)

group.budget = group.budget.sub(amount)

await store.save<WorkingGroup>(group)
}

export async function workingGroups_WorkingGroupBudgetFunded({
store,
event,
Expand Down
43 changes: 41 additions & 2 deletions query-node/schemas/workingGroupsEvents.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -671,8 +671,8 @@ type BudgetSpendingEvent implements Event @entity {
"Related group"
group: WorkingGroup!

"Reciever account address"
reciever: String!
"Receiver account address"
receiver: String!

"Amount beeing spent"
amount: BigInt!
Expand All @@ -681,6 +681,45 @@ type BudgetSpendingEvent implements Event @entity {
rationale: String
}

type VestedBudgetSpendingEvent implements Event @entity {
### GENERIC DATA ###

"(network}-{blockNumber}-{indexInBlock}"
id: ID!

"Hash of the extrinsic which caused the event to be emitted"
inExtrinsic: String

"Blocknumber of the block in which the event was emitted."
inBlock: Int!

"Network the block was produced in"
network: Network!

"Index of event in block from which it was emitted."
indexInBlock: Int!

### SPECIFIC DATA ###

"Related group"
group: WorkingGroup!

"Receiver account address"
receiver: String!

"Amount vested (this amount is fully locked until the starting block is reached)"
amount: BigInt!

"Amount unlock at every block"
perBlock: BigInt!

"Block height when the vesting schedule starts"
startingBlock: Int!

"Optional rationale"
rationale: String
}

enum RewardPaymentType {
"Regular reward payout"
REGULAR
Expand Down
14 changes: 14 additions & 0 deletions tests/network-tests/src/QueryNodeApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
BudgetFundedEventFieldsFragment,
BudgetSetEventFieldsFragment,
BudgetSpendingEventFieldsFragment,
VestedBudgetSpendingEventFieldsFragment,
CandidateFieldsFragment,
CategoryArchivalStatusUpdatedEventFieldsFragment,
CategoryCreatedEventFieldsFragment,
Expand Down Expand Up @@ -82,6 +83,9 @@ import {
GetBudgetSpendingEventsByEventIds,
GetBudgetSpendingEventsByEventIdsQuery,
GetBudgetSpendingEventsByEventIdsQueryVariables,
GetVestedBudgetSpendingEventsByEventIds,
GetVestedBudgetSpendingEventsByEventIdsQuery,
GetVestedBudgetSpendingEventsByEventIdsQueryVariables,
GetCategoriesByIds,
GetCategoriesByIdsQuery,
GetCategoriesByIdsQueryVariables,
Expand Down Expand Up @@ -988,6 +992,16 @@ export class QueryNodeApi {
>(GetBudgetSpendingEventsByEventIds, { eventIds }, 'budgetSpendingEvents')
}

public async getVestedBudgetSpendingEvents(
events: EventDetails[]
): Promise<VestedBudgetSpendingEventFieldsFragment[]> {
const eventIds = events.map((e) => this.getQueryNodeEventId(e.blockNumber, e.indexInBlock))
return this.multipleEntitiesQuery<
GetVestedBudgetSpendingEventsByEventIdsQuery,
GetVestedBudgetSpendingEventsByEventIdsQueryVariables
>(GetVestedBudgetSpendingEventsByEventIds, { eventIds }, 'vestedBudgetSpendingEvents')
}

public async getLeaderSetEvent(event: EventDetails): Promise<LeaderSetEventFieldsFragment | null> {
const eventId = this.getQueryNodeEventId(event.blockNumber, event.indexInBlock)
return this.firstEntityQuery<GetLeaderSetEventsByEventIdsQuery, GetLeaderSetEventsByEventIdsQueryVariables>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class SpendBudgetFixture extends BaseWorkingGroupFixture {
protected assertQueryNodeEventIsValid(qEvent: BudgetSpendingEventFieldsFragment, i: number): void {
assert.equal(qEvent.group.name, this.group)
assert.equal(qEvent.amount, this.amounts[i].toString())
assert.equal(qEvent.reciever, this.recievers[i])
assert.equal(qEvent.receiver, this.recievers[i])
assert.equal(qEvent.rationale, this.getRationale(this.recievers[i]))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import BN from 'bn.js'
import { assert } from 'chai'
import { Api } from '../../Api'
import { QueryNodeApi } from '../../QueryNodeApi'
import { EventDetails, WorkingGroupModuleName } from '../../types'
import { BaseWorkingGroupFixture } from './BaseWorkingGroupFixture'
import { SubmittableExtrinsic } from '@polkadot/api/types'
import { ISubmittableResult } from '@polkadot/types/types/'
import { Utils } from '../../utils'
import { VestedBudgetSpendingEventFieldsFragment, WorkingGroupFieldsFragment } from '../../graphql/generated/queries'

export type VestingSchedule = {
locked: BN
perBlock: BN
startingBlock: number
}

export class VestedSpendFromBudgetFixture extends BaseWorkingGroupFixture {
protected receivers: string[]
protected vestingSchedules: VestingSchedule[]
protected preExecuteBudget?: BN

public constructor(
api: Api,
query: QueryNodeApi,
group: WorkingGroupModuleName,
receivers: string[],
vestingSchedules: VestingSchedule[]
) {
super(api, query, group)
this.receivers = receivers
this.vestingSchedules = vestingSchedules
}

protected async getSignerAccountOrAccounts(): Promise<string> {
return this.api.getLeadRoleKey(this.group)
}

protected async getExtrinsics(): Promise<SubmittableExtrinsic<'promise'>[]> {
return this.receivers.map((reciever, i) =>
this.api.tx[this.group].vestedSpendFromBudget(reciever, this.vestingSchedules[i], this.getRationale(reciever))
)
}

protected getEventFromResult(result: ISubmittableResult): Promise<EventDetails> {
return this.api.getEventDetails(result, this.group, 'VestedBudgetSpending')
}

protected getRationale(receiver: string): string {
return `Vested budget spending to ${receiver} rationale`
}

public async execute(): Promise<void> {
this.preExecuteBudget = await this.api.query[this.group].budget()
await super.execute()
}

protected assertQueryNodeEventIsValid(qEvent: VestedBudgetSpendingEventFieldsFragment, i: number): void {
assert.equal(qEvent.group.name, this.group)
assert.equal(qEvent.amount, this.vestingSchedules[i].locked.toString())
assert.equal(qEvent.perBlock, this.vestingSchedules[i].perBlock.toString())
assert.equal(qEvent.startingBlock, this.vestingSchedules[i].startingBlock)
assert.equal(qEvent.receiver, this.receivers[i])
assert.equal(qEvent.rationale, this.getRationale(this.receivers[i]))
}

protected assertQueriedGroupIsValid(qGroup: WorkingGroupFieldsFragment | null): void {
Utils.assert(qGroup, 'Query node: Working group not found!')
assert.equal(
qGroup.budget,
this.preExecuteBudget!.sub(this.vestingSchedules.reduce((a, b) => a.add(b.locked), new BN(0)))
)
}

async runQueryNodeChecks(): Promise<void> {
await super.runQueryNodeChecks()

// Query and check the events
await this.query.tryQueryWithTimeout(
() => this.query.getVestedBudgetSpendingEvents(this.events),
(qEvents) => this.assertQueryNodeEventsAreValid(qEvents)
)

// Check the group
const qGroup = await this.query.getWorkingGroup(this.group)
this.assertQueriedGroupIsValid(qGroup)
}
}
1 change: 1 addition & 0 deletions tests/network-tests/src/fixtures/workingGroups/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export { UpdateGroupStatusFixture } from './UpdateGroupStatusFixture'
export { WithdrawApplicationsFixture } from './WithdrawApplicationsFixture'
export { TerminateWorkersFixture } from './TerminateWorkersFixture'
export { SpendBudgetFixture } from './SpendBudgetFixture'
export { VestedSpendFromBudgetFixture } from './VestedSpendFromBudgetFixture'
export { FundWorkingGroupBudgetFixture, FundWorkingGroupBudgetParams } from './FundWorkingGroupBudgetFixture'
Loading

0 comments on commit 713d105

Please sign in to comment.