Skip to content

Commit

Permalink
test(a3p): create a3p test for replace electorate core eval
Browse files Browse the repository at this point in the history
  • Loading branch information
frazarshad committed Oct 8, 2024
1 parent cba5d99 commit 5082910
Show file tree
Hide file tree
Showing 10 changed files with 6,127 additions and 2 deletions.
1 change: 1 addition & 0 deletions a3p-integration/proposals/b:replace-electorate/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
6 changes: 6 additions & 0 deletions a3p-integration/proposals/b:replace-electorate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# CoreEvalProposal to upgrade vaults and auctions

The `submission` for this proposal is automatically generated during `yarn build`
in [a3p-integration](../..) using the code in agoric-sdk through
[build-all-submissions.sh](../../scripts/build-all-submissions.sh) and
[build-submission.sh](../../scripts/build-submission.sh).
185 changes: 185 additions & 0 deletions a3p-integration/proposals/b:replace-electorate/agoric-tools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import assert from 'node:assert';
import {
agops,
agoric,
executeOffer,
queryVstorage,
} from '@agoric/synthetic-chain';
import { makeMarshal, Remotable } from '@endo/marshal';

/** @param {string} path */
export const queryVstorageFormatted = async (path, index, fromCapData) => {
const data = await queryVstorage(path);
const formattedData = JSON.parse(data.value);
const formattedDataAtIndex = JSON.parse(formattedData.values.at(index));
return fromCapData(formattedDataAtIndex);
};

const slotToRemotable = (_slotId, iface = 'Remotable') =>
Remotable(iface, undefined, {
getBoardId: () => _slotId,
});

// /** @param {BoardRemote | object} val */
const boardValToSlot = val => {
if ('getBoardId' in val) {
return val.getBoardId();
}
throw Error(`unknown obj in boardSlottingMarshaller.valToSlot ${val}`);
};

const boardSlottingMarshaller = slotToVal => {
return makeMarshal(boardValToSlot, slotToVal, {
serializeBodyFormat: 'smallcaps',
});
};

export const marshaller = boardSlottingMarshaller(slotToRemotable);

const generateVaultDirectorParamChange = async (
previousOfferId,
voteDur,
params,
paramsPath,
) => {
const voteDurSec = BigInt(voteDur);
const toSec = ms => BigInt(Math.round(ms / 1000));

const id = `propose-${Date.now()}`;
const deadline = toSec(Date.now()) + voteDurSec;

const a = await agoric.follow(
'-lF',
':published.agoricNames.instance',
'-o',
'text',
);
const instance = Object.fromEntries(marshaller.fromCapData(JSON.parse(a)));
assert(instance.VaultFactory);

const body = {
method: 'executeOffer',
offer: {
id,
invitationSpec: {
invitationMakerName: 'VoteOnParamChange',
previousOffer: previousOfferId,
source: 'continuing',
},
offerArgs: {
deadline: deadline,
instance: instance.VaultFactory,
params,
path: paramsPath,
},
proposal: {},
},
};

const capData = marshaller.toCapData(harden(body));
return JSON.stringify(capData);
};

export const generateVoteOffer = async previousOfferId => {
const id = `propose-${Date.now()}`;

const latestQuestionRecord = await queryVstorageFormatted(
'published.committees.Economic_Committee.latestQuestion',
-1,
marshaller.fromCapData,
);

const chosenPositions = [latestQuestionRecord.positions[0]];
const body = {
method: 'executeOffer',
offer: {
id,
invitationSpec: {
invitationMakerName: 'makeVoteInvitation',
previousOffer: previousOfferId,
source: 'continuing',
invitationArgs: harden([
chosenPositions,
latestQuestionRecord.questionHandle,
]),
},
proposal: {},
},
};

const capData = marshaller.toCapData(harden(body));
return JSON.stringify(capData);
};

export const proposeVaultDirectorParamChange = async (
address,
params,
path,
charterAcceptOfferId,
) => {
const offerId =
charterAcceptOfferId ||
(await agops.ec(
'find-continuing-id',
'--for',
`${'charter\\ member\\ invitation'}`,
'--from',
address,
));

return executeOffer(
address,
generateVaultDirectorParamChange(offerId, 10, params, path),
);
};

export const voteOnProposedChanges = async (
address,
committeeAcceptOfferId,
) => {
const offerId =
committeeAcceptOfferId ||
(await agops.ec(
'find-continuing-id',
'--for',
'Voter0',
'--from',
address,
));

return executeOffer(address, generateVoteOffer(offerId));
};

