Skip to content

Commit

Permalink
test(a3p): extend test coverage for Vaults on z:acceptance (#10297)
Browse files Browse the repository at this point in the history
closes: https://github.com/Agoric/BytePitchPartnerEng/issues/22
closes: https://github.com/Agoric/BytePitchPartnerEng/issues/15

## Description


The purpose of this PR is to extend the `z:acceptance` testing coverage of `Vaults` to include the following cases: 
- user cannot open a vault above debt limit
- user can open a vault under debt limit
- user cannot increase vault debt above debt limit
- MintFee is applied to users debt when creating a vault and minting more IST
- Oracle prices are being received
- vaults that existed before the most recent upgrade continue to be useable
- user can pay off debt when total debt is above debt limit

The existing tests were also refactored to take advantage of the new helper functions built and also included in this PR.

In addition to extending the test cases, other key update is the introduction of a new script, `openVault.js`, to open a new vault in the `use` phase of `n:upgrade-next` proposal. 
This process allow us to test that vaults that existed before the most recent upgrade continue to be useable

A more detailed discussion of the decisions made for the implementations above can be found on the issue: https://github.com/Agoric/BytePitchPartnerEng/issues/22

### Security Considerations


none

### Scaling Considerations


none

### Documentation Considerations


none

### Testing Considerations


This PR included a new file, `/z:acceptance/test-lib/ratio.js`, which exports the method `ceilMultiplyBy` , which is also exported by the `@agoric/zoe` package.

The reason why this file was created was because when trying to install the `@agoric/zoe` package at the a3p-integration z:acceptance proposal, it failed because `@agoric/xsnap` package couldn't be built successfully.
As described in the issue #10259 

When resolved, the `ratio.js` file should be removed and the `ceilMultiplyBy` method should be imported from the `@agoric/zoe` package.

### Upgrade Considerations


none
  • Loading branch information
mergify[bot] authored Nov 5, 2024
2 parents 44132c0 + 737765d commit d603b6c
Show file tree
Hide file tree
Showing 12 changed files with 1,842 additions and 161 deletions.
34 changes: 34 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/openVault.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env node

import {
GOV1ADDR,
CHAINID,
agd,
openVault,
addUser,
waitForBlock,
provisionSmartWallet,
ATOM_DENOM,
} from '@agoric/synthetic-chain';

export const bankSend = (from, addr, wanted) => {
const chain = ['--chain-id', CHAINID];
const fromArg = ['--from', from];
const testKeyring = ['--keyring-backend', 'test'];
const noise = [...fromArg, ...chain, ...testKeyring, '--yes'];

return agd.tx('bank', 'send', from, addr, wanted, ...noise);
};

const user = await addUser('long-living-vault');
console.log('USER', user);
await bankSend(GOV1ADDR, user, `80000000uist`);
console.log('IST sent');
await provisionSmartWallet(user, `20000000ubld,100000000${ATOM_DENOM}`);
console.log('Provision sent');
await waitForBlock(3);
console.log('Wait For Block done. Sending open vault offer');

const mint = '5.0';
const collateral = '10.0';
await openVault(user, mint, collateral);
72 changes: 72 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/sync-tools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* eslint-env node */

/**
* @file These tools mostly duplicate code that will be added in other PRs
* and eventually migrated to synthetic-chain. Sorry for the duplication.
*/

/**
* @typedef {object} RetryOptions
* @property {number} [maxRetries]
* @property {number} [retryIntervalMs]
* @property {(...arg0: string[]) => void} log
* @property {(object) => void} [setTimeout]
* @property {string} [errorMessage=Error]
*/

const ambientSetTimeout = global.setTimeout;

/**
* From https://github.com/Agoric/agoric-sdk/blob/442f07c8f0af03281b52b90e90c27131eef6f331/multichain-testing/tools/sleep.ts#L10
*
* @param {number} ms
* @param {*} sleepOptions
*/
const sleep = (ms, { log = () => {}, setTimeout = ambientSetTimeout }) =>
new Promise(resolve => {
log(`Sleeping for ${ms}ms...`);
setTimeout(resolve, ms);
});

/**
* From https://github.com/Agoric/agoric-sdk/blob/442f07c8f0af03281b52b90e90c27131eef6f331/multichain-testing/tools/sleep.ts#L24
*
* @param {() => Promise} operation
* @param {(result: any) => boolean} condition
* @param {string} message
* @param {RetryOptions} options
*/
export const retryUntilCondition = async (
operation,
condition,
message,
{ maxRetries = 6, retryIntervalMs = 3500, log, setTimeout },
) => {
console.log({ maxRetries, retryIntervalMs, message });
let retries = 0;

await null;
while (retries < maxRetries) {
try {
const result = await operation();
log('RESULT', result);
if (condition(result)) {
return result;
}
} catch (error) {
if (error instanceof Error) {
log(`Error: ${error.message}`);
} else {
log(`Unknown error: ${String(error)}`);
}
}

retries += 1;
console.log(
`Retry ${retries}/${maxRetries} - Waiting for ${retryIntervalMs}ms for ${message}...`,
);
await sleep(retryIntervalMs, { log, setTimeout });
}

throw Error(`${message} condition failed after ${maxRetries} retries.`);
};
2 changes: 2 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/use.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ node ./addGov4
# "oracles" accept their invitations and provide prices to priceFeeds
./verifyPushedPrice.js 'ATOM' 12.01
./verifyPushedPrice.js 'stATOM' 12.01

./openVault.js
5 changes: 5 additions & 0 deletions a3p-integration/proposals/z:acceptance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@agoric/internal": "dev",
"@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",
Expand All @@ -22,6 +23,10 @@
"execa": "^9.3.1",
"tsx": "^4.17.0"
},
"$comment": "UNTIL https://github.com/Agoric/agoric-sdk/issues/10259",
"resolutions": {
"@agoric/xsnap": "beta"
},
"ava": {
"concurrency": 1,
"serial": true,
Expand Down
62 changes: 62 additions & 0 deletions a3p-integration/proposals/z:acceptance/test-lib/price-feed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* eslint-env node */

import {
agoric,
getContractInfo,
pushPrices,
getPriceQuote,
} from '@agoric/synthetic-chain';
import { retryUntilCondition } from './sync-tools.js';

export const scale6 = x => BigInt(x * 1_000_000);

/**
*
* @param {Map<any, any>} oraclesByBrand
* @param {string} brand
* @param {number} price
* @param {number} roundId
* @returns {Promise<void>}
*/
export const verifyPushedPrice = async (
oraclesByBrand,
brand,
price,
roundId,
) => {
const pushPriceRetryOpts = {
maxRetries: 5, // arbitrary
retryIntervalMs: 5000, // in ms
};

await pushPrices(price, brand, oraclesByBrand, roundId);
console.log(`Pushing price ${price} for ${brand}`);

await retryUntilCondition(
() => getPriceQuote(brand),
res => res === `+${scale6(price).toString()}`,
'price not pushed yet',
{
log: console.log,
setTimeout: global.setTimeout,
...pushPriceRetryOpts,
},
);
console.log(`Price ${price} pushed for ${brand}`);
};

/**
*
* @param {string} brand
* @returns {Promise<number>}
*/
export const getPriceFeedRoundId = async brand => {
const latestRoundPath = `published.priceFeed.${brand}-USD_price_feed.latestRound`;
const latestRound = await getContractInfo(latestRoundPath, {
agoric,
prefix: '',
});

console.log('latestRound: ', latestRound);
return Number(latestRound.roundId);
};
2 changes: 1 addition & 1 deletion a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ const extractBalance = (balances, targetDenom) => {
* @param {number} actualBalance
* @param {number} expectedBalance
*/
const tryISTBalances = async (t, actualBalance, expectedBalance) => {
export const tryISTBalances = async (t, actualBalance, expectedBalance) => {
const firstTry = await t.try(
(tt, actual, expected) => {
tt.deepEqual(actual, expected);
Expand Down
22 changes: 21 additions & 1 deletion a3p-integration/proposals/z:acceptance/test-lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { makeAgd, agops } from '@agoric/synthetic-chain';
import { makeAgd, agops, agoric } from '@agoric/synthetic-chain';
import { execFileSync } from 'node:child_process';
import { readFile, writeFile } from 'node:fs/promises';
import { boardSlottingMarshaller, makeFromBoard } from './rpc.js';

/**
* @param {string} fileName base file name without .tjs extension
Expand Down Expand Up @@ -66,3 +67,22 @@ export const makeTimerUtils = ({ setTimeout }) => {
waitUntil,
};
};

const fromBoard = makeFromBoard();
const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal);

export const getAgoricNamesBrands = async () => {
const brands = await agoric
.follow('-lF', ':published.agoricNames.brand', '-o', 'text')
.then(res => Object.fromEntries(marshaller.fromCapData(JSON.parse(res))));

return brands;
};

export const getAgoricNamesInstances = async () => {
const instances = await agoric
.follow('-lF', ':published.agoricNames.instance', '-o', 'text')
.then(res => Object.fromEntries(marshaller.fromCapData(JSON.parse(res))));

return instances;
};
Loading

0 comments on commit d603b6c

Please sign in to comment.