Skip to content

Commit

Permalink
chore: cosmetic cleanups from review
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris-Hibbert committed Feb 28, 2023
1 parent ee1a59a commit 2b4e795
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 116 deletions.
65 changes: 32 additions & 33 deletions packages/inter-protocol/src/auction/auctionBook.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import {
import { E } from '@endo/captp';
import { makeTracer } from '@agoric/internal';

import { makeDiscountBook, makePriceBook } from './discountBook.js';
import { makeScaledBidBook, makePriceBook } from './offerBook.js';
import {
AuctionState,
isDiscountedPriceHigher,
isScaledBidPriceHigher,
makeBrandedRatioPattern,
priceFrom,
} from './util.js';
Expand All @@ -37,7 +37,7 @@ const { Fail } = assert;
* The book contains orders for the collateral. It holds two kinds of
* orders:
* - Prices express the bid in terms of a Currency amount
* - Discount express the bid in terms of a discount (or markup) from the
* - Scaled bid express the bid in terms of a discount (or markup) from the
* most recent oracle price.
*
* Offers can be added in three ways. When the auction is not active, prices are
Expand All @@ -58,28 +58,27 @@ export const makeAuctionBook = async (
collateralBrand,
priceAuthority,
) => {
const makeZeroRatio = () =>
makeRatioFromAmounts(
AmountMath.makeEmpty(currencyBrand),
AmountMath.make(collateralBrand, 1n),
);
const zeroRatio = makeRatioFromAmounts(
AmountMath.makeEmpty(currencyBrand),
AmountMath.make(collateralBrand, 1n),
);
const BidSpecShape = M.or(
{
want: AmountShape,
offerPrice: makeBrandedRatioPattern(currencyBrand, collateralBrand),
},
{
want: AmountShape,
offerDiscount: makeBrandedRatioPattern(currencyBrand, currencyBrand),
offerBidScaling: makeBrandedRatioPattern(currencyBrand, currencyBrand),
},
);

let assetsForSale = AmountMath.makeEmpty(collateralBrand);
const { zcfSeat: collateralSeat } = zcf.makeEmptySeatKit();
const { zcfSeat: currencySeat } = zcf.makeEmptySeatKit();

let lockedPriceForRound = makeZeroRatio();
let updatingOracleQuote = makeZeroRatio();
let lockedPriceForRound = zeroRatio;
let updatingOracleQuote = zeroRatio;
E.when(E(collateralBrand).getDisplayInfo(), ({ decimalPlaces = 9n }) => {
// TODO(#6946) use this to keep a current price that can be published in state.
const quoteNotifier = E(priceAuthority).makeQuoteNotifier(
Expand All @@ -105,17 +104,17 @@ export const makeAuctionBook = async (
});
});

let curAuctionPrice = makeZeroRatio();
let curAuctionPrice = zeroRatio;

const discountBook = provide(baggage, 'discountBook', () => {
const discountStore = makeScalarBigMapStore('orderedVaultStore', {
const scaledBidBook = provide(baggage, 'scaledBidBook', () => {
const scaledBidStore = makeScalarBigMapStore('scaledBidBookStore', {
durable: true,
});
return makeDiscountBook(discountStore, currencyBrand, collateralBrand);
return makeScaledBidBook(scaledBidStore, currencyBrand, collateralBrand);
});

const priceBook = provide(baggage, 'sortedOffers', () => {
const priceStore = makeScalarBigMapStore('orderedVaultStore', {
const priceStore = makeScalarBigMapStore('sortedOffersStore', {
durable: true,
});
return makePriceBook(priceStore, currencyBrand, collateralBrand);
Expand All @@ -125,7 +124,7 @@ export const makeAuctionBook = async (
if (isPriceBook) {
priceBook.delete(key);
} else {
discountBook.delete(key);
scaledBidBook.delete(key);
}
};

Expand Down Expand Up @@ -224,17 +223,17 @@ export const makeAuctionBook = async (
* the book.
*
* @param {ZCFSeat} seat
* @param {Ratio} discount
* @param {Ratio} bidScaling
* @param {Amount} want
* @param {AuctionState} auctionState
*/
const acceptDiscountOffer = (seat, discount, want, auctionState) => {
trace('accept discount');
const acceptScaledBidOffer = (seat, bidScaling, want, auctionState) => {
trace('accept scaled bid offer');
let collateralSold = AmountMath.makeEmptyFromAmount(want);

if (
isActive(auctionState) &&
isDiscountedPriceHigher(discount, curAuctionPrice, lockedPriceForRound)
isScaledBidPriceHigher(bidScaling, curAuctionPrice, lockedPriceForRound)
) {
collateralSold = settle(seat, want);
if (AmountMath.isEmpty(seat.getCurrentAllocation().Currency)) {
Expand All @@ -245,7 +244,7 @@ export const makeAuctionBook = async (

const stillWant = AmountMath.subtract(want, collateralSold);
if (!AmountMath.isEmpty(stillWant)) {
discountBook.add(seat, discount, stillWant);
scaledBidBook.add(seat, bidScaling, stillWant);
} else {
seat.exit();
}
Expand All @@ -264,14 +263,14 @@ export const makeAuctionBook = async (
curAuctionPrice = multiplyRatios(reduction, lockedPriceForRound);

const pricedOffers = priceBook.offersAbove(curAuctionPrice);
const discOffers = discountBook.offersAbove(reduction);
const discOffers = scaledBidBook.offersAbove(reduction);

// requested price or discount gives no priority beyond specifying which
// requested price or bid scaling gives no priority beyond specifying which
// round the order will be service in.
const prioritizedOffers = [...pricedOffers, ...discOffers].sort();

trace(`settling`, pricedOffers.length, discOffers.length);
prioritizedOffers.forEach(([key, { seat, price: p, wanted }]) => {
for (const [key, { seat, price: p, wanted }] of prioritizedOffers) {
if (seat.hasExited()) {
removeFromOneBook(p, key);
} else {
Expand All @@ -287,17 +286,17 @@ export const makeAuctionBook = async (
if (p) {
priceBook.updateReceived(key, collateralSold);
} else {
discountBook.updateReceived(key, collateralSold);
scaledBidBook.updateReceived(key, collateralSold);
}
}
}
});
}
},
getCurrentPrice() {
return curAuctionPrice;
},
hasOrders() {
return discountBook.hasOrders() || priceBook.hasOrders();
return scaledBidBook.hasOrders() || priceBook.hasOrders();
},
lockOraclePriceForRound() {
trace(`locking `, updatingOracleQuote);
Expand All @@ -318,23 +317,23 @@ export const makeAuctionBook = async (
bidSpec.want,
auctionState,
);
} else if (bidSpec.offerDiscount) {
return acceptDiscountOffer(
} else if (bidSpec.offerBidScaling) {
return acceptScaledBidOffer(
seat,
bidSpec.offerDiscount,
bidSpec.offerBidScaling,
bidSpec.want,
auctionState,
);
} else {
throw Fail`Offer was neither a price nor a discount`;
throw Fail`Offer was neither a price nor a scaled bid`;
}
},
getSeats() {
return { collateralSeat, currencySeat };
},
exitAllSeats() {
priceBook.exitAllSeats();
discountBook.exitAllSeats();
scaledBidBook.exitAllSeats();
},
});
};
22 changes: 12 additions & 10 deletions packages/inter-protocol/src/auction/auctioneer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { E } from '@endo/eventual-send';
import {
M,
makeScalarBigMapStore,
provide,
provideDurableMapStore,
} from '@agoric/vat-data';
import { AmountMath } from '@agoric/ertp';
Expand Down Expand Up @@ -47,8 +46,15 @@ const makeBPRatio = (rate, currencyBrand, collateralBrand = currencyBrand) =>
* StartingRate: 'nat',
* lowestRate: 'nat',
* DiscountStep: 'nat',
* }> & {timerService: import('@agoric/time/src/types').TimerService, priceAuthority: PriceAuthority}>} zcf
* @param {{initialPoserInvitation: Invitation, storageNode: StorageNode, marshaller: Marshaller}} privateArgs
* }> & {
* timerService: import('@agoric/time/src/types').TimerService,
* priceAuthority: PriceAuthority
* }>} zcf
* @param {{
* initialPoserInvitation: Invitation,
* storageNode: StorageNode,
* marshaller: Marshaller
* }} privateArgs
* @param {Baggage} baggage
*/
export const start = async (zcf, privateArgs, baggage) => {
Expand All @@ -58,11 +64,7 @@ export const start = async (zcf, privateArgs, baggage) => {

const books = provideDurableMapStore(baggage, 'auctionBooks');
const deposits = provideDurableMapStore(baggage, 'deposits');
const brandToKeyword = provide(baggage, 'brandToKeyword', () =>
makeScalarBigMapStore('deposits', {
durable: true,
}),
);
const brandToKeyword = provideDurableMapStore(baggage, 'brandToKeyword');

const reserveFunds = provideEmptySeat(zcf, baggage, 'collateral');

Expand Down Expand Up @@ -157,14 +159,14 @@ export const start = async (zcf, privateArgs, baggage) => {
);

const tradeEveryBook = () => {
const discountRatio = makeRatio(
const bidScalingRatio = makeRatio(
currentDiscountRateBP,
brands.Currency,
BASIS_POINTS,
);

[...books.entries()].forEach(([_collateralBrand, book]) => {
book.settleAtNewRate(discountRatio);
book.settleAtNewRate(bidScalingRatio);
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// book of offers to buy liquidating vaults with prices in terms of discount
// from the current oracle price.
// book of offers to buy liquidating vaults with prices in terms of
// discount/markup from the current oracle price.

import { Far } from '@endo/marshal';
import { M, mustMatch } from '@agoric/store';
import { AmountMath } from '@agoric/ertp';

import {
toDiscountComparator,
toDiscountedRateOfferKey,
toBidScalingComparator,
toScaledRateOfferKey,
toPartialOfferKey,
toPriceOfferKey,
} from './sortedOffers.js';
Expand All @@ -22,22 +22,28 @@ const nextSequenceNumber = () => {
return latestSequenceNumber;
};

// prices in this book are expressed as percentage of full price. .4 is 60% off.
// 1.1 is 10% above par.
export const makeDiscountBook = (store, currencyBrand, collateralBrand) => {
return Far('discountBook ', {
add(seat, discount, wanted) {
// XXX mustMatch(discount, DISCOUNT_PATTERN);
// prices in this book are expressed as percentage of the full oracle price
// snapshot taken when the auction started. .4 is 60% off. 1.1 is 10% above par.
export const makeScaledBidBook = (store, currencyBrand, collateralBrand) => {
return Far('scaledBidBook ', {
add(seat, bidScaling, wanted) {
// XXX mustMatch(bidScaling, BID_SCALING_PATTERN);

const seqNum = nextSequenceNumber();
const key = toDiscountedRateOfferKey(discount, seqNum);
const key = toScaledRateOfferKey(bidScaling, seqNum);
const empty = AmountMath.makeEmpty(collateralBrand);
const bidderRecord = { seat, discount, wanted, seqNum, received: empty };
const bidderRecord = {
seat,
bidScaling,
wanted,
seqNum,
received: empty,
};
store.init(key, harden(bidderRecord));
return key;
},
offersAbove(discount) {
return [...store.entries(M.gte(toDiscountComparator(discount)))];
offersAbove(bidScaling) {
return [...store.entries(M.gte(toBidScalingComparator(bidScaling)))];
},
hasOrders() {
return store.getSize() > 0;
Expand All @@ -62,9 +68,11 @@ export const makeDiscountBook = (store, currencyBrand, collateralBrand) => {
});
};

// prices in this book are actual prices expressed in terms of currency amount
// and collateral amount.
export const makePriceBook = (store, currencyBrand, collateralBrand) => {
const RATIO_PATTERN = makeBrandedRatioPattern(currencyBrand, collateralBrand);
return Far('discountBook ', {
return Far('priceBook ', {
add(seat, price, wanted) {
mustMatch(price, RATIO_PATTERN);

Expand Down
11 changes: 1 addition & 10 deletions packages/inter-protocol/src/auction/params.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ import {
makeParamManager,
ParamTypes,
} from '@agoric/governance';
import {
TimerBrandShape,
TimeMath,
RelativeTimeValueShape,
} from '@agoric/time';
import { TimeMath, RelativeTimeRecordShape } from '@agoric/time';
import { M } from '@agoric/store';

/** @typedef {import('@agoric/governance/src/contractGovernance/typedParamManager.js').AsyncSpecTuple} AsyncSpecTuple */
Expand Down Expand Up @@ -48,11 +44,6 @@ export const LIQUIDATION_PENALTY = 'LiquidationPenalty';
// time before each auction that the prices are locked.
export const PRICE_LOCK_PERIOD = 'PriceLockPeriod';

export const RelativeTimeRecordShape = harden({
timerBrand: TimerBrandShape,
relValue: RelativeTimeValueShape,
});

export const auctioneerParamPattern = M.splitRecord({
[CONTRACT_ELECTORATE]: InvitationShape,
[START_FREQUENCY]: RelativeTimeRecordShape,
Expand Down
2 changes: 1 addition & 1 deletion packages/inter-protocol/src/auction/scheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const trace = makeTracer('SCHED', false);
* should always be a next schedule, but between rounds, liveSchedule is null.
*
* The lock period that the liquidators use might start before the previous
* round has finished, so we need to scheduled the next round each time an
* round has finished, so we need to schedule the next round each time an
* auction starts. This means if the scheduling parameters change, it'll be a
* full cycle before we switch. Otherwise, the vaults wouldn't know when to
* start their lock period.
Expand Down
Loading

0 comments on commit 2b4e795

Please sign in to comment.