-
Notifications
You must be signed in to change notification settings - Fork 214
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(a3p): extend test coverage for Vaults on z:acceptance (#10297)
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
Showing
12 changed files
with
1,842 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.`); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
a3p-integration/proposals/z:acceptance/test-lib/price-feed.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.