Skip to content

Commit

Permalink
chore(a3p-integration): Type-check proposal z:acceptance (#10499)
Browse files Browse the repository at this point in the history
## Description
Add types to z:acceptance and npm scripts to validate them. Also includes a fix uncovered in `waitUntil` reversing the $then − $now direction for calculating the necessary delay duration.

### Security Considerations
n/a

### Scaling Considerations
n/a

### Documentation Considerations
n/a

### Testing Considerations
The a3p-integration proposals should be type-checked, but I don't know if CI does so.

### Upgrade Considerations
n/a
  • Loading branch information
mergify[bot] authored Nov 16, 2024
2 parents 76ad0fc + ed4732f commit b4b351e
Show file tree
Hide file tree
Showing 16 changed files with 1,584 additions and 175 deletions.
5 changes: 4 additions & 1 deletion a3p-integration/proposals/z:acceptance/governance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ test.serial(
'published.committees.Economic_Committee.latestQuestion',
)
);
await waitUntil(latestQuestion.closingRule.deadline);
/** @type {bigint} */
// @ts-expect-error assume POSIX seconds since epoch
const deadline = latestQuestion.closingRule.deadline;
await waitUntil(deadline);

t.log('check if latest outcome is correct');
const latestOutcome = await readLatestHead(
Expand Down
2 changes: 2 additions & 0 deletions a3p-integration/proposals/z:acceptance/kread.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ test.serial('Alice sells one unequipped Item', async t => {
);

const soldItemNode = itemListAfter.filter(
/** @param {unknown} itemNode */
itemNode => !itemListBefore.includes(itemNode),
);
const soldItem = await getMarketItem(soldItemNode);
Expand All @@ -102,6 +103,7 @@ test.serial('Bob buys an Item on marketplace', async t => {
);

const boughtItemNode = itemListBefore.filter(
/** @param {unknown} itemNode */
itemNode => !itemListAfter.includes(itemNode),
);
t.is(
Expand Down
2 changes: 1 addition & 1 deletion a3p-integration/proposals/z:acceptance/localchain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { agd, evalBundles } from '@agoric/synthetic-chain';
import test from 'ava';
import { retryUntilCondition } from './test-lib/sync-tools.js';
import { retryUntilCondition } from '@agoric/client-utils';

const SUBMISSION_DIR = 'localchaintest-submission';

Expand Down
18 changes: 12 additions & 6 deletions a3p-integration/proposals/z:acceptance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"@agoric/store": "dev",
"@agoric/synthetic-chain": "^0.3.0",
"@agoric/zoe": "dev",
"@endo/errors": "^1.2.2",
"@endo/far": "^1.1.5",
"@endo/init": "^1.1.4",
"@endo/marshal": "^1.5.3",
"@endo/errors": "^1.2.7",
"@endo/far": "^1.1.8",
"@endo/init": "^1.1.6",
"@endo/marshal": "^1.6.1",
"agoric": "dev",
"ava": "^6.1.2",
"execa": "9.1.0",
Expand Down Expand Up @@ -88,10 +88,16 @@
]
},
"scripts": {
"agops": "yarn --cwd /usr/src/agoric-sdk/ --silent agops"
"agops": "yarn --cwd /usr/src/agoric-sdk/ --silent agops",
"lint-fix": "yarn lint:eslint --fix",
"lint": "run-s --continue-on-error 'lint:*'",
"lint:types": "tsc",
"lint:eslint": "eslint ."
},
"packageManager": "[email protected]",
"devDependencies": {
"typescript": "^5.5.4"
"eslint": "^8.57.0",
"npm-run-all": "^4.1.5",
"typescript": "^5.6.3"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
pushPrices,
} from '@agoric/synthetic-chain';

/** @type {(x: number) => bigint} */
export const scale6 = x => BigInt(x * 1_000_000);

/**
Expand Down
26 changes: 14 additions & 12 deletions a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { getBalances } from './utils.js';
* | { failed: false }
* | Pick<
* ExecaError & { failed: true },
* 'failed',
* | 'failed'
* | 'shortMessage'
* | 'cause'
* | 'exitCode'
Expand Down Expand Up @@ -187,8 +187,7 @@ export const voteForNewParams = ({ committeeAddrs, position }) => {
console.log('ACTIONS voting for position', position, 'using', committeeAddrs);
return Promise.all(
committeeAddrs.map(account =>
// @ts-expect-error Casting
agops.ec('vote', '--forPosition', position, '--send-from', account),
agops.ec('vote', '--forPosition', `${position}`, '--send-from', account),
),
);
};
Expand All @@ -204,10 +203,10 @@ export const fetchLatestEcQuestion = async io => {

const [latestOutcome, latestQuestion] = await Promise.all([
follow('-lF', pathOutcome, '-o', 'text').then(outcomeRaw =>
marshaller.fromCapData(JSON.parse(outcomeRaw)),
marshaller.fromCapData(JSON.parse(/** @type {any} */ (outcomeRaw))),
),
follow('-lF', pathQuestion, '-o', 'text').then(questionRaw =>
marshaller.fromCapData(JSON.parse(questionRaw)),
marshaller.fromCapData(JSON.parse(/** @type {any} */ (questionRaw))),
),
]);

