Skip to content

Commit

Permalink
Merge pull request #1992 from Agoric/mfig/fake-prices
Browse files Browse the repository at this point in the history
feat: simple volatile priceAuthority
  • Loading branch information
michaelfig authored Nov 6, 2020
2 parents 40c27fd + d32f416 commit cce515f
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 34 deletions.
83 changes: 79 additions & 4 deletions packages/cosmic-swingset/lib/ag-solo/vats/bootstrap.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-nocheck
import { allComparable } from '@agoric/same-structure';
import {
makeLoopbackProtocolHandler,
Expand All @@ -12,6 +13,8 @@ import { GCI } from './gci';
import { makeBridgeManager } from './bridge';

const NUM_IBC_PORTS = 3;
const CENTRAL_ISSUER_NAME = 'Testnet.$USD';
const QUOTE_INTERVAL = 30;

console.debug(`loading bootstrap.js`);

Expand Down Expand Up @@ -60,17 +63,19 @@ export function buildRootObject(vatPowers, vatParameters) {
* @typedef {Object} IssuerRecord
* @property {Array<any>} [issuerArgs]
* @property {string} pursePetname
* @property {any} mintValue
* @property {number} mintValue
* @property {Array<[number, number]>} [fakeTradesGivenCentral]
*/
/** @type {Map<string, IssuerRecord>} */
const issuerNameToRecord = new Map(
harden([
[
'Testnet.$USD',
CENTRAL_ISSUER_NAME,
{
issuerArgs: [undefined, { decimalPlaces: 3 }],
mintValue: 20000,
pursePetname: 'Local currency',
fakeTradesGivenCentral: [[1, 1]],
},
],
[
Expand All @@ -79,25 +84,48 @@ export function buildRootObject(vatPowers, vatParameters) {
issuerArgs: [undefined, { decimalPlaces: 6 }],
mintValue: 7 * 10 ** 6,
pursePetname: 'Oracle fee',
fakeTradesGivenCentral: [
[1000, 3000000],
[1000, 2500000],
[1000, 2750000],
],
},
],
[
'moola',
{
mintValue: 1900,
pursePetname: 'Fun budget',
fakeTradesGivenCentral: [
[10, 1],
[13, 1],
[12, 1],
[18, 1],
[15, 1],
],
},
],
[
'simolean',
{
mintValue: 1900,
pursePetname: 'Nest egg',
fakeTradesGivenCentral: [
[2135, 50],
[2172, 50],
[2124, 50],
],
},
],
]),
);
const issuerNames = [...issuerNameToRecord.keys()];
const centralIssuerIndex = issuerNames.findIndex(
issuerName => issuerName === CENTRAL_ISSUER_NAME,
);
if (centralIssuerIndex < 0) {
throw Error(`Cannot find issuer ${CENTRAL_ISSUER_NAME}`);
}
const issuers = await Promise.all(
issuerNames.map(issuerName =>
E(vats.mints).makeMintAndIssuer(
Expand All @@ -107,8 +135,55 @@ export function buildRootObject(vatPowers, vatParameters) {
),
);

// TODO: Create priceAuthority pairs for moola-simolean based on the
// FakePriceAuthority.
const centralIssuer = issuers[centralIssuerIndex];

/**
* @param {ERef<Issuer>} issuerIn
* @param {ERef<Issuer>} issuerOut
* @param {Array<[number, number]>} tradeList
*/
const makeFakePriceAuthority = async (issuerIn, issuerOut, tradeList) => {
const [brandIn, brandOut, pa] = await Promise.all([
E(issuerIn).getBrand(),
E(issuerOut).getBrand(),
E(vats.priceAuthority).makeFakePriceAuthority({
issuerIn,
issuerOut,
tradeList,
timer: chainTimerService,
quoteInterval: QUOTE_INTERVAL,
}),
]);
return E(priceAuthorityAdmin).registerPriceAuthority(
pa,
brandIn,
brandOut,
);
};
await Promise.all(
issuers.map(async (issuer, i) => {
// Create priceAuthority pairs for centralIssuerIndex based on the
// FakePriceAuthority.
console.debug(`Creating ${issuerNames[i]}-${CENTRAL_ISSUER_NAME}`);
const { fakeTradesGivenCentral } = issuerNameToRecord.get(
issuerNames[i],
);
if (!fakeTradesGivenCentral) {
return;
}
const fakeTradesGivenOther =
centralIssuer !== issuer &&
fakeTradesGivenCentral.map(([valueCentral, valueOther]) => [
valueOther,
valueCentral,
]);
await Promise.all([
makeFakePriceAuthority(centralIssuer, issuer, fakeTradesGivenCentral),
fakeTradesGivenOther &&
makeFakePriceAuthority(issuer, centralIssuer, fakeTradesGivenOther),
]);
}),
);

return harden({
async createUserBundle(_nickname, powerFlags = []) {
Expand Down
17 changes: 3 additions & 14 deletions packages/cosmic-swingset/lib/ag-solo/vats/vat-priceAuthority.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,13 @@ import { makeLocalAmountMath } from '@agoric/ertp';
export function buildRootObject(_vatPowers) {
return harden({
makePriceAuthority: makePriceAuthorityRegistry,
async makeFakePriceAuthority(
issuerIn,
issuerOut,
priceList,
timer,
quoteInterval = undefined,
) {
async makeFakePriceAuthority(options) {
const { issuerIn, issuerOut } = options;
const [mathIn, mathOut] = await Promise.all([
makeLocalAmountMath(issuerIn),
makeLocalAmountMath(issuerOut),
]);
return makeFakePriceAuthority(
mathIn,
mathOut,
priceList,
timer,
quoteInterval,
);
return makeFakePriceAuthority({ ...options, mathIn, mathOut });
},
});
}
39 changes: 26 additions & 13 deletions packages/zoe/tools/fakePriceAuthority.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import '../exported';
* @typedef {Object} FakePriceAuthorityOptions
* @property {AmountMath} mathIn
* @property {AmountMath} mathOut
* @property {Array<number>} priceList
* @property {Array<number>} [priceList]
* @property {Array<[number, number]>} [tradeList]
* @property {ERef<TimerService>} timer
* @property {RelativeTime} [quoteInterval]
* @property {ERef<Mint>} [quoteMint]
Expand All @@ -33,20 +34,29 @@ export async function makeFakePriceAuthority(options) {
mathIn,
mathOut,
priceList,
tradeList,
timer,
unitAmountIn = mathIn.make(1),
quoteInterval = 1,
quoteMint = makeIssuerKit('quote', MathKind.SET).mint,
} = options;

assert(
tradeList || priceList,
details`One of priceList or tradeList must be specified`,
);

const unitValueIn = mathIn.getValue(unitAmountIn);

const comparisonQueue = [];

let currentPriceIndex = 0;

function currentPrice() {
return priceList[currentPriceIndex % priceList.length];
function currentTrade() {
if (tradeList) {
return tradeList[currentPriceIndex % tradeList.length];
}
return [unitValueIn, priceList[currentPriceIndex % priceList.length]];
}

/**
Expand Down Expand Up @@ -81,16 +91,17 @@ export async function makeFakePriceAuthority(options) {
*/
function priceInQuote(amountIn, brandOut, quoteTime) {
assertBrands(amountIn.brand, brandOut);
mathIn.coerce(amountIn);
const [tradeValueIn, tradeValueOut] = currentTrade();
const valueOut = natSafeMath.floorDivide(
natSafeMath.multiply(amountIn.value, tradeValueOut),
tradeValueIn,
);
const quoteAmount = quoteMath.make(
harden([
{
amountIn,
amountOut: mathOut.make(
natSafeMath.floorDivide(
currentPrice() * amountIn.value,
unitValueIn,
),
),
amountOut: mathOut.make(valueOut),
timer,
timestamp: quoteTime,
},
Expand All @@ -112,10 +123,12 @@ export async function makeFakePriceAuthority(options) {
*/
function priceOutQuote(brandIn, amountOut, quoteTime) {
assertBrands(brandIn, amountOut.brand);
const desiredValue = mathOut.getValue(amountOut);
const price = currentPrice();
// FIXME: Use natSafeMath.ceilDivide to calculate valueIn.
const valueIn = Math.ceil((desiredValue * unitValueIn) / price);
const valueOut = mathOut.getValue(amountOut);
const [tradeValueIn, tradeValueOut] = currentTrade();
const valueIn = natSafeMath.ceilDivide(
natSafeMath.multiply(valueOut, tradeValueIn),
tradeValueOut,
);
return priceInQuote(mathIn.make(valueIn), amountOut.brand, quoteTime);
}

Expand Down
11 changes: 8 additions & 3 deletions packages/zoe/tools/priceAuthorityRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import '../exported';

/**
* @typedef {Object} PriceAuthorityRegistryAdmin
* @property {(pa: ERef<PriceAuthority>, brandIn: Brand, brandOut: Brand)
* @property {(pa: ERef<PriceAuthority>, brandIn: Brand, brandOut: Brand, force:
* boolean | undefined)
* => Deleter} registerPriceAuthority Add a unique price authority for a given
* pair
*/
Expand Down Expand Up @@ -109,7 +110,7 @@ export const makePriceAuthorityRegistry = () => {

/** @type {PriceAuthorityRegistryAdmin} */
const adminFacet = {
registerPriceAuthority(pa, brandIn, brandOut) {
registerPriceAuthority(pa, brandIn, brandOut, force = false) {
/** @type {Store<Brand, PriceAuthorityRecord>} */
let priceStore;
if (assetToPriceStore.has(brandIn)) {
Expand All @@ -126,7 +127,11 @@ export const makePriceAuthorityRegistry = () => {
};

// Set up the record.
priceStore.init(brandOut, harden(record));
if (force && priceStore.has(brandOut)) {
priceStore.set(brandOut, harden(record));
} else {
priceStore.init(brandOut, harden(record));
}

return harden({
delete() {
Expand Down

0 comments on commit cce515f

Please sign in to comment.