Skip to content

Commit

Permalink
#41 #42 Helper modules for assertion and scenario is implemented. Lay…
Browse files Browse the repository at this point in the history
…ed out the required test code for `voteOnQuestion`. Implemented `voteOnQuestion` method body.
  • Loading branch information
anilhelvaci committed Nov 24, 2022
1 parent 1021468 commit 907bcc2
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 5 deletions.
38 changes: 36 additions & 2 deletions contract/src/governance/lendingPoolElectionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ const start = async (zcf, privateArgs) => {
vote
} = offerArgs;

const effectiveTotalSupply = vote ? totalSupply : AmountMath.subtract(totalSupply, amountToLock);
assert(!AmountMath.isEmpty(effectiveTotalSupply), X`Can't pose questions when the effectiveTotalSuplly is zero.`);

const { zcfSeat: questionSeat } = zcf.makeEmptySeatKit();

questionSeat.incrementBy(
Expand All @@ -153,7 +156,7 @@ const start = async (zcf, privateArgs) => {

zcf.reallocate(poserSeat, questionSeat);

await E(electorateFacet).updateTotalSupply(AmountMath.getValue(govBrand, totalSupply));
await E(electorateFacet).updateTotalSupply(AmountMath.getValue(govBrand, effectiveTotalSupply));

const {
details,
Expand Down Expand Up @@ -188,8 +191,39 @@ const start = async (zcf, privateArgs) => {

const makeVoteOnQuestionInvitation = () => {
/** @type OfferHandler */
const voteOnQuestion = (voterSeat) => {
const voteOnQuestion = async (voterSeat, offerArgs) => {
// TODO: assertOfferArgs - check positions valid
const { questionHandle, positions } = offerArgs;
assert(questions.has(questionHandle), X`There is no such question.`);

const { questionSeat, instance } = questions.get(questionHandle);
const voteCounterPublicFacetP = E(zoe).getPublicFacet(instance);
const isQuestionOpen = await E(voteCounterPublicFacetP).isOpen();
assert(isQuestionOpen, X`Voting is closed.`);

const {
give: { [governanceKeyword]: amountToLock }
} = voterSeat.getProposal();

questionSeat.incrementBy(
voterSeat.decrementBy(harden({ [governanceKeyword]: amountToLock }))
);
zcf.reallocate();

const popAmount = AmountMath.make(popBrand, harden([{
govLocked: amountToLock,
status: 'success',
role: 'voter',
questionHandle,
}]));

popMint.mintGains({ POP: popAmount }, voterSeat);
voterSeat.exit();

const voteWeight = AmountMath.getValue(govBrand, amountToLock);
await E(electorateFacet).voteOnQuestion(questionHandle, positions, voteWeight);

return 'Successfully voted. Do not forget to redeem your governance tokens once the voting is ended.';
};

return zcf.makeInvitation(voteOnQuestion, 'VoteOnQuestionInvitation');
Expand Down
1 change: 0 additions & 1 deletion contract/src/governance/lendingPoolElectorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ const start = (zcf) => {
getQuestionSubscriber: () => questionsSubscriber,
getOpenQuestions: () => getOpenQuestions(allQuestions),
getQuestion: handleP => getQuestion(handleP, allQuestions),
getGovernedBrand: () => governedContext.brand,
});

const creatorFacet = Far('CreatorFacet', {
Expand Down
80 changes: 80 additions & 0 deletions contract/test/governance/governanceAssertions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { assert, details as X } from '@agoric/assert';
import { E } from '@endo/far';
import { ceilMultiplyBy, makeRatio } from '@agoric/zoe/src/contractSupport/index.js';
import { AmountMath } from '@agoric/ertp';

const makeGovernanceAssertionHelpers = async (t, zoe, governedPF, electionManagerPublicFacet, electoratePublicFacet) => {

const govBrandP = E(governedPF).getGovernanceBrand();
const [govBrand, { decimalPlaces: govDecimals }, govIssuer, govKeyword, { popBrand, popIssuer }, electorateSubscriber] = await Promise.all([
govBrandP,
E(govBrandP).getDisplayInfo(),
E(governedPF).getGovernanceIssuer(),
E(governedPF).getGovernanceKeyword(),
E(electionManagerPublicFacet).getPopInfo(),
E(electoratePublicFacet).getQuestionSubscriber(),
]);

const checkGovFetchedCorrectly = async (fetchSeat, { unitsWanted }) => {
const [offerResult, govPayout, propTreshold] = await Promise.all([
E(fetchSeat).getOfferResult(),
E(fetchSeat).getPayout(govKeyword),
E(governedPF).getProposalTreshold(),
]);

const govAmountWanted = AmountMath.make(govBrand, unitsWanted * 10n ** BigInt(govDecimals));
const govAmountReceived = await E(govIssuer).getAmountOf(govPayout);
t.deepEqual(offerResult, 'Sucess! Check your payouts.')
t.deepEqual(govAmountReceived, govAmountWanted);
t.deepEqual(propTreshold, ceilMultiplyBy(
govAmountReceived,
makeRatio(2n, govBrand)
));

return govPayout;
};

/**
* @param {UserSeat} questionSeat
*/
const checkQuestionAskedCorrectly = async questionSeat => {

const questionOfferResult = await E(questionSeat).getOfferResult();
const popPayoutP = E(questionSeat).getPayout('POP');

const [openQuestions, popAmountReceived, publication] = await Promise.all([
E(electoratePublicFacet).getOpenQuestions(),
E(popIssuer).getAmountOf(popPayoutP),
E(electorateSubscriber).subscribeAfter()
]);

const { value: [{ questionHandle } ] } = popAmountReceived;
const questionFromElectorateP = E(electoratePublicFacet).getQuestion(openQuestions[0]);
const voteCounterFromElectorate = await E(questionFromElectorateP).getVoteCounter();
const { instance } = await E(electionManagerPublicFacet).getQuestionData(questionHandle);

t.log(popAmountReceived);
t.log(publication);

const { head: { value: { questionHandle: handleFromSubscriber } } } = publication;

t.deepEqual(questionOfferResult,
'The questison has been successfuly asked. Please redeem your tokens after the voting is ended.');
t.truthy(openQuestions.length === 1);
t.deepEqual(openQuestions[0], questionHandle);
t.deepEqual(handleFromSubscriber, questionHandle);
t.deepEqual(openQuestions[0], handleFromSubscriber);
t.deepEqual(voteCounterFromElectorate, instance);

return questionHandle;
};

return {
checkGovFetchedCorrectly,
checkQuestionAskedCorrectly
}
};

harden(makeGovernanceAssertionHelpers);
export { makeGovernanceAssertionHelpers };

70 changes: 70 additions & 0 deletions contract/test/governance/governanceScenarioHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { AmountMath, AssetKind } from '@agoric/ertp';
import { E } from '@endo/far';

/**
*
* @param {ZoeService} zoe
* @param governedPF
* @param electionManagerPublicFacet
*/
const makeGovernanceScenarioHeplpers = async (zoe, governedPF, electionManagerPublicFacet) => {

const govBrandP = E(governedPF).getGovernanceBrand();
const [govBrand, { decimalPlaces: govDecimals }, govIssuer, govKeyword, { popBrand, popIssuer }] = await Promise.all([
govBrandP,
E(govBrandP).getDisplayInfo(),
E(governedPF).getGovernanceIssuer(),
E(governedPF).getGovernanceKeyword(),
E(electionManagerPublicFacet).getPopInfo(),
]);

/**
* @param {BigInt} unitsWanted
*/
const fetchGovFromFaucet = async (unitsWanted) => {
const amountWanted = AmountMath.make(govBrand, unitsWanted * 10n ** BigInt(govDecimals));

return await E(zoe).offer(
E(governedPF).makeFaucetInvitation(),
harden({ want: { [govKeyword]: amountWanted } }),
);
};

/**
*
* @param {Payment} govPayment
* @param offerArgs
*/
const addQuestion = async (govPayment, offerArgs) => {
const govAmount = await E(govIssuer).getAmountOf(govPayment);

const propsal = harden({
give: { [govKeyword]: govAmount },
want: { POP: AmountMath.makeEmpty(popBrand, AssetKind.SET) },
});

const payment = harden({
[govKeyword]: govPayment,
});

return await E(zoe).offer(
E(electionManagerPublicFacet).makePoseQuestionsInvitation(),
propsal,
payment,
offerArgs,
);
};

return {
fetchGovFromFaucet,
addQuestion,
};
};

harden({
makeGovernanceScenarioHeplpers
});

export {
makeGovernanceScenarioHeplpers
};
37 changes: 35 additions & 2 deletions contract/test/governance/test-lendingPoolElectionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { makeMockChainStorageRoot } from '@agoric/vats/tools/storage-test-utils.
import { makeStorageNodeChild } from '@agoric/vats/src/lib-chainStorage.js';
import { makeBoard } from '@agoric/vats/src/lib-board.js';
import { ceilMultiplyBy, makeRatio } from '@agoric/zoe/src/contractSupport/ratio.js';
import { makeGovernanceScenarioHeplpers } from './governanceScenarioHelpers.js';
import { makeGovernanceAssertionHelpers } from './governanceAssertions.js';

// Paths are given according to ../lendingPool/setup.js
const CONTRACT_ROOTS = {
Expand Down Expand Up @@ -184,7 +186,7 @@ test('addQuestion', async t => {
methodArgs: ['Alice'],
voteCounterInstallation: installs.counter,
deadline: TimeMath.addAbsRel(timer.getCurrentTimestamp(), 10n),
vote: false,
vote: true,
});

const propsal = harden({
Expand Down Expand Up @@ -289,5 +291,36 @@ test('addQuestion-lower-than-treshold', async t => {
harden({}),
);

await t.throwsAsync(async () => await E(aliceBadQuestionSeat).getOfferResult());
await t.throwsAsync(async () => E(aliceBadQuestionSeat).getOfferResult());
});

test('voteOnQuestion', async t => {
const {
zoe,
timer,
electionManager: { electionManagerCreatorFacet, electionManagerPublicFacet },
electorate: { electoratePublicFacet },
governed: { governedPF },
installs
} = await setupServices(t);

const { fetchGovFromFaucet, addQuestion } = await makeGovernanceScenarioHeplpers(zoe, governedPF, electionManagerPublicFacet);
const { checkGovFetchedCorrectly, checkQuestionAskedCorrectly } = await makeGovernanceAssertionHelpers(t, zoe, governedPF, electionManagerPublicFacet, electoratePublicFacet);

const aliceGovSeat = await fetchGovFromFaucet(5n);
const aliceGovPayout = await checkGovFetchedCorrectly(aliceGovSeat, { unitsWanted: 5n});

const offerArgs = harden({
apiMethodName: 'resolveArgument',
methodArgs: ['Alice'],
voteCounterInstallation: installs.counter,
deadline: TimeMath.addAbsRel(timer.getCurrentTimestamp(), 10n),
vote: true,
});

const aliceQuestionSeat = await addQuestion(aliceGovPayout, offerArgs);
const aliceQuestionHandle = await checkQuestionAskedCorrectly(aliceQuestionSeat);

// Work in progress

});

0 comments on commit 907bcc2

Please sign in to comment.