Expand Down Expand Up @@ -411,13 +410,16 @@ export const sendOfferAgd = async (address, offerPromise) => {
const offer = await offerPromise;
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
const { chainName, rpcAddrs } = networkConfig;
const args = [].concat(
[`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`],
[`--keyring-backend=test`, `--from=${address}`],
['tx', 'swingset', 'wallet-action', '--allow-spend', offer],
'--yes',
'-bblock',
'-ojson',
const args = /** @type {string[]} */ (
// @ts-expect-error heterogeneous concat
[].concat(
[`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`],
[`--keyring-backend=test`, `--from=${address}`],
['tx', 'swingset', 'wallet-action', '--allow-spend', offer],
'--yes',
'-bblock',
'-ojson',
)
);

const [settlement] = await Promise.allSettled([
Expand Down
10 changes: 8 additions & 2 deletions a3p-integration/proposals/z:acceptance/test-lib/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ import { Fail } from '@endo/errors';

export { boardSlottingMarshaller };

/** @type {(val: any) => string} */
export const boardValToSlot = val => {
if ('getBoardId' in val) {
return val.getBoardId();
}
Fail`unknown obj in boardSlottingMarshaller.valToSlot ${val}`;
throw Fail`unknown obj in boardSlottingMarshaller.valToSlot ${val}`;
};

/** @param {string} agoricNetSubdomain */
export const networkConfigUrl = agoricNetSubdomain =>
`https://${agoricNetSubdomain}.agoric.net/network-config`;
/** @param {string} agoricNetSubdomain */
export const rpcUrl = agoricNetSubdomain =>
`https://${agoricNetSubdomain}.rpc.agoric.net:443`;

Expand Down Expand Up @@ -74,6 +77,7 @@ export const makeVStorage = (powers, config = networkConfig) => {

return {
url,
/** @param {{ result: { response: { code: number, value: string } } }} rawResponse */
decode({ result: { response } }) {
const { code } = response;
if (code !== 0) {
Expand Down Expand Up @@ -155,6 +159,7 @@ export const makeVStorage = (powers, config = networkConfig) => {

export const makeFromBoard = () => {
const cache = new Map();
/** @type {(boardId: string, iface?: string) => ReturnType<typeof makeBoardRemote>} */
const convertSlotToVal = (boardId, iface) => {
if (cache.has(boardId)) {
return cache.get(boardId);
Expand Down Expand Up @@ -211,6 +216,7 @@ harden(storageHelper);
* @returns {Promise<import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes>}
*/
export const makeAgoricNames = async (ctx, vstorage) => {
/** @type {Record<string, string>} */
const reverse = {};
const entries = await Promise.all(
['brand', 'instance', 'vbankAsset'].map(async kind => {
Expand All @@ -221,7 +227,7 @@ export const makeAgoricNames = async (ctx, vstorage) => {
const parts = storageHelper.unserializeTxt(content, ctx).at(-1);
for (const [name, remote] of parts) {
if ('getBoardId' in remote) {
reverse[remote.getBoardId()] = name;
reverse[/** @type {string} */ (remote.getBoardId())] = name;
}
}
return [kind, Object.fromEntries(parts)];
Expand Down
10 changes: 6 additions & 4 deletions a3p-integration/proposals/z:acceptance/test-lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ export const makeTimerUtils = ({ setTimeout }) => {
*/
const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));

/** @param {number} timestamp */
const waitUntil = async timestamp => {
const timeDelta = Math.floor(Date.now() / 1000) - Number(timestamp);
await delay(timeDelta);
/** @param {number | bigint} secondsSinceEpoch */
const waitUntil = async secondsSinceEpoch => {
await null;
const waitMs = Number(secondsSinceEpoch) * 1000 - Date.now();
if (waitMs <= 0) return;
await delay(waitMs);
};

return {
Expand Down
12 changes: 8 additions & 4 deletions a3p-integration/proposals/z:acceptance/test-lib/vaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ export const getMinInitialDebt = async () => {
*/
export const calculateMintFee = async (toMintValue, vaultManager) => {
const { brand } = await E.get(vstorageKitP).agoricNames;
/** @type {import('@agoric/ertp').Brand} */
// @ts-expect-error let this BoardRemote masquerade as a Brand
const ISTBrand = brand.IST;

const governancePath = `published.vaultFactory.managers.${vaultManager}.governance`;
const governance = await getContractInfo(governancePath, {
Expand All @@ -110,13 +113,12 @@ export const calculateMintFee = async (toMintValue, vaultManager) => {

const mintFeeRatio = makeRatio(
numerator.value,
brand.IST,
ISTBrand,
denominator.value,
brand.IST,
ISTBrand,
);

// @ts-expect-error XXX BoardRemote not Brand
const toMintAmount = AmountMath.make(brand.IST, toMintValue * 1_000_000n);
const toMintAmount = AmountMath.make(ISTBrand, toMintValue * 1_000_000n);
const expectedMintFee = ceilMultiplyBy(toMintAmount, mintFeeRatio);
const adjustedToMintAmount = AmountMath.add(toMintAmount, expectedMintFee);

Expand Down Expand Up @@ -164,6 +166,7 @@ const paramChangeOfferGeneration = async (

const voteDurSec = BigInt(voteDur);
const debtLimitValue = BigInt(debtLimit) * ISTunit;
/** @type {(ms: number) => bigint} */
const toSec = ms => BigInt(Math.round(ms / 1000));

const id = `propose-${Date.now()}`;
Expand Down Expand Up @@ -199,6 +202,7 @@ const paramChangeOfferGeneration = async (
},
};

// @ts-expect-error tolerate BoardRemote instances with getBoardId methods
return JSON.stringify(marshaller.toCapData(harden(body)));
};

Expand Down
4 changes: 3 additions & 1 deletion a3p-integration/proposals/z:acceptance/test-lib/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ import { makeTimerUtils } from './utils.js';
* fees?: string,
* verbose?: boolean,
* keyring?: {home?: string, backend: string},
* stdout: Pick<import('stream').Writable, 'write'>,
* stdout?: Pick<import('stream').Writable, 'write'>,
* execFileSync: typeof import('child_process').execFileSync,
* delay: (ms: number) => Promise<void>,
* dryRun?: boolean,
* }} opts
*/
export const sendAction = async (bridgeAction, opts) => {
const { marshaller } = opts;
// @ts-expect-error BridgeAction has methods disallowed by Passable
const offerBody = JSON.stringify(marshaller.toCapData(harden(bridgeAction)));

// tryExit should not require --allow-spend
Expand Down Expand Up @@ -80,6 +81,7 @@ export const makeAgdWalletUtils = async (
delay,
execFileSync,
from,
// @ts-expect-error version skew in @endo/marshal and/or @endo/pass-style
marshaller,
keyring: { backend: 'test' },
});
Expand Down
8 changes: 4 additions & 4 deletions a3p-integration/proposals/z:acceptance/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"compilerOptions": {
"noEmit": true,
"target": "esnext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"module": "esnext",
"moduleResolution": "bundler",
"allowJs": true,
"checkJs": true,
"strict": false,
"strictNullChecks": true,
"noImplicitThis": true,
"noImplicitAny": true,
// XXX synthetic-chain has some errors
"skipLibCheck": true
}
},
"exclude": ["restart-valueVow", "start-valueVow", "localchaintest-submission"]
}
1 change: 1 addition & 0 deletions a3p-integration/proposals/z:acceptance/valueVow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ test('vow survives restart', async t => {

t.log('confirm the value is not in offer results');
let getterStatus = await retryUntilCondition(
/** @type {() => Promise<any>} */
async () => walletUtils.readLatestHead(`published.wallet.${GETTER}`),
value => value.status.id === 'get-value' && value.updated === 'offerStatus',
'Offer get-value not succeeded',
Expand Down
1 change: 1 addition & 0 deletions a3p-integration/proposals/z:acceptance/vaults.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {

const VAULT_MANAGER = 'manager0';

/** @type {(x: number) => number} */
const scale6 = x => x * 1_000_000;

// TODO produce this dynamically from an Offers object exported from a package clientSupport
Expand Down
6 changes: 6 additions & 0 deletions a3p-integration/proposals/z:acceptance/wallet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ import { execFileSync } from 'node:child_process';
import { agdWalletUtils } from './test-lib/index.js';
import { getBalances, replaceTemplateValuesInFile } from './test-lib/utils.js';

/**
* @param {string} file
* @param {string[]} args
* @param {Parameters<typeof execFileSync>[2]} [opts]
*/
const showAndExec = (file, args, opts) => {
console.log('$', file, ...args);
return execFileSync(file, args, opts);
Expand Down Expand Up @@ -126,6 +131,7 @@ test.serial(`ante handler sends fee only to vbank/reserve`, async t => {
// The reserve balances should have increased by exactly the fee (possibly
// from zero, in which case start balances wouldn't include its denomination).
const feeDenomIndex = vbankReserveStartBalances.findIndex(
/** @param {{ denom: string }} balance */
({ denom }) => denom === feeDenom,
);
const preFeeAmount =
Expand Down
Loading

0 comments on commit b4b351e

Please sign in to comment.