-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(zoe): add priceAuthorityRegistry
- Loading branch information
1 parent
3bad7c5
commit 02c6147
Showing
3 changed files
with
183 additions
and
0 deletions.
There are no files selected for viewing
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
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,139 @@ | ||
// @ts-check | ||
|
||
import { E } from '@agoric/eventual-send'; | ||
import { makeStore } from '@agoric/store'; | ||
import { assert, details } from '@agoric/assert'; | ||
|
||
import '../exported'; | ||
|
||
/** | ||
* @typedef {Object} Deleter | ||
* @property {() => void} delete | ||
*/ | ||
|
||
/** | ||
* @typedef {Object} PriceAuthorityRegistryAdmin | ||
* @property {(pa: ERef<PriceAuthority>, assetBrand: Brand, priceBrand: Brand) | ||
* => Deleter} registerPriceAuthority Add a unique price authority for a given | ||
* asset/price pair | ||
*/ | ||
|
||
/** | ||
* @typedef {Object} PriceAuthorityRegistry A price authority that is a facade | ||
* for other backing price authorities registered for a given asset and price | ||
* brand | ||
* @property {PriceAuthority} priceAuthority | ||
* @property {PriceAuthorityRegistryAdmin} adminFacet | ||
*/ | ||
|
||
/** | ||
* @returns {PriceAuthorityRegistry} | ||
*/ | ||
export const makePriceAuthorityRegistry = () => { | ||
/** | ||
* @typedef {Object} PriceAuthorityRecord A record indicating a registered | ||
* price authority | ||
* @property {ERef<PriceAuthority>} priceAuthority | ||
*/ | ||
|
||
/** @type {Store<Brand, Store<Brand, PriceAuthorityRecord>>} */ | ||
const assetToPriceStore = makeStore('assetBrand'); | ||
|
||
/** | ||
* @param {Brand} assetBrand | ||
* @param {Brand} priceBrand | ||
*/ | ||
const lookup = (assetBrand, priceBrand) => { | ||
const priceStore = assetToPriceStore.get(assetBrand); | ||
return priceStore.get(priceBrand); | ||
}; | ||
|
||
/** | ||
* This PriceAuthority is just a wrapper for multiple registered | ||
* PriceAuthorities. | ||
* | ||
* @type {PriceAuthority} | ||
*/ | ||
const priceAuthority = { | ||
async getQuoteIssuer(assetBrand, priceBrand) { | ||
const record = lookup(assetBrand, priceBrand); | ||
return E(record.priceAuthority).getQuoteIssuer(assetBrand, priceBrand); | ||
}, | ||
async getInputPrice(amountIn, brandOut) { | ||
const record = lookup(amountIn.brand, brandOut); | ||
return E(record.priceAuthority).getInputPrice(amountIn, brandOut); | ||
}, | ||
async getOutputPrice(amountOut, brandIn) { | ||
const record = lookup(brandIn, amountOut.brand); | ||
return E(record.priceAuthority).getOutputPrice(amountOut, brandIn); | ||
}, | ||
async getPriceNotifier(assetBrand, priceBrand) { | ||
const record = lookup(assetBrand, priceBrand); | ||
return E(record.priceAuthority).getPriceNotifier(assetBrand, priceBrand); | ||
}, | ||
async priceAtTime(timer, deadline, assetAmount, priceBrand) { | ||
const record = lookup(assetAmount.brand, priceBrand); | ||
return E(record.priceAuthority).priceAtTime( | ||
timer, | ||
deadline, | ||
assetAmount, | ||
priceBrand, | ||
); | ||
}, | ||
async priceWhenLT(assetAmount, priceLimit) { | ||
const record = lookup(assetAmount.brand, priceLimit.brand); | ||
return E(record.priceAuthority).priceWhenLT(assetAmount, priceLimit); | ||
}, | ||
async priceWhenLTE(assetAmount, priceLimit) { | ||
const record = lookup(assetAmount.brand, priceLimit.brand); | ||
return E(record.priceAuthority).priceWhenLTE(assetAmount, priceLimit); | ||
}, | ||
async priceWhenGTE(assetAmount, priceLimit) { | ||
const record = lookup(assetAmount.brand, priceLimit.brand); | ||
return E(record.priceAuthority).priceWhenGT(assetAmount, priceLimit); | ||
}, | ||
async priceWhenGT(assetAmount, priceLimit) { | ||
const record = lookup(assetAmount.brand, priceLimit.brand); | ||
return E(record.priceAuthority).priceWhenGT(assetAmount, priceLimit); | ||
}, | ||
}; | ||
|
||
/** @type {PriceAuthorityRegistryAdmin} */ | ||
const adminFacet = { | ||
registerPriceAuthority(pa, assetBrand, priceBrand) { | ||
/** @type {Store<Brand, PriceAuthorityRecord>} */ | ||
let priceStore; | ||
if (assetToPriceStore.has(assetBrand)) { | ||
priceStore = assetToPriceStore.get(assetBrand); | ||
} else { | ||
priceStore = makeStore('priceBrand'); | ||
assetToPriceStore.init(assetBrand, priceStore); | ||
} | ||
|
||
// Put a box around the authority so that we can be ensured the deleter | ||
// won't delete the wrong thing. | ||
const record = { | ||
priceAuthority: pa, | ||
}; | ||
|
||
// Set up the record. | ||
priceStore.init(priceBrand, harden(record)); | ||
|
||
return harden({ | ||
delete() { | ||
assert.equal( | ||
priceStore.has(priceBrand) && priceStore.get(priceBrand), | ||
record, | ||
details`Price authority already dropped`, | ||
); | ||
priceStore.delete(priceBrand); | ||
}, | ||
}); | ||
}, | ||
}; | ||
|
||
return harden({ | ||
priceAuthority, | ||
adminFacet, | ||
}); | ||
}; |
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,42 @@ | ||
/** | ||
* @typedef {Object} PriceQuote | ||
* @property {Payment} quotePayment The quote wrapped as a payment | ||
* @property {Amount} quoteAmount Amount of `quotePayment` (`quoteIssuer.getAmountOf(quotePayment)`) | ||
*/ | ||
|
||
/** | ||
* @typedef {Object} PriceQuoteValue An individual quote's value | ||
* @property {Amount} assetAmount The amount of the asset being quoted | ||
* @property {Amount} price The quoted price for the `assetAmount` | ||
* @property {TimerService} timer The service that gave the `timestamp` | ||
* @property {number} timestamp A timestamp for the quote according to `timer` | ||
* @property {any=} conditions Additional conditions for the quote | ||
*/ | ||
|
||
/** | ||
* @typedef {Object} PriceAuthority An object that mints PriceQuotes and handles | ||
* triggers and notifiers for changes in the price | ||
* @property {(assetBrand: Brand, priceBrand: Brand) => ERef<Issuer>} | ||
* getQuoteIssuer Get the ERTP issuer of PriceQuotes | ||
* @property {(amountIn: Amount, brandOut: Brand) => Promise<PriceQuote>} | ||
* getInputPrice calculate the amount of brandOut that will be returned if the | ||
* amountIn is sold at the current price | ||
* @property {(amountOut: Amount, brandIn: Brand) => Promise<PriceQuote>} | ||
* getOutputPrice calculate the amount of brandIn that is required in order to | ||
* get amountOut using the current price | ||
* @property {(assetBrand: Brand, priceBrand: Brand) => ERef<Notifier<PriceQuote>>} | ||
* getPriceNotifier | ||
* @property {(timer: TimerService, deadline: number, assetAmount: Amount, | ||
* priceBrand: Brand) => Promise<PriceQuote>} priceAtTime Resolves after | ||
* `deadline` passes on `timer` with the price of `assetAmount` at that time | ||
* @property {(assetAmount: Amount, priceLimit: Amount) => Promise<PriceQuote>} | ||
* priceWhenGT Resolve when the price of `assetAmount` exceeds `priceLimit` | ||
* @property {(assetAmount: Amount, priceLimit: Amount) => Promise<PriceQuote>} | ||
* priceWhenGTE Resolve when the price of `assetAmount` reaches or exceeds | ||
* `priceLimit` | ||
* @property {(assetAmount: Amount, priceLimit: Amount) => Promise<PriceQuote>} | ||
* priceWhenLTE Resolve when the price of `assetAmount` reaches or drops below | ||
* `priceLimit` | ||
* @property {(assetAmount: Amount, priceLimit: Amount) => Promise<PriceQuote>} | ||
* priceWhenLT Resolve when the price of `assetAmount` drops below `priceLimit` | ||
*/ |