-
Notifications
You must be signed in to change notification settings - Fork 206
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: liquidation works with new price feeds, vaults, auctions
- Loading branch information
Showing
1 changed file
with
194 additions
and
0 deletions.
There are no files selected for viewing
194 changes: 194 additions & 0 deletions
194
packages/boot/test/bootstrapTests/price-feed-replace.test.ts
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,194 @@ | ||
/** | ||
* @file The goal of this test is to see that the | ||
* upgrade scripts re-wire all the contracts so new auctions and | ||
* price feeds are connected to vaults correctly. | ||
* | ||
* 1. enter a bid | ||
* 2. force prices to drop so a vault liquidates | ||
* 3. verify that the bidder gets the liquidated assets. | ||
*/ | ||
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; | ||
|
||
import type { TestFn } from 'ava'; | ||
import { ScheduleNotification } from '@agoric/inter-protocol/src/auction/scheduler.js'; | ||
import { NonNullish } from '@agoric/internal'; | ||
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; | ||
import { | ||
LiquidationTestContext, | ||
likePayouts, | ||
makeLiquidationTestContext, | ||
scale6, | ||
LiquidationSetup, | ||
atomConfig, | ||
} from '../../tools/liquidation.js'; | ||
|
||
const test = anyTest as TestFn<LiquidationTestContext>; | ||
test.before( | ||
async t => | ||
(t.context = await makeLiquidationTestContext(t, { env: process.env })), | ||
); | ||
test.after.always(t => t.context.shutdown()); | ||
|
||
const collateralBrandKey = 'ATOM'; | ||
const managerIndex = 0; | ||
|
||
const setup: LiquidationSetup = { | ||
vaults: [{ atom: 15, ist: 100, debt: 100.5 }], | ||
bids: [{ give: '20IST', discount: 0.1 }], | ||
price: { | ||
starting: 12.34, | ||
trigger: 9.99, | ||
}, | ||
auction: { | ||
start: { collateral: 15, debt: 100.5 }, | ||
end: { collateral: 9.659301, debt: 0 }, | ||
}, | ||
}; | ||
|
||
const outcome = { | ||
bids: [{ payouts: { Bid: 0, Collateral: 1.800828 } }], | ||
}; | ||
|
||
test.serial('setupVaults; run replace-price-feeds proposals', async t => { | ||
const { | ||
agoricNamesRemotes, | ||
buildProposal, | ||
evalProposal, | ||
priceFeedDrivers, | ||
refreshAgoricNamesRemotes, | ||
setupVaults, | ||
} = t.context; | ||
|
||
await setupVaults(collateralBrandKey, managerIndex, setup); | ||
|
||
const instancePre = agoricNamesRemotes.instance['ATOM-USD price feed']; | ||
|
||
const perFeedBuilder = '@agoric/builders/scripts/vats/priceFeedSupport.js'; | ||
t.log('building', perFeedBuilder); | ||
const brandName = collateralBrandKey; | ||
const opts = { | ||
AGORIC_INSTANCE_NAME: `${brandName}-USD price feed`, | ||
ORACLE_ADDRESSES: atomConfig.oracleAddresses, | ||
IN_BRAND_LOOKUP: ['agoricNames', 'oracleBrand', brandName], | ||
IN_BRAND_DECIMALS: 6, | ||
OUT_BRAND_LOOKUP: ['agoricNames', 'oracleBrand', 'USD'], | ||
OUT_BRAND_DECIMALS: 4, | ||
}; | ||
|
||
t.log('building all relevant CoreEvals'); | ||
const coreEvals = await Promise.all([ | ||
buildProposal(perFeedBuilder, opts), | ||
// '@agoric/builders/scripts/vats/upgradeScaledPriceAuthorities.js', | ||
buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'), | ||
buildProposal('@agoric/builders/scripts/vats/add-auction.js'), | ||
]); | ||
const combined = { | ||
evals: coreEvals.flatMap(e => e.evals), | ||
bundles: coreEvals.flatMap(e => e.bundles), | ||
}; | ||
t.log('evaluating', coreEvals.length, 'scripts'); | ||
await evalProposal(combined); | ||
|
||
refreshAgoricNamesRemotes(); | ||
const instancePost = agoricNamesRemotes.instance['ATOM-USD price feed']; | ||
t.not(instancePre, instancePost); | ||
|
||
await priceFeedDrivers[collateralBrandKey].refreshInvitations(); | ||
}); | ||
|
||
test.serial('1. place bid', async t => { | ||
const { placeBids, readLatest } = t.context; | ||
await placeBids(collateralBrandKey, 'agoric1buyer', setup, 0); | ||
|
||
t.like(readLatest('published.wallet.agoric1buyer.current'), { | ||
liveOffers: [['ATOM-bid1', { id: 'ATOM-bid1' }]], | ||
}); | ||
}); | ||
|
||
test.serial('2. trigger liquidation by changing price', async t => { | ||
const { priceFeedDrivers, readLatest } = t.context; | ||
|
||
await priceFeedDrivers[collateralBrandKey].setPrice(9.99); | ||
|
||
t.log(readLatest('published.priceFeed.ATOM-USD_price_feed'), { | ||
// aka 9.99 | ||
amountIn: { value: 1000000n }, | ||
amountOut: { value: 9990000n }, | ||
}); | ||
|
||
// check nothing liquidating yet | ||
const liveSchedule: ScheduleNotification = readLatest( | ||
'published.auction.schedule', | ||
); | ||
t.is(liveSchedule.activeStartTime, null); | ||
const metricsPath = `published.vaultFactory.managers.manager${managerIndex}.metrics`; | ||
|
||
t.like(readLatest(metricsPath), { | ||
numActiveVaults: setup.vaults.length, | ||
numLiquidatingVaults: 0, | ||
}); | ||
}); | ||
|
||
test.serial('3. verify liquidation', async t => { | ||
const { advanceTimeBy, advanceTimeTo, readLatest } = t.context; | ||
|
||
const liveSchedule: ScheduleNotification = readLatest( | ||
'published.auction.schedule', | ||
); | ||
const metricsPath = `published.vaultFactory.managers.manager${managerIndex}.metrics`; | ||
|
||
// advance time to start an auction | ||
console.log(collateralBrandKey, 'step 1 of 10'); | ||
await advanceTimeTo(NonNullish(liveSchedule.nextDescendingStepTime)); | ||
await eventLoopIteration(); // let promises to update vstorage settle | ||
|
||
// vaultFactory sent collateral for liquidation | ||
t.like(readLatest(metricsPath), { | ||
numActiveVaults: 0, | ||
numLiquidatingVaults: setup.vaults.length, | ||
liquidatingCollateral: { | ||
value: scale6(setup.auction.start.collateral), | ||
}, | ||
liquidatingDebt: { value: scale6(setup.auction.start.debt) }, | ||
lockedQuote: null, | ||
}); | ||
|
||
console.log(collateralBrandKey, 'step 2 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
t.like(readLatest(`published.auction.book${managerIndex}`), { | ||
collateralAvailable: { value: scale6(setup.auction.start.collateral) }, | ||
startCollateral: { value: scale6(setup.auction.start.collateral) }, | ||
startProceedsGoal: { value: scale6(setup.auction.start.debt) }, | ||
}); | ||
|
||
console.log(collateralBrandKey, 'step 3 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
|
||
console.log(collateralBrandKey, 'step 4 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
|
||
console.log(collateralBrandKey, 'step 5 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
|
||
console.log(collateralBrandKey, 'step 6 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
t.like(readLatest(`published.auction.book${managerIndex}`), { | ||
collateralAvailable: { value: 13199172n }, | ||
}); | ||
|
||
console.log(collateralBrandKey, 'step 7 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
|
||
console.log(collateralBrandKey, 'step 8 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
|
||
console.log(collateralBrandKey, 'step 9 of 10'); | ||
await advanceTimeBy(3, 'minutes'); | ||
|
||
t.like(readLatest('published.wallet.agoric1buyer'), { | ||
status: { | ||
id: `${collateralBrandKey}-bid1`, | ||
payouts: likePayouts(outcome.bids[0].payouts), | ||
}, | ||
}); | ||
}); |