export const acceptInvitation = async (
address,
instanceName,
description,
offerId,
) => {
const instanceDataRaw = await agoric.follow(
'-lF',
':published.agoricNames.instance',
'-o',
'text',
);
const instance = Object.fromEntries(
marshaller.fromCapData(JSON.parse(instanceDataRaw)),
);
assert(instance[instanceName]);
const id = offerId || `econ-${Date.now()}`;
const body = {
method: 'executeOffer',
offer: {
id: id,
invitationSpec: {
source: 'purse',
instance: instance[instanceName],
description,
},
proposal: {},
},
};

const capData = marshaller.toCapData(harden(body));
return executeOffer(address, JSON.stringify(capData));
};
26 changes: 26 additions & 0 deletions a3p-integration/proposals/b:replace-electorate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"agoricProposal": {
"type": "/agoric.swingset.CoreEvalProposal",
"source": "subdir",
"sdk-generate": [
"inter-protocol/replace-electorate-core.js submission A3P_INTEGRATION"
]
},
"type": "module",
"license": "Apache-2.0",
"dependencies": {
"@agoric/synthetic-chain": "^0.3.0",
"@agoric/vats": "0.15.1",
"@endo/init": "^1.1.4",
"@endo/marshal": "^1.5.3",
"ava": "^6.1.3"
},
"ava": {
"concurrency": 1,
"serial": true,
"files": [
"!submission"
]
},
"packageManager": "[email protected]"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import test from 'ava';
import 'ses';
import '@endo/init';
import {
agops,
ATOM_DENOM,
getISTBalance,
GOV1ADDR,
GOV2ADDR,
GOV3ADDR,
openVault,
queryVstorage,
USER1ADDR,
} from '@agoric/synthetic-chain';
import {
acceptInvitation,
marshaller,
proposeVaultDirectorParamChange,
voteOnProposedChanges,
queryVstorageFormatted,
} from './agoric-tools.js';
import { waitUntil } from './utils.js';

test('new committee should be able to vote', async t => {
const params = {
ChargingPeriod: 400n,
};

const { fromCapData } = marshaller;
const charterOfferId = 'newEcCharter';
const committeeOfferId = 'newEcCommittee';

const path = { paramPath: { key: 'governedParams' } };

t.log('accept new invitations');
await acceptInvitation(
GOV1ADDR,
'economicCommittee',
'Voter0',
committeeOfferId,
);
await acceptInvitation(
GOV1ADDR,
'econCommitteeCharter',
'charter member invitation',
charterOfferId,
);

t.log('propose a param change with the new invitation');
await proposeVaultDirectorParamChange(GOV1ADDR, params, path, charterOfferId);

// const wallet = await queryVstorageFormatted(
// `published.wallet.${GOV1ADDR}.current`,
// -1,
// fromCapData,
// );
// console.log('wallet', wallet);

t.log('vote on proposed changes');
await voteOnProposedChanges(GOV1ADDR, committeeOfferId);

t.log('wait until the vote is closed');
const latestQuestion = await queryVstorageFormatted(
'published.committees.Economic_Committee.latestQuestion',
-1,
fromCapData,
);
await waitUntil(latestQuestion.closingRule.deadline);

t.log('check if latest outcome is correct');
const latestOutcome = await queryVstorageFormatted(
'published.committees.Economic_Committee.latestOutcome',
-1,
fromCapData,
);
t.is(latestOutcome.outcome, 'win');
});
6 changes: 6 additions & 0 deletions a3p-integration/proposals/b:replace-electorate/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

# Place here any test that should be run using the executed proposal.
# The effects of this step are not persisted in further proposal layers.

yarn ava ./*.test.js
16 changes: 16 additions & 0 deletions a3p-integration/proposals/b:replace-electorate/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"noEmit": true,
"target": "esnext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowJs": true,
"checkJs": true,
"strict": false,
"strictNullChecks": true,
"noImplicitThis": true,
// XXX synthetic-chain has some errors
"skipLibCheck": true,
}
}

5 changes: 5 additions & 0 deletions a3p-integration/proposals/b:replace-electorate/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const waitUntil = async waitTime => {
while (Math.floor(Date.now() / 1000) < waitTime) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
};
Loading

0 comments on commit 5082910

Please sign in to comment.