Skip to content

Commit

Permalink
feat(auction): durable offer book
Browse files Browse the repository at this point in the history
  • Loading branch information
turadg committed Mar 16, 2023
1 parent 1233e09 commit fe85bd9
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 111 deletions.
10 changes: 6 additions & 4 deletions packages/inter-protocol/src/auction/auctionBook.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import { E } from '@endo/captp';
import { makeTracer } from '@agoric/internal';

import { makeScaledBidBook, makePriceBook } from './offerBook.js';
import { preparePriceBook, prepareScaledBidBook } from './offerBook.js';
import {
isScaledBidPriceHigher,
makeBrandedRatioPattern,
Expand Down Expand Up @@ -168,13 +168,15 @@ export const makeAuctionBook = async (

let curAuctionPrice = zeroRatio;

// FIXME the maker callbacks return a non-durable object
const makeScaledBidBook = prepareScaledBidBook(baggage);
const makePriceBook = preparePriceBook(baggage);

const scaledBidBook = provide(baggage, 'scaledBidBook', () => {
const ratioPattern = makeBrandedRatioPattern(
currencyAmountShape,
currencyAmountShape,
);
return makeScaledBidBook(baggage, ratioPattern, collateralBrand);
return makeScaledBidBook(ratioPattern, collateralBrand);
});

const priceBook = provide(baggage, 'sortedOffers', () => {
Expand All @@ -183,7 +185,7 @@ export const makeAuctionBook = async (
collateralAmountShape,
);

return makePriceBook(baggage, ratioPattern, collateralBrand);
return makePriceBook(ratioPattern, collateralBrand);
});

/**
Expand Down
248 changes: 141 additions & 107 deletions packages/inter-protocol/src/auction/offerBook.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
// 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 { provideDurableMapStore } from '@agoric/vat-data';
import { M, mustMatch } from '@agoric/store';
import { makeScalarBigMapStore, prepareExoClass } from '@agoric/vat-data';

import {
toBidScalingComparator,
toScaledRateOfferKey,
toPartialOfferKey,
toPriceOfferKey,
toScaledRateOfferKey,
} from './sortedOffers.js';

/** @typedef {import('@agoric/vat-data').Baggage} Baggage */
Expand Down Expand Up @@ -39,122 +38,157 @@ const nextSequenceNumber = () => {
* snapshot taken when the auction started. .4 is 60% off. 1.1 is 10% above par.
*
* @param {Baggage} baggage
* @param {Pattern} bidScalingPattern
* @param {Brand} collateralBrand
*/
export const makeScaledBidBook = (
baggage,
bidScalingPattern,
collateralBrand,
) => {
/** @type {MapStore<string, BidderRecord>} */
const store = provideDurableMapStore(baggage, 'scaledBidStore');

return Far('scaledBidBook ', {
export const prepareScaledBidBook = baggage =>
prepareExoClass(
baggage,
'scaledBidBook',
undefined,
/**
* @param {ZCFSeat} seat
* @param {Ratio} bidScaling
* @param {Amount<'nat'>} wanted
*
* @param {Pattern} bidScalingPattern
* @param {Brand} collateralBrand
*/
add(seat, bidScaling, wanted) {
mustMatch(bidScaling, bidScalingPattern);
(bidScalingPattern, collateralBrand) => ({
bidScalingPattern,
collateralBrand,
/** @type {MapStore<string, BidderRecord>} */
records: makeScalarBigMapStore('scaledBidRecords'),
}),
{
/**
* @param {ZCFSeat} seat
* @param {Ratio} bidScaling
* @param {Amount<'nat'>} wanted
*/
add(seat, bidScaling, wanted) {
const { bidScalingPattern, collateralBrand, records } = this.state;
mustMatch(bidScaling, bidScalingPattern);

const seqNum = nextSequenceNumber();
const key = toScaledRateOfferKey(bidScaling, seqNum);
const empty = AmountMath.makeEmpty(collateralBrand);
/** @type {BidderRecord} */
const bidderRecord = {
bidScaling,
price: undefined,
received: empty,
seat,
seqNum,
wanted,
};
store.init(key, harden(bidderRecord));
return key;
},
/** @param {Ratio} bidScaling */
offersAbove(bidScaling) {
return [...store.entries(M.gte(toBidScalingComparator(bidScaling)))];
},
hasOrders() {
return store.getSize() > 0;
},
delete(key) {
store.delete(key);
},
updateReceived(key, sold) {
const oldRec = store.get(key);
store.set(
key,
harden({ ...oldRec, received: AmountMath.add(oldRec.received, sold) }),
);
},
exitAllSeats() {
for (const [key, { seat }] of store.entries()) {
if (!seat.hasExited()) {
seat.exit();
store.delete(key);
const seqNum = nextSequenceNumber();
const key = toScaledRateOfferKey(bidScaling, seqNum);
const empty = AmountMath.makeEmpty(collateralBrand);
/** @type {BidderRecord} */
const bidderRecord = {
bidScaling,
price: undefined,
received: empty,
seat,
seqNum,
wanted,
};
records.init(key, harden(bidderRecord));
return key;
},
/** @param {Ratio} bidScaling */
offersAbove(bidScaling) {
const { records } = this.state;
return [...records.entries(M.gte(toBidScalingComparator(bidScaling)))];
},
hasOrders() {
const { records } = this.state;
return records.getSize() > 0;
},
delete(key) {
const { records } = this.state;
records.delete(key);
},
updateReceived(key, sold) {
const { records } = this.state;
const oldRec = records.get(key);
records.set(
key,
harden({
...oldRec,
received: AmountMath.add(oldRec.received, sold),
}),
);
},
exitAllSeats() {
const { records } = this.state;
for (const [key, { seat }] of records.entries()) {
if (!seat.hasExited()) {
seat.exit();
records.delete(key);
}
}
}
},
},
});
};
);

/**
* Prices in this book are actual prices expressed in terms of currency amount
* and collateral amount.
*
* @param {Baggage} baggage
* @param {Pattern} ratioPattern
* @param {Brand} collateralBrand
*/
export const makePriceBook = (baggage, ratioPattern, collateralBrand) => {
/** @type {MapStore<string, BidderRecord>} */
const store = provideDurableMapStore(baggage, 'pricedBidStore');
return Far('priceBook ', {
add(seat, price, wanted) {
mustMatch(price, ratioPattern);
export const preparePriceBook = baggage =>
prepareExoClass(
baggage,
'priceBook',
undefined,
/**
*
* @param {Pattern} priceRatioPattern
* @param {Brand} collateralBrand
*/
(priceRatioPattern, collateralBrand) => ({
priceRatioPattern,
collateralBrand,
/** @type {MapStore<string, BidderRecord>} */
records: makeScalarBigMapStore('scaledBidRecords'),
}),
{
add(seat, price, wanted) {
const { priceRatioPattern, collateralBrand, records } = this.state;
mustMatch(price, priceRatioPattern);

const seqNum = nextSequenceNumber();
const key = toPriceOfferKey(price, seqNum);
const empty = AmountMath.makeEmpty(collateralBrand);
/** @type {BidderRecord} */
const bidderRecord = {
bidScaling: undefined,
price,
received: empty,
seat,
seqNum,
wanted,
};
store.init(key, harden(bidderRecord));
return key;
},
offersAbove(price) {
return [...store.entries(M.gte(toPartialOfferKey(price)))];
},
hasOrders() {
return store.getSize() > 0;
},
delete(key) {
store.delete(key);
},
updateReceived(key, sold) {
const oldRec = store.get(key);
store.set(
key,
harden({ ...oldRec, received: AmountMath.add(oldRec.received, sold) }),
);
},
exitAllSeats() {
for (const [key, { seat }] of store.entries()) {
if (!seat.hasExited()) {
seat.exit();
store.delete(key);
const seqNum = nextSequenceNumber();
const key = toPriceOfferKey(price, seqNum);
const empty = AmountMath.makeEmpty(collateralBrand);
/** @type {BidderRecord} */
const bidderRecord = {
bidScaling: undefined,
price,
received: empty,
seat,
seqNum,
wanted,
};
records.init(key, harden(bidderRecord));
return key;
},
offersAbove(price) {
const { records } = this.state;
return [...records.entries(M.gte(toPartialOfferKey(price)))];
},
hasOrders() {
const { records } = this.state;
return records.getSize() > 0;
},
delete(key) {
const { records } = this.state;
records.delete(key);
},
updateReceived(key, sold) {
const { records } = this.state;
const oldRec = records.get(key);
records.set(
key,
harden({
...oldRec,
received: AmountMath.add(oldRec.received, sold),
}),
);
},
exitAllSeats() {
const { records } = this.state;
for (const [key, { seat }] of records.entries()) {
if (!seat.hasExited()) {
seat.exit();
records.delete(key);
}
}
}
},
},
});
};
);

0 comments on commit fe85bd9

Please sign in to comment.