From d6ec0f7f8306ca7faf71d2accdb1729436b683d2 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Thu, 4 Sep 2025 22:03:54 +0530 Subject: [PATCH 01/66] bounties module added --- packages/kusama/src/kusama.bounties.e2e.test.ts | 4 ++++ packages/polkadot/src/polkadot.bounties.e2e.test.ts | 4 ++++ packages/shared/src/index.ts | 1 + 3 files changed, 9 insertions(+) create mode 100644 packages/kusama/src/kusama.bounties.e2e.test.ts create mode 100644 packages/polkadot/src/polkadot.bounties.e2e.test.ts diff --git a/packages/kusama/src/kusama.bounties.e2e.test.ts b/packages/kusama/src/kusama.bounties.e2e.test.ts new file mode 100644 index 000000000..fa0158ec1 --- /dev/null +++ b/packages/kusama/src/kusama.bounties.e2e.test.ts @@ -0,0 +1,4 @@ +import { kusama } from '@e2e-test/networks/chains' +import { baseBountiesE2ETests, registerTestTree } from '@e2e-test/shared' + +registerTestTree(baseBountiesE2ETests(kusama, { testSuiteName: 'Kusama Bounties', addressEncoding: 2 })) diff --git a/packages/polkadot/src/polkadot.bounties.e2e.test.ts b/packages/polkadot/src/polkadot.bounties.e2e.test.ts new file mode 100644 index 000000000..4bdce449a --- /dev/null +++ b/packages/polkadot/src/polkadot.bounties.e2e.test.ts @@ -0,0 +1,4 @@ +import { polkadot } from '@e2e-test/networks/chains' +import { baseBountiesE2ETests, registerTestTree } from '@e2e-test/shared' + +registerTestTree(baseBountiesE2ETests(polkadot, { testSuiteName: 'Polkadot Bounties', addressEncoding: 0 })) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 03bdeff09..c0cc2f5d4 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,3 +1,4 @@ +export * from './bounties.js' export * from './collectives.js' export * from './governance.js' export * from './helpers/proxyTypes.js' From b2aeffb0e678fd529d70e848b4966727ca5e5ea2 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Thu, 4 Sep 2025 22:04:55 +0530 Subject: [PATCH 02/66] Creating a bounty test added --- packages/shared/src/bounties.ts | 148 ++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 packages/shared/src/bounties.ts diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts new file mode 100644 index 000000000..45a4d94b8 --- /dev/null +++ b/packages/shared/src/bounties.ts @@ -0,0 +1,148 @@ +import { sendTransaction } from '@acala-network/chopsticks-testing' + +import { type Chain, defaultAccountsSr25519 as devAccounts } from '@e2e-test/networks' +import { setupNetworks } from '@e2e-test/shared' + +import { expect } from 'vitest' + +import { checkEvents, checkSystemEvents, scheduleInlineCallWithOrigin } from './helpers/index.js' +import type { RootTestTree } from './types.js' + +/// ------- +/// Helpers +/// ------- + +/** + * Get the current bounty count + */ +async function getBountyCount(client: any): Promise { + return (await client.api.query.bounties.bountyCount()).toNumber() +} + +/** + * Get a bounty by index + */ +async function getBounty(client: any, bountyIndex: number): Promise { + const bounty = await client.api.query.bounties.bounties(bountyIndex) + return bounty.isSome ? bounty.unwrap() : null +} + +/** + * Get bounty description by index + */ +async function getBountyDescription(client: any, bountyIndex: number): Promise { + const description = await client.api.query.bounties.bountyDescriptions(bountyIndex) + return description.isSome ? description.unwrap().toUtf8() : null +} + +/** + * Setup accounts with funds for testing + */ +async function setupTestAccounts(client: any, accounts: string[] = ['alice', 'bob']) { + const accountData: any[] = [] + + if (accounts.includes('alice')) { + accountData.push([[devAccounts.alice.address], { providers: 1, data: { free: 100000000000000n } }]) + } + if (accounts.includes('bob')) { + accountData.push([[devAccounts.bob.address], { providers: 1, data: { free: 100000000000000n } }]) + } + if (accounts.includes('charlie')) { + accountData.push([[devAccounts.charlie.address], { providers: 1, data: { free: 100000000000000n } }]) + } + + await client.dev.setStorage({ + System: { + account: accountData, + }, + }) +} + +/** + * Get bounty index from BountyProposed event + */ +async function getBountyIndexFromEvent(client: any): Promise { + const [bountyProposedEvent] = (await client.api.query.system.events()).filter( + ({ event }: any) => event.section === 'bounties' && event.method === 'BountyProposed', + ) + expect(bountyProposedEvent).toBeDefined() + return (bountyProposedEvent.event.data as any).index.toNumber() +} + +/// ------- +/// Tests +/// ------- + +/** + * Test 1: Creating a bounty + * + * Verifies: + * - Bounty proposal is successful + * - Correct events are emitted + * - Bounty data is stored correctly + * - Bounty count increases + */ +export async function bountyCreationTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + // Setup test accounts + await setupTestAccounts(client, ['alice']) + + const initialBountyCount = await getBountyCount(client) + const bountyValue = 10000000000000n // 1000 tokens + const description = 'Test bounty for development work' + + // Propose a bounty + const bountyProposalEvents = await sendTransaction( + client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), + ) + + await client.dev.newBlock() + + // Verify events + await checkEvents(bountyProposalEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposal events') + + // Verify bounty count increased + const newBountyCount = await getBountyCount(client) + expect(newBountyCount).toBe(initialBountyCount + 1) + + // Get bounty index and verify bounty data + const bountyIndex = await getBountyIndexFromEvent(client) + const bounty = await getBounty(client, bountyIndex) + expect(bounty).toBeDefined() + expect(bounty.value.toBigInt()).toBe(bountyValue) + expect(bounty.status.isProposed).toBe(true) + + // Verify description was stored + const storedDescription = await getBountyDescription(client, bountyIndex) + expect(storedDescription).toBeTruthy() + expect(storedDescription).toBe(description) + + await client.teardown() +} + +/// ------- +/// Test Suite +/// ------- + +export function baseBountiesE2ETests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain, testConfig: { testSuiteName: string; addressEncoding: number }): RootTestTree { + return { + kind: 'describe', + label: testConfig.testSuiteName, + children: [ + { + kind: 'test', + label: 'Creating a bounty', + testFn: async () => await bountyCreationTest(chain), + }, + ], + } +} From 289da9e9ddc3a6b4b8806c7c4798766a36d6952e Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Thu, 4 Sep 2025 22:18:17 +0530 Subject: [PATCH 03/66] bounty approval flow test added --- packages/shared/src/bounties.ts | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 45a4d94b8..988b7a2a3 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -35,6 +35,14 @@ async function getBountyDescription(client: any, bountyIndex: number): Promise { + const approvals = await client.api.query.bounties.bountyApprovals() + return approvals.map((index: any) => index.toNumber()) +} + /** * Setup accounts with funds for testing */ @@ -126,6 +134,59 @@ export async function bountyCreationTest< await client.teardown() } +/** + * Test 2: Bounty approval flow + * + * Verifies: + * - Bounty can be approved by treasurer + * - Status changes from Proposed to Approved + * - Bounty is added to approvals queue + * - Correct events are emitted + */ +export async function bountyApprovalTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const bountyValue = 10000000000000n // 1000 + const description = 'Test bounty for approval' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Verify initial state + const proposedBounty = await getBounty(client, bountyIndex) + expect(proposedBounty.status.isProposed).toBe(true) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify approval events + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approval events') + + // Verify status changed + const approvedBounty = await getBounty(client, bountyIndex) + expect(approvedBounty.status.isApproved).toBe(true) + + // Verify bounty is in approvals queue + const approvals = await getBountyApprovals(client) + expect(approvals).toContain(bountyIndex) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -143,6 +204,11 @@ export function baseBountiesE2ETests< label: 'Creating a bounty', testFn: async () => await bountyCreationTest(chain), }, + { + kind: 'test', + label: 'Bounty approval flow', + testFn: async () => await bountyApprovalTest(chain), + }, ], } } From 6583de25b05b457747482dfbdba6ee496e7c044d Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 5 Sep 2025 22:27:01 +0530 Subject: [PATCH 04/66] curator assignment and acceptance test added --- packages/shared/src/bounties.ts | 80 ++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 988b7a2a3..9ade74a99 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -83,7 +83,7 @@ async function getBountyIndexFromEvent(client: any): Promise { /** * Test 1: Creating a bounty - * + * Propose a bounty * Verifies: * - Bounty proposal is successful * - Correct events are emitted @@ -187,6 +187,79 @@ export async function bountyApprovalTest< await client.teardown() } +/** + * Test 3: Curator assignment and acceptance + * + * Verifies: + * - Curator can be proposed for a funded bounty + * - Curator can accept the role + * - Status transitions correctly + * - Curator deposit is reserved + * - Correct events are emitted + */ +export async function curatorAssignmentTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice', 'bob']) + + const bountyValue = 10000000000000n // 1000 tokens + const curatorFee = 1000000000000n // 100 tokens (10% fee) + const description = 'Test bounty with curator' + + // Propose and approve bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // Verify curator proposed events + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // Verify bounty status + const bounty = await getBounty(client, bountyIndex) + expect(bounty.status.isCuratorProposed).toBeTruthy() + expect(bounty.fee.toBigInt()).toBe(curatorFee) + + // Curator accepts the role + const acceptCuratorEvents = await sendTransaction( + client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + // Verify curator accepted events + await checkEvents(acceptCuratorEvents, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // Verify bounty is now active + const activeBounty = await getBounty(client, bountyIndex) + console.log('Active bounty status:', activeBounty.status.toHuman()) + expect(activeBounty.status.isActive).toBeTruthy() + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -209,6 +282,11 @@ export function baseBountiesE2ETests< label: 'Bounty approval flow', testFn: async () => await bountyApprovalTest(chain), }, + { + kind: 'test', + label: 'Curator assignment and acceptance', + testFn: async () => await curatorAssignmentTest(chain), + }, ], } } From c1279dbbacf8eae25eb76511f8bc0de2db749e0b Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 9 Sep 2025 23:31:51 +0530 Subject: [PATCH 05/66] rafac: setupTestAccounts function using a map --- packages/shared/src/bounties.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 9ade74a99..b116aaa22 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -47,18 +47,19 @@ async function getBountyApprovals(client: any): Promise { * Setup accounts with funds for testing */ async function setupTestAccounts(client: any, accounts: string[] = ['alice', 'bob']) { - const accountData: any[] = [] - - if (accounts.includes('alice')) { - accountData.push([[devAccounts.alice.address], { providers: 1, data: { free: 100000000000000n } }]) - } - if (accounts.includes('bob')) { - accountData.push([[devAccounts.bob.address], { providers: 1, data: { free: 100000000000000n } }]) - } - if (accounts.includes('charlie')) { - accountData.push([[devAccounts.charlie.address], { providers: 1, data: { free: 100000000000000n } }]) + const accountMap = { + alice: devAccounts.alice.address, + bob: devAccounts.bob.address, + charlie: devAccounts.charlie.address, } + const accountData = accounts + .filter((account) => accountMap[account as keyof typeof accountMap]) + .map((account) => [ + [accountMap[account as keyof typeof accountMap]], + { providers: 1, data: { free: 100000000000000n } }, + ]) + await client.dev.setStorage({ System: { account: accountData, From aacbce13aa0c322222cdd7997157b7add00f309a Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 9 Sep 2025 23:58:56 +0530 Subject: [PATCH 06/66] rafac: bountyValue is changed to exential deposit multiple --- packages/shared/src/bounties.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index b116aaa22..e1ea7b38b 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -101,7 +101,9 @@ export async function bountyCreationTest< await setupTestAccounts(client, ['alice']) const initialBountyCount = await getBountyCount(client) - const bountyValue = 10000000000000n // 1000 tokens + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.muln(1000) // 1000 EDs const description = 'Test bounty for development work' // Propose a bounty @@ -152,7 +154,8 @@ export async function bountyApprovalTest< await setupTestAccounts(client, ['alice']) - const bountyValue = 10000000000000n // 1000 + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.muln(1000) // 1000 EDs const description = 'Test bounty for approval' // Propose a bounty @@ -206,8 +209,9 @@ export async function curatorAssignmentTest< await setupTestAccounts(client, ['alice', 'bob']) - const bountyValue = 10000000000000n // 1000 tokens - const curatorFee = 1000000000000n // 100 tokens (10% fee) + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.muln(1000) // 1000 EDs + const curatorFee = existentialDeposit.muln(100) // 100 EDs (10% fee) const description = 'Test bounty with curator' // Propose and approve bounty From ac3066a8cd008270c9a0d5b8654cf5139961273f Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 10 Sep 2025 19:52:53 +0530 Subject: [PATCH 07/66] fix: bountyValue type is set to BigInt --- packages/shared/src/bounties.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index e1ea7b38b..437e22807 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -103,7 +103,7 @@ export async function bountyCreationTest< const initialBountyCount = await getBountyCount(client) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.muln(1000) // 1000 EDs + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs const description = 'Test bounty for development work' // Propose a bounty @@ -155,7 +155,7 @@ export async function bountyApprovalTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.muln(1000) // 1000 EDs + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs const description = 'Test bounty for approval' // Propose a bounty @@ -210,8 +210,8 @@ export async function curatorAssignmentTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.muln(1000) // 1000 EDs - const curatorFee = existentialDeposit.muln(100) // 100 EDs (10% fee) + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) const description = 'Test bounty with curator' // Propose and approve bounty From 46a8d53ea5e2143b51aa7ad0a973252a743ab0b6 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 10 Sep 2025 20:40:52 +0530 Subject: [PATCH 08/66] Bountry approval flow with Curator test added --- packages/shared/src/bounties.ts | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 437e22807..473cfd153 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -191,6 +191,65 @@ export async function bountyApprovalTest< await client.teardown() } +/** + * Bounty approval flow with curator + * + * Verifies: + * - Bounty can be approved by treasurer with curator + * - Status changes from Proposed to ApprovedWithCurator + * - Bounty is added to approvals queue + * - Correct events are emitted + */ +export async function bountyApprovalWithCuratorTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + const description = 'Test bounty for approval with curator' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Verify initial state + const proposedBounty = await getBounty(client, bountyIndex) + expect(proposedBounty.status.isProposed).toBe(true) + + // Approve the bounty with curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.approveBountyWithCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // Verify approval events + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApprovedWithCurator' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approval with curator events') + + // Verify status changed + const approvedBounty = await getBounty(client, bountyIndex) + expect(approvedBounty.status.isApprovedWithCurator).toBe(true) + + // Verify bounty is in approvals queue + const approvals = await getBountyApprovals(client) + expect(approvals).toContain(bountyIndex) + + await client.teardown() +} + /** * Test 3: Curator assignment and acceptance * From 0e4e845404276a5c6fa4f3ddc8724888c88aea08 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 10 Sep 2025 21:31:27 +0530 Subject: [PATCH 09/66] fix: added event verification in bountyApprovalWithCuratorTest --- packages/shared/src/bounties.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 473cfd153..cb641ac1e 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -235,10 +235,14 @@ export async function bountyApprovalWithCuratorTest< await client.dev.newBlock() // Verify approval events - await checkSystemEvents(client, { section: 'bounties', method: 'BountyApprovedWithCurator' }) + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty approval with curator events') + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + // Verify status changed const approvedBounty = await getBounty(client, bountyIndex) expect(approvedBounty.status.isApprovedWithCurator).toBe(true) From b68fbe8050fb7096cef76142832b059786deb7e1 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 10 Sep 2025 22:00:51 +0530 Subject: [PATCH 10/66] bountyFundingTest added --- packages/shared/src/bounties.ts | 125 +++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 44 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index cb641ac1e..04b9a2825 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -255,75 +255,107 @@ export async function bountyApprovalWithCuratorTest< } /** - * Test 3: Curator assignment and acceptance + * Bounty funding for Approved Bounties * * Verifies: - * - Curator can be proposed for a funded bounty - * - Curator can accept the role - * - Status transitions correctly - * - Curator deposit is reserved + * - Approved Bounties get funded by treasury automatically + * - Status changes from Approved -> Funded * - Correct events are emitted */ -export async function curatorAssignmentTest< +export async function bountyFundingTest< TCustom extends Record | undefined, TInitStorages extends Record> | undefined, >(chain: Chain) { const [client] = await setupNetworks(chain) + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty funding test') + return + } + + // move client head to the last spend period block - 2 + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 2) + await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) - const description = 'Test bounty with curator' + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const description = 'Test bounty for funding' - // Propose and approve bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + // get bountycount and increase it by 1 + const bountyCount = await getBountyCount(client) + const bountyIndex = bountyCount + 1 - await client.dev.newBlock() - const bountyIndex = await getBountyIndexFromEvent(client) + // increase the bounty count + await client.dev.setStorage({ + Bounties: { + bountyCount: bountyIndex, + }, + }) - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { - Origins: 'Treasurer', + // get the bounty count from the storage and verify it is same as the bounty index + const bountyCountFromStorage = await client.api.query.bounties.bountyCount() + expect(bountyCountFromStorage.toNumber()).toBe(bountyIndex) + + // add a bounty description using the setStorage with correct format + await client.dev.setStorage({ + Bounties: { + bountyDescriptions: [[[bountyIndex], description]], + }, }) - await client.dev.newBlock() + // verify the bounty description is added to the storage + const bountyDescriptionFromStorage = await client.api.query.bounties.bountyDescriptions(bountyIndex) + expect(bountyDescriptionFromStorage.isSome).toBe(true) + expect(bountyDescriptionFromStorage.unwrap().toUtf8()).toBe(description) - // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + // add a bounty using the setStorage with correct format + await client.dev.setStorage({ + Bounties: { + bounties: [ + [ + [bountyIndex], + { + proposer: devAccounts.alice.address, + value: bountyValue, + fee: 0, + curatorDeposit: 0, + bond: 1000000000, + status: { proposed: null }, + }, + ], + ], + }, + }) + + // verify the bounty is added to the storage + const bountyFromStorage = await getBounty(client, bountyIndex) + expect(bountyFromStorage.status.isProposed).toBe(true) await client.dev.newBlock() - // Verify curator proposed events - await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) - .redact({ redactKeys: /bountyId/ }) - .toMatchSnapshot('curator proposed events') + // add a bounty in the approvals queue by using setStorage + await client.dev.setStorage({ + Bounties: { + bountyApprovals: [bountyIndex], + }, + }) - // Verify bounty status - const bounty = await getBounty(client, bountyIndex) - expect(bounty.status.isCuratorProposed).toBeTruthy() - expect(bounty.fee.toBigInt()).toBe(curatorFee) + // verify the bounty is added to the approvals queue + const approvals = await getBountyApprovals(client) + expect(approvals).toContain(bountyIndex) - // Curator accepts the role - const acceptCuratorEvents = await sendTransaction( - client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob), - ) + await client.dev.newBlock() await client.dev.newBlock() - // Verify curator accepted events - await checkEvents(acceptCuratorEvents, { section: 'bounties', method: 'CuratorAccepted' }) - .redact({ redactKeys: /bountyId/ }) - .toMatchSnapshot('curator accepted events') + // TODO: Verify that the `BountyBecameActive` event occurred in the block just before this one (i.e., after the bounty is funded) - // Verify bounty is now active - const activeBounty = await getBounty(client, bountyIndex) - console.log('Active bounty status:', activeBounty.status.toHuman()) - expect(activeBounty.status.isActive).toBeTruthy() + // verify that the bounty is funded + const bountyStatus = await getBounty(client, bountyIndex) + expect(bountyStatus.status.isFunded).toBe(true) await client.teardown() } @@ -352,8 +384,13 @@ export function baseBountiesE2ETests< }, { kind: 'test', - label: 'Curator assignment and acceptance', - testFn: async () => await curatorAssignmentTest(chain), + label: 'Bounty approval flow with curator', + testFn: async () => await bountyApprovalWithCuratorTest(chain), + }, + { + kind: 'test', + label: 'Bounty funding for Approved Bounties', + testFn: async () => await bountyFundingTest(chain), }, ], } From 31dd6ac239eea57afb4ffa3e58e76bca23e5e900 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 10 Sep 2025 23:07:42 +0530 Subject: [PATCH 11/66] Bounty funding for ApprovedWithCurator Bounties test added --- packages/shared/src/bounties.ts | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 04b9a2825..f24a2f9b7 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -360,6 +360,90 @@ export async function bountyFundingTest< await client.teardown() } +/** + * Bounty funding for ApprovedWithCurator Bounties + * + * Verifies: + * - When a bounty is approved with curator, status changes to ApprovedWithCurator + * - ApprovedWithCurator Bounties get funded by treasury automatically + * - Status changes from ApprovedWithCurator -> CuratorProposed + * - Correct events are emitted + */ +export async function bountyFundingForApprovedWithCuratorTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + // go the block number when the last spend period block - 1 + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 1) + + await setupTestAccounts(client, ['alice', 'bob']) + + // get the bounty count and increase it by 1 + const bountyCount = await getBountyCount(client) + const bountyIndex = bountyCount + 1 + + // increase the bounty count + await client.dev.setStorage({ + Bounties: { + bountyCount: bountyIndex, + }, + }) + + // verify the bounty count is increased + const bountyCountFromStorage = await client.api.query.bounties.bountyCount() + expect(bountyCountFromStorage.toNumber()).toBe(bountyIndex) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 tokens (10% fee) + + const bondValue = existentialDeposit.toBigInt() * 10n // 10 EDs + const bountyWithCurator = { + proposer: devAccounts.alice.address, + value: bountyValue, + fee: curatorFee, + curatorDeposit: 0, + bond: bondValue, + status: { approvedWithCurator: { curator: devAccounts.bob.address } }, + } + + // add the bounty to the storage + await client.dev.setStorage({ + Bounties: { + bounties: [[[bountyIndex], bountyWithCurator]], + }, + }) + + // verify the bounty is added to the storage + const bountyFromStorage = await getBounty(client, bountyIndex) + expect(bountyFromStorage.status.isApprovedWithCurator).toBe(true) + + // add bouty to the approvals queue + await client.dev.setStorage({ + Bounties: { + bountyApprovals: [bountyIndex], + }, + }) + + // verify the bounty is added to the approvals queue + const approvals = await getBountyApprovals(client) + expect(approvals).toContain(bountyIndex) + + await client.dev.newBlock() + // bounty is funded in this block + await client.dev.newBlock() + + // verify the bounty is funded + const bountyAfterFunding = await getBounty(client, bountyIndex) + expect(bountyAfterFunding.status.isCuratorProposed).toBe(true) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -392,6 +476,11 @@ export function baseBountiesE2ETests< label: 'Bounty funding for Approved Bounties', testFn: async () => await bountyFundingTest(chain), }, + { + kind: 'test', + label: 'Bounty funding for ApprovedWithCurator Bounties', + testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), + }, ], } } From 39c758e88de236bd713eeba58f50ded71da70c92 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 10 Sep 2025 23:45:56 +0530 Subject: [PATCH 12/66] Curator assignment and acceptance test added --- packages/shared/src/bounties.ts | 107 ++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index f24a2f9b7..d2873aefe 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -444,6 +444,108 @@ export async function bountyFundingForApprovedWithCuratorTest< await client.teardown() } +/** + * Curator assignment and acceptance + * + * Verifies: + * - Curator can be proposed for a funded bounty + * - Status changes from Funded -> CuratorProposed + * - Curator can accept the role + * - Status changes from CuratorProposed -> Active + * - Curator deposit is reserved + * - Correct events are emitted + */ +export async function curatorAssignmentAndAcceptanceTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice', 'bob']) + + // get bounty count and increase it by 1 + const bountyCount = await getBountyCount(client) + const bountyIndex = bountyCount + 1 + + // increase the bounty count + await client.dev.setStorage({ + Bounties: { + bountyCount: bountyIndex, + }, + }) + + // verify the bounty count is increased + const bountyCountFromStorage = await client.api.query.bounties.bountyCount() + expect(bountyCountFromStorage.toNumber()).toBe(bountyIndex) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const bondValue = existentialDeposit.toBigInt() * 10n // 10 EDs + + // add the below funded bounty to the storage + const fundedBounty = { + proposer: devAccounts.alice.address, + value: bountyValue, + fee: 0, + curatorDeposit: 0, + bond: bondValue, + status: { funded: null }, + } + + await client.dev.setStorage({ + Bounties: { + bounties: [[[bountyIndex], fundedBounty]], + }, + }) + + // verify the bounty is added to the storage + const bountyFromStorage = await getBounty(client, bountyIndex) + expect(bountyFromStorage.status.isFunded).toBe(true) + + await client.dev.newBlock() + + // propose a curator + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 tokens (10% fee) + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // verify events + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('curator proposed events') + + // verify the curator is proposed + const curatorProposed = await getBounty(client, bountyIndex) + expect(curatorProposed.status.isCuratorProposed).toBe(true) + + await client.dev.newBlock() + + // accept the curator + const acceptCuratorEvents = await sendTransaction( + client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + // verify events + await checkEvents(acceptCuratorEvents, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('curator accepted events') + + // verify the curator is accepted + const curatorAccepted = await getBounty(client, bountyIndex) + expect(curatorAccepted.status.isActive).toBe(true) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -481,6 +583,11 @@ export function baseBountiesE2ETests< label: 'Bounty funding for ApprovedWithCurator Bounties', testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), }, + { + kind: 'test', + label: 'Curator assignment and acceptance', + testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + }, ], } } From cd0d3539f41ca48d0ac8fb03d50ace2ed1e56b5a Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 12 Sep 2025 23:51:40 +0530 Subject: [PATCH 13/66] improve: setStorage replaced with extrinsics call --- packages/shared/src/bounties.ts | 91 ++++++++++++--------------------- 1 file changed, 33 insertions(+), 58 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index d2873aefe..276075c11 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -274,9 +274,9 @@ export async function bountyFundingTest< return } - // move client head to the last spend period block - 2 + // move client head to the last spend period block - 3 const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 2) + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) await setupTestAccounts(client, ['alice', 'bob']) @@ -284,78 +284,53 @@ export async function bountyFundingTest< const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens const description = 'Test bounty for funding' - // get bountycount and increase it by 1 - const bountyCount = await getBountyCount(client) - const bountyIndex = bountyCount + 1 - - // increase the bounty count - await client.dev.setStorage({ - Bounties: { - bountyCount: bountyIndex, - }, - }) - - // get the bounty count from the storage and verify it is same as the bounty index - const bountyCountFromStorage = await client.api.query.bounties.bountyCount() - expect(bountyCountFromStorage.toNumber()).toBe(bountyIndex) - - // add a bounty description using the setStorage with correct format - await client.dev.setStorage({ - Bounties: { - bountyDescriptions: [[[bountyIndex], description]], - }, - }) + // propose a bounty + const bountyProposedEvents = await sendTransaction( + client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), + ) - // verify the bounty description is added to the storage - const bountyDescriptionFromStorage = await client.api.query.bounties.bountyDescriptions(bountyIndex) - expect(bountyDescriptionFromStorage.isSome).toBe(true) - expect(bountyDescriptionFromStorage.unwrap().toUtf8()).toBe(description) + await client.dev.newBlock() - // add a bounty using the setStorage with correct format - await client.dev.setStorage({ - Bounties: { - bounties: [ - [ - [bountyIndex], - { - proposer: devAccounts.alice.address, - value: bountyValue, - fee: 0, - curatorDeposit: 0, - bond: 1000000000, - status: { proposed: null }, - }, - ], - ], - }, - }) + // verify the BountyProposed event + await checkEvents(bountyProposedEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') // verify the bounty is added to the storage + const bountyIndex = await getBountyIndexFromEvent(client) const bountyFromStorage = await getBounty(client, bountyIndex) expect(bountyFromStorage.status.isProposed).toBe(true) + // approve the bounty with origin treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + await client.dev.newBlock() - // add a bounty in the approvals queue by using setStorage - await client.dev.setStorage({ - Bounties: { - bountyApprovals: [bountyIndex], - }, - }) + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') // verify the bounty is added to the approvals queue - const approvals = await getBountyApprovals(client) - expect(approvals).toContain(bountyIndex) + const approvalsforStorage = await getBountyApprovals(client) + expect(approvalsforStorage).toContain(bountyIndex) await client.dev.newBlock() - + // This is the spendPeriodBlock i.e bounty will be funded in this block await client.dev.newBlock() - // TODO: Verify that the `BountyBecameActive` event occurred in the block just before this one (i.e., after the bounty is funded) + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // verify the status of the bounty after funding is funded + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isFunded).toBe(true) - // verify that the bounty is funded - const bountyStatus = await getBounty(client, bountyIndex) - expect(bountyStatus.status.isFunded).toBe(true) + // TODO: @dhirajs0 - verify that the bond of the proposer is reserved and it's unreserved after the bounty is funded await client.teardown() } From b6baac512c6c574ce7a2994547e843278c43ded8 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 12 Sep 2025 23:52:17 +0530 Subject: [PATCH 14/66] helper function getBountyEvents added --- packages/shared/src/bounties.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 276075c11..ce8a3012c 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -78,6 +78,14 @@ async function getBountyIndexFromEvent(client: any): Promise { return (bountyProposedEvent.event.data as any).index.toNumber() } +/** + * Get bounties events from the system events + */ +async function getBountyEvents(client: any): Promise { + const events = await client.api.query.system.events() + return events.filter((record) => record.event.section === 'bounties') +} + /// ------- /// Tests /// ------- From 64d8ce6a05bfd01f09ecbcfa66632068b1078bb2 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 12:54:17 +0530 Subject: [PATCH 15/66] setStorage replaces with Extrinsic call in fundind with curator test --- packages/shared/src/bounties.ts | 151 ++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 68 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index ce8a3012c..d1f1b8cd0 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -86,6 +86,16 @@ async function getBountyEvents(client: any): Promise { return events.filter((record) => record.event.section === 'bounties') } +/** + * Log the bounties events + */ +async function logBountyEvents(client: any) { + const events = await getBountyEvents(client) + events.forEach((evt: any, idx: number) => { + console.log(`Event #${idx}:`, evt.event?.toHuman?.() ?? evt.event) + }) +} + /// ------- /// Tests /// ------- @@ -358,71 +368,76 @@ export async function bountyFundingForApprovedWithCuratorTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // go the block number when the last spend period block - 1 + // go the block number when the last spend period block - 3 const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 1) + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) await setupTestAccounts(client, ['alice', 'bob']) - // get the bounty count and increase it by 1 - const bountyCount = await getBountyCount(client) - const bountyIndex = bountyCount + 1 - - // increase the bounty count - await client.dev.setStorage({ - Bounties: { - bountyCount: bountyIndex, - }, - }) - - // verify the bounty count is increased - const bountyCountFromStorage = await client.api.query.bounties.bountyCount() - expect(bountyCountFromStorage.toNumber()).toBe(bountyIndex) - const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens const curatorFee = existentialDeposit.toBigInt() * 100n // 100 tokens (10% fee) + const description = 'Test bounty for funding with curator' - const bondValue = existentialDeposit.toBigInt() * 10n // 10 EDs - const bountyWithCurator = { - proposer: devAccounts.alice.address, - value: bountyValue, - fee: curatorFee, - curatorDeposit: 0, - bond: bondValue, - status: { approvedWithCurator: { curator: devAccounts.bob.address } }, - } + // propose a bounty + const bountyProposedEvents = await sendTransaction( + client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), + ) - // add the bounty to the storage - await client.dev.setStorage({ - Bounties: { - bounties: [[[bountyIndex], bountyWithCurator]], - }, - }) + await client.dev.newBlock() - // verify the bounty is added to the storage + // verify the BountyProposed event + await checkEvents(bountyProposedEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + // verify the bounty is added to the storage and the status is Proposed + const bountyIndex = await getBountyIndexFromEvent(client) const bountyFromStorage = await getBounty(client, bountyIndex) - expect(bountyFromStorage.status.isApprovedWithCurator).toBe(true) + expect(bountyFromStorage.status.isProposed).toBe(true) - // add bouty to the approvals queue - await client.dev.setStorage({ - Bounties: { - bountyApprovals: [bountyIndex], + // approve the bounty with origin treasurer with curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.approveBountyWithCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', }, - }) + ) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') // verify the bounty is added to the approvals queue const approvals = await getBountyApprovals(client) expect(approvals).toContain(bountyIndex) + // verify the bounty status is ApprovedWithCurator + const bountyStatus = await getBounty(client, bountyIndex) + expect(bountyStatus.status.isApprovedWithCurator).toBe(true) + await client.dev.newBlock() - // bounty is funded in this block + // In this block the bounty is funded and the status changes to CuratorProposed await client.dev.newBlock() - // verify the bounty is funded - const bountyAfterFunding = await getBounty(client, bountyIndex) - expect(bountyAfterFunding.status.isCuratorProposed).toBe(true) + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // verify the bounty status is CuratorProposed + const bountyStatusAfterFunding = await getBounty(client, bountyIndex) + expect(bountyStatusAfterFunding.status.isCuratorProposed).toBe(true) await client.teardown() } @@ -541,36 +556,36 @@ export function baseBountiesE2ETests< kind: 'describe', label: testConfig.testSuiteName, children: [ - { - kind: 'test', - label: 'Creating a bounty', - testFn: async () => await bountyCreationTest(chain), - }, - { - kind: 'test', - label: 'Bounty approval flow', - testFn: async () => await bountyApprovalTest(chain), - }, - { - kind: 'test', - label: 'Bounty approval flow with curator', - testFn: async () => await bountyApprovalWithCuratorTest(chain), - }, - { - kind: 'test', - label: 'Bounty funding for Approved Bounties', - testFn: async () => await bountyFundingTest(chain), - }, + // { + // kind: 'test', + // label: 'Creating a bounty', + // testFn: async () => await bountyCreationTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty approval flow', + // testFn: async () => await bountyApprovalTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty approval flow with curator', + // testFn: async () => await bountyApprovalWithCuratorTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty funding for Approved Bounties', + // testFn: async () => await bountyFundingTest(chain), + // }, { kind: 'test', label: 'Bounty funding for ApprovedWithCurator Bounties', testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), }, - { - kind: 'test', - label: 'Curator assignment and acceptance', - testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), - }, + // { + // kind: 'test', + // label: 'Curator assignment and acceptance', + // testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + // }, ], } } From bca934b3cf581020769db3891799861316d466cb Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 13:21:55 +0530 Subject: [PATCH 16/66] replaced the setStorage with Extrinsic calls in curator assignment and acceptance test --- packages/shared/src/bounties.ts | 126 ++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 54 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index d1f1b8cd0..9c468676f 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -459,51 +459,71 @@ export async function curatorAssignmentAndAcceptanceTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - await setupTestAccounts(client, ['alice', 'bob']) - - // get bounty count and increase it by 1 - const bountyCount = await getBountyCount(client) - const bountyIndex = bountyCount + 1 + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty funding test') + return + } - // increase the bounty count - await client.dev.setStorage({ - Bounties: { - bountyCount: bountyIndex, - }, - }) + // move client head to the last spend period block - 3 + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) - // verify the bounty count is increased - const bountyCountFromStorage = await client.api.query.bounties.bountyCount() - expect(bountyCountFromStorage.toNumber()).toBe(bountyIndex) + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens - const bondValue = existentialDeposit.toBigInt() * 10n // 10 EDs - - // add the below funded bounty to the storage - const fundedBounty = { - proposer: devAccounts.alice.address, - value: bountyValue, - fee: 0, - curatorDeposit: 0, - bond: bondValue, - status: { funded: null }, - } + const description = 'Test bounty for funding' - await client.dev.setStorage({ - Bounties: { - bounties: [[[bountyIndex], fundedBounty]], - }, - }) + // propose a bounty + const bountyProposedEvents = await sendTransaction( + client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), + ) + + await client.dev.newBlock() + + // verify the BountyProposed event + await checkEvents(bountyProposedEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') // verify the bounty is added to the storage + const bountyIndex = await getBountyIndexFromEvent(client) const bountyFromStorage = await getBounty(client, bountyIndex) - expect(bountyFromStorage.status.isFunded).toBe(true) + expect(bountyFromStorage.status.isProposed).toBe(true) + + // approve the bounty with origin treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() - // propose a curator - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 tokens (10% fee) + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the bounty is added to the approvals queue + const approvalsforStorage = await getBountyApprovals(client) + expect(approvalsforStorage).toContain(bountyIndex) + + await client.dev.newBlock() + // This is the spendPeriodBlock i.e bounty will be funded in this block + await client.dev.newBlock() + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // verify the status of the bounty after funding is funded + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isFunded).toBe(true) + + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + + // assign curator to the bounty await scheduleInlineCallWithOrigin( client, client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), @@ -514,32 +534,30 @@ export async function curatorAssignmentAndAcceptanceTest< await client.dev.newBlock() - // verify events + // verify the CuratorProposed event await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) - .redact({ redactKeys: /index/ }) + .redact({ redactKeys: /bountyId/ }) .toMatchSnapshot('curator proposed events') - // verify the curator is proposed - const curatorProposed = await getBounty(client, bountyIndex) - expect(curatorProposed.status.isCuratorProposed).toBe(true) + // verify the bounty status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) await client.dev.newBlock() // accept the curator - const acceptCuratorEvents = await sendTransaction( - client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob), - ) + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) await client.dev.newBlock() - // verify events - await checkEvents(acceptCuratorEvents, { section: 'bounties', method: 'CuratorAccepted' }) - .redact({ redactKeys: /index/ }) + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) .toMatchSnapshot('curator accepted events') - // verify the curator is accepted - const curatorAccepted = await getBounty(client, bountyIndex) - expect(curatorAccepted.status.isActive).toBe(true) + // verify the bounty status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) await client.teardown() } @@ -576,16 +594,16 @@ export function baseBountiesE2ETests< // label: 'Bounty funding for Approved Bounties', // testFn: async () => await bountyFundingTest(chain), // }, - { - kind: 'test', - label: 'Bounty funding for ApprovedWithCurator Bounties', - testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), - }, // { // kind: 'test', - // label: 'Curator assignment and acceptance', - // testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + // label: 'Bounty funding for ApprovedWithCurator Bounties', + // testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), // }, + { + kind: 'test', + label: 'Curator assignment and acceptance', + testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + }, ], } } From 33019a2cbd341fe736da80bd45031a77fd8c527d Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 13:36:43 +0530 Subject: [PATCH 17/66] bounty extension test added --- packages/shared/src/bounties.ts | 155 +++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 9c468676f..b1fa3be77 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -562,6 +562,152 @@ export async function curatorAssignmentAndAcceptanceTest< await client.teardown() } +/** + * Bounty extension + * + * Verifies: + * - Curator can extend bounty expiry + * - Update due date is extended + * - Correct events are emitted + */ +export async function bountyExtensionTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty funding test') + return + } + + // move client head to the last spend period block - 3 + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const description = 'Test bounty for funding' + + // propose a bounty + const bountyProposedEvents = await sendTransaction( + client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), + ) + + await client.dev.newBlock() + + // verify the BountyProposed event + await checkEvents(bountyProposedEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + // verify the bounty is added to the storage + const bountyIndex = await getBountyIndexFromEvent(client) + const bountyFromStorage = await getBounty(client, bountyIndex) + expect(bountyFromStorage.status.isProposed).toBe(true) + + // approve the bounty with origin treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the bounty is added to the approvals queue + const approvalsforStorage = await getBountyApprovals(client) + expect(approvalsforStorage).toContain(bountyIndex) + + await client.dev.newBlock() + // This is the spendPeriodBlock i.e bounty will be funded in this block + await client.dev.newBlock() + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // verify the status of the bounty after funding is funded + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isFunded).toBe(true) + + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + + // assign curator to the bounty + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // verify the bounty status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) + + await client.dev.newBlock() + + // accept the curator + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // verify the bounty status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + await client.dev.newBlock() + + // log the bounty and get updateDue before extension + const bountyForExtending = await getBounty(client, bountyIndex) + + // Get updateDue before extension + const updateDueBefore = bountyForExtending.status.asActive.updateDue.toNumber() + + // extend the bounty expiry + const extendBountyEvents = await sendTransaction( + client.api.tx.bounties.extendBountyExpiry(bountyIndex, 'Testing the bounty extension').signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + // verify the BountyExtended events + await checkEvents(extendBountyEvents, { section: 'bounties', method: 'BountyExtended' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty extended events') + + // verify the bounty is extended and get updateDue after extension + const bountyExtended = await getBounty(client, bountyIndex) + expect(bountyExtended.status.isActive).toBe(true) + + // Get updateDue after extension + const updateDueAfter = bountyExtended.status.asActive.updateDue.toNumber() + + // Assert that updateDue after extension is greater than before + expect(updateDueAfter).toBeGreaterThan(updateDueBefore) + + await client.teardown() +} /// ------- /// Test Suite /// ------- @@ -599,10 +745,15 @@ export function baseBountiesE2ETests< // label: 'Bounty funding for ApprovedWithCurator Bounties', // testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), // }, + // { + // kind: 'test', + // label: 'Curator assignment and acceptance', + // testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + // }, { kind: 'test', - label: 'Curator assignment and acceptance', - testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + label: 'Bounty extension', + testFn: async () => await bountyExtensionTest(chain), }, ], } From 7e20cdbf60bd92b8b31da284f6837dd907e640de Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 15:32:09 +0530 Subject: [PATCH 18/66] bounty awading and claiming tests added --- packages/shared/src/bounties.ts | 232 +++++++++++++++++++++++++++----- 1 file changed, 202 insertions(+), 30 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index b1fa3be77..ba1e8d77a 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -708,6 +708,173 @@ export async function bountyExtensionTest< await client.teardown() } + +/** + * Bounty awarding and claiming + * + * Verifies: + * - Curator can award bounty to beneficiary + * - Status changes to PendingPayout + * - Curator can claim the bounty after delay period + * - Correct events are emitted + */ +export async function bountyAwardingAndClaimingTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty funding test') + return + } + + // move client head to the last spend period block - 3 + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const description = 'Test bounty for funding' + + // propose a bounty + const bountyProposedEvents = await sendTransaction( + client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), + ) + + await client.dev.newBlock() + + // verify the BountyProposed event + await checkEvents(bountyProposedEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + // verify the bounty is added to the storage + const bountyIndex = await getBountyIndexFromEvent(client) + const bountyFromStorage = await getBounty(client, bountyIndex) + expect(bountyFromStorage.status.isProposed).toBe(true) + + // approve the bounty with origin treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the bounty is added to the approvals queue + const approvalsforStorage = await getBountyApprovals(client) + expect(approvalsforStorage).toContain(bountyIndex) + + await client.dev.newBlock() + // This is the spendPeriodBlock i.e bounty will be funded in this block + await client.dev.newBlock() + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // verify the status of the bounty after funding is funded + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isFunded).toBe(true) + + const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + + // assign curator to the bounty + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // verify the bounty status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) + + await client.dev.newBlock() + + // accept the curator + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // verify the bounty status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + await client.dev.newBlock() + + // award the bounty to the beneficiary + const awardBountyEvents = await sendTransaction( + client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address).signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + // verify events + await checkEvents(awardBountyEvents, { section: 'bounties', method: 'BountyAwarded' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty awarded events') + + // verify the bounty is awarded + const bountyAwarded = await getBounty(client, bountyIndex) + expect(bountyAwarded.status.isPendingPayout).toBe(true) + + // Calculate the claimable at block number + const currentBlock = await client.api.rpc.chain.getHeader() + const bountyDepositPayoutDelay = await client.api.consts.bounties.bountyDepositPayoutDelay + const claimableAtBlock = currentBlock.number.toNumber() + Number(bountyDepositPayoutDelay.toNumber()) + + // wait for the unlock at block number + await client.dev.setHead(claimableAtBlock) + + await client.dev.newBlock() + + // claim the bounty + const claimBountyEvents = await sendTransaction( + client.api.tx.bounties.claimBounty(bountyIndex).signAsync(devAccounts.alice), + ) + + await client.dev.newBlock() + + // verify events + await checkEvents(claimBountyEvents, { section: 'bounties', method: 'BountyClaimed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty claimed events') + + // verify that the bounty is removed from the storage + const bountyFromStorageAfterClaiming = await getBounty(client, bountyIndex) + expect(bountyFromStorageAfterClaiming).toBeNull() + + // verify that the bounty description is removed from the storage + const bountyDescriptionFromStorageAfterClaiming = await getBountyDescription(client, bountyIndex) + expect(bountyDescriptionFromStorageAfterClaiming).toBeNull() + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -720,41 +887,46 @@ export function baseBountiesE2ETests< kind: 'describe', label: testConfig.testSuiteName, children: [ - // { - // kind: 'test', - // label: 'Creating a bounty', - // testFn: async () => await bountyCreationTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty approval flow', - // testFn: async () => await bountyApprovalTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty approval flow with curator', - // testFn: async () => await bountyApprovalWithCuratorTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty funding for Approved Bounties', - // testFn: async () => await bountyFundingTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty funding for ApprovedWithCurator Bounties', - // testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), - // }, - // { - // kind: 'test', - // label: 'Curator assignment and acceptance', - // testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), - // }, + { + kind: 'test', + label: 'Creating a bounty', + testFn: async () => await bountyCreationTest(chain), + }, + { + kind: 'test', + label: 'Bounty approval flow', + testFn: async () => await bountyApprovalTest(chain), + }, + { + kind: 'test', + label: 'Bounty approval flow with curator', + testFn: async () => await bountyApprovalWithCuratorTest(chain), + }, + { + kind: 'test', + label: 'Bounty funding for Approved Bounties', + testFn: async () => await bountyFundingTest(chain), + }, + { + kind: 'test', + label: 'Bounty funding for ApprovedWithCurator Bounties', + testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), + }, + { + kind: 'test', + label: 'Curator assignment and acceptance', + testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + }, { kind: 'test', label: 'Bounty extension', testFn: async () => await bountyExtensionTest(chain), }, + { + kind: 'test', + label: 'Bounty awarding and claiming', + testFn: async () => await bountyAwardingAndClaimingTest(chain), + }, ], } } From 1f4ac58731cf553eb12b11285e44ee2263b2c0da Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 17:19:52 +0530 Subject: [PATCH 19/66] bounty closure on proposed test added --- packages/shared/src/bounties.ts | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index ba1e8d77a..8ba030146 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -875,6 +875,67 @@ export async function bountyAwardingAndClaimingTest< await client.teardown() } +/** + * Test: Bounty closure in Proposed state + * + * Verifies: + * - Bounty can be closed by GeneralAdmin when in Proposed state + * - Proposer's bond is slashed + * - Bounty is removed from storage + * - BountyRejected event is emitted + */ +export async function bountyClosureProposedTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const description = 'Test bounty for closure in proposed state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Verify bounty is in Proposed state + const proposedBounty = await getBounty(client, bountyIndex) + expect(proposedBounty.status.isProposed).toBe(true) + + // Close the bounty using Treasurer origin + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify BountyRejected event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyRejected' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty rejected events') + + // Verify bounty is removed from storage + const bountyAfterClosure = await getBounty(client, bountyIndex) + expect(bountyAfterClosure).toBeNull() + + // Verify description is removed + const descriptionAfterClosure = await getBountyDescription(client, bountyIndex) + expect(descriptionAfterClosure).toBeNull() + + // Verify proposer's bond was slashed + const finalBalance = await client.api.query.system.account(devAccounts.alice.address) + const reservedBalance = finalBalance.data.reserved.toBigInt() + + // The bond should be slashed (not returned to free balance) + expect(reservedBalance).toBe(0n) // Reserved should be 0 after slash + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -927,6 +988,11 @@ export function baseBountiesE2ETests< label: 'Bounty awarding and claiming', testFn: async () => await bountyAwardingAndClaimingTest(chain), }, + { + kind: 'test', + label: 'Bounty closure in proposed state', + testFn: async () => await bountyClosureProposedTest(chain), + }, ], } } From 8c5ae5e3271e04e0001fb3c1aea93b5ede40a52c Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 19:42:35 +0530 Subject: [PATCH 20/66] bounty closure in funded state test added --- packages/shared/src/bounties.ts | 107 ++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 8ba030146..810f31019 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -24,6 +24,7 @@ async function getBountyCount(client: any): Promise { */ async function getBounty(client: any, bountyIndex: number): Promise { const bounty = await client.api.query.bounties.bounties(bountyIndex) + if (!bounty) return null return bounty.isSome ? bounty.unwrap() : null } @@ -936,6 +937,107 @@ export async function bountyClosureProposedTest< await client.teardown() } +/** + * Test: Bounty closure in Funded state + * + * Verifies: + * - Bounty can be closed when in Funded state + * - Funds are transferred back to treasury + * - Bounty is removed from storage + * - BountyCanceled event is emitted + */ +export async function bountyClosureFundedTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + // Move to spend period + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty closure funded test') + return + } + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const description = 'Test bounty for closure in funded state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + await client.dev.newBlock() + // Bounty will be funded in this block + await client.dev.newBlock() + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // Verify bounty is funded + const fundedBounty = await getBounty(client, bountyIndex) + expect(fundedBounty.status.isFunded).toBe(true) + + // get treasury balance before closure + const treasuryAccountId = client.api.consts.treasury.potAccount.toHex() + const treasuryAccountBeforeClosureInfo = await client.api.query.system.account(treasuryAccountId) + const treasuryBalanceBeforeClosure = treasuryAccountBeforeClosureInfo.data.free.toBigInt() + + // Close the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify BountyCanceled event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyCanceled' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty canceled events') + + // verify the transfer event + await checkSystemEvents(client, { section: 'balances', method: 'Transfer' }) + .redact({ redactKeys: /from|to/ }) + .toMatchSnapshot('bounty value transfered to treasury') + + // get treasury balance after closure + const treasuryAccountAfterClosureInfo = await client.api.query.system.account(treasuryAccountId) + const treasuryBalanceAfterClosure = treasuryAccountAfterClosureInfo.data.free.toBigInt() + expect(treasuryBalanceAfterClosure).toBeGreaterThan(treasuryBalanceBeforeClosure) + + await client.dev.newBlock() + + // Verify bounty is removed from storage + const bountyAfterClosure = await getBounty(client, bountyIndex) + expect(bountyAfterClosure).toBeNull() + + // Verify description is removed + const descriptionAfterClosure = await getBountyDescription(client, bountyIndex) + expect(descriptionAfterClosure).toBeNull() + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -993,6 +1095,11 @@ export function baseBountiesE2ETests< label: 'Bounty closure in proposed state', testFn: async () => await bountyClosureProposedTest(chain), }, + { + kind: 'test', + label: 'Bounty closure in funded state', + testFn: async () => await bountyClosureFundedTest(chain), + }, ], } } From e5403b636799b6dc47ae89ca4e261d2f587c0f35 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 19:43:13 +0530 Subject: [PATCH 21/66] helper function to log all events added --- packages/shared/src/bounties.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 810f31019..dc6248332 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -97,6 +97,13 @@ async function logBountyEvents(client: any) { }) } +async function logAllEvents(client: any) { + const events = await client.api.query.system.events() + events.forEach((evt: any, idx: number) => { + console.log(`Event #${idx}:`, evt.event?.toHuman?.() ?? evt.event) + }) +} + /// ------- /// Tests /// ------- From 3bff36de38075821ca286386c3cf3b523ad8e2fc Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 19:57:58 +0530 Subject: [PATCH 22/66] update: blance slash check added in bounty closure of proposed bounty test --- packages/shared/src/bounties.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index dc6248332..8aed621fc 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -926,6 +926,11 @@ export async function bountyClosureProposedTest< .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty rejected events') + // verify the Slash event + await checkSystemEvents(client, { section: 'balances', method: 'Slashed' }) + .redact({ redactKeys: /who/ }) + .toMatchSnapshot('proposer bond slashed event') + // Verify bounty is removed from storage const bountyAfterClosure = await getBounty(client, bountyIndex) expect(bountyAfterClosure).toBeNull() From de4380dd58fa1fbb0f881abcd68964e5cca156be Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 20:13:13 +0530 Subject: [PATCH 23/66] bounty closure in active state test added --- packages/shared/src/bounties.ts | 127 ++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 8aed621fc..29a7a234c 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1050,6 +1050,128 @@ export async function bountyClosureFundedTest< await client.teardown() } +/** + * Test: Bounty closure in Active state + * + * Verifies: + * - Bounty can be closed when in Active state + * - Curator deposit is refunded + * - Funds are transferred back to treasury + * - Bounty is removed from storage + * - BountyCanceled event is emitted + */ +export async function bountyClosureActiveTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty closure active test') + return + } + + // Move to spend period + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for closure in active state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + await client.dev.newBlock() + // Bounty will be funded in this block + await client.dev.newBlock() + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // Accept curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // Verify bounty is in Active state + const activeBounty = await getBounty(client, bountyIndex) + expect(activeBounty.status.isActive).toBe(true) + + // Get curator reserved balance before closure + const curatorBalanceBeforeClosure = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceBeforeClosure = curatorBalanceBeforeClosure.data.reserved.toBigInt() + console.log('Curator reserved balance before:', curatorReservedBalanceBeforeClosure) + + // Close the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify BountyCanceled event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyCanceled' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty canceled event') + + // verify the curator transfer of balance event to the treasury + await checkSystemEvents(client, { section: 'balances', method: 'Transfer' }) + .redact({ redactKeys: /from|to/ }) + .toMatchSnapshot('Bounty value is transferred to the treasury') + + // Verify bounty is removed from storage + const bountyAfterClosure = await getBounty(client, bountyIndex) + expect(bountyAfterClosure).toBeNull() + + // Verify curator deposit was refunded + const curatorBalanceAfterClosure = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceAfterClosure = curatorBalanceAfterClosure.data.reserved.toBigInt() + expect(curatorReservedBalanceBeforeClosure).toBeGreaterThan(curatorReservedBalanceAfterClosure) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -1112,6 +1234,11 @@ export function baseBountiesE2ETests< label: 'Bounty closure in funded state', testFn: async () => await bountyClosureFundedTest(chain), }, + { + kind: 'test', + label: 'Bounty closure in active state', + testFn: async () => await bountyClosureActiveTest(chain), + }, ], } } From df503aa416083ac63cab5a11493b312e90db7f8d Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 15 Sep 2025 21:07:27 +0530 Subject: [PATCH 24/66] unassign curator when bounty state is ApprovedWithCurator test is added --- packages/shared/src/bounties.ts | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 29a7a234c..fd41be835 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1172,6 +1172,65 @@ export async function bountyClosureActiveTest< await client.teardown() } +/** + * Test: Unassign curator in ApprovedWithCurator state + * + * Verifies: + * - Treasurer can unassign curator from ApprovedWithCurator state + * - Status changes back to Approved + * - CuratorUnassigned event is emitted + */ +export async function unassignCuratorApprovedWithCuratorTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for unassign curator in approved with curator state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Approve bounty with curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.approveBountyWithCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // Verify bounty is in ApprovedWithCurator state + const approvedWithCuratorBounty = await getBounty(client, bountyIndex) + expect(approvedWithCuratorBounty.status.isApprovedWithCurator).toBe(true) + + // Unassign curator using Treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify CuratorUnassigned event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorUnassigned' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator unassigned approved with curator events') + + // Verify bounty status changed back to Approved + const bountyAfterUnassign = await getBounty(client, bountyIndex) + expect(bountyAfterUnassign.status.isApproved).toBe(true) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -1239,6 +1298,11 @@ export function baseBountiesE2ETests< label: 'Bounty closure in active state', testFn: async () => await bountyClosureActiveTest(chain), }, + { + kind: 'test', + label: 'Unassign curator in ApprovedWithCurator state', + testFn: async () => await unassignCuratorApprovedWithCuratorTest(chain), + }, ], } } From 2297f8dce7a49444415d2779a00b50db1969b930 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 16 Sep 2025 22:03:58 +0530 Subject: [PATCH 25/66] unassign curator of bounty in curator proposed state test added --- packages/shared/src/bounties.ts | 107 ++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index fd41be835..6628679b3 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1231,6 +1231,108 @@ export async function unassignCuratorApprovedWithCuratorTest< await client.teardown() } +/** + * Test: Unassign curator in CuratorProposed state + * + * Verifies: + * - Treasurer can unassign curator from CuratorProposed state + * - Status changes to Funded + * - CuratorUnassigned event is emitted + */ +export async function unassignCuratorCuratorProposedTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping unassign curator curator proposed test') + return + } + + // Move to spend period + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for unassign curator in curator proposed state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // verify status of the bounty + const bountyStatusAfterProposal = await getBounty(client, bountyIndex) + expect(bountyStatusAfterProposal.status.isProposed).toBe(true) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify status of the bounty + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isApproved).toBe(true) + + await client.dev.newBlock() + // Bounty will be funded in this block + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + await client.dev.newBlock() + + const bountyStatusAfterFunding = await getBounty(client, bountyIndex) + expect(bountyStatusAfterFunding.status.isFunded).toBe(true) + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // Verify bounty is in CuratorProposed state + const curatorProposedBounty = await getBounty(client, bountyIndex) + expect(curatorProposedBounty.status.isCuratorProposed).toBe(true) + + // Unassign curator using Treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify CuratorUnassigned event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorUnassigned' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator unassigned curator proposed events') + + // Verify bounty status changed to Funded + const bountyAfterUnassign = await getBounty(client, bountyIndex) + expect(bountyAfterUnassign.status.isFunded).toBe(true) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -1303,6 +1405,11 @@ export function baseBountiesE2ETests< label: 'Unassign curator in ApprovedWithCurator state', testFn: async () => await unassignCuratorApprovedWithCuratorTest(chain), }, + { + kind: 'test', + label: 'Unassign curator in CuratorProposed state', + testFn: async () => await unassignCuratorCuratorProposedTest(chain), + }, ], } } From 51e55e75e210f887b850f9b894d231614d5b8d6c Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 16 Sep 2025 22:18:34 +0530 Subject: [PATCH 26/66] unassign curator by curator when bounty status is Active test added --- packages/shared/src/bounties.ts | 140 ++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 6628679b3..70e910852 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1333,6 +1333,141 @@ export async function unassignCuratorCuratorProposedTest< await client.teardown() } +/** + * Test: Unassign curator in Active state by curator themselves + * + * Verifies: + * - Curator can unassign themselves from Active state + * - Curator deposit is refunded + * - Status changes to Funded + * - CuratorUnassigned event is emitted + */ +export async function unassignCuratorActiveByCuratorTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping unassign curator active by curator test') + return + } + + // Move to spend period + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for unassign curator active by curator' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // verify the status is Proposed + const bountyIndex = await getBountyIndexFromEvent(client) + const bountyStatus = await getBounty(client, bountyIndex) + expect(bountyStatus.status.isProposed).toBe(true) + + // verify the BountyProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the status is Approved + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isApproved).toBe(true) + + await client.dev.newBlock() + // Bounty will be funded in this block + + // verify the event BountyBecameActive + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + await client.dev.newBlock() + + // verify the status is Funded + const bountyStatusAfterFunding = await getBounty(client, bountyIndex) + expect(bountyStatusAfterFunding.status.isFunded).toBe(true) + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // verify the status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) + + // Accept curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // verify the status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + // Get curator reserved balance before unassign + const curatorBalanceBefore = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() + + // Unassign curator by curator themselves + await sendTransaction(client.api.tx.bounties.unassignCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // Verify CuratorUnassigned event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorUnassigned' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator unassigned active by curator events') + + // Verify bounty status changed to Funded + const bountyAfterUnassign = await getBounty(client, bountyIndex) + expect(bountyAfterUnassign.status.isFunded).toBe(true) + + // Verify curator deposit was refunded as the caller is the curator so dont slash the curator + const curatorBalanceAfter = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceAfter = curatorBalanceAfter.data.reserved.toBigInt() + expect(curatorReservedBalanceAfter).toBeLessThan(curatorReservedBalanceBefore) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -1410,6 +1545,11 @@ export function baseBountiesE2ETests< label: 'Unassign curator in CuratorProposed state', testFn: async () => await unassignCuratorCuratorProposedTest(chain), }, + { + kind: 'test', + label: 'Unassign curator in Active state by curator themselves', + testFn: async () => await unassignCuratorActiveByCuratorTest(chain), + }, ], } } From 02241668a3feec28a12530eb2eed7d9a7d3df7c8 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 16 Sep 2025 22:26:18 +0530 Subject: [PATCH 27/66] unassign curator by treasury when bounty is active test is added --- packages/shared/src/bounties.ts | 154 ++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 70e910852..c99fedc5f 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1468,6 +1468,155 @@ export async function unassignCuratorActiveByCuratorTest< await client.teardown() } +/** + * Test: Unassign curator in Active state by Treasurer (slashes curator) + * + * Verifies: + * - Treasurer can unassign curator from Active state + * - Curator deposit is slashed + * - Status changes to Funded + * - CuratorUnassigned event is emitted + */ +export async function unassignCuratorActiveByTreasurerTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping unassign curator active by treasurer test') + return + } + + // Move to spend period + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for unassign curator active by treasurer' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // verify the BountyProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + // verify the status is Proposed + const bountyIndex = await getBountyIndexFromEvent(client) + const bountyStatus = await getBounty(client, bountyIndex) + expect(bountyStatus.status.isProposed).toBe(true) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the status is Approved + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isApproved).toBe(true) + + await client.dev.newBlock() + // Bounty will be funded in this block + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + await client.dev.newBlock() + + // verify the status is Funded + const bountyStatusAfterFunding = await getBounty(client, bountyIndex) + expect(bountyStatusAfterFunding.status.isFunded).toBe(true) + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // verify the status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) + + // Accept curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // verify the status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + // Get curator balance before unassign + const curatorBalanceBefore = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() + + // Unassign curator by Treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await logAllEvents(client) + + // Verify CuratorUnassigned event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorUnassigned' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator unassigned active by treasurer events') + + // verify the curator slash event as the unassignCurator is called by the treasurer + await checkSystemEvents(client, { section: 'balances', method: 'Slashed' }) + .redact({ redactKeys: /who/ }) + .toMatchSnapshot('curator slash event') + + // verify that the slashed amout is deposited to the treasury + await checkSystemEvents(client, { section: 'treasury', method: 'Deposit' }) + .redact({ redactKeys: /data/ }) + .toMatchSnapshot('Bounty bond is deposited to the treasury') + + // Verify bounty status changed to Funded + const bountyAfterUnassign = await getBounty(client, bountyIndex) + expect(bountyAfterUnassign.status.isFunded).toBe(true) + + // Verify curator deposit was slashed + const curatorBalanceAfter = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceAfter = curatorBalanceAfter.data.reserved.toBigInt() + expect(curatorReservedBalanceBefore).toBeGreaterThan(curatorReservedBalanceAfter) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -1550,6 +1699,11 @@ export function baseBountiesE2ETests< label: 'Unassign curator in Active state by curator themselves', testFn: async () => await unassignCuratorActiveByCuratorTest(chain), }, + { + kind: 'test', + label: 'Unassign curator in Active state by Treasurer', + testFn: async () => await unassignCuratorActiveByTreasurerTest(chain), + }, ], } } From 1de2dfb4b8be581f59dcb00c092e84f161841feb Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 16 Sep 2025 22:57:23 +0530 Subject: [PATCH 28/66] unassign curator by treasury when bounty status is PendingPayout test added --- packages/shared/src/bounties.ts | 169 ++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index c99fedc5f..55b1e2516 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1617,6 +1617,170 @@ export async function unassignCuratorActiveByTreasurerTest< await client.teardown() } +/** + * Test: Unassign curator in PendingPayout state by Treasurer + * + * Verifies: + * - Treasurer can unassign curator from PendingPayout state + * - Curator deposit is slashed + * - Status changes to Funded + * - CuratorUnassigned event is emitted + */ +export async function unassignCuratorPendingPayoutTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping unassign curator pending payout test') + return + } + + // Move to spend period + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for unassign curator pending payout' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // verify the BountyProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + const bountyIndex = await getBountyIndexFromEvent(client) + + // verify the status is Proposed + const bountyStatus = await getBounty(client, bountyIndex) + expect(bountyStatus.status.isProposed).toBe(true) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the status is Approved + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isApproved).toBe(true) + + await client.dev.newBlock() + // Bounty will be funded in this block + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + await client.dev.newBlock() + + // verify the status is Funded + const bountyStatusAfterFunding = await getBounty(client, bountyIndex) + expect(bountyStatusAfterFunding.status.isFunded).toBe(true) + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // verify the status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) + + // Accept curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // verify the status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + // Award the bounty + await sendTransaction( + client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address).signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + // verify the BountyAwarded event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyAwarded' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty awarded events') + + // verify the status is PendingPayout + const bountyStatusAfterAwarding = await getBounty(client, bountyIndex) + expect(bountyStatusAfterAwarding.status.isPendingPayout).toBe(true) + + // Get curator reserved balance before unassign + const curatorBalanceBefore = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() + + // Unassign curator by Treasurer + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify CuratorUnassigned event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorUnassigned' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator unassigned pending payout events') + + // verify the curator slash event as the unassignCurator is called by the treasurer + await checkSystemEvents(client, { section: 'balances', method: 'Slashed' }) + .redact({ redactKeys: /who/ }) + .toMatchSnapshot('curator slash event') + + // verify that the slashed amout is deposited to the treasury + await checkSystemEvents(client, { section: 'treasury', method: 'Deposit' }) + .redact({ redactKeys: /data/ }) + .toMatchSnapshot('Bounty bond is deposited to the treasury') + + // Verify bounty status changed to Funded + const bountyAfterUnassign = await getBounty(client, bountyIndex) + expect(bountyAfterUnassign.status.isFunded).toBe(true) + + // Verify curator reserved balance was slashed + const curatorBalanceAfter = await client.api.query.system.account(devAccounts.bob.address) + const curatorReservedBalanceAfter = curatorBalanceAfter.data.reserved.toBigInt() + expect(curatorReservedBalanceBefore).toBeGreaterThan(curatorReservedBalanceAfter) + + await client.teardown() +} + /// ------- /// Test Suite /// ------- @@ -1704,6 +1868,11 @@ export function baseBountiesE2ETests< label: 'Unassign curator in Active state by Treasurer', testFn: async () => await unassignCuratorActiveByTreasurerTest(chain), }, + { + kind: 'test', + label: 'Unassign curator in PendingPayout state', + testFn: async () => await unassignCuratorPendingPayoutTest(chain), + }, ], } } From 4dff492072ceacc56d08ea25433d2d56056cd322 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 16 Sep 2025 23:08:23 +0530 Subject: [PATCH 29/66] refac: unassign curates tests are grouped --- packages/shared/src/bounties.ts | 76 ++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 55b1e2516..6c44a01e3 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1785,6 +1785,56 @@ export async function unassignCuratorPendingPayoutTest< /// Test Suite /// ------- +/** + * All curator unassign tests + * @param chain + * @returns RootTestTree + */ +export function allCuratorUnassignTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'All curator unassign tests', + children: [ + { + kind: 'test', + label: 'Unassign curator in ApprovedWithCurator state', + testFn: async () => await unassignCuratorApprovedWithCuratorTest(chain), + }, + { + kind: 'test', + label: 'Unassign curator in CuratorProposed state', + testFn: async () => await unassignCuratorCuratorProposedTest(chain), + }, + { + kind: 'test', + label: 'Unassign curator in Active state by curator themselves', + testFn: async () => await unassignCuratorActiveByCuratorTest(chain), + }, + { + kind: 'test', + label: 'Unassign curator in Active state by Treasurer', + testFn: async () => await unassignCuratorActiveByTreasurerTest(chain), + }, + { + kind: 'test', + label: 'Unassign curator in PendingPayout state', + testFn: async () => await unassignCuratorPendingPayoutTest(chain), + }, + ], + } as RootTestTree +} + +/** + * Base set of bounty end-to-end tests. + * + * Includes both success and failure cases. + * A test tree structure allows some extensibility in case a chain needs to + * change/add/remove default tests. + */ + export function baseBountiesE2ETests< TCustom extends Record | undefined, TInitStorages extends Record> | undefined, @@ -1848,31 +1898,7 @@ export function baseBountiesE2ETests< label: 'Bounty closure in active state', testFn: async () => await bountyClosureActiveTest(chain), }, - { - kind: 'test', - label: 'Unassign curator in ApprovedWithCurator state', - testFn: async () => await unassignCuratorApprovedWithCuratorTest(chain), - }, - { - kind: 'test', - label: 'Unassign curator in CuratorProposed state', - testFn: async () => await unassignCuratorCuratorProposedTest(chain), - }, - { - kind: 'test', - label: 'Unassign curator in Active state by curator themselves', - testFn: async () => await unassignCuratorActiveByCuratorTest(chain), - }, - { - kind: 'test', - label: 'Unassign curator in Active state by Treasurer', - testFn: async () => await unassignCuratorActiveByTreasurerTest(chain), - }, - { - kind: 'test', - label: 'Unassign curator in PendingPayout state', - testFn: async () => await unassignCuratorPendingPayoutTest(chain), - }, + allCuratorUnassignTests(chain), ], } } From 4284aa9ec11e5641507dab693b148dc454978053 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 16 Sep 2025 23:10:51 +0530 Subject: [PATCH 30/66] refac: bounty clousure tests are grouped together --- packages/shared/src/bounties.ts | 48 ++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 6c44a01e3..0146184a7 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1785,6 +1785,38 @@ export async function unassignCuratorPendingPayoutTest< /// Test Suite /// ------- +/** + * Bounty Closure Tests + * @param chain + * @returns RootTestTree + */ +export function bountyClosureTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'Bounty Closure Tests', + children: [ + { + kind: 'test', + label: 'Bounty closure in proposed state', + testFn: async () => await bountyClosureProposedTest(chain), + }, + { + kind: 'test', + label: 'Bounty closure in funded state', + testFn: async () => await bountyClosureFundedTest(chain), + }, + { + kind: 'test', + label: 'Bounty closure in active state', + testFn: async () => await bountyClosureActiveTest(chain), + }, + ], + } as RootTestTree +} + /** * All curator unassign tests * @param chain @@ -1883,21 +1915,7 @@ export function baseBountiesE2ETests< label: 'Bounty awarding and claiming', testFn: async () => await bountyAwardingAndClaimingTest(chain), }, - { - kind: 'test', - label: 'Bounty closure in proposed state', - testFn: async () => await bountyClosureProposedTest(chain), - }, - { - kind: 'test', - label: 'Bounty closure in funded state', - testFn: async () => await bountyClosureFundedTest(chain), - }, - { - kind: 'test', - label: 'Bounty closure in active state', - testFn: async () => await bountyClosureActiveTest(chain), - }, + bountyClosureTests(chain), allCuratorUnassignTests(chain), ], } From 8f25c6849cb4ae6bafcf26268d698d891a416fbb Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Thu, 18 Sep 2025 19:27:28 +0530 Subject: [PATCH 31/66] debug logs removed --- packages/shared/src/bounties.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 0146184a7..77ec6b545 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1141,7 +1141,6 @@ export async function bountyClosureActiveTest< // Get curator reserved balance before closure const curatorBalanceBeforeClosure = await client.api.query.system.account(devAccounts.bob.address) const curatorReservedBalanceBeforeClosure = curatorBalanceBeforeClosure.data.reserved.toBigInt() - console.log('Curator reserved balance before:', curatorReservedBalanceBeforeClosure) // Close the bounty await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { @@ -1588,8 +1587,6 @@ export async function unassignCuratorActiveByTreasurerTest< await client.dev.newBlock() - await logAllEvents(client) - // Verify CuratorUnassigned event await checkSystemEvents(client, { section: 'bounties', method: 'CuratorUnassigned' }) .redact({ redactKeys: /bountyId/ }) From cbb429154b8dc1f0218063a6fe953faffb31e633 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 13:49:19 +0530 Subject: [PATCH 32/66] removed unused functions --- packages/shared/src/bounties.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 77ec6b545..c93f50841 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -87,23 +87,6 @@ async function getBountyEvents(client: any): Promise { return events.filter((record) => record.event.section === 'bounties') } -/** - * Log the bounties events - */ -async function logBountyEvents(client: any) { - const events = await getBountyEvents(client) - events.forEach((evt: any, idx: number) => { - console.log(`Event #${idx}:`, evt.event?.toHuman?.() ?? evt.event) - }) -} - -async function logAllEvents(client: any) { - const events = await client.api.query.system.events() - events.forEach((evt: any, idx: number) => { - console.log(`Event #${idx}:`, evt.event?.toHuman?.() ?? evt.event) - }) -} - /// ------- /// Tests /// ------- From 60e0cec386af843b60fbb0dbb2fa9b0e0ae4f7ae Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 13:50:01 +0530 Subject: [PATCH 33/66] polkadot snaps added --- .../polkadot.bounties.e2e.test.ts.snap | 771 ++++++++++++++++++ 1 file changed, 771 insertions(+) create mode 100644 packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap diff --git a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap new file mode 100644 index 000000000..82ec4429a --- /dev/null +++ b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap @@ -0,0 +1,771 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > Bounty bond is deposited to the treasury 1`] = ` +[ + { + "data": "(redacted)", + "method": "Deposit", + "section": "treasury", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator slash event 1`] = ` +[ + { + "data": { + "amount": 500000000000, + "who": "(redacted)", + }, + "method": "Slashed", + "section": "balances", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator unassigned active by treasurer events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator unassigned active by curator events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in ApprovedWithCurator state > curator unassigned approved with curator events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > curator unassigned curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > Bounty bond is deposited to the treasury 1`] = ` +[ + { + "data": "(redacted)", + "method": "Deposit", + "section": "treasury", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty awarded events 1`] = ` +[ + { + "data": { + "beneficiary": "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", + "index": "(redacted)", + }, + "method": "BountyAwarded", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator slash event 1`] = ` +[ + { + "data": { + "amount": 500000000000, + "who": "(redacted)", + }, + "method": "Slashed", + "section": "balances", + }, +] +`; + +exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator unassigned pending payout events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > Bounty value is transferred to the treasury 1`] = ` +[ + { + "data": { + "amount": 10000000000000, + "from": "(redacted)", + "to": "(redacted)", + }, + "method": "Transfer", + "section": "balances", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyCanceled", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyCanceled", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` +[ + { + "data": { + "amount": 10000000000000, + "from": "(redacted)", + "to": "(redacted)", + }, + "method": "Transfer", + "section": "balances", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in proposed state > bounty rejected events 1`] = ` +[ + { + "data": { + "bond": "(rounded 14000000000)", + "index": "(redacted)", + }, + "method": "BountyRejected", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in proposed state > proposer bond slashed event 1`] = ` +[ + { + "data": { + "amount": "(rounded 14000000000)", + "who": "(redacted)", + }, + "method": "Slashed", + "section": "balances", + }, +] +`; + +exports[`Polkadot Bounties > Bounty approval flow > bounty approval events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty approval flow with curator > bounty approval with curator events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty approval flow with curator > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > bounty awarded events 1`] = ` +[ + { + "data": { + "beneficiary": "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", + "index": "(redacted)", + }, + "method": "BountyAwarded", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > bounty claimed events 1`] = ` +[ + { + "data": { + "beneficiary": "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", + "index": "(redacted)", + "payout": 9000000000000, + }, + "method": "BountyClaimed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty awarding and claiming > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty extension > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty extension > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Bounty extension > bounty extended events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyExtended", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty extension > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty extension > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty extension > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Creating a bounty > bounty proposal events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Curator assignment and acceptance > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Curator assignment and acceptance > bounty became active events 1`] = `[]`; + +exports[`Polkadot Bounties > Curator assignment and acceptance > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Curator assignment and acceptance > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > Curator assignment and acceptance > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; From 290a044dcde96fae41f58ac0c404af23aed7fafd Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 17:24:27 +0530 Subject: [PATCH 34/66] kusama snapshot added --- .../kusama.bounties.e2e.test.ts.snap | 771 ++++++++++++++++++ 1 file changed, 771 insertions(+) create mode 100644 packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap diff --git a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap new file mode 100644 index 000000000..e10e6d691 --- /dev/null +++ b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap @@ -0,0 +1,771 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > Bounty bond is deposited to the treasury 1`] = ` +[ + { + "data": "(redacted)", + "method": "Deposit", + "section": "treasury", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator slash event 1`] = ` +[ + { + "data": { + "amount": "(rounded 17000000000)", + "who": "(redacted)", + }, + "method": "Slashed", + "section": "balances", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator unassigned active by treasurer events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator unassigned active by curator events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in ApprovedWithCurator state > curator unassigned approved with curator events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > curator unassigned curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > Bounty bond is deposited to the treasury 1`] = ` +[ + { + "data": "(redacted)", + "method": "Deposit", + "section": "treasury", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty awarded events 1`] = ` +[ + { + "data": { + "beneficiary": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "index": "(redacted)", + }, + "method": "BountyAwarded", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator slash event 1`] = ` +[ + { + "data": { + "amount": "(rounded 17000000000)", + "who": "(redacted)", + }, + "method": "Slashed", + "section": "balances", + }, +] +`; + +exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator unassigned pending payout events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + }, + "method": "CuratorUnassigned", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > Bounty value is transferred to the treasury 1`] = ` +[ + { + "data": { + "amount": "(rounded 330000000000)", + "from": "(redacted)", + "to": "(redacted)", + }, + "method": "Transfer", + "section": "balances", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyCanceled", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyCanceled", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` +[ + { + "data": { + "amount": "(rounded 330000000000)", + "from": "(redacted)", + "to": "(redacted)", + }, + "method": "Transfer", + "section": "balances", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in proposed state > bounty rejected events 1`] = ` +[ + { + "data": { + "bond": "(rounded 35000000000)", + "index": "(redacted)", + }, + "method": "BountyRejected", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in proposed state > proposer bond slashed event 1`] = ` +[ + { + "data": { + "amount": "(rounded 35000000000)", + "who": "(redacted)", + }, + "method": "Slashed", + "section": "balances", + }, +] +`; + +exports[`Kusama Bounties > Bounty approval flow > bounty approval events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty approval flow with curator > bounty approval with curator events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty approval flow with curator > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty awarding and claiming > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty awarding and claiming > bounty awarded events 1`] = ` +[ + { + "data": { + "beneficiary": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "index": "(redacted)", + }, + "method": "BountyAwarded", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty awarding and claiming > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Bounty awarding and claiming > bounty claimed events 1`] = ` +[ + { + "data": { + "beneficiary": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "index": "(redacted)", + "payout": "(rounded 300000000000)", + }, + "method": "BountyClaimed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty awarding and claiming > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty awarding and claiming > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty awarding and claiming > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty extension > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty extension > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Bounty extension > bounty extended events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyExtended", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty extension > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty extension > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty extension > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Creating a bounty > bounty proposal events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Curator assignment and acceptance > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Curator assignment and acceptance > bounty became active events 1`] = `[]`; + +exports[`Kusama Bounties > Curator assignment and acceptance > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Curator assignment and acceptance > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > Curator assignment and acceptance > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; From 78b145d81fa36faffeaad05f5c706c47cd73bee7 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 18:19:52 +0530 Subject: [PATCH 35/66] failure test: close bounty in approved status emits UnexpectedStatus error --- packages/shared/src/bounties.ts | 101 +++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index c93f50841..893839f0b 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -3,7 +3,7 @@ import { sendTransaction } from '@acala-network/chopsticks-testing' import { type Chain, defaultAccountsSr25519 as devAccounts } from '@e2e-test/networks' import { setupNetworks } from '@e2e-test/shared' -import { expect } from 'vitest' +import { assert, expect } from 'vitest' import { checkEvents, checkSystemEvents, scheduleInlineCallWithOrigin } from './helpers/index.js' import type { RootTestTree } from './types.js' @@ -1839,6 +1839,104 @@ export function allCuratorUnassignTests< } as RootTestTree } +/** + * Test: Bounty closure in Approved state (should fail) + * + * Verifies: + * - Bounty closure fails with UnexpectedStatus when in Approved state (GeneralAdmin cannot close approved bounties) + * - Bounty remains in storage + */ +export async function bountyClosureApprovedTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const description = 'Test bounty for closure in approved state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // Verify bounty is in Approved state + const approvedBounty = await getBounty(client, bountyIndex) + expect(approvedBounty.status.isApproved).toBe(true) + + // Try to close the bounty - should fail + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await checkSystemEvents(client, { section: 'scheduler', method: 'Dispatched' }) + .redact({ redactKeys: /task/ }) + .toMatchSnapshot('scheduler events when closing bounty with approved state fails') + + // check he result of dispatched event + const events = await client.api.query.system.events() + + // Find the Dispatched event from scheduler + const dispatchedEvent = events.find((record) => { + const { event } = record + return event.section === 'scheduler' && event.method === 'Dispatched' + }) + + assert(dispatchedEvent) + assert(client.api.events.scheduler.Dispatched.is(dispatchedEvent.event)) + + const dispatchedData = dispatchedEvent.event.data + expect(dispatchedData.result.isErr).toBe(true) + + // Decode the module error to get human-readable details + const dispatchError = dispatchedData.result.asErr + assert(dispatchError.isModule) + expect(client.api.errors.bounties.UnexpectedStatus.is(dispatchError.asModule)).toBeTruthy() + + // Verify bounty is still in storage and still Approved + const bountyAfterFailedClosure = await getBounty(client, bountyIndex) + expect(bountyAfterFailedClosure).toBeDefined() + expect(bountyAfterFailedClosure.status.isApproved).toBe(true) + + await client.teardown() +} + +/** + * All the failure cases for bounty + * + * @param chain + * @returns RootTestTree + */ +export function allBountyFailureTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'All bounty failure tests', + children: [ + { + kind: 'test', + label: 'Bounty closure in approved state', + testFn: async () => await bountyClosureApprovedTest(chain), + }, + ], + } as RootTestTree +} + /** * Base set of bounty end-to-end tests. * @@ -1897,6 +1995,7 @@ export function baseBountiesE2ETests< }, bountyClosureTests(chain), allCuratorUnassignTests(chain), + allBountyFailureTests(chain), ], } } From 34c295ae24b0f3842564ef0abe4e3a40828259c9 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 18:20:49 +0530 Subject: [PATCH 36/66] removed get all bounty events --- packages/shared/src/bounties.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 893839f0b..cdad15015 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -79,14 +79,6 @@ async function getBountyIndexFromEvent(client: any): Promise { return (bountyProposedEvent.event.data as any).index.toNumber() } -/** - * Get bounties events from the system events - */ -async function getBountyEvents(client: any): Promise { - const events = await client.api.query.system.events() - return events.filter((record) => record.event.section === 'bounties') -} - /// ------- /// Tests /// ------- From c9dbc24b0443ea938ac5fdd959db8823bafbef03 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 18:27:13 +0530 Subject: [PATCH 37/66] failure test: added bountyClosure in PendingPayoutTest emits PendingPayout Error --- packages/shared/src/bounties.ts | 113 ++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index cdad15015..760e493ae 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1906,6 +1906,114 @@ export async function bountyClosureApprovedTest< await client.teardown() } +/** + * Test: Bounty closure in PendingPayout state (should fail) + * + * Verifies: + * - Bounty closure fails with PendingPayout error when in PendingPayout state (GeneralAdmin must unassign curator first) + * - Bounty remains in storage + */ +export async function bountyClosurePendingPayoutTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping bounty closure pending payout test') + return + } + + // Move to spend period + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for closure in pending payout state' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // Approve the bounty + const bountyIndex = await getBountyIndexFromEvent(client) + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await client.dev.newBlock() + // Bounty will be funded in this block + await client.dev.newBlock() + + // Propose a curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { Origins: 'Treasurer' }, + ) + + await client.dev.newBlock() + + // Accept curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // Award the bounty + await sendTransaction( + client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address).signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + // Verify bounty is in PendingPayout state + const pendingPayoutBounty = await getBounty(client, bountyIndex) + expect(pendingPayoutBounty.status.isPendingPayout).toBe(true) + + // Try to close the bounty - should fail + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await checkSystemEvents(client, { section: 'scheduler', method: 'Dispatched' }) + .redact({ redactKeys: /task/ }) + .toMatchSnapshot('scheduler events when closing bounty with pending payout fails') + + const events = await client.api.query.system.events() + + const dispatchedEvent = events.find((record) => { + const { event } = record + return event.section === 'scheduler' && event.method === 'Dispatched' + }) + + assert(dispatchedEvent) + assert(client.api.events.scheduler.Dispatched.is(dispatchedEvent.event)) + + const dispatchedData = dispatchedEvent.event.data + expect(dispatchedData.result.isErr).toBe(true) + + const dispatchError = dispatchedData.result.asErr + assert(dispatchError.isModule) + expect(client.api.errors.bounties.PendingPayout.is(dispatchError.asModule)).toBeTruthy() + + // Verify bounty is still in storage and still PendingPayout + const bountyAfterFailedClosure = await getBounty(client, bountyIndex) + expect(bountyAfterFailedClosure).toBeDefined() + expect(bountyAfterFailedClosure.status.isPendingPayout).toBe(true) + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -1925,6 +2033,11 @@ export function allBountyFailureTests< label: 'Bounty closure in approved state', testFn: async () => await bountyClosureApprovedTest(chain), }, + { + kind: 'test', + label: 'Bounty closure in pending payout state', + testFn: async () => await bountyClosurePendingPayoutTest(chain), + }, ], } as RootTestTree } From d10c4cda3157ec77617aa595eb465f26cacf2e49 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 18:49:23 +0530 Subject: [PATCH 38/66] failure test: added unassignCuratorActiveStateByPublicPrematureTest emits Premature Error --- packages/shared/src/bounties.ts | 197 ++++++++++++++++++++++++-------- 1 file changed, 148 insertions(+), 49 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 760e493ae..3b906329c 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2014,6 +2014,100 @@ export async function bountyClosurePendingPayoutTest< await client.teardown() } +/** + * Test that unassigning curator in Active state by public fails with `Premature`. + * + * 1. Alice proposes a bounty, it gets approved, curator is proposed and accepted + * 2. Public user attempts to unassign curator immediately (before proper timing) + * 3. Verify that the transaction fails with the appropriate error + */ +async function unassignCuratorActiveStateByPublicPrematureTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + // move to spend period + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping unassign curator active state by public premature test') + return + } + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const curatorFee = existentialDeposit.toBigInt() * 100n + const description = 'Test bounty for premature unassign curator by public' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // Approve the bounty + const bountyIndex = await getBountyIndexFromEvent(client) + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await client.dev.newBlock() + // Bounty will be funded in this block + await client.dev.newBlock() + + // Propose Bob as curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // Bob accepts curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // Verify bounty is in Active state + const bountyStatus = await getBounty(client, bountyIndex) + expect(bountyStatus.status.isActive).toBe(true) + + // Charlie (public user) tries to unassign curator immediately (premature) + // Using scheduleInlineCallWithOrigin to simulate public call + await sendTransaction(client.api.tx.bounties.unassignCurator(bountyIndex).signAsync(devAccounts.charlie)) + + await client.dev.newBlock() + + // Check the result of dispatched event + const events = await client.api.query.system.events() + + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'system' && event.method === 'ExtrinsicFailed' + }) + + assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) + const dispatchError = ev.event.data.dispatchError + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.Premature.is(dispatchError.asModule)).toBeTruthy() + + // Verify bounty is still in storage and still Active + const bountyAfterFailedUnassign = await getBounty(client, bountyIndex) + expect(bountyAfterFailedUnassign).toBeDefined() + expect(bountyAfterFailedUnassign.status.isActive).toBe(true) + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2028,15 +2122,20 @@ export function allBountyFailureTests< kind: 'describe', label: 'All bounty failure tests', children: [ + // { + // kind: 'test', + // label: 'Bounty closure in approved state', + // testFn: async () => await bountyClosureApprovedTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty closure in pending payout state', + // testFn: async () => await bountyClosurePendingPayoutTest(chain), + // }, { kind: 'test', - label: 'Bounty closure in approved state', - testFn: async () => await bountyClosureApprovedTest(chain), - }, - { - kind: 'test', - label: 'Bounty closure in pending payout state', - testFn: async () => await bountyClosurePendingPayoutTest(chain), + label: 'Unassign curator in active state by public premature', + testFn: async () => await unassignCuratorActiveStateByPublicPrematureTest(chain), }, ], } as RootTestTree @@ -2058,48 +2157,48 @@ export function baseBountiesE2ETests< kind: 'describe', label: testConfig.testSuiteName, children: [ - { - kind: 'test', - label: 'Creating a bounty', - testFn: async () => await bountyCreationTest(chain), - }, - { - kind: 'test', - label: 'Bounty approval flow', - testFn: async () => await bountyApprovalTest(chain), - }, - { - kind: 'test', - label: 'Bounty approval flow with curator', - testFn: async () => await bountyApprovalWithCuratorTest(chain), - }, - { - kind: 'test', - label: 'Bounty funding for Approved Bounties', - testFn: async () => await bountyFundingTest(chain), - }, - { - kind: 'test', - label: 'Bounty funding for ApprovedWithCurator Bounties', - testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), - }, - { - kind: 'test', - label: 'Curator assignment and acceptance', - testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), - }, - { - kind: 'test', - label: 'Bounty extension', - testFn: async () => await bountyExtensionTest(chain), - }, - { - kind: 'test', - label: 'Bounty awarding and claiming', - testFn: async () => await bountyAwardingAndClaimingTest(chain), - }, - bountyClosureTests(chain), - allCuratorUnassignTests(chain), + // { + // kind: 'test', + // label: 'Creating a bounty', + // testFn: async () => await bountyCreationTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty approval flow', + // testFn: async () => await bountyApprovalTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty approval flow with curator', + // testFn: async () => await bountyApprovalWithCuratorTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty funding for Approved Bounties', + // testFn: async () => await bountyFundingTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty funding for ApprovedWithCurator Bounties', + // testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), + // }, + // { + // kind: 'test', + // label: 'Curator assignment and acceptance', + // testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty extension', + // testFn: async () => await bountyExtensionTest(chain), + // }, + // { + // kind: 'test', + // label: 'Bounty awarding and claiming', + // testFn: async () => await bountyAwardingAndClaimingTest(chain), + // }, + // bountyClosureTests(chain), + // allCuratorUnassignTests(chain), allBountyFailureTests(chain), ], } From c39685627f9521928eddd3f8d98bc93e26dafee0 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 18:52:43 +0530 Subject: [PATCH 39/66] failure test: reasonTooBigTest added --- packages/shared/src/bounties.ts | 53 +++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 3b906329c..4c9c7888b 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2108,6 +2108,50 @@ async function unassignCuratorActiveStateByPublicPrematureTest< await client.teardown() } +/** + * Test that proposing a bounty with description too long fails with `ReasonTooBig`. + * + * 1. Alice attempts to propose a bounty with a description that exceeds the maximum length + * 2. Verify that the transaction fails with the appropriate error + */ +async function reasonTooBigTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const maxReasonLength = client.api.consts.bounties.maximumReasonLength.toNumber() + + // Create a description that exceeds the maximum length + const longDescription = 'x'.repeat(maxReasonLength + 1000) + + const proposeTx = client.api.tx.bounties.proposeBounty(bountyValue, longDescription) + + await sendTransaction(proposeTx.signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // Check for ExtrinsicFailed event + const events = await client.api.query.system.events() + + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'system' && event.method === 'ExtrinsicFailed' + }) + + assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) + const dispatchError = ev.event.data.dispatchError + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.ReasonTooBig.is(dispatchError.asModule)).toBeTruthy() + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2132,10 +2176,15 @@ export function allBountyFailureTests< // label: 'Bounty closure in pending payout state', // testFn: async () => await bountyClosurePendingPayoutTest(chain), // }, + // { + // kind: 'test', + // label: 'Unassign curator in active state by public premature', + // testFn: async () => await unassignCuratorActiveStateByPublicPrematureTest(chain), + // }, { kind: 'test', - label: 'Unassign curator in active state by public premature', - testFn: async () => await unassignCuratorActiveStateByPublicPrematureTest(chain), + label: 'Reason too big', + testFn: async () => await reasonTooBigTest(chain), }, ], } as RootTestTree From f32a1abc311c3b3468ae0a5d6661a1dc019e88b3 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 18:57:25 +0530 Subject: [PATCH 40/66] failure test: invalidValueTest --- packages/shared/src/bounties.ts | 53 +++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 4c9c7888b..9de7769bb 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2152,6 +2152,50 @@ async function reasonTooBigTest< await client.teardown() } +/** + * Test that proposing a bounty with value below minimum fails with `InvalidValue`. + * + * 1. Alice attempts to propose a bounty with value below the minimum required + * 2. Verify that the transaction fails with the appropriate error + */ +async function invalidValueTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const bountyValueMinimum = client.api.consts.bounties.bountyValueMinimum.toBigInt() + const description = 'Test bounty with invalid value' + + // Use a value below the minimum + const existentialDeposit = client.api.consts.balances.existentialDeposit + const invalidValue = bountyValueMinimum - existentialDeposit.toBigInt() + + const proposeTx = client.api.tx.bounties.proposeBounty(invalidValue, description) + + await sendTransaction(proposeTx.signAsync(devAccounts.alice)) + + await client.dev.newBlock() + + // Check for ExtrinsicFailed event + const events = await client.api.query.system.events() + + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'system' && event.method === 'ExtrinsicFailed' + }) + + assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) + const dispatchError = ev.event.data.dispatchError + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.InvalidValue.is(dispatchError.asModule)).toBeTruthy() + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2181,10 +2225,15 @@ export function allBountyFailureTests< // label: 'Unassign curator in active state by public premature', // testFn: async () => await unassignCuratorActiveStateByPublicPrematureTest(chain), // }, + // { + // kind: 'test', + // label: 'Reason too big', + // testFn: async () => await reasonTooBigTest(chain), + // }, { kind: 'test', - label: 'Reason too big', - testFn: async () => await reasonTooBigTest(chain), + label: 'Invalid value', + testFn: async () => await invalidValueTest(chain), }, ], } as RootTestTree From 92873dd86de9f26a3e9e0d5929c3132d51d67e53 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 19:26:01 +0530 Subject: [PATCH 41/66] failure test: invalidIndexApprovalTest added --- packages/shared/src/bounties.ts | 53 +++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 9de7769bb..f1bd39286 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2196,6 +2196,50 @@ async function invalidValueTest< await client.teardown() } +/** + * Test that approving a non-existent bounty fails with `InvalidIndex`. + * + * 1. Treasurer attempts to approve a bounty that doesn't exist + * 2. Verify that the transaction fails with the appropriate error + */ +async function invalidIndexApprovalTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + const nonExistentBountyIndex = 999 + + await setupTestAccounts(client, ['alice']) + + // approve transaction with origin treasurer + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.approveBounty(nonExistentBountyIndex).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // Check for scheduler Dispatched event + const events = await client.api.query.system.events() + + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'scheduler' && event.method === 'Dispatched' + }) + + assert(client.api.events.scheduler.Dispatched.is(ev.event)) + const dispatchError = ev.event.data.result.asErr + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.InvalidIndex.is(dispatchError.asModule)).toBeTruthy() + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2230,10 +2274,15 @@ export function allBountyFailureTests< // label: 'Reason too big', // testFn: async () => await reasonTooBigTest(chain), // }, + // { + // kind: 'test', + // label: 'Invalid value', + // testFn: async () => await invalidValueTest(chain), + // }, { kind: 'test', - label: 'Invalid value', - testFn: async () => await invalidValueTest(chain), + label: 'Invalid bounty index approval', + testFn: async () => await invalidIndexApprovalTest(chain), }, ], } as RootTestTree From 166deaac73b2103ed7cb993a94870120f36a9f10 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 19:37:33 +0530 Subject: [PATCH 42/66] failure test: unexpectedStatusProposeCuratorTest proposing curator before bounty is funded --- packages/shared/src/bounties.ts | 62 +++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index f1bd39286..8ad6b90c5 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2240,6 +2240,59 @@ async function invalidIndexApprovalTest< await client.teardown() } +/** + * Test that proposing a curator for a non-funded bounty fails with `UnexpectedStatus`. + * + * 1. Alice proposes a bounty + * 2. Treasurer attempts to propose a curator before the bounty is funded + * 3. Verify that the transaction fails with the appropriate error + */ +async function unexpectedStatusProposeCuratorTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const description = 'Test bounty for curator proposal' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // propose curator by Treasurer + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, 1000n).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // Check for scheduler Dispatched event + const events = await client.api.query.system.events() + + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'scheduler' && event.method === 'Dispatched' + }) + + assert(client.api.events.scheduler.Dispatched.is(ev.event)) + const dispatchError = ev.event.data.result.asErr + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.UnexpectedStatus.is(dispatchError.asModule)).toBeTruthy() + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2279,10 +2332,15 @@ export function allBountyFailureTests< // label: 'Invalid value', // testFn: async () => await invalidValueTest(chain), // }, + // { + // kind: 'test', + // label: 'Invalid bounty index approval', + // testFn: async () => await invalidIndexApprovalTest(chain), + // }, { kind: 'test', - label: 'Invalid bounty index approval', - testFn: async () => await invalidIndexApprovalTest(chain), + label: 'Unexpected status when proposing curator before bounty is funded', + testFn: async () => await unexpectedStatusProposeCuratorTest(chain), }, ], } as RootTestTree From 7615e6f012b10fcbd08959f1752d42b03b7227d4 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 20:17:05 +0530 Subject: [PATCH 43/66] failure test: requireCuratorAcceptTest i.e Non-curator trying to accept curator role --- packages/shared/src/bounties.ts | 89 ++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 8ad6b90c5..608e4e480 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2293,6 +2293,86 @@ async function unexpectedStatusProposeCuratorTest< await client.teardown() } +/** + * Test that a non-curator trying to accept curator role fails with `RequireCurator`. + * + * 1. Alice proposes a bounty and treasurer proposes Bob as curator + * 2. Charlie attempts to accept the curator role (should be Bob) + * 3. Verify that the transaction fails with the appropriate error + */ +async function requireCuratorAcceptTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + // move client head to the last spend period block + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping curator assignment test') + return + } + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const description = 'Test bounty for curator requirement' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await client.dev.newBlock() + // Bounty will be funded in this block + await client.dev.newBlock() + + // Propose Bob as curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, 1000n).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // Charlie tries to accept curator role (should be Bob) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.charlie)) + + await client.dev.newBlock() + + // Check for ExtrinsicFailed event + const events = await client.api.query.system.events() + + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'system' && event.method === 'ExtrinsicFailed' + }) + + assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) + const dispatchError = ev.event.data.dispatchError + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.RequireCurator.is(dispatchError.asModule)).toBeTruthy() + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2337,10 +2417,15 @@ export function allBountyFailureTests< // label: 'Invalid bounty index approval', // testFn: async () => await invalidIndexApprovalTest(chain), // }, + // { + // kind: 'test', + // label: 'Unexpected status when proposing curator before bounty is funded', + // testFn: async () => await unexpectedStatusProposeCuratorTest(chain), + // }, { kind: 'test', - label: 'Unexpected status when proposing curator before bounty is funded', - testFn: async () => await unexpectedStatusProposeCuratorTest(chain), + label: 'Non-curator trying to accept curator role', + testFn: async () => await requireCuratorAcceptTest(chain), }, ], } as RootTestTree From f23a752ac8abc279440fccbd88a3676ac58818a0 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 20:40:25 +0530 Subject: [PATCH 44/66] fix: typecasting removed from getBountyIndexFromEvent --- packages/shared/src/bounties.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 608e4e480..b6f4d693d 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -76,7 +76,8 @@ async function getBountyIndexFromEvent(client: any): Promise { ({ event }: any) => event.section === 'bounties' && event.method === 'BountyProposed', ) expect(bountyProposedEvent).toBeDefined() - return (bountyProposedEvent.event.data as any).index.toNumber() + assert(client.api.events.bounties.BountyProposed.is(bountyProposedEvent.event)) + return bountyProposedEvent.event.data.index.toNumber() } /// ------- From bace3c8a6b5711a08e01fd72d93b7ca09dd1b3ee Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:02:01 +0530 Subject: [PATCH 45/66] refac --- packages/shared/src/bounties.ts | 154 ++++++++++++++++---------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index b6f4d693d..5b71b625a 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2388,41 +2388,41 @@ export function allBountyFailureTests< kind: 'describe', label: 'All bounty failure tests', children: [ - // { - // kind: 'test', - // label: 'Bounty closure in approved state', - // testFn: async () => await bountyClosureApprovedTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty closure in pending payout state', - // testFn: async () => await bountyClosurePendingPayoutTest(chain), - // }, - // { - // kind: 'test', - // label: 'Unassign curator in active state by public premature', - // testFn: async () => await unassignCuratorActiveStateByPublicPrematureTest(chain), - // }, - // { - // kind: 'test', - // label: 'Reason too big', - // testFn: async () => await reasonTooBigTest(chain), - // }, - // { - // kind: 'test', - // label: 'Invalid value', - // testFn: async () => await invalidValueTest(chain), - // }, - // { - // kind: 'test', - // label: 'Invalid bounty index approval', - // testFn: async () => await invalidIndexApprovalTest(chain), - // }, - // { - // kind: 'test', - // label: 'Unexpected status when proposing curator before bounty is funded', - // testFn: async () => await unexpectedStatusProposeCuratorTest(chain), - // }, + { + kind: 'test', + label: 'Bounty closure in approved state', + testFn: async () => await bountyClosureApprovedTest(chain), + }, + { + kind: 'test', + label: 'Bounty closure in pending payout state', + testFn: async () => await bountyClosurePendingPayoutTest(chain), + }, + { + kind: 'test', + label: 'Unassign curator in active state by public premature', + testFn: async () => await unassignCuratorActiveStateByPublicPrematureTest(chain), + }, + { + kind: 'test', + label: 'Reason too big', + testFn: async () => await reasonTooBigTest(chain), + }, + { + kind: 'test', + label: 'Invalid value', + testFn: async () => await invalidValueTest(chain), + }, + { + kind: 'test', + label: 'Invalid bounty index approval', + testFn: async () => await invalidIndexApprovalTest(chain), + }, + { + kind: 'test', + label: 'Unexpected status when proposing curator before bounty is funded', + testFn: async () => await unexpectedStatusProposeCuratorTest(chain), + }, { kind: 'test', label: 'Non-curator trying to accept curator role', @@ -2448,48 +2448,48 @@ export function baseBountiesE2ETests< kind: 'describe', label: testConfig.testSuiteName, children: [ - // { - // kind: 'test', - // label: 'Creating a bounty', - // testFn: async () => await bountyCreationTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty approval flow', - // testFn: async () => await bountyApprovalTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty approval flow with curator', - // testFn: async () => await bountyApprovalWithCuratorTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty funding for Approved Bounties', - // testFn: async () => await bountyFundingTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty funding for ApprovedWithCurator Bounties', - // testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), - // }, - // { - // kind: 'test', - // label: 'Curator assignment and acceptance', - // testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty extension', - // testFn: async () => await bountyExtensionTest(chain), - // }, - // { - // kind: 'test', - // label: 'Bounty awarding and claiming', - // testFn: async () => await bountyAwardingAndClaimingTest(chain), - // }, - // bountyClosureTests(chain), - // allCuratorUnassignTests(chain), + { + kind: 'test', + label: 'Creating a bounty', + testFn: async () => await bountyCreationTest(chain), + }, + { + kind: 'test', + label: 'Bounty approval flow', + testFn: async () => await bountyApprovalTest(chain), + }, + { + kind: 'test', + label: 'Bounty approval flow with curator', + testFn: async () => await bountyApprovalWithCuratorTest(chain), + }, + { + kind: 'test', + label: 'Bounty funding for Approved Bounties', + testFn: async () => await bountyFundingTest(chain), + }, + { + kind: 'test', + label: 'Bounty funding for ApprovedWithCurator Bounties', + testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), + }, + { + kind: 'test', + label: 'Curator assignment and acceptance', + testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + }, + { + kind: 'test', + label: 'Bounty extension', + testFn: async () => await bountyExtensionTest(chain), + }, + { + kind: 'test', + label: 'Bounty awarding and claiming', + testFn: async () => await bountyAwardingAndClaimingTest(chain), + }, + bountyClosureTests(chain), + allCuratorUnassignTests(chain), allBountyFailureTests(chain), ], } From c90ef96808c2451c54c9993b3f054b9252ceef64 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:04:53 +0530 Subject: [PATCH 46/66] refac: grouped bounty success tests --- packages/shared/src/bounties.ts | 35 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 5b71b625a..7431dfc62 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2433,20 +2433,19 @@ export function allBountyFailureTests< } /** - * Base set of bounty end-to-end tests. * - * Includes both success and failure cases. - * A test tree structure allows some extensibility in case a chain needs to - * change/add/remove default tests. + * All success cases for bounty + * + * @param chain + * @returns RootTestTree */ - -export function baseBountiesE2ETests< +export function allBountySuccessTests< TCustom extends Record | undefined, TInitStorages extends Record> | undefined, ->(chain: Chain, testConfig: { testSuiteName: string; addressEncoding: number }): RootTestTree { +>(chain: Chain): RootTestTree { return { kind: 'describe', - label: testConfig.testSuiteName, + label: 'All bounty success tests', children: [ { kind: 'test', @@ -2490,7 +2489,25 @@ export function baseBountiesE2ETests< }, bountyClosureTests(chain), allCuratorUnassignTests(chain), - allBountyFailureTests(chain), ], + } as RootTestTree +} + +/** + * Base set of bounty end-to-end tests. + * + * Includes both success and failure cases. + * A test tree structure allows some extensibility in case a chain needs to + * change/add/remove default tests. + */ + +export function baseBountiesE2ETests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain, testConfig: { testSuiteName: string; addressEncoding: number }): RootTestTree { + return { + kind: 'describe', + label: testConfig.testSuiteName, + children: [allBountyFailureTests(chain), allBountySuccessTests(chain)], } } From fc819c7576282e8bb88824e87d0e70bd92fa12bd Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:08:39 +0530 Subject: [PATCH 47/66] refac: grouped approval tests and funding tests --- packages/shared/src/bounties.ts | 57 +++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 7431dfc62..d13f65ec1 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2433,25 +2433,19 @@ export function allBountyFailureTests< } /** - * - * All success cases for bounty + * Bounty approval tests * * @param chain * @returns RootTestTree */ -export function allBountySuccessTests< +export function bountyApprovalTests< TCustom extends Record | undefined, TInitStorages extends Record> | undefined, >(chain: Chain): RootTestTree { return { kind: 'describe', - label: 'All bounty success tests', + label: 'Bounty approval tests', children: [ - { - kind: 'test', - label: 'Creating a bounty', - testFn: async () => await bountyCreationTest(chain), - }, { kind: 'test', label: 'Bounty approval flow', @@ -2462,6 +2456,25 @@ export function allBountySuccessTests< label: 'Bounty approval flow with curator', testFn: async () => await bountyApprovalWithCuratorTest(chain), }, + ], + } as RootTestTree +} + +/** + * Bounty funding tests + * + * @param chain + * @returns RootTestTree + */ + +export function bountyFundingTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'Bounty funding tests', + children: [ { kind: 'test', label: 'Bounty funding for Approved Bounties', @@ -2472,6 +2485,30 @@ export function allBountySuccessTests< label: 'Bounty funding for ApprovedWithCurator Bounties', testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), }, + ], + } as RootTestTree +} + +/** + * + * All success cases for bounty + * + * @param chain + * @returns RootTestTree + */ +export function allBountySuccessTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'All bounty success tests', + children: [ + { + kind: 'test', + label: 'Creating a bounty', + testFn: async () => await bountyCreationTest(chain), + }, { kind: 'test', label: 'Curator assignment and acceptance', @@ -2487,6 +2524,8 @@ export function allBountySuccessTests< label: 'Bounty awarding and claiming', testFn: async () => await bountyAwardingAndClaimingTest(chain), }, + bountyFundingTests(chain), + bountyApprovalTests(chain), bountyClosureTests(chain), allCuratorUnassignTests(chain), ], From 5b23af8b4a42c12add0d1a52b1a5b2137358ed68 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:21:53 +0530 Subject: [PATCH 48/66] failure test: hasActiveChildBountyTest added, Bounty cannot be awarded if it has an active child bounty --- packages/shared/src/bounties.ts | 121 +++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index d13f65ec1..1853625eb 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -2374,6 +2374,120 @@ async function requireCuratorAcceptTest< await client.teardown() } +/** + * Test creating a child bounty from an active parent bounty and then trying to close it should fail with `HasActiveChildBounty`. + * + * Verifies: + * - Curator can create child bounty when parent bounty is in Active state + * - ChildBountyAdded event is emitted + * - Child bounty gets proper funding from parent bounty + */ +async function hasActiveChildBountyTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + // move client head to the last spend period block + const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping child bounty test') + return + } + const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() + await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + + await setupTestAccounts(client, ['alice', 'bob']) + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * 1000n + const description = 'Test bounty for child bounty check' + + // Propose a bounty + await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + + await client.dev.newBlock() + const bountyIndex = await getBountyIndexFromEvent(client) + + // Approve the bounty + await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + await client.dev.newBlock() + // Bounty will be funded in this block + await client.dev.newBlock() + + const curatorFee = existentialDeposit.toBigInt() * 100n + + // Propose Bob as curator + await scheduleInlineCallWithOrigin( + client, + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), + { + Origins: 'Treasurer', + }, + ) + + await client.dev.newBlock() + + // Bob accepts curator role + await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + + await client.dev.newBlock() + + // Verify bounty is in Active state before creating child bounty + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + // Note: The curator (Bob) should create the child bounty, not Alice + const childBountyValue = existentialDeposit.toBigInt() * 100n // Smaller value for child bounty + const childBountyDescription = 'Test child bounty' + + await sendTransaction( + client.api.tx.childBounties + .addChildBounty(bountyIndex, childBountyValue, childBountyDescription) + .signAsync(devAccounts.bob), // Bob is the curator, so he should create the child bounty + ) + + await client.dev.newBlock() + + // Check for ChildBountyAdded event + await checkSystemEvents(client, { section: 'childBounties', method: 'Added' }) + .redact({ redactKeys: /index|data/ }) + .toMatchSnapshot('child bounty added events') + + // Verify parent bounty is still in Active state + const parentBounty = await getBounty(client, bountyIndex) + expect(parentBounty.status.isActive).toBe(true) + + // award the parent bounty + await sendTransaction( + client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.bob.address).signAsync(devAccounts.bob), + ) + + await client.dev.newBlock() + + const events = await client.api.query.system.events() + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'system' && event.method === 'ExtrinsicFailed' + }) + assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) + const dispatchError = ev.event.data.dispatchError + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.HasActiveChildBounty.is(dispatchError.asModule)).toBeTruthy() + + // Verify parent bounty is still in Active state + const parentBountyAfterAward = await getBounty(client, bountyIndex) + expect(parentBountyAfterAward.status.isActive).toBe(true) + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2428,6 +2542,11 @@ export function allBountyFailureTests< label: 'Non-curator trying to accept curator role', testFn: async () => await requireCuratorAcceptTest(chain), }, + { + kind: 'test', + label: 'Bounty cannot be awarded if it has an active child bounty', + testFn: async () => await hasActiveChildBountyTest(chain), + }, ], } as RootTestTree } @@ -2547,6 +2666,6 @@ export function baseBountiesE2ETests< return { kind: 'describe', label: testConfig.testSuiteName, - children: [allBountyFailureTests(chain), allBountySuccessTests(chain)], + children: [allBountySuccessTests(chain), allBountyFailureTests(chain)], } } From f645277574c1eaf8eb47bc6cfa9f93df83dd88aa Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:22:54 +0530 Subject: [PATCH 49/66] refac --- packages/shared/src/bounties.ts | 200 ++++++++++++++++---------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 1853625eb..7a132c215 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1832,6 +1832,106 @@ export function allCuratorUnassignTests< } as RootTestTree } +/** + * Bounty approval tests + * + * @param chain + * @returns RootTestTree + */ +export function bountyApprovalTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'Bounty approval tests', + children: [ + { + kind: 'test', + label: 'Bounty approval flow', + testFn: async () => await bountyApprovalTest(chain), + }, + { + kind: 'test', + label: 'Bounty approval flow with curator', + testFn: async () => await bountyApprovalWithCuratorTest(chain), + }, + ], + } as RootTestTree +} + +/** + * Bounty funding tests + * + * @param chain + * @returns RootTestTree + */ + +export function bountyFundingTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'Bounty funding tests', + children: [ + { + kind: 'test', + label: 'Bounty funding for Approved Bounties', + testFn: async () => await bountyFundingTest(chain), + }, + { + kind: 'test', + label: 'Bounty funding for ApprovedWithCurator Bounties', + testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), + }, + ], + } as RootTestTree +} + +/** + * + * All success cases for bounty + * + * @param chain + * @returns RootTestTree + */ +export function allBountySuccessTests< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain): RootTestTree { + return { + kind: 'describe', + label: 'All bounty success tests', + children: [ + { + kind: 'test', + label: 'Creating a bounty', + testFn: async () => await bountyCreationTest(chain), + }, + { + kind: 'test', + label: 'Curator assignment and acceptance', + testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), + }, + { + kind: 'test', + label: 'Bounty extension', + testFn: async () => await bountyExtensionTest(chain), + }, + { + kind: 'test', + label: 'Bounty awarding and claiming', + testFn: async () => await bountyAwardingAndClaimingTest(chain), + }, + bountyFundingTests(chain), + bountyApprovalTests(chain), + bountyClosureTests(chain), + allCuratorUnassignTests(chain), + ], + } as RootTestTree +} + /** * Test: Bounty closure in Approved state (should fail) * @@ -2551,106 +2651,6 @@ export function allBountyFailureTests< } as RootTestTree } -/** - * Bounty approval tests - * - * @param chain - * @returns RootTestTree - */ -export function bountyApprovalTests< - TCustom extends Record | undefined, - TInitStorages extends Record> | undefined, ->(chain: Chain): RootTestTree { - return { - kind: 'describe', - label: 'Bounty approval tests', - children: [ - { - kind: 'test', - label: 'Bounty approval flow', - testFn: async () => await bountyApprovalTest(chain), - }, - { - kind: 'test', - label: 'Bounty approval flow with curator', - testFn: async () => await bountyApprovalWithCuratorTest(chain), - }, - ], - } as RootTestTree -} - -/** - * Bounty funding tests - * - * @param chain - * @returns RootTestTree - */ - -export function bountyFundingTests< - TCustom extends Record | undefined, - TInitStorages extends Record> | undefined, ->(chain: Chain): RootTestTree { - return { - kind: 'describe', - label: 'Bounty funding tests', - children: [ - { - kind: 'test', - label: 'Bounty funding for Approved Bounties', - testFn: async () => await bountyFundingTest(chain), - }, - { - kind: 'test', - label: 'Bounty funding for ApprovedWithCurator Bounties', - testFn: async () => await bountyFundingForApprovedWithCuratorTest(chain), - }, - ], - } as RootTestTree -} - -/** - * - * All success cases for bounty - * - * @param chain - * @returns RootTestTree - */ -export function allBountySuccessTests< - TCustom extends Record | undefined, - TInitStorages extends Record> | undefined, ->(chain: Chain): RootTestTree { - return { - kind: 'describe', - label: 'All bounty success tests', - children: [ - { - kind: 'test', - label: 'Creating a bounty', - testFn: async () => await bountyCreationTest(chain), - }, - { - kind: 'test', - label: 'Curator assignment and acceptance', - testFn: async () => await curatorAssignmentAndAcceptanceTest(chain), - }, - { - kind: 'test', - label: 'Bounty extension', - testFn: async () => await bountyExtensionTest(chain), - }, - { - kind: 'test', - label: 'Bounty awarding and claiming', - testFn: async () => await bountyAwardingAndClaimingTest(chain), - }, - bountyFundingTests(chain), - bountyApprovalTests(chain), - bountyClosureTests(chain), - allCuratorUnassignTests(chain), - ], - } as RootTestTree -} - /** * Base set of bounty end-to-end tests. * From cef1c55ba5c4c2ce9cc4b1ce885679a83e8f8f50 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:33:47 +0530 Subject: [PATCH 50/66] improv: explicit expect are used --- packages/shared/src/bounties.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 7a132c215..bb1b4fbd7 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -127,7 +127,7 @@ export async function bountyCreationTest< // Get bounty index and verify bounty data const bountyIndex = await getBountyIndexFromEvent(client) const bounty = await getBounty(client, bountyIndex) - expect(bounty).toBeDefined() + expect(bounty).toBeTruthy() expect(bounty.value.toBigInt()).toBe(bountyValue) expect(bounty.status.isProposed).toBe(true) @@ -150,7 +150,7 @@ export async function bountyCreationTest< */ export async function bountyApprovalTest< TCustom extends Record | undefined, - TInitStorages extends Record> | undefined, + TInitStorages extends Record> | undefined, >(chain: Chain) { const [client] = await setupNetworks(chain) @@ -1889,7 +1889,7 @@ export function bountyFundingTests< } as RootTestTree } -/** +/**≠ * * All success cases for bounty * @@ -2001,7 +2001,7 @@ export async function bountyClosureApprovedTest< // Verify bounty is still in storage and still Approved const bountyAfterFailedClosure = await getBounty(client, bountyIndex) - expect(bountyAfterFailedClosure).toBeDefined() + expect(bountyAfterFailedClosure).toBeTruthy() expect(bountyAfterFailedClosure.status.isApproved).toBe(true) await client.teardown() @@ -2109,7 +2109,7 @@ export async function bountyClosurePendingPayoutTest< // Verify bounty is still in storage and still PendingPayout const bountyAfterFailedClosure = await getBounty(client, bountyIndex) - expect(bountyAfterFailedClosure).toBeDefined() + expect(bountyAfterFailedClosure).toBeTruthy() expect(bountyAfterFailedClosure.status.isPendingPayout).toBe(true) await client.teardown() @@ -2203,7 +2203,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< // Verify bounty is still in storage and still Active const bountyAfterFailedUnassign = await getBounty(client, bountyIndex) - expect(bountyAfterFailedUnassign).toBeDefined() + expect(bountyAfterFailedUnassign).toBeTruthy() expect(bountyAfterFailedUnassign.status.isActive).toBe(true) await client.teardown() From 35bc7025af7fe0b2252251fae039524f58689b82 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 21:48:41 +0530 Subject: [PATCH 51/66] refac: added helper fun, removed magic nums --- packages/shared/src/bounties.ts | 123 +++++++++++++++++--------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index bb1b4fbd7..c913c6fbf 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -12,6 +12,10 @@ import type { RootTestTree } from './types.js' /// Helpers /// ------- +// multipliers for the bounty and curator fee +const BOUNTY_MULTIPLIER = 1000n +const CURATOR_FEE_MULTIPLIER = 100n + /** * Get the current bounty count */ @@ -75,11 +79,19 @@ async function getBountyIndexFromEvent(client: any): Promise { const [bountyProposedEvent] = (await client.api.query.system.events()).filter( ({ event }: any) => event.section === 'bounties' && event.method === 'BountyProposed', ) - expect(bountyProposedEvent).toBeDefined() + expect(bountyProposedEvent).toBeTruthy() assert(client.api.events.bounties.BountyProposed.is(bountyProposedEvent.event)) return bountyProposedEvent.event.data.index.toNumber() } +async function ensureSpendPeriodAvailable(lastSpendPeriodBlock: any): Promise { + if (lastSpendPeriodBlock.isNone) { + console.warn('Last spend period block is none, skipping test') + return false + } + return true +} + /// ------- /// Tests /// ------- @@ -105,7 +117,7 @@ export async function bountyCreationTest< const initialBountyCount = await getBountyCount(client) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 EDs const description = 'Test bounty for development work' // Propose a bounty @@ -157,7 +169,7 @@ export async function bountyApprovalTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 EDs const description = 'Test bounty for approval' // Propose a bounty @@ -211,8 +223,8 @@ export async function bountyApprovalWithCuratorTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 EDs - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 EDs + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // 100 EDs (10% fee) const description = 'Test bounty for approval with curator' // Propose a bounty @@ -271,8 +283,7 @@ export async function bountyFundingTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty funding test') + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -283,7 +294,7 @@ export async function bountyFundingTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens const description = 'Test bounty for funding' // propose a bounty @@ -360,8 +371,8 @@ export async function bountyFundingForApprovedWithCuratorTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 tokens (10% fee) + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // 100 tokens (10% fee) const description = 'Test bounty for funding with curator' // propose a bounty @@ -444,8 +455,7 @@ export async function curatorAssignmentAndAcceptanceTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty funding test') + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -456,7 +466,7 @@ export async function curatorAssignmentAndAcceptanceTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens const description = 'Test bounty for funding' // propose a bounty @@ -505,8 +515,7 @@ export async function curatorAssignmentAndAcceptanceTest< const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) - + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty await scheduleInlineCallWithOrigin( client, @@ -561,8 +570,7 @@ export async function bountyExtensionTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty funding test') + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -573,7 +581,7 @@ export async function bountyExtensionTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens const description = 'Test bounty for funding' // propose a bounty @@ -622,7 +630,7 @@ export async function bountyExtensionTest< const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty await scheduleInlineCallWithOrigin( @@ -709,8 +717,7 @@ export async function bountyAwardingAndClaimingTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty funding test') + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -721,7 +728,7 @@ export async function bountyAwardingAndClaimingTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n // 1000 tokens + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens const description = 'Test bounty for funding' // propose a bounty @@ -770,7 +777,7 @@ export async function bountyAwardingAndClaimingTest< const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) - const curatorFee = existentialDeposit.toBigInt() * 100n // 100 EDs (10% fee) + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty await scheduleInlineCallWithOrigin( @@ -877,7 +884,7 @@ export async function bountyClosureProposedTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for closure in proposed state' // Propose a bounty @@ -952,7 +959,7 @@ export async function bountyClosureFundedTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for closure in funded state' // Propose a bounty @@ -1043,8 +1050,7 @@ export async function bountyClosureActiveTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty closure active test') + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -1055,8 +1061,8 @@ export async function bountyClosureActiveTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for closure in active state' // Propose a bounty @@ -1164,8 +1170,8 @@ export async function unassignCuratorApprovedWithCuratorTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for unassign curator in approved with curator state' // Propose a bounty @@ -1221,8 +1227,7 @@ export async function unassignCuratorCuratorProposedTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping unassign curator curator proposed test') + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -1233,8 +1238,8 @@ export async function unassignCuratorCuratorProposedTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for unassign curator in curator proposed state' // Propose a bounty @@ -1324,8 +1329,7 @@ export async function unassignCuratorActiveByCuratorTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping unassign curator active by curator test') + if (!ensureSpendPeriodAvailable(client)) { return } @@ -1336,8 +1340,8 @@ export async function unassignCuratorActiveByCuratorTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for unassign curator active by curator' // Propose a bounty @@ -1459,8 +1463,7 @@ export async function unassignCuratorActiveByTreasurerTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping unassign curator active by treasurer test') + if (!ensureSpendPeriodAvailable(client)) { return } @@ -1471,8 +1474,8 @@ export async function unassignCuratorActiveByTreasurerTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for unassign curator active by treasurer' // Propose a bounty @@ -1618,8 +1621,8 @@ export async function unassignCuratorPendingPayoutTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for unassign curator pending payout' // Propose a bounty @@ -1948,7 +1951,7 @@ export async function bountyClosureApprovedTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for closure in approved state' // Propose a bounty @@ -2033,8 +2036,8 @@ export async function bountyClosurePendingPayoutTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for closure in pending payout state' // Propose a bounty @@ -2140,8 +2143,8 @@ async function unassignCuratorActiveStateByPublicPrematureTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n - const curatorFee = existentialDeposit.toBigInt() * 100n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER const description = 'Test bounty for premature unassign curator by public' // Propose a bounty @@ -2224,7 +2227,7 @@ async function reasonTooBigTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const maxReasonLength = client.api.consts.bounties.maximumReasonLength.toNumber() // Create a description that exceeds the maximum length @@ -2357,7 +2360,7 @@ async function unexpectedStatusProposeCuratorTest< await setupTestAccounts(client, ['alice']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for curator proposal' // Propose a bounty @@ -2366,10 +2369,12 @@ async function unexpectedStatusProposeCuratorTest< await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER + // propose curator by Treasurer await scheduleInlineCallWithOrigin( client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, 1000n).method.toHex(), + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), { Origins: 'Treasurer', }, @@ -2419,7 +2424,7 @@ async function requireCuratorAcceptTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for curator requirement' // Propose a bounty @@ -2439,10 +2444,12 @@ async function requireCuratorAcceptTest< // Bounty will be funded in this block await client.dev.newBlock() + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER + // Propose Bob as curator await scheduleInlineCallWithOrigin( client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, 1000n).method.toHex(), + client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), { Origins: 'Treasurer', }, @@ -2500,7 +2507,7 @@ async function hasActiveChildBountyTest< await setupTestAccounts(client, ['alice', 'bob']) const existentialDeposit = client.api.consts.balances.existentialDeposit - const bountyValue = existentialDeposit.toBigInt() * 1000n + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for child bounty check' // Propose a bounty @@ -2520,7 +2527,7 @@ async function hasActiveChildBountyTest< // Bounty will be funded in this block await client.dev.newBlock() - const curatorFee = existentialDeposit.toBigInt() * 100n + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Propose Bob as curator await scheduleInlineCallWithOrigin( @@ -2543,7 +2550,7 @@ async function hasActiveChildBountyTest< expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) // Note: The curator (Bob) should create the child bounty, not Alice - const childBountyValue = existentialDeposit.toBigInt() * 100n // Smaller value for child bounty + const childBountyValue = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Smaller value for child bounty const childBountyDescription = 'Test child bounty' await sendTransaction( From 1bf7448221ef50f4f3b63cb0c4487d3bb31528c8 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 22:00:11 +0530 Subject: [PATCH 52/66] refac: defined type of params --- packages/shared/src/bounties.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index c913c6fbf..c35213630 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1,7 +1,7 @@ import { sendTransaction } from '@acala-network/chopsticks-testing' import { type Chain, defaultAccountsSr25519 as devAccounts } from '@e2e-test/networks' -import { setupNetworks } from '@e2e-test/shared' +import { type Client, setupNetworks } from '@e2e-test/shared' import { assert, expect } from 'vitest' @@ -19,14 +19,14 @@ const CURATOR_FEE_MULTIPLIER = 100n /** * Get the current bounty count */ -async function getBountyCount(client: any): Promise { +async function getBountyCount(client: Client): Promise { return (await client.api.query.bounties.bountyCount()).toNumber() } /** * Get a bounty by index */ -async function getBounty(client: any, bountyIndex: number): Promise { +async function getBounty(client: Client, bountyIndex: number): Promise { const bounty = await client.api.query.bounties.bounties(bountyIndex) if (!bounty) return null return bounty.isSome ? bounty.unwrap() : null @@ -35,7 +35,7 @@ async function getBounty(client: any, bountyIndex: number): Promise /** * Get bounty description by index */ -async function getBountyDescription(client: any, bountyIndex: number): Promise { +async function getBountyDescription(client: Client, bountyIndex: number): Promise { const description = await client.api.query.bounties.bountyDescriptions(bountyIndex) return description.isSome ? description.unwrap().toUtf8() : null } @@ -43,7 +43,7 @@ async function getBountyDescription(client: any, bountyIndex: number): Promise { +async function getBountyApprovals(client: Client): Promise { const approvals = await client.api.query.bounties.bountyApprovals() return approvals.map((index: any) => index.toNumber()) } @@ -51,7 +51,7 @@ async function getBountyApprovals(client: any): Promise { /** * Setup accounts with funds for testing */ -async function setupTestAccounts(client: any, accounts: string[] = ['alice', 'bob']) { +async function setupTestAccounts(client: Client, accounts: string[] = ['alice', 'bob']) { const accountMap = { alice: devAccounts.alice.address, bob: devAccounts.bob.address, @@ -75,7 +75,7 @@ async function setupTestAccounts(client: any, accounts: string[] = ['alice', 'bo /** * Get bounty index from BountyProposed event */ -async function getBountyIndexFromEvent(client: any): Promise { +async function getBountyIndexFromEvent(client: Client): Promise { const [bountyProposedEvent] = (await client.api.query.system.events()).filter( ({ event }: any) => event.section === 'bounties' && event.method === 'BountyProposed', ) @@ -343,8 +343,6 @@ export async function bountyFundingTest< const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) - // TODO: @dhirajs0 - verify that the bond of the proposer is reserved and it's unreserved after the bounty is funded - await client.teardown() } From 0f24e0dfa89e486926b25e44614932be873dafcb Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 19 Sep 2025 23:39:54 +0530 Subject: [PATCH 53/66] snanpshots updated for polkadot and kusama --- .../kusama.bounties.e2e.test.ts.snap | 188 +++++++++++------- .../polkadot.bounties.e2e.test.ts.snap | 188 +++++++++++------- 2 files changed, 240 insertions(+), 136 deletions(-) diff --git a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap index e10e6d691..f74cc5ba6 100644 --- a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap +++ b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap @@ -1,6 +1,58 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > Bounty bond is deposited to the treasury 1`] = ` +exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be awarded if it has an active child bounty > child bounty added events 1`] = ` +[ + { + "data": "(redacted)", + "method": "Added", + "section": "childBounties", + }, +] +`; + +exports[`Kusama Bounties > All bounty failure tests > Bounty closure in approved state > scheduler events when closing bounty with approved state fails 1`] = ` +[ + { + "data": { + "id": null, + "result": { + "Err": { + "Module": { + "error": "0x03000000", + "index": 35, + }, + }, + }, + "task": "(redacted)", + }, + "method": "Dispatched", + "section": "scheduler", + }, +] +`; + +exports[`Kusama Bounties > All bounty failure tests > Bounty closure in pending payout state > scheduler events when closing bounty with pending payout fails 1`] = ` +[ + { + "data": { + "id": null, + "result": { + "Err": { + "Module": { + "error": "0x07000000", + "index": 35, + }, + }, + }, + "task": "(redacted)", + }, + "method": "Dispatched", + "section": "scheduler", + }, +] +`; + +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > Bounty bond is deposited to the treasury 1`] = ` [ { "data": "(redacted)", @@ -10,7 +62,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty approved events 1`] = ` [ { "data": { @@ -22,7 +74,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty became active events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty became active events 1`] = ` [ { "data": { @@ -34,7 +86,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty proposed events 1`] = ` [ { "data": { @@ -46,7 +98,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator accepted events 1`] = ` [ { "data": { @@ -59,7 +111,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator proposed events 1`] = ` [ { "data": { @@ -72,7 +124,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator slash event 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator slash event 1`] = ` [ { "data": { @@ -85,7 +137,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator unassigned active by treasurer events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator unassigned active by treasurer events 1`] = ` [ { "data": { @@ -97,7 +149,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty approved events 1`] = ` [ { "data": { @@ -109,7 +161,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty became active events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty became active events 1`] = ` [ { "data": { @@ -121,7 +173,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty proposed events 1`] = ` [ { "data": { @@ -133,7 +185,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > curator accepted events 1`] = ` [ { "data": { @@ -146,7 +198,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > curator proposed events 1`] = ` [ { "data": { @@ -159,7 +211,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator unassigned active by curator events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > curator unassigned active by curator events 1`] = ` [ { "data": { @@ -171,7 +223,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Acti ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in ApprovedWithCurator state > curator unassigned approved with curator events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in ApprovedWithCurator state > curator unassigned approved with curator events 1`] = ` [ { "data": { @@ -183,7 +235,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Appr ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in CuratorProposed state > bounty approved events 1`] = ` [ { "data": { @@ -195,7 +247,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Cura ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty became active events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in CuratorProposed state > bounty became active events 1`] = ` [ { "data": { @@ -207,7 +259,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Cura ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > curator unassigned curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in CuratorProposed state > curator unassigned curator proposed events 1`] = ` [ { "data": { @@ -219,7 +271,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Cura ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > Bounty bond is deposited to the treasury 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > Bounty bond is deposited to the treasury 1`] = ` [ { "data": "(redacted)", @@ -229,7 +281,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty approved events 1`] = ` [ { "data": { @@ -241,7 +293,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty awarded events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty awarded events 1`] = ` [ { "data": { @@ -254,7 +306,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty became active events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty became active events 1`] = ` [ { "data": { @@ -266,7 +318,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty proposed events 1`] = ` [ { "data": { @@ -278,7 +330,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator accepted events 1`] = ` [ { "data": { @@ -291,7 +343,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator proposed events 1`] = ` [ { "data": { @@ -304,7 +356,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator slash event 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator slash event 1`] = ` [ { "data": { @@ -317,7 +369,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator unassigned pending payout events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator unassigned pending payout events 1`] = ` [ { "data": { @@ -329,7 +381,7 @@ exports[`Kusama Bounties > All curator unassign tests > Unassign curator in Pend ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > Bounty value is transferred to the treasury 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > Bounty value is transferred to the treasury 1`] = ` [ { "data": { @@ -343,7 +395,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty approved events 1`] = ` [ { "data": { @@ -355,9 +407,9 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` [ { "data": { @@ -369,7 +421,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > curator accepted events 1`] = ` [ { "data": { @@ -382,7 +434,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > curator proposed events 1`] = ` [ { "data": { @@ -395,7 +447,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in active state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty approved events 1`] = ` [ { "data": { @@ -407,9 +459,9 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` [ { "data": { @@ -421,7 +473,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` [ { "data": { @@ -435,7 +487,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in funded state ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in proposed state > bounty rejected events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in proposed state > bounty rejected events 1`] = ` [ { "data": { @@ -448,7 +500,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in proposed sta ] `; -exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in proposed state > proposer bond slashed event 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in proposed state > proposer bond slashed event 1`] = ` [ { "data": { @@ -461,7 +513,7 @@ exports[`Kusama Bounties > Bounty Closure Tests > Bounty closure in proposed sta ] `; -exports[`Kusama Bounties > Bounty approval flow > bounty approval events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty approval tests > Bounty approval flow > bounty approval events 1`] = ` [ { "data": { @@ -473,7 +525,7 @@ exports[`Kusama Bounties > Bounty approval flow > bounty approval events 1`] = ` ] `; -exports[`Kusama Bounties > Bounty approval flow with curator > bounty approval with curator events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty approval tests > Bounty approval flow with curator > bounty approval with curator events 1`] = ` [ { "data": { @@ -485,7 +537,7 @@ exports[`Kusama Bounties > Bounty approval flow with curator > bounty approval w ] `; -exports[`Kusama Bounties > Bounty approval flow with curator > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty approval tests > Bounty approval flow with curator > curator proposed events 1`] = ` [ { "data": { @@ -498,7 +550,7 @@ exports[`Kusama Bounties > Bounty approval flow with curator > curator proposed ] `; -exports[`Kusama Bounties > Bounty awarding and claiming > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty approved events 1`] = ` [ { "data": { @@ -510,7 +562,7 @@ exports[`Kusama Bounties > Bounty awarding and claiming > bounty approved events ] `; -exports[`Kusama Bounties > Bounty awarding and claiming > bounty awarded events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty awarded events 1`] = ` [ { "data": { @@ -523,9 +575,9 @@ exports[`Kusama Bounties > Bounty awarding and claiming > bounty awarded events ] `; -exports[`Kusama Bounties > Bounty awarding and claiming > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Bounty awarding and claiming > bounty claimed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty claimed events 1`] = ` [ { "data": { @@ -539,7 +591,7 @@ exports[`Kusama Bounties > Bounty awarding and claiming > bounty claimed events ] `; -exports[`Kusama Bounties > Bounty awarding and claiming > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty proposed events 1`] = ` [ { "data": { @@ -551,7 +603,7 @@ exports[`Kusama Bounties > Bounty awarding and claiming > bounty proposed events ] `; -exports[`Kusama Bounties > Bounty awarding and claiming > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > curator accepted events 1`] = ` [ { "data": { @@ -564,7 +616,7 @@ exports[`Kusama Bounties > Bounty awarding and claiming > curator accepted event ] `; -exports[`Kusama Bounties > Bounty awarding and claiming > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > curator proposed events 1`] = ` [ { "data": { @@ -577,7 +629,7 @@ exports[`Kusama Bounties > Bounty awarding and claiming > curator proposed event ] `; -exports[`Kusama Bounties > Bounty extension > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty approved events 1`] = ` [ { "data": { @@ -589,9 +641,9 @@ exports[`Kusama Bounties > Bounty extension > bounty approved events 1`] = ` ] `; -exports[`Kusama Bounties > Bounty extension > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Bounty extension > bounty extended events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty extended events 1`] = ` [ { "data": { @@ -603,7 +655,7 @@ exports[`Kusama Bounties > Bounty extension > bounty extended events 1`] = ` ] `; -exports[`Kusama Bounties > Bounty extension > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty proposed events 1`] = ` [ { "data": { @@ -615,7 +667,7 @@ exports[`Kusama Bounties > Bounty extension > bounty proposed events 1`] = ` ] `; -exports[`Kusama Bounties > Bounty extension > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty extension > curator accepted events 1`] = ` [ { "data": { @@ -628,7 +680,7 @@ exports[`Kusama Bounties > Bounty extension > curator accepted events 1`] = ` ] `; -exports[`Kusama Bounties > Bounty extension > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty extension > curator proposed events 1`] = ` [ { "data": { @@ -641,7 +693,7 @@ exports[`Kusama Bounties > Bounty extension > curator proposed events 1`] = ` ] `; -exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty approved events 1`] = ` [ { "data": { @@ -653,9 +705,9 @@ exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty approve ] `; -exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` [ { "data": { @@ -667,7 +719,7 @@ exports[`Kusama Bounties > Bounty funding for Approved Bounties > bounty propose ] `; -exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty approved events 1`] = ` [ { "data": { @@ -679,9 +731,9 @@ exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bou ] `; -exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` [ { "data": { @@ -693,7 +745,7 @@ exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > bou ] `; -exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > curator proposed events 1`] = ` [ { "data": { @@ -706,7 +758,7 @@ exports[`Kusama Bounties > Bounty funding for ApprovedWithCurator Bounties > cur ] `; -exports[`Kusama Bounties > Creating a bounty > bounty proposal events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Creating a bounty > bounty proposal events 1`] = ` [ { "data": { @@ -718,7 +770,7 @@ exports[`Kusama Bounties > Creating a bounty > bounty proposal events 1`] = ` ] `; -exports[`Kusama Bounties > Curator assignment and acceptance > bounty approved events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > bounty approved events 1`] = ` [ { "data": { @@ -730,9 +782,9 @@ exports[`Kusama Bounties > Curator assignment and acceptance > bounty approved e ] `; -exports[`Kusama Bounties > Curator assignment and acceptance > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > bounty became active events 1`] = `[]`; -exports[`Kusama Bounties > Curator assignment and acceptance > bounty proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > bounty proposed events 1`] = ` [ { "data": { @@ -744,7 +796,7 @@ exports[`Kusama Bounties > Curator assignment and acceptance > bounty proposed e ] `; -exports[`Kusama Bounties > Curator assignment and acceptance > curator accepted events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > curator accepted events 1`] = ` [ { "data": { @@ -757,7 +809,7 @@ exports[`Kusama Bounties > Curator assignment and acceptance > curator accepted ] `; -exports[`Kusama Bounties > Curator assignment and acceptance > curator proposed events 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > curator proposed events 1`] = ` [ { "data": { diff --git a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap index 82ec4429a..054a432d6 100644 --- a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap +++ b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap @@ -1,6 +1,58 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > Bounty bond is deposited to the treasury 1`] = ` +exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be awarded if it has an active child bounty > child bounty added events 1`] = ` +[ + { + "data": "(redacted)", + "method": "Added", + "section": "childBounties", + }, +] +`; + +exports[`Polkadot Bounties > All bounty failure tests > Bounty closure in approved state > scheduler events when closing bounty with approved state fails 1`] = ` +[ + { + "data": { + "id": null, + "result": { + "Err": { + "Module": { + "error": "0x03000000", + "index": 34, + }, + }, + }, + "task": "(redacted)", + }, + "method": "Dispatched", + "section": "scheduler", + }, +] +`; + +exports[`Polkadot Bounties > All bounty failure tests > Bounty closure in pending payout state > scheduler events when closing bounty with pending payout fails 1`] = ` +[ + { + "data": { + "id": null, + "result": { + "Err": { + "Module": { + "error": "0x07000000", + "index": 34, + }, + }, + }, + "task": "(redacted)", + }, + "method": "Dispatched", + "section": "scheduler", + }, +] +`; + +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > Bounty bond is deposited to the treasury 1`] = ` [ { "data": "(redacted)", @@ -10,7 +62,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty approved events 1`] = ` [ { "data": { @@ -22,7 +74,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty became active events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty became active events 1`] = ` [ { "data": { @@ -34,7 +86,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > bounty proposed events 1`] = ` [ { "data": { @@ -46,7 +98,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator accepted events 1`] = ` [ { "data": { @@ -59,7 +111,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator proposed events 1`] = ` [ { "data": { @@ -72,7 +124,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator slash event 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator slash event 1`] = ` [ { "data": { @@ -85,7 +137,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by Treasurer > curator unassigned active by treasurer events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by Treasurer > curator unassigned active by treasurer events 1`] = ` [ { "data": { @@ -97,7 +149,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty approved events 1`] = ` [ { "data": { @@ -109,7 +161,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty became active events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty became active events 1`] = ` [ { "data": { @@ -121,7 +173,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > bounty proposed events 1`] = ` [ { "data": { @@ -133,7 +185,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > curator accepted events 1`] = ` [ { "data": { @@ -146,7 +198,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > curator proposed events 1`] = ` [ { "data": { @@ -159,7 +211,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Active state by curator themselves > curator unassigned active by curator events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in Active state by curator themselves > curator unassigned active by curator events 1`] = ` [ { "data": { @@ -171,7 +223,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ac ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in ApprovedWithCurator state > curator unassigned approved with curator events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in ApprovedWithCurator state > curator unassigned approved with curator events 1`] = ` [ { "data": { @@ -183,7 +235,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Ap ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in CuratorProposed state > bounty approved events 1`] = ` [ { "data": { @@ -195,7 +247,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Cu ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > bounty became active events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in CuratorProposed state > bounty became active events 1`] = ` [ { "data": { @@ -207,7 +259,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Cu ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in CuratorProposed state > curator unassigned curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in CuratorProposed state > curator unassigned curator proposed events 1`] = ` [ { "data": { @@ -219,7 +271,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Cu ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > Bounty bond is deposited to the treasury 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > Bounty bond is deposited to the treasury 1`] = ` [ { "data": "(redacted)", @@ -229,7 +281,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty approved events 1`] = ` [ { "data": { @@ -241,7 +293,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty awarded events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty awarded events 1`] = ` [ { "data": { @@ -254,7 +306,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty became active events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty became active events 1`] = ` [ { "data": { @@ -266,7 +318,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > bounty proposed events 1`] = ` [ { "data": { @@ -278,7 +330,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator accepted events 1`] = ` [ { "data": { @@ -291,7 +343,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator proposed events 1`] = ` [ { "data": { @@ -304,7 +356,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator slash event 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator slash event 1`] = ` [ { "data": { @@ -317,7 +369,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in PendingPayout state > curator unassigned pending payout events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > All curator unassign tests > Unassign curator in PendingPayout state > curator unassigned pending payout events 1`] = ` [ { "data": { @@ -329,7 +381,7 @@ exports[`Polkadot Bounties > All curator unassign tests > Unassign curator in Pe ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > Bounty value is transferred to the treasury 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > Bounty value is transferred to the treasury 1`] = ` [ { "data": { @@ -343,7 +395,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty approved events 1`] = ` [ { "data": { @@ -355,9 +407,9 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` [ { "data": { @@ -369,7 +421,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > curator accepted events 1`] = ` [ { "data": { @@ -382,7 +434,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active state > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > curator proposed events 1`] = ` [ { "data": { @@ -395,7 +447,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in active sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty approved events 1`] = ` [ { "data": { @@ -407,9 +459,9 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` [ { "data": { @@ -421,7 +473,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` [ { "data": { @@ -435,7 +487,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in funded sta ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in proposed state > bounty rejected events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in proposed state > bounty rejected events 1`] = ` [ { "data": { @@ -448,7 +500,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in proposed s ] `; -exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in proposed state > proposer bond slashed event 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in proposed state > proposer bond slashed event 1`] = ` [ { "data": { @@ -461,7 +513,7 @@ exports[`Polkadot Bounties > Bounty Closure Tests > Bounty closure in proposed s ] `; -exports[`Polkadot Bounties > Bounty approval flow > bounty approval events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty approval tests > Bounty approval flow > bounty approval events 1`] = ` [ { "data": { @@ -473,7 +525,7 @@ exports[`Polkadot Bounties > Bounty approval flow > bounty approval events 1`] = ] `; -exports[`Polkadot Bounties > Bounty approval flow with curator > bounty approval with curator events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty approval tests > Bounty approval flow with curator > bounty approval with curator events 1`] = ` [ { "data": { @@ -485,7 +537,7 @@ exports[`Polkadot Bounties > Bounty approval flow with curator > bounty approval ] `; -exports[`Polkadot Bounties > Bounty approval flow with curator > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty approval tests > Bounty approval flow with curator > curator proposed events 1`] = ` [ { "data": { @@ -498,7 +550,7 @@ exports[`Polkadot Bounties > Bounty approval flow with curator > curator propose ] `; -exports[`Polkadot Bounties > Bounty awarding and claiming > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty approved events 1`] = ` [ { "data": { @@ -510,7 +562,7 @@ exports[`Polkadot Bounties > Bounty awarding and claiming > bounty approved even ] `; -exports[`Polkadot Bounties > Bounty awarding and claiming > bounty awarded events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty awarded events 1`] = ` [ { "data": { @@ -523,9 +575,9 @@ exports[`Polkadot Bounties > Bounty awarding and claiming > bounty awarded event ] `; -exports[`Polkadot Bounties > Bounty awarding and claiming > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Bounty awarding and claiming > bounty claimed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty claimed events 1`] = ` [ { "data": { @@ -539,7 +591,7 @@ exports[`Polkadot Bounties > Bounty awarding and claiming > bounty claimed event ] `; -exports[`Polkadot Bounties > Bounty awarding and claiming > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty proposed events 1`] = ` [ { "data": { @@ -551,7 +603,7 @@ exports[`Polkadot Bounties > Bounty awarding and claiming > bounty proposed even ] `; -exports[`Polkadot Bounties > Bounty awarding and claiming > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > curator accepted events 1`] = ` [ { "data": { @@ -564,7 +616,7 @@ exports[`Polkadot Bounties > Bounty awarding and claiming > curator accepted eve ] `; -exports[`Polkadot Bounties > Bounty awarding and claiming > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > curator proposed events 1`] = ` [ { "data": { @@ -577,7 +629,7 @@ exports[`Polkadot Bounties > Bounty awarding and claiming > curator proposed eve ] `; -exports[`Polkadot Bounties > Bounty extension > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty approved events 1`] = ` [ { "data": { @@ -589,9 +641,9 @@ exports[`Polkadot Bounties > Bounty extension > bounty approved events 1`] = ` ] `; -exports[`Polkadot Bounties > Bounty extension > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Bounty extension > bounty extended events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty extended events 1`] = ` [ { "data": { @@ -603,7 +655,7 @@ exports[`Polkadot Bounties > Bounty extension > bounty extended events 1`] = ` ] `; -exports[`Polkadot Bounties > Bounty extension > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty proposed events 1`] = ` [ { "data": { @@ -615,7 +667,7 @@ exports[`Polkadot Bounties > Bounty extension > bounty proposed events 1`] = ` ] `; -exports[`Polkadot Bounties > Bounty extension > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > curator accepted events 1`] = ` [ { "data": { @@ -628,7 +680,7 @@ exports[`Polkadot Bounties > Bounty extension > curator accepted events 1`] = ` ] `; -exports[`Polkadot Bounties > Bounty extension > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > curator proposed events 1`] = ` [ { "data": { @@ -641,7 +693,7 @@ exports[`Polkadot Bounties > Bounty extension > curator proposed events 1`] = ` ] `; -exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty approved events 1`] = ` [ { "data": { @@ -653,9 +705,9 @@ exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty appro ] `; -exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` [ { "data": { @@ -667,7 +719,7 @@ exports[`Polkadot Bounties > Bounty funding for Approved Bounties > bounty propo ] `; -exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty approved events 1`] = ` [ { "data": { @@ -679,9 +731,9 @@ exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > b ] `; -exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` [ { "data": { @@ -693,7 +745,7 @@ exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > b ] `; -exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > curator proposed events 1`] = ` [ { "data": { @@ -706,7 +758,7 @@ exports[`Polkadot Bounties > Bounty funding for ApprovedWithCurator Bounties > c ] `; -exports[`Polkadot Bounties > Creating a bounty > bounty proposal events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Creating a bounty > bounty proposal events 1`] = ` [ { "data": { @@ -718,7 +770,7 @@ exports[`Polkadot Bounties > Creating a bounty > bounty proposal events 1`] = ` ] `; -exports[`Polkadot Bounties > Curator assignment and acceptance > bounty approved events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > bounty approved events 1`] = ` [ { "data": { @@ -730,9 +782,9 @@ exports[`Polkadot Bounties > Curator assignment and acceptance > bounty approved ] `; -exports[`Polkadot Bounties > Curator assignment and acceptance > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > bounty became active events 1`] = `[]`; -exports[`Polkadot Bounties > Curator assignment and acceptance > bounty proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > bounty proposed events 1`] = ` [ { "data": { @@ -744,7 +796,7 @@ exports[`Polkadot Bounties > Curator assignment and acceptance > bounty proposed ] `; -exports[`Polkadot Bounties > Curator assignment and acceptance > curator accepted events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > curator accepted events 1`] = ` [ { "data": { @@ -757,7 +809,7 @@ exports[`Polkadot Bounties > Curator assignment and acceptance > curator accepte ] `; -exports[`Polkadot Bounties > Curator assignment and acceptance > curator proposed events 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > curator proposed events 1`] = ` [ { "data": { From 37cfb5a9e4dff2c856ed305a6ab3db2837cba6d5 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 23 Sep 2025 11:27:31 +0530 Subject: [PATCH 54/66] fix --- packages/shared/src/bounties.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index c35213630..3a0948aef 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1327,7 +1327,7 @@ export async function unassignCuratorActiveByCuratorTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(client)) { + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } @@ -1461,7 +1461,7 @@ export async function unassignCuratorActiveByTreasurerTest< const [client] = await setupNetworks(chain) const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(client)) { + if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { return } From c37a27ef459865011d1ad60988204fe18016cddd Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 23 Sep 2025 22:24:25 +0530 Subject: [PATCH 55/66] refac: parameterize the sendTransation and scheduleInlineCallWithOrigin calls --- packages/shared/src/bounties.ts | 413 ++++++++++++++++---------------- 1 file changed, 208 insertions(+), 205 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 3a0948aef..96ac04ff3 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -13,7 +13,9 @@ import type { RootTestTree } from './types.js' /// ------- // multipliers for the bounty and curator fee +// 1000x existential deposit for substantial bounty value const BOUNTY_MULTIPLIER = 1000n +// 10% curator fee (100/1000) const CURATOR_FEE_MULTIPLIER = 100n /** @@ -121,9 +123,8 @@ export async function bountyCreationTest< const description = 'Test bounty for development work' // Propose a bounty - const bountyProposalEvents = await sendTransaction( - client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), - ) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposalEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -162,7 +163,7 @@ export async function bountyCreationTest< */ export async function bountyApprovalTest< TCustom extends Record | undefined, - TInitStorages extends Record> | undefined, + TInitStorages extends Record> | undefined, >(chain: Chain) { const [client] = await setupNetworks(chain) @@ -173,7 +174,8 @@ export async function bountyApprovalTest< const description = 'Test bounty for approval' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -183,7 +185,8 @@ export async function bountyApprovalTest< expect(proposedBounty.status.isProposed).toBe(true) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -228,7 +231,8 @@ export async function bountyApprovalWithCuratorTest< const description = 'Test bounty for approval with curator' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -238,13 +242,14 @@ export async function bountyApprovalWithCuratorTest< expect(proposedBounty.status.isProposed).toBe(true) // Approve the bounty with curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.approveBountyWithCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, + const approveBountyWithCuratorTx = client.api.tx.bounties.approveBountyWithCurator( + bountyIndex, + devAccounts.bob.address, + curatorFee, ) + await scheduleInlineCallWithOrigin(client, approveBountyWithCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -287,7 +292,7 @@ export async function bountyFundingTest< return } - // move client head to the last spend period block - 3 + // Move to spend period boundary to trigger automatic funding const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() await client.dev.setHead(lastSpendPeriodBlockNumber - 3) @@ -298,9 +303,8 @@ export async function bountyFundingTest< const description = 'Test bounty for funding' // propose a bounty - const bountyProposedEvents = await sendTransaction( - client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), - ) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -315,7 +319,8 @@ export async function bountyFundingTest< expect(bountyFromStorage.status.isProposed).toBe(true) // approve the bounty with origin treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -361,7 +366,7 @@ export async function bountyFundingForApprovedWithCuratorTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // go the block number when the last spend period block - 3 + // Move to spend period boundary to trigger automatic funding const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() await client.dev.setHead(lastSpendPeriodBlockNumber - 3) @@ -374,9 +379,8 @@ export async function bountyFundingForApprovedWithCuratorTest< const description = 'Test bounty for funding with curator' // propose a bounty - const bountyProposedEvents = await sendTransaction( - client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), - ) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -391,13 +395,14 @@ export async function bountyFundingForApprovedWithCuratorTest< expect(bountyFromStorage.status.isProposed).toBe(true) // approve the bounty with origin treasurer with curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.approveBountyWithCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, + const approveBountyWithCuratorTx = client.api.tx.bounties.approveBountyWithCurator( + bountyIndex, + devAccounts.bob.address, + curatorFee, ) + await scheduleInlineCallWithOrigin(client, approveBountyWithCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -457,7 +462,7 @@ export async function curatorAssignmentAndAcceptanceTest< return } - // move client head to the last spend period block - 3 + // Move to spend period boundary to trigger automatic funding const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() await client.dev.setHead(lastSpendPeriodBlockNumber - 3) @@ -468,9 +473,8 @@ export async function curatorAssignmentAndAcceptanceTest< const description = 'Test bounty for funding' // propose a bounty - const bountyProposedEvents = await sendTransaction( - client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), - ) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -485,7 +489,8 @@ export async function curatorAssignmentAndAcceptanceTest< expect(bountyFromStorage.status.isProposed).toBe(true) // approve the bounty with origin treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -515,13 +520,10 @@ export async function curatorAssignmentAndAcceptanceTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -537,7 +539,8 @@ export async function curatorAssignmentAndAcceptanceTest< await client.dev.newBlock() // accept the curator - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -572,7 +575,7 @@ export async function bountyExtensionTest< return } - // move client head to the last spend period block - 3 + // Move to spend period boundary to trigger automatic funding const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() await client.dev.setHead(lastSpendPeriodBlockNumber - 3) @@ -583,9 +586,8 @@ export async function bountyExtensionTest< const description = 'Test bounty for funding' // propose a bounty - const bountyProposedEvents = await sendTransaction( - client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), - ) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -600,7 +602,8 @@ export async function bountyExtensionTest< expect(bountyFromStorage.status.isProposed).toBe(true) // approve the bounty with origin treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -631,13 +634,10 @@ export async function bountyExtensionTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -653,7 +653,8 @@ export async function bountyExtensionTest< await client.dev.newBlock() // accept the curator - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -675,9 +676,8 @@ export async function bountyExtensionTest< const updateDueBefore = bountyForExtending.status.asActive.updateDue.toNumber() // extend the bounty expiry - const extendBountyEvents = await sendTransaction( - client.api.tx.bounties.extendBountyExpiry(bountyIndex, 'Testing the bounty extension').signAsync(devAccounts.bob), - ) + const extendBountyTx = client.api.tx.bounties.extendBountyExpiry(bountyIndex, 'Testing the bounty extension') + const extendBountyEvents = await sendTransaction(extendBountyTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -719,7 +719,7 @@ export async function bountyAwardingAndClaimingTest< return } - // move client head to the last spend period block - 3 + // Move to spend period boundary to trigger automatic funding const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() await client.dev.setHead(lastSpendPeriodBlockNumber - 3) @@ -730,9 +730,8 @@ export async function bountyAwardingAndClaimingTest< const description = 'Test bounty for funding' // propose a bounty - const bountyProposedEvents = await sendTransaction( - client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice), - ) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -747,7 +746,8 @@ export async function bountyAwardingAndClaimingTest< expect(bountyFromStorage.status.isProposed).toBe(true) // approve the bounty with origin treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -778,13 +778,10 @@ export async function bountyAwardingAndClaimingTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -800,7 +797,8 @@ export async function bountyAwardingAndClaimingTest< await client.dev.newBlock() // accept the curator - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -816,9 +814,8 @@ export async function bountyAwardingAndClaimingTest< await client.dev.newBlock() // award the bounty to the beneficiary - const awardBountyEvents = await sendTransaction( - client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address).signAsync(devAccounts.bob), - ) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address) + const awardBountyEvents = await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -842,9 +839,8 @@ export async function bountyAwardingAndClaimingTest< await client.dev.newBlock() // claim the bounty - const claimBountyEvents = await sendTransaction( - client.api.tx.bounties.claimBounty(bountyIndex).signAsync(devAccounts.alice), - ) + const claimBountyTx = client.api.tx.bounties.claimBounty(bountyIndex) + const claimBountyEvents = await sendTransaction(claimBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -886,7 +882,8 @@ export async function bountyClosureProposedTest< const description = 'Test bounty for closure in proposed state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -896,7 +893,8 @@ export async function bountyClosureProposedTest< expect(proposedBounty.status.isProposed).toBe(true) // Close the bounty using Treasurer origin - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + const closeBountyTx = client.api.tx.bounties.closeBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, closeBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -961,13 +959,15 @@ export async function bountyClosureFundedTest< const description = 'Test bounty for closure in funded state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -997,7 +997,8 @@ export async function bountyClosureFundedTest< const treasuryBalanceBeforeClosure = treasuryAccountBeforeClosureInfo.data.free.toBigInt() // Close the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + const closeBountyTx = client.api.tx.bounties.closeBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, closeBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1064,13 +1065,15 @@ export async function bountyClosureActiveTest< const description = 'Test bounty for closure in active state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1091,11 +1094,8 @@ export async function bountyClosureActiveTest< .toMatchSnapshot('bounty became active events') // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1105,7 +1105,8 @@ export async function bountyClosureActiveTest< .toMatchSnapshot('curator proposed events') // Accept curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -1123,7 +1124,8 @@ export async function bountyClosureActiveTest< const curatorReservedBalanceBeforeClosure = curatorBalanceBeforeClosure.data.reserved.toBigInt() // Close the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + const closeBountyTx = client.api.tx.bounties.closeBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, closeBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1173,17 +1175,19 @@ export async function unassignCuratorApprovedWithCuratorTest< const description = 'Test bounty for unassign curator in approved with curator state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) // Approve bounty with curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.approveBountyWithCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, + const approveBountyWithCuratorTx = client.api.tx.bounties.approveBountyWithCurator( + bountyIndex, + devAccounts.bob.address, + curatorFee, ) + await scheduleInlineCallWithOrigin(client, approveBountyWithCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1192,7 +1196,8 @@ export async function unassignCuratorApprovedWithCuratorTest< expect(approvedWithCuratorBounty.status.isApprovedWithCurator).toBe(true) // Unassign curator using Treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) + await scheduleInlineCallWithOrigin(client, unassignCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1241,7 +1246,8 @@ export async function unassignCuratorCuratorProposedTest< const description = 'Test bounty for unassign curator in curator proposed state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -1251,7 +1257,8 @@ export async function unassignCuratorCuratorProposedTest< expect(bountyStatusAfterProposal.status.isProposed).toBe(true) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1280,11 +1287,8 @@ export async function unassignCuratorCuratorProposedTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1293,7 +1297,8 @@ export async function unassignCuratorCuratorProposedTest< expect(curatorProposedBounty.status.isCuratorProposed).toBe(true) // Unassign curator using Treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) + await scheduleInlineCallWithOrigin(client, unassignCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1343,7 +1348,8 @@ export async function unassignCuratorActiveByCuratorTest< const description = 'Test bounty for unassign curator active by curator' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -1358,7 +1364,8 @@ export async function unassignCuratorActiveByCuratorTest< .toMatchSnapshot('bounty proposed events') // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1388,11 +1395,8 @@ export async function unassignCuratorActiveByCuratorTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1406,7 +1410,8 @@ export async function unassignCuratorActiveByCuratorTest< expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) // Accept curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -1424,7 +1429,8 @@ export async function unassignCuratorActiveByCuratorTest< const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() // Unassign curator by curator themselves - await sendTransaction(client.api.tx.bounties.unassignCurator(bountyIndex).signAsync(devAccounts.bob)) + const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) + await sendTransaction(unassignCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -1477,7 +1483,8 @@ export async function unassignCuratorActiveByTreasurerTest< const description = 'Test bounty for unassign curator active by treasurer' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -1492,7 +1499,8 @@ export async function unassignCuratorActiveByTreasurerTest< expect(bountyStatus.status.isProposed).toBe(true) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1522,11 +1530,8 @@ export async function unassignCuratorActiveByTreasurerTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1540,7 +1545,8 @@ export async function unassignCuratorActiveByTreasurerTest< expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) // Accept curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -1558,7 +1564,8 @@ export async function unassignCuratorActiveByTreasurerTest< const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() // Unassign curator by Treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) + await scheduleInlineCallWithOrigin(client, unassignCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1624,7 +1631,8 @@ export async function unassignCuratorPendingPayoutTest< const description = 'Test bounty for unassign curator pending payout' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() @@ -1640,7 +1648,8 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatus.status.isProposed).toBe(true) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1670,11 +1679,8 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1688,7 +1694,8 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) // Accept curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -1702,9 +1709,8 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) // Award the bounty - await sendTransaction( - client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address).signAsync(devAccounts.bob), - ) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address) + await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -1722,7 +1728,8 @@ export async function unassignCuratorPendingPayoutTest< const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() // Unassign curator by Treasurer - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.unassignCurator(bountyIndex).method.toHex(), { + const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) + await scheduleInlineCallWithOrigin(client, unassignCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1890,7 +1897,7 @@ export function bountyFundingTests< } as RootTestTree } -/**≠ +/** * * All success cases for bounty * @@ -1953,13 +1960,15 @@ export async function bountyClosureApprovedTest< const description = 'Test bounty for closure in approved state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1970,7 +1979,8 @@ export async function bountyClosureApprovedTest< expect(approvedBounty.status.isApproved).toBe(true) // Try to close the bounty - should fail - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + const closeBountyTx = client.api.tx.bounties.closeBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, closeBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -1980,7 +1990,7 @@ export async function bountyClosureApprovedTest< .redact({ redactKeys: /task/ }) .toMatchSnapshot('scheduler events when closing bounty with approved state fails') - // check he result of dispatched event + // check the result of dispatched event const events = await client.api.query.system.events() // Find the Dispatched event from scheduler @@ -2039,13 +2049,15 @@ export async function bountyClosurePendingPayoutTest< const description = 'Test bounty for closure in pending payout state' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() // Approve the bounty const bountyIndex = await getBountyIndexFromEvent(client) - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2056,23 +2068,20 @@ export async function bountyClosurePendingPayoutTest< await client.dev.newBlock() // Propose a curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { Origins: 'Treasurer' }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() // Accept curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() // Award the bounty - await sendTransaction( - client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address).signAsync(devAccounts.bob), - ) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address) + await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -2081,7 +2090,8 @@ export async function bountyClosurePendingPayoutTest< expect(pendingPayoutBounty.status.isPendingPayout).toBe(true) // Try to close the bounty - should fail - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.closeBounty(bountyIndex).method.toHex(), { + const closeBountyTx = client.api.tx.bounties.closeBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, closeBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2146,13 +2156,15 @@ async function unassignCuratorActiveStateByPublicPrematureTest< const description = 'Test bounty for premature unassign curator by public' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() // Approve the bounty const bountyIndex = await getBountyIndexFromEvent(client) - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2163,18 +2175,16 @@ async function unassignCuratorActiveStateByPublicPrematureTest< await client.dev.newBlock() // Propose Bob as curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() // Bob accepts curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -2184,7 +2194,8 @@ async function unassignCuratorActiveStateByPublicPrematureTest< // Charlie (public user) tries to unassign curator immediately (premature) // Using scheduleInlineCallWithOrigin to simulate public call - await sendTransaction(client.api.tx.bounties.unassignCurator(bountyIndex).signAsync(devAccounts.charlie)) + const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) + await sendTransaction(unassignCuratorTx.signAsync(devAccounts.charlie)) await client.dev.newBlock() @@ -2315,13 +2326,10 @@ async function invalidIndexApprovalTest< await setupTestAccounts(client, ['alice']) // approve transaction with origin treasurer - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.approveBounty(nonExistentBountyIndex).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const approveBountyTx = client.api.tx.bounties.approveBounty(nonExistentBountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -2362,7 +2370,8 @@ async function unexpectedStatusProposeCuratorTest< const description = 'Test bounty for curator proposal' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -2370,13 +2379,10 @@ async function unexpectedStatusProposeCuratorTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // propose curator by Treasurer - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() @@ -2426,13 +2432,15 @@ async function requireCuratorAcceptTest< const description = 'Test bounty for curator requirement' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2445,19 +2453,15 @@ async function requireCuratorAcceptTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Propose Bob as curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() // Charlie tries to accept curator role (should be Bob) const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.charlie)) await client.dev.newBlock() @@ -2509,13 +2513,15 @@ async function hasActiveChildBountyTest< const description = 'Test bounty for child bounty check' // Propose a bounty - await sendTransaction(client.api.tx.bounties.proposeBounty(bountyValue, description).signAsync(devAccounts.alice)) + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) // Approve the bounty - await scheduleInlineCallWithOrigin(client, client.api.tx.bounties.approveBounty(bountyIndex).method.toHex(), { + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2528,18 +2534,16 @@ async function hasActiveChildBountyTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Propose Bob as curator - await scheduleInlineCallWithOrigin( - client, - client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee).method.toHex(), - { - Origins: 'Treasurer', - }, - ) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) await client.dev.newBlock() // Bob accepts curator role - await sendTransaction(client.api.tx.bounties.acceptCurator(bountyIndex).signAsync(devAccounts.bob)) + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -2550,12 +2554,12 @@ async function hasActiveChildBountyTest< // Note: The curator (Bob) should create the child bounty, not Alice const childBountyValue = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Smaller value for child bounty const childBountyDescription = 'Test child bounty' - - await sendTransaction( - client.api.tx.childBounties - .addChildBounty(bountyIndex, childBountyValue, childBountyDescription) - .signAsync(devAccounts.bob), // Bob is the curator, so he should create the child bounty + const addChildBountyTx = client.api.tx.childBounties.addChildBounty( + bountyIndex, + childBountyValue, + childBountyDescription, ) + await sendTransaction(addChildBountyTx.signAsync(devAccounts.bob)) await client.dev.newBlock() @@ -2569,9 +2573,8 @@ async function hasActiveChildBountyTest< expect(parentBounty.status.isActive).toBe(true) // award the parent bounty - await sendTransaction( - client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.bob.address).signAsync(devAccounts.bob), - ) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.bob.address) + await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) await client.dev.newBlock() From ed92bea0c6293c7475d57f8535785fbc4240ada7 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Wed, 24 Sep 2025 21:05:32 +0530 Subject: [PATCH 56/66] readme: added bounties tests convered --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 4ffa43bc0..aec7e4245 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,18 @@ These include: - Requesting judgement requests on registrars, and providing it - Adding registrars to the people chain by sending, from the relay chain, an XCM call with root origin - Adding, modifying, and removing subidentities for an account +- E2E test suite for bounties infrastructure: + - Bounty creation, approval, and funding workflows + - Curator assignment, acceptance, and management + - Bounty extension, awarding, and claiming processes + - Bounty closure in various states (proposed, funded, active) + - Curator unassignment scenarios (by curator themselves vs. treasurer) + - Comprehensive failure mode testing: + - Invalid bounty values and descriptions + - Premature curator unassignment + - Bounty closure restrictions (approved/pending payout states) + - Non-curator attempting to accept curator role + - Child bounty constraints preventing parent bounty closure The intent behind these end-to-end tests is to cover the basic behavior of relay chains' and system parachains' runtimes. From 379c601f87fc02167600076575544478f1e8364c Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 26 Sep 2025 17:17:53 +0530 Subject: [PATCH 57/66] devAccounts replaced with testAccounts --- packages/shared/src/bounties.ts | 176 +++++++++++++++++--------------- 1 file changed, 91 insertions(+), 85 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 96ac04ff3..0577d68a1 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -1,6 +1,6 @@ import { sendTransaction } from '@acala-network/chopsticks-testing' -import { type Chain, defaultAccountsSr25519 as devAccounts } from '@e2e-test/networks' +import { type Chain, testAccounts } from '@e2e-test/networks' import { type Client, setupNetworks } from '@e2e-test/shared' import { assert, expect } from 'vitest' @@ -55,9 +55,9 @@ async function getBountyApprovals(client: Client): Promise { */ async function setupTestAccounts(client: Client, accounts: string[] = ['alice', 'bob']) { const accountMap = { - alice: devAccounts.alice.address, - bob: devAccounts.bob.address, - charlie: devAccounts.charlie.address, + alice: testAccounts.alice.address, + bob: testAccounts.bob.address, + charlie: testAccounts.charlie.address, } const accountData = accounts @@ -124,7 +124,7 @@ export async function bountyCreationTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - const bountyProposalEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + const bountyProposalEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -175,7 +175,7 @@ export async function bountyApprovalTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -232,7 +232,7 @@ export async function bountyApprovalWithCuratorTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -244,7 +244,7 @@ export async function bountyApprovalWithCuratorTest< // Approve the bounty with curator const approveBountyWithCuratorTx = client.api.tx.bounties.approveBountyWithCurator( bountyIndex, - devAccounts.bob.address, + testAccounts.bob.address, curatorFee, ) await scheduleInlineCallWithOrigin(client, approveBountyWithCuratorTx.method.toHex(), { @@ -304,7 +304,7 @@ export async function bountyFundingTest< // propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -380,7 +380,7 @@ export async function bountyFundingForApprovedWithCuratorTest< // propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -397,7 +397,7 @@ export async function bountyFundingForApprovedWithCuratorTest< // approve the bounty with origin treasurer with curator const approveBountyWithCuratorTx = client.api.tx.bounties.approveBountyWithCurator( bountyIndex, - devAccounts.bob.address, + testAccounts.bob.address, curatorFee, ) await scheduleInlineCallWithOrigin(client, approveBountyWithCuratorTx.method.toHex(), { @@ -474,7 +474,7 @@ export async function curatorAssignmentAndAcceptanceTest< // propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -520,7 +520,7 @@ export async function curatorAssignmentAndAcceptanceTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -540,7 +540,7 @@ export async function curatorAssignmentAndAcceptanceTest< // accept the curator const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -587,7 +587,7 @@ export async function bountyExtensionTest< // propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -634,7 +634,7 @@ export async function bountyExtensionTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -654,7 +654,7 @@ export async function bountyExtensionTest< // accept the curator const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -677,7 +677,7 @@ export async function bountyExtensionTest< // extend the bounty expiry const extendBountyTx = client.api.tx.bounties.extendBountyExpiry(bountyIndex, 'Testing the bounty extension') - const extendBountyEvents = await sendTransaction(extendBountyTx.signAsync(devAccounts.bob)) + const extendBountyEvents = await sendTransaction(extendBountyTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -714,14 +714,20 @@ export async function bountyAwardingAndClaimingTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + const spendPeriod = await client.api.consts.treasury.spendPeriod + let currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - // Move to spend period boundary to trigger automatic funding - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() await setupTestAccounts(client, ['alice', 'bob', 'charlie']) @@ -731,7 +737,7 @@ export async function bountyAwardingAndClaimingTest< // propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -778,7 +784,7 @@ export async function bountyAwardingAndClaimingTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // assign curator to the bounty - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -798,7 +804,7 @@ export async function bountyAwardingAndClaimingTest< // accept the curator const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -814,8 +820,8 @@ export async function bountyAwardingAndClaimingTest< await client.dev.newBlock() // award the bounty to the beneficiary - const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address) - const awardBountyEvents = await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, testAccounts.alice.address) + const awardBountyEvents = await sendTransaction(awardBountyTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -829,7 +835,7 @@ export async function bountyAwardingAndClaimingTest< expect(bountyAwarded.status.isPendingPayout).toBe(true) // Calculate the claimable at block number - const currentBlock = await client.api.rpc.chain.getHeader() + currentBlock = await client.api.rpc.chain.getHeader() const bountyDepositPayoutDelay = await client.api.consts.bounties.bountyDepositPayoutDelay const claimableAtBlock = currentBlock.number.toNumber() + Number(bountyDepositPayoutDelay.toNumber()) @@ -840,7 +846,7 @@ export async function bountyAwardingAndClaimingTest< // claim the bounty const claimBountyTx = client.api.tx.bounties.claimBounty(bountyIndex) - const claimBountyEvents = await sendTransaction(claimBountyTx.signAsync(devAccounts.alice)) + const claimBountyEvents = await sendTransaction(claimBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -883,7 +889,7 @@ export async function bountyClosureProposedTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -919,7 +925,7 @@ export async function bountyClosureProposedTest< expect(descriptionAfterClosure).toBeNull() // Verify proposer's bond was slashed - const finalBalance = await client.api.query.system.account(devAccounts.alice.address) + const finalBalance = await client.api.query.system.account(testAccounts.alice.address) const reservedBalance = finalBalance.data.reserved.toBigInt() // The bond should be slashed (not returned to free balance) @@ -960,7 +966,7 @@ export async function bountyClosureFundedTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -1066,7 +1072,7 @@ export async function bountyClosureActiveTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -1094,7 +1100,7 @@ export async function bountyClosureActiveTest< .toMatchSnapshot('bounty became active events') // Propose a curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1106,7 +1112,7 @@ export async function bountyClosureActiveTest< // Accept curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -1120,7 +1126,7 @@ export async function bountyClosureActiveTest< expect(activeBounty.status.isActive).toBe(true) // Get curator reserved balance before closure - const curatorBalanceBeforeClosure = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceBeforeClosure = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceBeforeClosure = curatorBalanceBeforeClosure.data.reserved.toBigInt() // Close the bounty @@ -1146,7 +1152,7 @@ export async function bountyClosureActiveTest< expect(bountyAfterClosure).toBeNull() // Verify curator deposit was refunded - const curatorBalanceAfterClosure = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceAfterClosure = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceAfterClosure = curatorBalanceAfterClosure.data.reserved.toBigInt() expect(curatorReservedBalanceBeforeClosure).toBeGreaterThan(curatorReservedBalanceAfterClosure) @@ -1176,7 +1182,7 @@ export async function unassignCuratorApprovedWithCuratorTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -1184,7 +1190,7 @@ export async function unassignCuratorApprovedWithCuratorTest< // Approve bounty with curator const approveBountyWithCuratorTx = client.api.tx.bounties.approveBountyWithCurator( bountyIndex, - devAccounts.bob.address, + testAccounts.bob.address, curatorFee, ) await scheduleInlineCallWithOrigin(client, approveBountyWithCuratorTx.method.toHex(), { Origins: 'Treasurer' }) @@ -1247,7 +1253,7 @@ export async function unassignCuratorCuratorProposedTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -1287,7 +1293,7 @@ export async function unassignCuratorCuratorProposedTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1349,7 +1355,7 @@ export async function unassignCuratorActiveByCuratorTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -1395,7 +1401,7 @@ export async function unassignCuratorActiveByCuratorTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1411,7 +1417,7 @@ export async function unassignCuratorActiveByCuratorTest< // Accept curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -1425,12 +1431,12 @@ export async function unassignCuratorActiveByCuratorTest< expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) // Get curator reserved balance before unassign - const curatorBalanceBefore = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceBefore = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() // Unassign curator by curator themselves const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) - await sendTransaction(unassignCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(unassignCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -1444,7 +1450,7 @@ export async function unassignCuratorActiveByCuratorTest< expect(bountyAfterUnassign.status.isFunded).toBe(true) // Verify curator deposit was refunded as the caller is the curator so dont slash the curator - const curatorBalanceAfter = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceAfter = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceAfter = curatorBalanceAfter.data.reserved.toBigInt() expect(curatorReservedBalanceAfter).toBeLessThan(curatorReservedBalanceBefore) @@ -1484,7 +1490,7 @@ export async function unassignCuratorActiveByTreasurerTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -1530,7 +1536,7 @@ export async function unassignCuratorActiveByTreasurerTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1546,7 +1552,7 @@ export async function unassignCuratorActiveByTreasurerTest< // Accept curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -1560,7 +1566,7 @@ export async function unassignCuratorActiveByTreasurerTest< expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) // Get curator balance before unassign - const curatorBalanceBefore = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceBefore = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() // Unassign curator by Treasurer @@ -1591,7 +1597,7 @@ export async function unassignCuratorActiveByTreasurerTest< expect(bountyAfterUnassign.status.isFunded).toBe(true) // Verify curator deposit was slashed - const curatorBalanceAfter = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceAfter = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceAfter = curatorBalanceAfter.data.reserved.toBigInt() expect(curatorReservedBalanceBefore).toBeGreaterThan(curatorReservedBalanceAfter) @@ -1632,7 +1638,7 @@ export async function unassignCuratorPendingPayoutTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -1679,7 +1685,7 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatusAfterFunding.status.isFunded).toBe(true) // Propose a curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() @@ -1695,7 +1701,7 @@ export async function unassignCuratorPendingPayoutTest< // Accept curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -1709,8 +1715,8 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) // Award the bounty - const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address) - await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, testAccounts.alice.address) + await sendTransaction(awardBountyTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -1724,7 +1730,7 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyStatusAfterAwarding.status.isPendingPayout).toBe(true) // Get curator reserved balance before unassign - const curatorBalanceBefore = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceBefore = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceBefore = curatorBalanceBefore.data.reserved.toBigInt() // Unassign curator by Treasurer @@ -1755,7 +1761,7 @@ export async function unassignCuratorPendingPayoutTest< expect(bountyAfterUnassign.status.isFunded).toBe(true) // Verify curator reserved balance was slashed - const curatorBalanceAfter = await client.api.query.system.account(devAccounts.bob.address) + const curatorBalanceAfter = await client.api.query.system.account(testAccounts.bob.address) const curatorReservedBalanceAfter = curatorBalanceAfter.data.reserved.toBigInt() expect(curatorReservedBalanceBefore).toBeGreaterThan(curatorReservedBalanceAfter) @@ -1961,7 +1967,7 @@ export async function bountyClosureApprovedTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -2050,7 +2056,7 @@ export async function bountyClosurePendingPayoutTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -2068,20 +2074,20 @@ export async function bountyClosurePendingPayoutTest< await client.dev.newBlock() // Propose a curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) await client.dev.newBlock() // Accept curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() // Award the bounty - const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.alice.address) - await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, testAccounts.alice.address) + await sendTransaction(awardBountyTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -2157,7 +2163,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -2175,7 +2181,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< await client.dev.newBlock() // Propose Bob as curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2184,7 +2190,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< // Bob accepts curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -2195,7 +2201,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< // Charlie (public user) tries to unassign curator immediately (premature) // Using scheduleInlineCallWithOrigin to simulate public call const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) - await sendTransaction(unassignCuratorTx.signAsync(devAccounts.charlie)) + await sendTransaction(unassignCuratorTx.signAsync(testAccounts.charlie)) await client.dev.newBlock() @@ -2244,7 +2250,7 @@ async function reasonTooBigTest< const proposeTx = client.api.tx.bounties.proposeBounty(bountyValue, longDescription) - await sendTransaction(proposeTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -2288,7 +2294,7 @@ async function invalidValueTest< const proposeTx = client.api.tx.bounties.proposeBounty(invalidValue, description) - await sendTransaction(proposeTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeTx.signAsync(testAccounts.alice)) await client.dev.newBlock() @@ -2371,7 +2377,7 @@ async function unexpectedStatusProposeCuratorTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -2379,7 +2385,7 @@ async function unexpectedStatusProposeCuratorTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // propose curator by Treasurer - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2433,7 +2439,7 @@ async function requireCuratorAcceptTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -2453,7 +2459,7 @@ async function requireCuratorAcceptTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Propose Bob as curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2462,7 +2468,7 @@ async function requireCuratorAcceptTest< // Charlie tries to accept curator role (should be Bob) const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.charlie)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.charlie)) await client.dev.newBlock() @@ -2514,7 +2520,7 @@ async function hasActiveChildBountyTest< // Propose a bounty const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) - await sendTransaction(proposeBountyTx.signAsync(devAccounts.alice)) + await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) await client.dev.newBlock() const bountyIndex = await getBountyIndexFromEvent(client) @@ -2534,7 +2540,7 @@ async function hasActiveChildBountyTest< const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Propose Bob as curator - const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, devAccounts.bob.address, curatorFee) + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer', }) @@ -2543,7 +2549,7 @@ async function hasActiveChildBountyTest< // Bob accepts curator role const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) - await sendTransaction(acceptCuratorTx.signAsync(devAccounts.bob)) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -2559,7 +2565,7 @@ async function hasActiveChildBountyTest< childBountyValue, childBountyDescription, ) - await sendTransaction(addChildBountyTx.signAsync(devAccounts.bob)) + await sendTransaction(addChildBountyTx.signAsync(testAccounts.bob)) await client.dev.newBlock() @@ -2573,8 +2579,8 @@ async function hasActiveChildBountyTest< expect(parentBounty.status.isActive).toBe(true) // award the parent bounty - const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, devAccounts.bob.address) - await sendTransaction(awardBountyTx.signAsync(devAccounts.bob)) + const awardBountyTx = client.api.tx.bounties.awardBounty(bountyIndex, testAccounts.bob.address) + await sendTransaction(awardBountyTx.signAsync(testAccounts.bob)) await client.dev.newBlock() From 67da6c03d371d4c729de25282ea7efb43c307484 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 26 Sep 2025 17:41:05 +0530 Subject: [PATCH 58/66] set the lastSpendPeriod such that the next spend is few block ahead --- packages/shared/src/bounties.ts | 328 ++++++++++++++++++++------------ 1 file changed, 203 insertions(+), 125 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 0577d68a1..c1b7da437 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -86,14 +86,6 @@ async function getBountyIndexFromEvent(client: Client): Promise { - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping test') - return false - } - return true -} - /// ------- /// Tests /// ------- @@ -287,16 +279,22 @@ export async function bountyFundingTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - // Move to spend period boundary to trigger automatic funding - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - await setupTestAccounts(client, ['alice', 'bob']) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens @@ -366,12 +364,22 @@ export async function bountyFundingForApprovedWithCuratorTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // Move to spend period boundary to trigger automatic funding - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - await setupTestAccounts(client, ['alice', 'bob']) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) + + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens @@ -457,16 +465,22 @@ export async function curatorAssignmentAndAcceptanceTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - // Move to spend period boundary to trigger automatic funding - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) - await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens @@ -570,16 +584,22 @@ export async function bountyExtensionTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - // Move to spend period boundary to trigger automatic funding - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens @@ -714,6 +734,8 @@ export async function bountyAwardingAndClaimingTest< >(chain: Chain) { const [client] = await setupNetworks(chain) + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + const spendPeriod = await client.api.consts.treasury.spendPeriod let currentBlock = await client.api.rpc.chain.getHeader() const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 @@ -729,8 +751,6 @@ export async function bountyAwardingAndClaimingTest< await client.dev.newBlock() - await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens const description = 'Test bounty for funding' @@ -949,16 +969,22 @@ export async function bountyClosureFundedTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // Move to spend period - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty closure funded test') - return - } - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - await setupTestAccounts(client, ['alice', 'bob']) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) + + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -1054,16 +1080,22 @@ export async function bountyClosureActiveTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - // Move to spend period - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) - await setupTestAccounts(client, ['alice', 'bob']) + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -1235,16 +1267,22 @@ export async function unassignCuratorCuratorProposedTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - // Move to spend period - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - await setupTestAccounts(client, ['alice', 'bob']) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -1337,16 +1375,22 @@ export async function unassignCuratorActiveByCuratorTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - // Move to spend period - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - await setupTestAccounts(client, ['alice', 'bob']) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -1472,16 +1516,22 @@ export async function unassignCuratorActiveByTreasurerTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (!ensureSpendPeriodAvailable(lastSpendPeriodBlock)) { - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - // Move to spend period - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - await setupTestAccounts(client, ['alice', 'bob']) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -1619,17 +1669,22 @@ export async function unassignCuratorPendingPayoutTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping unassign curator pending payout test') - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - // Move to spend period - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - await setupTestAccounts(client, ['alice', 'bob']) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -2037,17 +2092,22 @@ export async function bountyClosurePendingPayoutTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping bounty closure pending payout test') - return - } + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) - // Move to spend period - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) - await setupTestAccounts(client, ['alice', 'bob']) + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER @@ -2145,17 +2205,23 @@ async function unassignCuratorActiveStateByPublicPrematureTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // move to spend period - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping unassign curator active state by public premature test') - return - } - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) - await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) + + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() + const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER @@ -2422,17 +2488,23 @@ async function requireCuratorAcceptTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // move client head to the last spend period block - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping curator assignment test') - return - } - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) - await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) + + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() + const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER const description = 'Test bounty for curator requirement' @@ -2503,16 +2575,22 @@ async function hasActiveChildBountyTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - // move client head to the last spend period block - const lastSpendPeriodBlock = await client.api.query.treasury.lastSpendPeriod() - if (lastSpendPeriodBlock.isNone) { - console.warn('Last spend period block is none, skipping child bounty test') - return - } - const lastSpendPeriodBlockNumber = lastSpendPeriodBlock.unwrap().toNumber() - await client.dev.setHead(lastSpendPeriodBlockNumber - 3) + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - await setupTestAccounts(client, ['alice', 'bob']) + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) + + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + + await client.dev.newBlock() const existentialDeposit = client.api.consts.balances.existentialDeposit const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER From 6a0f9fc5c4963864b4241b6016c279f8b933b802 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Fri, 26 Sep 2025 17:49:09 +0530 Subject: [PATCH 59/66] snapshot of bounties updated --- .../kusama.bounties.e2e.test.ts.snap | 38 +++++++++---------- .../polkadot.bounties.e2e.test.ts.snap | 38 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap index f74cc5ba6..674335c73 100644 --- a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap +++ b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap @@ -103,7 +103,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -116,7 +116,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -190,7 +190,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -203,7 +203,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -297,7 +297,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests [ { "data": { - "beneficiary": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "beneficiary": "D8ew585BL5H1ALhn4kmJoxhgqcgKDZLPc6xunJNv4mmrBns", "index": "(redacted)", }, "method": "BountyAwarded", @@ -335,7 +335,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -348,7 +348,7 @@ exports[`Kusama Bounties > All bounty success tests > All curator unassign tests { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -426,7 +426,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bou { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -439,7 +439,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bou { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -542,7 +542,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty approval tests > Bo { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -566,7 +566,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claimi [ { "data": { - "beneficiary": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "beneficiary": "D8ew585BL5H1ALhn4kmJoxhgqcgKDZLPc6xunJNv4mmrBns", "index": "(redacted)", }, "method": "BountyAwarded", @@ -581,7 +581,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claimi [ { "data": { - "beneficiary": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "beneficiary": "D8ew585BL5H1ALhn4kmJoxhgqcgKDZLPc6xunJNv4mmrBns", "index": "(redacted)", "payout": "(rounded 300000000000)", }, @@ -608,7 +608,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claimi { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -621,7 +621,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claimi { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -672,7 +672,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty extension > curator { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -685,7 +685,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty extension > curator { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -750,7 +750,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bou { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", @@ -801,7 +801,7 @@ exports[`Kusama Bounties > All bounty success tests > Curator assignment and acc { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorAccepted", "section": "bounties", @@ -814,7 +814,7 @@ exports[`Kusama Bounties > All bounty success tests > Curator assignment and acc { "data": { "bountyId": "(redacted)", - "curator": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", }, "method": "CuratorProposed", "section": "bounties", diff --git a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap index 054a432d6..979396a6e 100644 --- a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap +++ b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap @@ -103,7 +103,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -116,7 +116,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -190,7 +190,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -203,7 +203,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -297,7 +297,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes [ { "data": { - "beneficiary": "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", + "beneficiary": "1ZLR63GQkKph3XmxzziZ1RrPsL6CrJJ1izhgR1mzMaoHZJA", "index": "(redacted)", }, "method": "BountyAwarded", @@ -335,7 +335,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -348,7 +348,7 @@ exports[`Polkadot Bounties > All bounty success tests > All curator unassign tes { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -426,7 +426,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > B { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -439,7 +439,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > B { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -542,7 +542,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty approval tests > { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -566,7 +566,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and clai [ { "data": { - "beneficiary": "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", + "beneficiary": "1ZLR63GQkKph3XmxzziZ1RrPsL6CrJJ1izhgR1mzMaoHZJA", "index": "(redacted)", }, "method": "BountyAwarded", @@ -581,7 +581,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and clai [ { "data": { - "beneficiary": "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", + "beneficiary": "1ZLR63GQkKph3XmxzziZ1RrPsL6CrJJ1izhgR1mzMaoHZJA", "index": "(redacted)", "payout": 9000000000000, }, @@ -608,7 +608,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and clai { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -621,7 +621,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and clai { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -672,7 +672,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty extension > curat { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -685,7 +685,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty extension > curat { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -750,7 +750,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > B { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", @@ -801,7 +801,7 @@ exports[`Polkadot Bounties > All bounty success tests > Curator assignment and a { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorAccepted", "section": "bounties", @@ -814,7 +814,7 @@ exports[`Polkadot Bounties > All bounty success tests > Curator assignment and a { "data": { "bountyId": "(redacted)", - "curator": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", }, "method": "CuratorProposed", "section": "bounties", From 656ddd4881adf3da12b81fdc232df6b0f11fcf37 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 30 Sep 2025 00:47:18 +0530 Subject: [PATCH 60/66] added setLastSpendPeriodBlockNumber() fn for repeated logic --- packages/shared/src/bounties.ts | 228 ++++++-------------------------- 1 file changed, 44 insertions(+), 184 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index c1b7da437..e27f91089 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -12,6 +12,12 @@ import type { RootTestTree } from './types.js' /// Helpers /// ------- +// initial funding balance for accounts +const TEST_ACCOUNT_BALANCE = 100000000000000n + +// 4 blocks before the spend period block +const TREASURY_SETUP_OFFSET = 4 + // multipliers for the bounty and curator fee // 1000x existential deposit for substantial bounty value const BOUNTY_MULTIPLIER = 1000n @@ -64,7 +70,7 @@ async function setupTestAccounts(client: Client, accounts: string[] = .filter((account) => accountMap[account as keyof typeof accountMap]) .map((account) => [ [accountMap[account as keyof typeof accountMap]], - { providers: 1, data: { free: 100000000000000n } }, + { providers: 1, data: { free: TEST_ACCOUNT_BALANCE } }, ]) await client.dev.setStorage({ @@ -86,6 +92,25 @@ async function getBountyIndexFromEvent(client: Client): Promise) { + const spendPeriod = await client.api.consts.treasury.spendPeriod + const currentBlock = await client.api.rpc.chain.getHeader() + const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + TREASURY_SETUP_OFFSET + await client.dev.setStorage({ + Treasury: { + lastSpendPeriod: newLastSpendPeriodBlockNumber, + }, + }) + + // ensure the last spend period block number is updated in storage + const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() + expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) +} + /// ------- /// Tests /// ------- @@ -281,18 +306,7 @@ export async function bountyFundingTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -366,18 +380,7 @@ export async function bountyFundingForApprovedWithCuratorTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -467,18 +470,7 @@ export async function curatorAssignmentAndAcceptanceTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -586,18 +578,7 @@ export async function bountyExtensionTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -736,18 +717,7 @@ export async function bountyAwardingAndClaimingTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - let currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -855,7 +825,7 @@ export async function bountyAwardingAndClaimingTest< expect(bountyAwarded.status.isPendingPayout).toBe(true) // Calculate the claimable at block number - currentBlock = await client.api.rpc.chain.getHeader() + const currentBlock = await client.api.rpc.chain.getHeader() const bountyDepositPayoutDelay = await client.api.consts.bounties.bountyDepositPayoutDelay const claimableAtBlock = currentBlock.number.toNumber() + Number(bountyDepositPayoutDelay.toNumber()) @@ -971,18 +941,7 @@ export async function bountyClosureFundedTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -1082,18 +1041,7 @@ export async function bountyClosureActiveTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -1269,18 +1217,7 @@ export async function unassignCuratorCuratorProposedTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -1377,18 +1314,7 @@ export async function unassignCuratorActiveByCuratorTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -1518,18 +1444,7 @@ export async function unassignCuratorActiveByTreasurerTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -1671,18 +1586,7 @@ export async function unassignCuratorPendingPayoutTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -2094,18 +1998,7 @@ export async function bountyClosurePendingPayoutTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -2207,18 +2100,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -2393,7 +2275,7 @@ async function invalidIndexApprovalTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const nonExistentBountyIndex = 999 + const nonExistentBountyIndex = 999 // random index that doesn't exist await setupTestAccounts(client, ['alice']) @@ -2490,18 +2372,7 @@ async function requireCuratorAcceptTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -2577,18 +2448,7 @@ async function hasActiveChildBountyTest< await setupTestAccounts(client, ['alice', 'bob', 'charlie']) - const spendPeriod = await client.api.consts.treasury.spendPeriod - const currentBlock = await client.api.rpc.chain.getHeader() - const newLastSpendPeriodBlockNumber = currentBlock.number.toNumber() - spendPeriod.toNumber() + 4 - await client.dev.setStorage({ - Treasury: { - lastSpendPeriod: newLastSpendPeriodBlockNumber, - }, - }) - - // ensure the last spend period block number is updated in storage - const fetchedLastSpendPeriodBlockNumber = await client.api.query.treasury.lastSpendPeriod() - expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) + await setLastSpendPeriodBlockNumber(client) await client.dev.newBlock() @@ -2636,7 +2496,7 @@ async function hasActiveChildBountyTest< expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) // Note: The curator (Bob) should create the child bounty, not Alice - const childBountyValue = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // Smaller value for child bounty + const childBountyValue = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER // value for child bounty const childBountyDescription = 'Test child bounty' const addChildBountyTx = client.api.tx.childBounties.addChildBounty( bountyIndex, From 7fb4b4f8b8afe6adf714f6e5981c86ed28a98472 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 30 Sep 2025 00:49:17 +0530 Subject: [PATCH 61/66] added extractExtrinsicFailedEvent() for repeated logic --- packages/shared/src/bounties.ts | 47 +++++++++++++-------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index e27f91089..33c3cd9ea 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -111,6 +111,19 @@ async function setLastSpendPeriodBlockNumber(client: Client) { expect(fetchedLastSpendPeriodBlockNumber.unwrap().toNumber()).toBe(newLastSpendPeriodBlockNumber) } +async function extractExtrinsicFailedEvent(client: Client): Promise { + const events = await client.api.query.system.events() + const [ev] = events.filter((record) => { + const { event } = record + return event.section === 'system' && event.method === 'ExtrinsicFailed' + }) + + if (!ev) { + throw new Error('No ExtrinsicFailed event found') + } + return ev +} + /// ------- /// Tests /// ------- @@ -2154,12 +2167,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< await client.dev.newBlock() // Check the result of dispatched event - const events = await client.api.query.system.events() - - const [ev] = events.filter((record) => { - const { event } = record - return event.section === 'system' && event.method === 'ExtrinsicFailed' - }) + const ev = await extractExtrinsicFailedEvent(client) assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) const dispatchError = ev.event.data.dispatchError @@ -2203,12 +2211,7 @@ async function reasonTooBigTest< await client.dev.newBlock() // Check for ExtrinsicFailed event - const events = await client.api.query.system.events() - - const [ev] = events.filter((record) => { - const { event } = record - return event.section === 'system' && event.method === 'ExtrinsicFailed' - }) + const ev = await extractExtrinsicFailedEvent(client) assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) const dispatchError = ev.event.data.dispatchError @@ -2247,12 +2250,7 @@ async function invalidValueTest< await client.dev.newBlock() // Check for ExtrinsicFailed event - const events = await client.api.query.system.events() - - const [ev] = events.filter((record) => { - const { event } = record - return event.section === 'system' && event.method === 'ExtrinsicFailed' - }) + const ev = await extractExtrinsicFailedEvent(client) assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) const dispatchError = ev.event.data.dispatchError @@ -2416,12 +2414,7 @@ async function requireCuratorAcceptTest< await client.dev.newBlock() // Check for ExtrinsicFailed event - const events = await client.api.query.system.events() - - const [ev] = events.filter((record) => { - const { event } = record - return event.section === 'system' && event.method === 'ExtrinsicFailed' - }) + const ev = await extractExtrinsicFailedEvent(client) assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) const dispatchError = ev.event.data.dispatchError @@ -2522,11 +2515,7 @@ async function hasActiveChildBountyTest< await client.dev.newBlock() - const events = await client.api.query.system.events() - const [ev] = events.filter((record) => { - const { event } = record - return event.section === 'system' && event.method === 'ExtrinsicFailed' - }) + const ev = await extractExtrinsicFailedEvent(client) assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) const dispatchError = ev.event.data.dispatchError From 871110a8a5ec74d6fccbdb8c1999ae34ef5e40a9 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 30 Sep 2025 00:57:27 +0530 Subject: [PATCH 62/66] minor improvements --- packages/shared/src/bounties.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 33c3cd9ea..578bf3c76 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -15,14 +15,14 @@ import type { RootTestTree } from './types.js' // initial funding balance for accounts const TEST_ACCOUNT_BALANCE = 100000000000000n +const NON_EXISTENT_BOUNTY_INDEX = 999 // randombounty index that doesn't exist + // 4 blocks before the spend period block const TREASURY_SETUP_OFFSET = 4 // multipliers for the bounty and curator fee -// 1000x existential deposit for substantial bounty value -const BOUNTY_MULTIPLIER = 1000n -// 10% curator fee (100/1000) -const CURATOR_FEE_MULTIPLIER = 100n +const BOUNTY_MULTIPLIER = 1000n // 1000x existential deposit for substantial bounty value +const CURATOR_FEE_MULTIPLIER = 100n // 10% curator fee (100/1000) /** * Get the current bounty count @@ -357,8 +357,8 @@ export async function bountyFundingTest< .toMatchSnapshot('bounty approved events') // verify the bounty is added to the approvals queue - const approvalsforStorage = await getBountyApprovals(client) - expect(approvalsforStorage).toContain(bountyIndex) + const approvalsFromStorage = await getBountyApprovals(client) + expect(approvalsFromStorage).toContain(bountyIndex) await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block @@ -521,8 +521,8 @@ export async function curatorAssignmentAndAcceptanceTest< .toMatchSnapshot('bounty approved events') // verify the bounty is added to the approvals queue - const approvalsforStorage = await getBountyApprovals(client) - expect(approvalsforStorage).toContain(bountyIndex) + const approvalsFromStorage = await getBountyApprovals(client) + expect(approvalsFromStorage).toContain(bountyIndex) await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block @@ -629,8 +629,8 @@ export async function bountyExtensionTest< .toMatchSnapshot('bounty approved events') // verify the bounty is added to the approvals queue - const approvalsforStorage = await getBountyApprovals(client) - expect(approvalsforStorage).toContain(bountyIndex) + const approvalsFromStorage = await getBountyApprovals(client) + expect(approvalsFromStorage).toContain(bountyIndex) await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block @@ -768,8 +768,8 @@ export async function bountyAwardingAndClaimingTest< .toMatchSnapshot('bounty approved events') // verify the bounty is added to the approvals queue - const approvalsforStorage = await getBountyApprovals(client) - expect(approvalsforStorage).toContain(bountyIndex) + const approvalsFromStorage = await getBountyApprovals(client) + expect(approvalsFromStorage).toContain(bountyIndex) await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block @@ -2202,7 +2202,7 @@ async function reasonTooBigTest< const maxReasonLength = client.api.consts.bounties.maximumReasonLength.toNumber() // Create a description that exceeds the maximum length - const longDescription = 'x'.repeat(maxReasonLength + 1000) + const longDescription = 'x'.repeat(maxReasonLength + 1) const proposeTx = client.api.tx.bounties.proposeBounty(bountyValue, longDescription) @@ -2273,7 +2273,7 @@ async function invalidIndexApprovalTest< >(chain: Chain) { const [client] = await setupNetworks(chain) - const nonExistentBountyIndex = 999 // random index that doesn't exist + const nonExistentBountyIndex = NON_EXISTENT_BOUNTY_INDEX // random index that doesn't exist await setupTestAccounts(client, ['alice']) From 1598eb0e6e4e2276f1288cb899885b7673064f23 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Tue, 30 Sep 2025 08:15:42 +0530 Subject: [PATCH 63/66] linter warning fixed --- packages/shared/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index a3dc117c9..90d48a106 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,4 +1,5 @@ export * from './accounts.js' +export * from './bounties.js' export * from './collectives.js' export * from './governance.js' export * from './helpers/index.js' @@ -13,4 +14,3 @@ export * from './staking.js' export * from './treasury.js' export * from './types.js' export * from './vesting.js' -export * from './bounties.js' \ No newline at end of file From 5a11ba611ee365db83432ca9d142dbd01e305770 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 6 Oct 2025 02:11:15 +0530 Subject: [PATCH 64/66] empty events fixed and docs updated --- packages/shared/src/bounties.ts | 586 ++++++++++++++++++++++++-------- 1 file changed, 440 insertions(+), 146 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 578bf3c76..26cc36fdf 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -13,7 +13,7 @@ import type { RootTestTree } from './types.js' /// ------- // initial funding balance for accounts -const TEST_ACCOUNT_BALANCE = 100000000000000n +const TEST_ACCOUNT_BALANCE_MULTIPLIER = 10000n // 10,000x existential deposit const NON_EXISTENT_BOUNTY_INDEX = 999 // randombounty index that doesn't exist @@ -36,7 +36,6 @@ async function getBountyCount(client: Client): Promise { */ async function getBounty(client: Client, bountyIndex: number): Promise { const bounty = await client.api.query.bounties.bounties(bountyIndex) - if (!bounty) return null return bounty.isSome ? bounty.unwrap() : null } @@ -66,11 +65,14 @@ async function setupTestAccounts(client: Client, accounts: string[] = charlie: testAccounts.charlie.address, } + const existentialDeposit = client.api.consts.balances.existentialDeposit.toBigInt() + const testAccountBalance = TEST_ACCOUNT_BALANCE_MULTIPLIER * existentialDeposit + const accountData = accounts .filter((account) => accountMap[account as keyof typeof accountMap]) .map((account) => [ [accountMap[account as keyof typeof accountMap]], - { providers: 1, data: { free: TEST_ACCOUNT_BALANCE } }, + { providers: 1, data: { free: testAccountBalance } }, ]) await client.dev.setStorage({ @@ -129,13 +131,18 @@ async function extractExtrinsicFailedEvent(client: Client): Promise | undefined, @@ -183,13 +190,18 @@ export async function bountyCreationTest< } /** - * Test 2: Bounty approval flow + * Test: Bounty Approval Flow * - * Verifies: - * - Bounty can be approved by treasurer - * - Status changes from Proposed to Approved - * - Bounty is added to approvals queue - * - Correct events are emitted + * This test verifies that treasury administrators can approve bounty proposals, + * transitioning them from the proposed state to the approved state. This is + * a critical governance step that ensures only legitimate bounties receive funding. + * + * The test achieves this by: + * - Having Alice propose a bounty + * - Using the `Treasurer` origin to approve the bounty + * - Verifying the status changes from `Proposed` to `Approved` + * - Confirming the bounty is added to the approvals queue + * - Checking that appropriate `BountyApproved` events are emitted */ export async function bountyApprovalTest< TCustom extends Record | undefined, @@ -239,13 +251,19 @@ export async function bountyApprovalTest< } /** - * Bounty approval flow with curator + * Test: Bounty Approval with Curator Assignment + * + * This test verifies that treasury administrators can approve bounty proposals + * while simultaneously assigning a curator. This streamlines the workflow by + * combining approval and curator assignment into a single operation, reducing + * the number of transactions needed to activate a bounty. * - * Verifies: - * - Bounty can be approved by treasurer with curator - * - Status changes from Proposed to ApprovedWithCurator - * - Bounty is added to approvals queue - * - Correct events are emitted + * The test achieves this by: + * - Having Alice propose a bounty + * - Using the `Treasurer` origin to approve the bounty with a curator + * - Verifying the status changes from `Proposed` to `ApprovedWithCurator` + * - Confirming the bounty is added to the approvals queue + * - Checking that both `BountyApproved` and `CuratorProposed` events are emitted */ export async function bountyApprovalWithCuratorTest< TCustom extends Record | undefined, @@ -304,12 +322,19 @@ export async function bountyApprovalWithCuratorTest< } /** - * Bounty funding for Approved Bounties + * Test: Automatic Bounty Funding for Approved Bounties + * + * This test verifies that approved bounties are automatically funded by the + * treasury during the spend period. This ensures that approved bounties receive + * their allocated funds without manual intervention, maintaining the automated + * nature of the bounty system. * - * Verifies: - * - Approved Bounties get funded by treasury automatically - * - Status changes from Approved -> Funded - * - Correct events are emitted + * The test achieves this by: + * - Setting up the treasury spend period timing + * - Having Alice propose and get a bounty approved + * - Advancing blocks to trigger the spend period + * - Verifying the bounty status changes from `Approved` to `Funded` + * - Confirming the `BountyBecameActive` event is emitted */ export async function bountyFundingTest< TCustom extends Record | undefined, @@ -362,13 +387,14 @@ export async function bountyFundingTest< await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // verify the status of the bounty after funding is funded const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) @@ -377,13 +403,20 @@ export async function bountyFundingTest< } /** - * Bounty funding for ApprovedWithCurator Bounties + * Test: Automatic Bounty Funding for `ApprovedWithCurator` Bounties * - * Verifies: - * - When a bounty is approved with curator, status changes to ApprovedWithCurator - * - ApprovedWithCurator Bounties get funded by treasury automatically - * - Status changes from ApprovedWithCurator -> CuratorProposed - * - Correct events are emitted + * This test verifies that bounties approved with a curator are automatically + * funded by the treasury and transition to the `CuratorProposed` state. This + * ensures that curator-assigned bounties receive funding and are ready for + * curator acceptance without additional manual steps. + * + * The test achieves this by: + * - Setting up the treasury spend period timing + * - Having Alice propose a bounty + * - Approving the bounty with a curator assignment + * - Advancing blocks to trigger the spend period + * - Verifying the status changes from `ApprovedWithCurator` to `CuratorProposed` + * - Confirming appropriate events are emitted */ export async function bountyFundingForApprovedWithCuratorTest< TCustom extends Record | undefined, @@ -450,13 +483,14 @@ export async function bountyFundingForApprovedWithCuratorTest< await client.dev.newBlock() // In this block the bounty is funded and the status changes to CuratorProposed - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // verify the bounty status is CuratorProposed const bountyStatusAfterFunding = await getBounty(client, bountyIndex) expect(bountyStatusAfterFunding.status.isCuratorProposed).toBe(true) @@ -465,15 +499,19 @@ export async function bountyFundingForApprovedWithCuratorTest< } /** - * Curator assignment and acceptance + * Test: Curator Assignment and Acceptance Workflow + * + * This test verifies the complete curator lifecycle from assignment to acceptance. + * Curators are responsible for managing bounties and must deposit funds as collateral + * to ensure they fulfill their responsibilities. * - * Verifies: - * - Curator can be proposed for a funded bounty - * - Status changes from Funded -> CuratorProposed - * - Curator can accept the role - * - Status changes from CuratorProposed -> Active - * - Curator deposit is reserved - * - Correct events are emitted + * The test achieves this by: + * - Creating a funded bounty through the approval process + * - Having the `Treasurer` propose Bob as curator + * - Verifying the status changes from `Funded` to `CuratorProposed` + * - Having Bob accept the curator role + * - Confirming the status changes to `Active` and curator deposit is reserved + * - Checking that appropriate events are emitted throughout the process */ export async function curatorAssignmentAndAcceptanceTest< TCustom extends Record | undefined, @@ -526,13 +564,14 @@ export async function curatorAssignmentAndAcceptanceTest< await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // verify the status of the bounty after funding is funded const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) @@ -576,12 +615,18 @@ export async function curatorAssignmentAndAcceptanceTest< } /** - * Bounty extension + * Test: Bounty Expiry Extension * - * Verifies: - * - Curator can extend bounty expiry - * - Update due date is extended - * - Correct events are emitted + * This test verifies that curators can extend the expiry date of active bounties. + * This functionality is crucial for allowing curators additional time to complete + * their work or find suitable beneficiaries when needed. + * + * The test achieves this by: + * - Creating an active bounty with a curator + * - Having the curator extend the bounty expiry + * - Verifying the `updateDue` date is extended + * - Confirming the `BountyExtended` event is emitted + * - Checking that the bounty remains in `Active` state */ export async function bountyExtensionTest< TCustom extends Record | undefined, @@ -634,13 +679,14 @@ export async function bountyExtensionTest< await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // verify the status of the bounty after funding is funded const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) @@ -714,13 +760,21 @@ export async function bountyExtensionTest< } /** - * Bounty awarding and claiming + * Test: Complete Bounty Awarding and Claiming Workflow + * + * This test verifies the end-to-end process of awarding a bounty to a beneficiary + * and allowing them to claim the funds after the required delay period. This + * ensures that completed work is properly rewarded while maintaining security + * through the delay mechanism. * - * Verifies: - * - Curator can award bounty to beneficiary - * - Status changes to PendingPayout - * - Curator can claim the bounty after delay period - * - Correct events are emitted + * The test achieves this by: + * - Creating an active bounty with a curator + * - Having the curator award the bounty to Alice + * - Verifying the status changes to `PendingPayout` + * - Advancing blocks to reach the claimable period + * - Having Alice claim the bounty + * - Confirming the bounty is removed from storage + * - Checking that appropriate events are emitted throughout */ export async function bountyAwardingAndClaimingTest< TCustom extends Record | undefined, @@ -773,13 +827,14 @@ export async function bountyAwardingAndClaimingTest< await client.dev.newBlock() // This is the spendPeriodBlock i.e bounty will be funded in this block - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // verify the status of the bounty after funding is funded const bountyStatusAfterApproval = await getBounty(client, bountyIndex) expect(bountyStatusAfterApproval.status.isFunded).toBe(true) @@ -837,13 +892,11 @@ export async function bountyAwardingAndClaimingTest< const bountyAwarded = await getBounty(client, bountyIndex) expect(bountyAwarded.status.isPendingPayout).toBe(true) - // Calculate the claimable at block number - const currentBlock = await client.api.rpc.chain.getHeader() + // get the bounty deposit payout delay const bountyDepositPayoutDelay = await client.api.consts.bounties.bountyDepositPayoutDelay - const claimableAtBlock = currentBlock.number.toNumber() + Number(bountyDepositPayoutDelay.toNumber()) // wait for the unlock at block number - await client.dev.setHead(claimableAtBlock) + await client.dev.newBlock({ blocks: bountyDepositPayoutDelay.toNumber() }) await client.dev.newBlock() @@ -870,13 +923,19 @@ export async function bountyAwardingAndClaimingTest< } /** - * Test: Bounty closure in Proposed state + * Test: Bounty Closure in `Proposed` State + * + * This test verifies that treasury administrators can close bounties that are + * still in the proposed state, rejecting them before they receive approval. + * This is important for governance as it allows removal of inappropriate or + * outdated bounty proposals while penalizing proposers for wasted resources. * - * Verifies: - * - Bounty can be closed by GeneralAdmin when in Proposed state - * - Proposer's bond is slashed - * - Bounty is removed from storage - * - BountyRejected event is emitted + * The test achieves this by: + * - Having Alice propose a bounty + * - Using the `Treasurer` origin to close the bounty + * - Verifying the proposer's bond is slashed (not returned) + * - Confirming the bounty is removed from storage + * - Checking that `BountyRejected` and `Slashed` events are emitted */ export async function bountyClosureProposedTest< TCustom extends Record | undefined, @@ -938,13 +997,18 @@ export async function bountyClosureProposedTest< } /** - * Test: Bounty closure in Funded state + * Test: Bounty Closure in ``Funded`` State + * + * This test verifies that treasury administrators can close bounties that have + * been funded but not yet assigned to curators. This allows recovery of treasury + * funds from bounties that are no longer needed or have become obsolete. * - * Verifies: - * - Bounty can be closed when in Funded state - * - Funds are transferred back to treasury - * - Bounty is removed from storage - * - BountyCanceled event is emitted + * The test achieves this by: + * - Creating a funded bounty through the approval process + * - Using the `Treasurer` origin to close the bounty + * - Verifying the bounty funds are transferred back to treasury + * - Confirming the bounty is removed from storage + * - Checking that `BountyCanceled` and `Transfer` events are emitted */ export async function bountyClosureFundedTest< TCustom extends Record | undefined, @@ -984,13 +1048,14 @@ export async function bountyClosureFundedTest< await client.dev.newBlock() // Bounty will be funded in this block - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // Verify bounty is funded const fundedBounty = await getBounty(client, bountyIndex) expect(fundedBounty.status.isFunded).toBe(true) @@ -1016,7 +1081,7 @@ export async function bountyClosureFundedTest< // verify the transfer event await checkSystemEvents(client, { section: 'balances', method: 'Transfer' }) .redact({ redactKeys: /from|to/ }) - .toMatchSnapshot('bounty value transfered to treasury') + .toMatchSnapshot('bounty value transferred to treasury') // get treasury balance after closure const treasuryAccountAfterClosureInfo = await client.api.query.system.account(treasuryAccountId) @@ -1037,14 +1102,19 @@ export async function bountyClosureFundedTest< } /** - * Test: Bounty closure in Active state + * Test: Bounty Closure in Active State * - * Verifies: - * - Bounty can be closed when in Active state - * - Curator deposit is refunded - * - Funds are transferred back to treasury - * - Bounty is removed from storage - * - BountyCanceled event is emitted + * This test verifies that treasury administrators can close bounties that are + * currently active with assigned curators. This allows recovery of both treasury + * funds and curator deposits when bounties need to be terminated. + * + * The test achieves this by: + * - Creating an active bounty with an assigned curator + * - Using the `Treasurer` origin to close the bounty + * - Verifying the curator deposit is refunded + * - Confirming the bounty funds are transferred back to treasury + * - Checking that the bounty is removed from storage + * - Validating that `BountyCanceled` and `Transfer` events are emitted */ export async function bountyClosureActiveTest< TCustom extends Record | undefined, @@ -1085,13 +1155,14 @@ export async function bountyClosureActiveTest< await client.dev.newBlock() // Bounty will be funded in this block - await client.dev.newBlock() // verify the BountyBecameActive event await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) .redact({ redactKeys: /index/ }) .toMatchSnapshot('bounty became active events') + await client.dev.newBlock() + // Propose a curator const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { Origins: 'Treasurer' }) @@ -1153,12 +1224,18 @@ export async function bountyClosureActiveTest< } /** - * Test: Unassign curator in ApprovedWithCurator state + * Test: Curator Unassignment in ApprovedWithCurator State + * + * This test verifies that treasury administrators can unassign curators from + * bounties that are in the `ApprovedWithCurator` state. This provides flexibility + * to change curator assignments before the bounty becomes active. * - * Verifies: - * - Treasurer can unassign curator from ApprovedWithCurator state - * - Status changes back to Approved - * - CuratorUnassigned event is emitted + * The test achieves this by: + * - Having Alice propose a bounty + * - Approving the bounty with a curator assignment + * - Using the `Treasurer` origin to unassign the curator + * - Verifying the status changes back to `Approved` + * - Confirming the `CuratorUnassigned` event is emitted */ export async function unassignCuratorApprovedWithCuratorTest< TCustom extends Record | undefined, @@ -1215,12 +1292,18 @@ export async function unassignCuratorApprovedWithCuratorTest< } /** - * Test: Unassign curator in CuratorProposed state + * Test: Curator Unassignment in `CuratorProposed` State * - * Verifies: - * - Treasurer can unassign curator from CuratorProposed state - * - Status changes to Funded - * - CuratorUnassigned event is emitted + * This test verifies that treasury administrators can unassign curators from + * bounties that are in the `CuratorProposed` state. This allows changing curator + * assignments even after the bounty has been funded but before the curator + * has accepted their role. + * + * The test achieves this by: + * - Creating a funded bounty with a proposed curator + * - Using the `Treasurer` origin to unassign the curator + * - Verifying the status changes to `Funded` + * - Confirming the `CuratorUnassigned` event is emitted */ export async function unassignCuratorCuratorProposedTest< TCustom extends Record | undefined, @@ -1311,13 +1394,19 @@ export async function unassignCuratorCuratorProposedTest< } /** - * Test: Unassign curator in Active state by curator themselves + * Test: Curator Self-Unassignment in Active State + * + * This test verifies that curators can voluntarily unassign themselves from + * active bounties. This provides curators with an exit mechanism when they + * cannot fulfill their responsibilities, with their deposit being refunded + * since they initiated the unassignment. * - * Verifies: - * - Curator can unassign themselves from Active state - * - Curator deposit is refunded - * - Status changes to Funded - * - CuratorUnassigned event is emitted + * The test achieves this by: + * - Creating an active bounty with Bob as curator + * - Having Bob unassign himself from the bounty + * - Verifying the status changes to `Funded` + * - Confirming the curator deposit is refunded (not slashed) + * - Checking that the `CuratorUnassigned` event is emitted */ export async function unassignCuratorActiveByCuratorTest< TCustom extends Record | undefined, @@ -1441,13 +1530,18 @@ export async function unassignCuratorActiveByCuratorTest< } /** - * Test: Unassign curator in Active state by Treasurer (slashes curator) + * Test: Curator Unassignment by `Treasurer` in `Active` State * - * Verifies: - * - Treasurer can unassign curator from Active state - * - Curator deposit is slashed - * - Status changes to Funded - * - CuratorUnassigned event is emitted + * This test verifies that treasury administrators can forcibly unassign curators + * from active bounties. This is a disciplinary action where the curator's + * deposit is slashed as a penalty for not fulfilling their responsibilities or acting maliciously. + * + * The test achieves this by: + * - Creating an active bounty with Bob as curator + * - Using the `Treasurer` origin to unassign Bob + * - Verifying the status changes to `Funded` + * - Confirming the curator deposit is slashed (not refunded) + * - Checking that `CuratorUnassigned`, `Slashed`, and `Deposit` events are emitted */ export async function unassignCuratorActiveByTreasurerTest< TCustom extends Record | undefined, @@ -1583,13 +1677,18 @@ export async function unassignCuratorActiveByTreasurerTest< } /** - * Test: Unassign curator in PendingPayout state by Treasurer + * Test: Curator Unassignment in `PendingPayout` State + * + * This test verifies that treasury administrators can unassign curators from + * bounties that are in the `PendingPayout` state. By doing so, they are claiming the curator is acting maliciously, + * so we slash the curator. * - * Verifies: - * - Treasurer can unassign curator from PendingPayout state - * - Curator deposit is slashed - * - Status changes to Funded - * - CuratorUnassigned event is emitted + * The test achieves this by: + * - Creating a bounty that has been awarded (`PendingPayout` state) + * - Using the `Treasurer` origin to unassign the curator + * - Verifying the status changes to `Funded` + * - Confirming the curator deposit is slashed + * - Checking that appropriate events are emitted */ export async function unassignCuratorPendingPayoutTest< TCustom extends Record | undefined, @@ -1919,11 +2018,17 @@ export function allBountySuccessTests< } /** - * Test: Bounty closure in Approved state (should fail) + * Test: Bounty Closure Failure in Approved State + * + * This test verifies that treasury(council) administrators cannot close bounties that are + * in the `Approved` state. For weight reasons, we don't allow a council to cancel in this phase. * - * Verifies: - * - Bounty closure fails with UnexpectedStatus when in Approved state (GeneralAdmin cannot close approved bounties) - * - Bounty remains in storage + * The test achieves this by: + * - Having Alice propose and get a bounty approved + * - Attempting to close the bounty using the `Treasurer` (council) origin + * - Verifying the transaction fails with `UnexpectedStatus` error + * - Confirming the bounty remains in Approved state + * - Checking that the error is properly reported through scheduler events */ export async function bountyClosureApprovedTest< TCustom extends Record | undefined, @@ -1997,11 +2102,20 @@ export async function bountyClosureApprovedTest< } /** - * Test: Bounty closure in PendingPayout state (should fail) + * Test: Bounty Closure Failure in `PendingPayout` State * - * Verifies: - * - Bounty closure fails with PendingPayout error when in PendingPayout state (GeneralAdmin must unassign curator first) - * - Bounty remains in storage + * This test verifies that treasury administrators cannot directly close bounties + * that are in the `PendingPayout` state. If council wants to cancel + * this bounty, it should mean the curator was acting maliciously. + * So the council should first unassign the curator, slashing their + * deposit. + * + * The test achieves this by: + * - Creating a bounty that has been awarded (`PendingPayout` state) + * - Attempting to close the bounty using the `Treasurer` origin + * - Verifying the transaction fails with `PendingPayout` error + * - Confirming the bounty remains in `PendingPayout` state + * - Checking that the error is properly reported through scheduler events */ export async function bountyClosurePendingPayoutTest< TCustom extends Record | undefined, @@ -2099,11 +2213,19 @@ export async function bountyClosurePendingPayoutTest< } /** - * Test that unassigning curator in Active state by public fails with `Premature`. + * Test: Premature Curator Unassignment by Public User + * + * This test verifies that public users cannot immediately unassign curators + * from active bounties. There is a timing restriction to prevent malicious + * actors from disrupting bounty operations. Users must wait for the proper + * timing window before they can unassign curators. * - * 1. Alice proposes a bounty, it gets approved, curator is proposed and accepted - * 2. Public user attempts to unassign curator immediately (before proper timing) - * 3. Verify that the transaction fails with the appropriate error + * The test achieves this by: + * - Creating an active bounty with an assigned curator + * - Having Charlie (public user) attempt to unassign the curator immediately + * - Verifying the transaction fails with `Premature` error + * - Confirming the bounty remains in Active state + * - Checking that the error is properly reported through `ExtrinsicFailed` event */ async function unassignCuratorActiveStateByPublicPrematureTest< TCustom extends Record | undefined, @@ -2160,7 +2282,7 @@ async function unassignCuratorActiveStateByPublicPrematureTest< expect(bountyStatus.status.isActive).toBe(true) // Charlie (public user) tries to unassign curator immediately (premature) - // Using scheduleInlineCallWithOrigin to simulate public call + // Using sendTransaction to simulate public call const unassignCuratorTx = client.api.tx.bounties.unassignCurator(bountyIndex) await sendTransaction(unassignCuratorTx.signAsync(testAccounts.charlie)) @@ -2184,10 +2306,16 @@ async function unassignCuratorActiveStateByPublicPrematureTest< } /** - * Test that proposing a bounty with description too long fails with `ReasonTooBig`. + * Test: Bounty Proposal with Oversized Description * - * 1. Alice attempts to propose a bounty with a description that exceeds the maximum length - * 2. Verify that the transaction fails with the appropriate error + * This test verifies that the system properly rejects bounty proposals with + * descriptions that exceed the maximum allowed length. This prevents storage + * bloat and ensures reasonable description sizes for governance efficiency. + * + * The test achieves this by: + * - Having Alice attempt to propose a bounty with an oversized description + * - Verifying the transaction fails with `ReasonTooBig` error + * - Confirming the error is properly reported through `ExtrinsicFailed` event */ async function reasonTooBigTest< TCustom extends Record | undefined, @@ -2223,10 +2351,16 @@ async function reasonTooBigTest< } /** - * Test that proposing a bounty with value below minimum fails with `InvalidValue`. + * Test: Bounty Proposal with Insufficient Value + * + * This test verifies that the system properly rejects bounty proposals with + * values below the minimum threshold. This ensures bounties have meaningful + * value and prevents spam proposals with negligible amounts. * - * 1. Alice attempts to propose a bounty with value below the minimum required - * 2. Verify that the transaction fails with the appropriate error + * The test achieves this by: + * - Having Alice attempt to propose a bounty with value below the minimum + * - Verifying the transaction fails with `InvalidValue` error + * - Confirming the error is properly reported through `ExtrinsicFailed` event */ async function invalidValueTest< TCustom extends Record | undefined, @@ -2262,10 +2396,16 @@ async function invalidValueTest< } /** - * Test that approving a non-existent bounty fails with `InvalidIndex`. + * Test: Approval of Non-Existent Bounty + * + * This test verifies that the system properly handles attempts to approve + * bounties that do not exist. This prevents errors and ensures robust error + * handling when invalid bounty indices are provided. * - * 1. Treasurer attempts to approve a bounty that doesn't exist - * 2. Verify that the transaction fails with the appropriate error + * The test achieves this by: + * - Attempting to approve a bounty with a non-existent index + * - Verifying the transaction fails with `InvalidIndex` error + * - Confirming the error is properly reported through scheduler events */ async function invalidIndexApprovalTest< TCustom extends Record | undefined, @@ -2303,11 +2443,17 @@ async function invalidIndexApprovalTest< } /** - * Test that proposing a curator for a non-funded bounty fails with `UnexpectedStatus`. + * Test: Curator Proposal Before Bounty Funding * - * 1. Alice proposes a bounty - * 2. Treasurer attempts to propose a curator before the bounty is funded - * 3. Verify that the transaction fails with the appropriate error + * This test verifies that curators cannot be proposed for bounties that + * have not yet been funded. This ensures the proper sequence of operations: + * bounty must be funded before curator assignment can occur. + * + * The test achieves this by: + * - Having Alice propose a bounty + * - Attempting to propose a curator before the bounty is funded + * - Verifying the transaction fails with `UnexpectedStatus` error + * - Confirming the error is properly reported through scheduler events */ async function unexpectedStatusProposeCuratorTest< TCustom extends Record | undefined, @@ -2356,11 +2502,17 @@ async function unexpectedStatusProposeCuratorTest< } /** - * Test that a non-curator trying to accept curator role fails with `RequireCurator`. + * Test: Unauthorized Curator Acceptance + * + * This test verifies that only the designated curator can accept a curator + * role for a bounty. This prevents unauthorized users from accepting + * curator positions they were not assigned to. * - * 1. Alice proposes a bounty and treasurer proposes Bob as curator - * 2. Charlie attempts to accept the curator role (should be Bob) - * 3. Verify that the transaction fails with the appropriate error + * The test achieves this by: + * - Creating a funded bounty with Bob proposed as curator + * - Having Charlie attempt to accept the curator role + * - Verifying the transaction fails with `RequireCurator` error + * - Confirming the error is properly reported through `ExtrinsicFailed` event */ async function requireCuratorAcceptTest< TCustom extends Record | undefined, @@ -2426,12 +2578,18 @@ async function requireCuratorAcceptTest< } /** - * Test creating a child bounty from an active parent bounty and then trying to close it should fail with `HasActiveChildBounty`. + * Test: Bounty Awarding with Active Child Bounties + * + * This test verifies that bounties with active child bounties cannot be + * awarded. This prevents disruption of ongoing child bounty work and + * ensures proper completion of all related child bounty activities. * - * Verifies: - * - Curator can create child bounty when parent bounty is in Active state - * - ChildBountyAdded event is emitted - * - Child bounty gets proper funding from parent bounty + * The test achieves this by: + * - Creating an active bounty with a curator + * - Having the curator create a child bounty + * - Attempting to award the parent bounty + * - Verifying the transaction fails with `HasActiveChildBounty` error + * - Confirming the parent bounty remains in Active state */ async function hasActiveChildBountyTest< TCustom extends Record | undefined, @@ -2529,6 +2687,137 @@ async function hasActiveChildBountyTest< await client.teardown() } +/** + * Test: Premature Bounty Claiming in Active State + * + * This test verifies that beneficiaries cannot claim bounties that are + * still in the Active state. Bounties must first be awarded by the curator + * and reach the `PendingPayout` state before they can be claimed. + * + * The test achieves this by: + * - Creating an active bounty with a curator + * - Having Alice(beneficiary) attempt to claim the bounty while it's still active + * - Verifying the transaction fails with `UnexpectedStatus` error + * - Confirming the error is properly reported through `ExtrinsicFailed` event + */ +export async function bountyAwardingAndClaimingInActiveStateTest< + TCustom extends Record | undefined, + TInitStorages extends Record> | undefined, +>(chain: Chain) { + const [client] = await setupNetworks(chain) + + await setupTestAccounts(client, ['alice', 'bob', 'charlie']) + + await setLastSpendPeriodBlockNumber(client) + + await client.dev.newBlock() + + const existentialDeposit = client.api.consts.balances.existentialDeposit + const bountyValue = existentialDeposit.toBigInt() * BOUNTY_MULTIPLIER // 1000 tokens + const description = 'Test bounty for funding' + + // propose a bounty + const proposeBountyTx = client.api.tx.bounties.proposeBounty(bountyValue, description) + const bountyProposedEvents = await sendTransaction(proposeBountyTx.signAsync(testAccounts.alice)) + + await client.dev.newBlock() + + // verify the BountyProposed event + await checkEvents(bountyProposedEvents, { section: 'bounties', method: 'BountyProposed' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty proposed events') + + // verify the bounty is added to the storage + const bountyIndex = await getBountyIndexFromEvent(client) + const bountyFromStorage = await getBounty(client, bountyIndex) + expect(bountyFromStorage.status.isProposed).toBe(true) + + // approve the bounty with origin treasurer + const approveBountyTx = client.api.tx.bounties.approveBounty(bountyIndex) + await scheduleInlineCallWithOrigin(client, approveBountyTx.method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the BountyApproved event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyApproved' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty approved events') + + // verify the bounty is added to the approvals queue + const approvalsFromStorage = await getBountyApprovals(client) + expect(approvalsFromStorage).toContain(bountyIndex) + + await client.dev.newBlock() + // This is the spendPeriodBlock i.e bounty will be funded in this block + + // verify the BountyBecameActive event + await checkSystemEvents(client, { section: 'bounties', method: 'BountyBecameActive' }) + .redact({ redactKeys: /index/ }) + .toMatchSnapshot('bounty became active events') + + await client.dev.newBlock() + + // verify the status of the bounty after funding is funded + const bountyStatusAfterApproval = await getBounty(client, bountyIndex) + expect(bountyStatusAfterApproval.status.isFunded).toBe(true) + + const curatorFee = existentialDeposit.toBigInt() * CURATOR_FEE_MULTIPLIER + + // assign curator to the bounty + const proposeCuratorTx = client.api.tx.bounties.proposeCurator(bountyIndex, testAccounts.bob.address, curatorFee) + await scheduleInlineCallWithOrigin(client, proposeCuratorTx.method.toHex(), { + Origins: 'Treasurer', + }) + + await client.dev.newBlock() + + // verify the CuratorProposed event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorProposed' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator proposed events') + + // verify the bounty status is CuratorProposed + const bountyStatusAfterCuratorProposed = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorProposed.status.isCuratorProposed).toBe(true) + + await client.dev.newBlock() + + // accept the curator + const acceptCuratorTx = client.api.tx.bounties.acceptCurator(bountyIndex) + await sendTransaction(acceptCuratorTx.signAsync(testAccounts.bob)) + + await client.dev.newBlock() + + // verify the CuratorAccepted event + await checkSystemEvents(client, { section: 'bounties', method: 'CuratorAccepted' }) + .redact({ redactKeys: /bountyId/ }) + .toMatchSnapshot('curator accepted events') + + // verify the bounty status is Active + const bountyStatusAfterCuratorAccepted = await getBounty(client, bountyIndex) + expect(bountyStatusAfterCuratorAccepted.status.isActive).toBe(true) + + await client.dev.newBlock() + + // try to claim the bounty by beneficiary in active state + const claimBountyTx = client.api.tx.bounties.claimBounty(bountyIndex) + await sendTransaction(claimBountyTx.signAsync(testAccounts.alice)) + + await client.dev.newBlock() + + const ev = await extractExtrinsicFailedEvent(client) + + assert(client.api.events.system.ExtrinsicFailed.is(ev.event)) + const dispatchError = ev.event.data.dispatchError + + assert(dispatchError.isModule) + expect(client.api.errors.bounties.UnexpectedStatus.is(dispatchError.asModule)).toBeTruthy() + + await client.teardown() +} + /** * All the failure cases for bounty * @@ -2588,6 +2877,11 @@ export function allBountyFailureTests< label: 'Bounty cannot be awarded if it has an active child bounty', testFn: async () => await hasActiveChildBountyTest(chain), }, + { + kind: 'test', + label: 'Bounty cannot be claimed in active state', + testFn: async () => await bountyAwardingAndClaimingInActiveStateTest(chain), + }, ], } as RootTestTree } From 33d26883467ca49466dc8aa7c7a69f88733b81ce Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 6 Oct 2025 02:44:52 +0530 Subject: [PATCH 65/66] snapshot updated --- .../kusama.bounties.e2e.test.ts.snap | 148 +++++++++++++++++- .../polkadot.bounties.e2e.test.ts.snap | 148 +++++++++++++++++- 2 files changed, 280 insertions(+), 16 deletions(-) diff --git a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap index 674335c73..d0d87969f 100644 --- a/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap +++ b/packages/kusama/src/__snapshots__/kusama.bounties.e2e.test.ts.snap @@ -10,6 +10,68 @@ exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be awarded i ] `; +exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be claimed in active state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be claimed in active state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be claimed in active state > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be claimed in active state > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Kusama Bounties > All bounty failure tests > Bounty cannot be claimed in active state > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "EvvS4HELEC1nxVHsjYUsPvypd2kXeu78AguyiSN7kV2pTnk", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + exports[`Kusama Bounties > All bounty failure tests > Bounty closure in approved state > scheduler events when closing bounty with approved state fails 1`] = ` [ { @@ -407,7 +469,17 @@ exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bou ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` [ @@ -459,7 +531,17 @@ exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bou ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` [ @@ -473,7 +555,7 @@ exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bou ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` +exports[`Kusama Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty value transferred to treasury 1`] = ` [ { "data": { @@ -575,7 +657,17 @@ exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claimi ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Bounty awarding and claiming > bounty claimed events 1`] = ` [ @@ -641,7 +733,17 @@ exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Bounty extension > bounty extended events 1`] = ` [ @@ -705,7 +807,17 @@ exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bou ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` [ @@ -731,7 +843,17 @@ exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bou ] `; -exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` [ @@ -782,7 +904,17 @@ exports[`Kusama Bounties > All bounty success tests > Curator assignment and acc ] `; -exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > bounty became active events 1`] = `[]`; +exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Kusama Bounties > All bounty success tests > Curator assignment and acceptance > bounty proposed events 1`] = ` [ diff --git a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap index 979396a6e..76f110754 100644 --- a/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap +++ b/packages/polkadot/src/__snapshots__/polkadot.bounties.e2e.test.ts.snap @@ -10,6 +10,68 @@ exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be awarded ] `; +exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be claimed in active state > bounty approved events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyApproved", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be claimed in active state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be claimed in active state > bounty proposed events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyProposed", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be claimed in active state > curator accepted events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", + }, + "method": "CuratorAccepted", + "section": "bounties", + }, +] +`; + +exports[`Polkadot Bounties > All bounty failure tests > Bounty cannot be claimed in active state > curator proposed events 1`] = ` +[ + { + "data": { + "bountyId": "(redacted)", + "curator": "13Mbv5CRZeSZUqgN4fnS7bQ8XekARHe4kHaekM9mC3J4Fh7e", + }, + "method": "CuratorProposed", + "section": "bounties", + }, +] +`; + exports[`Polkadot Bounties > All bounty failure tests > Bounty closure in approved state > scheduler events when closing bounty with approved state fails 1`] = ` [ { @@ -407,7 +469,17 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > B ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in active state > bounty canceled event 1`] = ` [ @@ -459,7 +531,17 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > B ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty canceled events 1`] = ` [ @@ -473,7 +555,7 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > B ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty value transfered to treasury 1`] = ` +exports[`Polkadot Bounties > All bounty success tests > Bounty Closure Tests > Bounty closure in funded state > bounty value transferred to treasury 1`] = ` [ { "data": { @@ -575,7 +657,17 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and clai ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Bounty awarding and claiming > bounty claimed events 1`] = ` [ @@ -641,7 +733,17 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bount ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Bounty extension > bounty extended events 1`] = ` [ @@ -705,7 +807,17 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > B ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for Approved Bounties > bounty proposed events 1`] = ` [ @@ -731,7 +843,17 @@ exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > B ] `; -exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Bounty funding tests > Bounty funding for ApprovedWithCurator Bounties > bounty proposed events 1`] = ` [ @@ -782,7 +904,17 @@ exports[`Polkadot Bounties > All bounty success tests > Curator assignment and a ] `; -exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > bounty became active events 1`] = `[]`; +exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > bounty became active events 1`] = ` +[ + { + "data": { + "index": "(redacted)", + }, + "method": "BountyBecameActive", + "section": "bounties", + }, +] +`; exports[`Polkadot Bounties > All bounty success tests > Curator assignment and acceptance > bounty proposed events 1`] = ` [ From c1e3a92a5f8260444ce59ac18a9a4a347d199bf5 Mon Sep 17 00:00:00 2001 From: Dhiraj Sah Date: Mon, 6 Oct 2025 03:04:37 +0530 Subject: [PATCH 66/66] openng docs updated --- packages/shared/src/bounties.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/shared/src/bounties.ts b/packages/shared/src/bounties.ts index 26cc36fdf..e236d3cd9 100644 --- a/packages/shared/src/bounties.ts +++ b/packages/shared/src/bounties.ts @@ -83,7 +83,7 @@ async function setupTestAccounts(client: Client, accounts: string[] = } /** - * Get bounty index from BountyProposed event + * Get bounty index from `BountyProposed` event */ async function getBountyIndexFromEvent(client: Client): Promise { const [bountyProposedEvent] = (await client.api.query.system.events()).filter( @@ -138,7 +138,7 @@ async function extractExtrinsicFailedEvent(client: Client): Promise | undefined, @@ -2688,15 +2688,15 @@ async function hasActiveChildBountyTest< } /** - * Test: Premature Bounty Claiming in Active State + * Test: Premature Bounty Claiming in `Active` State * * This test verifies that beneficiaries cannot claim bounties that are - * still in the Active state. Bounties must first be awarded by the curator + * still in the `Active` state. Bounties must first be awarded by the curator * and reach the `PendingPayout` state before they can be claimed. * * The test achieves this by: * - Creating an active bounty with a curator - * - Having Alice(beneficiary) attempt to claim the bounty while it's still active + * - Having `Alice` (beneficiary) attempt to claim the bounty while it's still active * - Verifying the transaction fails with `UnexpectedStatus` error * - Confirming the error is properly reported through `ExtrinsicFailed` event */