Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Make the auction schedule robust when adding collateral types #8301

Merged
merged 6 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions packages/inter-protocol/src/auction/auctionBook.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,12 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {

trace(this.state.collateralBrand, 'settleAtNewRate', reduction);
const { capturedPriceForRound, priceBook, scaledBidBook } = state;
capturedPriceForRound !== null ||
Fail`price must be captured before auction starts`;
assert(capturedPriceForRound);
if (!capturedPriceForRound) {
console.error(
`⚠️No price for ${this.state.collateralBrand}, skipping auction.`,
);
return;
}

state.curAuctionPrice = multiplyRatios(
reduction,
Expand Down
10 changes: 10 additions & 0 deletions packages/inter-protocol/src/auction/scheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,17 @@ export const makeScheduler = async (
async updateState(_newState) {
trace('received param update', _newState);
await null;

let fixableSchedule;
if (!nextSchedule) {
fixableSchedule = true;
} else {
now = await E(timer).getCurrentTimestamp();
fixableSchedule =
TimeMath.compareAbs(nextSchedule.startTime, now) < 0;
}

if (fixableSchedule) {
trace('repairing nextSchedule and restarting');
({ nextSchedule } = await initializeNextSchedule());
startSchedulingFromScratch();
Expand Down
87 changes: 87 additions & 0 deletions packages/inter-protocol/test/auction/test-auctionContract.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { assertPayoutAmount } from '@agoric/zoe/test/zoeTestHelpers.js';
import { makeManualPriceAuthority } from '@agoric/zoe/tools/manualPriceAuthority.js';
import { providePriceAuthorityRegistry } from '@agoric/zoe/tools/priceAuthorityRegistry.js';
import { E } from '@endo/eventual-send';
import { NonNullish } from '@agoric/assert';

import {
setupReserve,
Expand Down Expand Up @@ -110,6 +111,11 @@ export const setupServices = async (t, params = defaultParams) => {
const space = await setupBootstrap(t, timer);
installPuppetGovernance(zoe, space.installation.produce);

t.context.puppetGovernors = {
auctioneer: E.get(space.consume.auctioneerKit).governorCreatorFacet,
vaultFactory: E.get(space.consume.vaultFactoryKit).governorCreatorFacet,
};

// @ts-expect-error not all installs are needed for auctioneer.
produceInstallations(space, t.context.installs);

Expand Down Expand Up @@ -309,6 +315,15 @@ const makeAuctionDriver = async (t, params = defaultParams) => {
await eventLoopIteration();
}
},

setGovernedParam: (name, newValue) => {
trace(t, 'setGovernedParam', name);
const auctionGov = NonNullish(t.context.puppetGovernors.auctioneer);
return E(auctionGov).changeParams(
harden({ changes: { [name]: newValue } }),
);
},

async updatePriceAuthority(newPrice) {
priceAuthorities.get(newPrice.denominator.brand).setPrice(newPrice);
await eventLoopIteration();
Expand Down Expand Up @@ -1408,3 +1423,75 @@ test.serial('time jumps forward', async t => {
t.is(schedules.liveAuctionSchedule?.startTime.absValue, 1530n);
t.is(schedules.liveAuctionSchedule?.endTime.absValue, 1550n);
});

// serial because dynamicConfig is shared across tests
test.serial('add collateral type during auction', async t => {
const { collateral, bid } = t.context;
const driver = await makeAuctionDriver(t);
const asset = withAmountUtils(makeIssuerKit('Asset'));
const timerBrand = await E(driver.getTimerService()).getTimerBrand();

const liqSeat = await driver.setupCollateralAuction(
collateral,
collateral.make(1000n),
);
await driver.updatePriceAuthority(
makeRatioFromAmounts(bid.make(11n), collateral.make(10n)),
);

const result = await E(liqSeat).getOfferResult();
t.is(result, 'deposited');

await driver.advanceTo(167n);
const seat = await driver.bidForCollateralSeat(
// 1.1 * 1.05 * 200
bid.make(231n),
collateral.make(200n),
);
t.is(await E(seat).getOfferResult(), 'Your bid has been accepted');
t.false(await E(seat).hasExited());

const scheduleTracker = await driver.getScheduleTracker();
await scheduleTracker.assertInitial({
activeStartTime: TimeMath.coerceTimestampRecord(170n, timerBrand),
nextDescendingStepTime: TimeMath.coerceTimestampRecord(170n, timerBrand),
nextStartTime: TimeMath.coerceTimestampRecord(210n, timerBrand),
});

await driver.advanceTo(170n, 'wait');
await scheduleTracker.assertChange({
nextDescendingStepTime: { absValue: 175n },
});

await driver.advanceTo(175n, 'wait');
await scheduleTracker.assertChange({
nextDescendingStepTime: { absValue: 180n },
});

// before the fix for #8296 in AuctionBook, this broke the ongoing auction.
await driver.setupCollateralAuction(asset, asset.make(500n));

await driver.advanceTo(180n, 'wait');
await scheduleTracker.assertChange({
nextDescendingStepTime: { absValue: 185n },
});

await driver.advanceTo(185n, 'wait');

await scheduleTracker.assertChange({
nextDescendingStepTime: { absValue: 190n },
});

t.true(await E(seat).hasExited());
await assertPayouts(t, seat, bid, collateral, 0n, 200n);

await driver.advanceTo(210n, 'wait');

t.true(await E(liqSeat).hasExited());
await assertPayouts(t, liqSeat, bid, collateral, 231n, 800n);

await scheduleTracker.assertChange({
activeStartTime: null,
nextDescendingStepTime: { absValue: 210n },
});
});
Loading