Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
NeverHappened committed Sep 15, 2023
1 parent 69c953e commit f22db19
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 16 deletions.
45 changes: 44 additions & 1 deletion src/helpers/dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ export type TimelockConfig = {
subdao: string;
};

export type SubdaoProposalConfig = {
threshold: any;
max_voting_period: Duration;
min_voting_period: Duration;
allow_revoting: boolean;
dao: string;
close_proposal_on_execution_failure: boolean;
};

export type Duration = {
height: number | null;
time: number | null;
};

export type TimelockProposalListResponse = {
proposals: Array<TimeLockSingleChoiceProposal>;
};
Expand Down Expand Up @@ -915,6 +929,32 @@ export class DaoMember {
);
}

async submitUpdateConfigProposal(
title: string,
description: string,
config: SubdaoProposalConfig,
deposit: string,
): Promise<number> {
const msg = {
update_config: config,
};
const message = {
wasm: {
execute: {
contract_addr: this.dao.contracts.proposals['single'].address,
msg: Buffer.from(JSON.stringify(msg)).toString('base64'),
funds: [],
},
},
};
return await this.submitSingleChoiceProposal(
title,
description,
[message],
deposit,
);
}

async overruleTimelockedProposal(
timelockAddress: string,
proposalId: number,
Expand Down Expand Up @@ -1317,6 +1357,7 @@ export const deploySubdao = async (
mainDaoCoreAddress: string,
overrulePreProposeAddress: string,
securityDaoAddr: string,
closeProposalOnExecutionFailure: boolean,
): Promise<Dao> => {
const coreCodeId = await cm.storeWasm(NeutronContract.SUBDAO_CORE);
const cw4VotingCodeId = await cm.storeWasm(NeutronContract.CW4_VOTING);
Expand Down Expand Up @@ -1366,7 +1407,7 @@ export const deploySubdao = async (
},
},
},
close_proposal_on_execution_failure: false,
close_proposal_on_execution_failure: closeProposalOnExecutionFailure,
};
const proposalModuleInstantiateInfo = {
code_id: proposeCodeId,
Expand Down Expand Up @@ -1460,13 +1501,15 @@ export const setupSubDaoTimelockSet = async (
mainDaoAddress: string,
securityDaoAddr: string,
mockMainDao: boolean,
closeProposalOnExecutionFailure: boolean,
): Promise<Dao> => {
const daoContracts = await getDaoContracts(cm.chain, mainDaoAddress);
const subDao = await deploySubdao(
cm,
mockMainDao ? cm.wallet.address.toString() : daoContracts.core.address,
daoContracts.proposals.overrule.pre_propose.address,
securityDaoAddr,
closeProposalOnExecutionFailure,
);

const mainDaoMember = new DaoMember(cm, new Dao(cm.chain, daoContracts));
Expand Down
153 changes: 138 additions & 15 deletions src/testcases/parallel/subdao.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {
DaoMember,
setupSubDaoTimelockSet,
deployNeutronDao,
SubdaoProposalConfig,
} from '../../helpers/dao';
import { getHeight, wait } from '../../helpers/wait';
import { TestStateLocalCosmosTestNet } from '../common_localcosmosnet';
import { AccAddress, ValAddress } from '@cosmos-client/core/cjs/types';
import { Wallet } from '../../types';
import { BroadcastTx200ResponseTxResponse } from '@cosmos-client/core/cjs/openapi/api';
import { paramChangeProposal, sendProposal } from '../../helpers/proposal';
import Long from 'long';

describe('Neutron / Subdao', () => {
let testState: TestStateLocalCosmosTestNet;
Expand Down Expand Up @@ -64,6 +67,7 @@ describe('Neutron / Subdao', () => {
mainDao.contracts.core.address,
securityDaoAddr.toString(),
true,
true, // close proposal on execution failure
);

subdaoMember1 = new DaoMember(neutronAccount1, subDao);
Expand Down Expand Up @@ -112,7 +116,7 @@ describe('Neutron / Subdao', () => {
expect(timelockedProp.msgs).toHaveLength(1);
});

test('execute timelocked: nonexistant ', async () => {
test('execute timelocked: nonexistant', async () => {
await expect(
subdaoMember1.executeTimelockedProposal(1_000_000),
).rejects.toThrow(/SingleChoiceProposal not found/);
Expand Down Expand Up @@ -153,16 +157,36 @@ describe('Neutron / Subdao', () => {
});

let proposalId2: number;
test('proposal timelock 2', async () => {
proposalId2 = await subdaoMember1.submitParameterChangeProposal(
'paramchange',
'paramchange',
'icahost',
'HostEnabled',
'123123123', // expected boolean, provided number
test('proposal timelock 2 with two messages, one of them fails', async () => {
// pack two messages in one proposal
const failMessage = paramChangeProposal({
title: 'paramchange',
description: 'paramchange',
subspace: 'icahost',
key: 'HostEnabled',
value: '123123123', // expected boolean, provided number
});
const goodMessage = sendProposal({
to: neutronAccount2.wallet.address.toString(),
denom: NEUTRON_DENOM,
amount: '100',
});
const fee = {
gas_limit: Long.fromString('4000000'),
amount: [{ denom: NEUTRON_DENOM, amount: '10000' }],
};
proposalId2 = await subdaoMember1.submitSingleChoiceProposal(
'proposal2',
'proposal2',
[goodMessage, failMessage],
'1000',
'single',
fee,
);

// TODO: remove wait?
neutronChain.blockWaiter.waitBlocks(2);

const timelockedProp = await subdaoMember1.supportAndExecuteProposal(
proposalId2,
);
Expand All @@ -172,7 +196,11 @@ describe('Neutron / Subdao', () => {
expect(timelockedProp.msgs).toHaveLength(1);
});

test('execute timelocked: execution failed', async () => {
test('execute timelocked 2: execution failed', async () => {
// from here
await neutronAccount1.msgSend(subDao.contracts.core.address, '100000'); // fund the subdao treasury
const balance2 = await neutronAccount2.queryDenomBalance(NEUTRON_DENOM);

//wait for timelock durations
await wait(20);
// timelocked proposal execution failed due to invalid param value
Expand All @@ -186,13 +214,104 @@ describe('Neutron / Subdao', () => {
expect(res.errors.length).toEqual(1);
expect(res.errors[0].error).toEqual('codespace: undefined, code: 1');

// try execute second time
await subdaoMember1.executeTimelockedProposal(proposalId2);
// check that goodMessage failed as well
const balance2After = await neutronAccount2.queryDenomBalance(
NEUTRON_DENOM,
);
expect(balance2After).toEqual(balance2);

// cannot execute failed proposal with closeOnProposalExecutionFailed=true
await expect(
subdaoMember1.executeTimelockedProposal(proposalId2),
).rejects.toThrow(/Wrong proposal status \(execution_failed\)/);
await neutronChain.blockWaiter.waitBlocks(2);
});

// should add new error here
const res2 = await subDao.getTimelockedProposalErrors(proposalId2);
expect(res2.errors.length).toEqual(2);
test('prepare subdao with closeOnProposalExecutionFailed = false', async () => {
const subdaoConfig =
await neutronChain.queryContract<SubdaoProposalConfig>(
subDao.contracts.proposals.single.address,
{
config: {},
},
);
expect(subdaoConfig.close_proposal_on_execution_failure).toEqual(true);
subdaoConfig.close_proposal_on_execution_failure = false;

const proposalId = await subdaoMember1.submitUpdateConfigProposal(
'updateconfig',
'updateconfig',
subdaoConfig,
'1000',
);
const timelockedProp = await subdaoMember1.supportAndExecuteProposal(
proposalId,
); // Q: will throw?
expect(timelockedProp.status).toEqual('timelocked');
//wait for timelock durations
await wait(20);
await subdaoMember1.executeTimelockedProposal(proposalId); // should execute no problem

neutronChain.blockWaiter.waitBlocks(2);
});

let proposalId3: number;
test('proposal timelock 3', async () => {
proposalId3 = await subdaoMember1.submitParameterChangeProposal(
'paramchange',
'paramchange',
'icahost',
'HostEnabled',
'123123123', // expected boolean, provided number
'1000',
);

const timelockedProp = await subdaoMember1.supportAndExecuteProposal(
proposalId3,
); // Q: will throw?

expect(timelockedProp.id).toEqual(proposalId3);
expect(timelockedProp.status).toEqual('timelocked');
expect(timelockedProp.msgs).toHaveLength(1);
});

test('execute timelocked 3: execution failed', async () => {
const subdaoConfig =
await neutronChain.queryContract<SubdaoProposalConfig>(
subDao.contracts.proposals.single.address,
{
config: {},
},
);
expect(subdaoConfig.close_proposal_on_execution_failure).toEqual(false);

//wait for timelock durations
await wait(20);
// timelocked proposal execution failed due to invalid param value
await subdaoMember1.executeTimelockedProposal(proposalId3);
const timelockedProp = await subDao.getTimelockedProposal(proposalId3);
expect(timelockedProp.id).toEqual(proposalId3);
expect(timelockedProp.status).toEqual('timelocked');
expect(timelockedProp.msgs).toHaveLength(1);

const res = await subDao.getTimelockedProposalErrors(proposalId3);
expect(res.errors.length).toEqual(0); // do not have errors because we do not write error here

await subdaoMember1.executeTimelockedProposal(proposalId3); // should execute no problem
await neutronChain.blockWaiter.waitBlocks(2);
});

test('get back subdao proposal params', async () => {
const subdaoConfig =
await neutronChain.queryContract<SubdaoProposalConfig>(
subDao.contracts.proposals.single.address,
{
config: {},
},
);
expect(subdaoConfig.close_proposal_on_execution_failure).toEqual(false);
subdaoConfig.close_proposal_on_execution_failure = true;
// TODO: set them
});
});

Expand All @@ -218,6 +337,7 @@ describe('Neutron / Subdao', () => {
});

test('execute timelocked: success', async () => {
// from here
await neutronAccount1.msgSend(subDao.contracts.core.address, '20000'); // fund the subdao treasury
const balance2 = await neutronAccount2.queryDenomBalance(NEUTRON_DENOM);
await wait(20);
Expand Down Expand Up @@ -731,6 +851,7 @@ describe('Neutron / Subdao', () => {
mainDao.contracts.core.address,
demo1Addr.toString(),
true,
true,
);
subDAOQueryTestScopeMember = new DaoMember(
neutronAccount1,
Expand Down Expand Up @@ -870,7 +991,9 @@ describe('Neutron / Subdao', () => {
await subdaoMember1.supportAndExecuteProposal(proposalId);

await wait(20);
await subdaoMember1.executeTimelockedProposal(proposalId);
await expect(
subdaoMember1.executeTimelockedProposal(proposalId),
).rejects.toThrow(/config name cannot be empty/);
const timelockedProp = await subDao.getTimelockedProposal(proposalId);
expect(timelockedProp.id).toEqual(proposalId);
expect(timelockedProp.status).toEqual('execution_failed');
Expand Down

0 comments on commit f22db19

Please sign in to comment.