-
Notifications
You must be signed in to change notification settings - Fork 212
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
feat: publish econ stats from AMM #5420
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,19 @@ | ||
// @ts-check | ||
|
||
import { makeWeakStore } from '@agoric/store'; | ||
import { makeStore, makeWeakStore } from '@agoric/store'; | ||
import { Far } from '@endo/marshal'; | ||
|
||
import { AssetKind, makeIssuerKit } from '@agoric/ertp'; | ||
import { handleParamGovernance, ParamTypes } from '@agoric/governance'; | ||
import { makeSubscriptionKit } from '@agoric/notifier'; | ||
|
||
import { assertIssuerKeywords } from '@agoric/zoe/src/contractSupport/index.js'; | ||
import { E } from '@endo/far'; | ||
import { makeAddIssuer, makeAddPoolInvitation } from './addPool.js'; | ||
import { publicPrices } from './pool.js'; | ||
import { | ||
makeMakeAddLiquidityInvitation, | ||
makeMakeAddLiquidityAtRateInvitation, | ||
makeMakeAddLiquidityInvitation, | ||
} from './addLiquidity.js'; | ||
import { makeMakeRemoveLiquidityInvitation } from './removeLiquidity.js'; | ||
|
||
|
@@ -28,6 +29,11 @@ import { | |
|
||
const { quote: q, details: X } = assert; | ||
|
||
/** | ||
* @typedef {object} MetricsNotification | ||
* @property {Brand[]} XYK brands of pools that use an X*Y=K pricing policy | ||
*/ | ||
|
||
/** | ||
* Multipool AMM is a rewrite of Uniswap that supports multiple liquidity pools, | ||
* and direct exchanges across pools. Please see the documentation for more: | ||
|
@@ -133,8 +139,8 @@ const start = async (zcf, privateArgs) => { | |
)}`, | ||
); | ||
|
||
/** @type {WeakStore<Brand,PoolFacets>} */ | ||
const secondaryBrandToPool = makeWeakStore('secondaryBrand'); | ||
/** @type {Store<Brand,PoolFacets>} */ | ||
const secondaryBrandToPool = makeStore('secondaryBrand'); | ||
const getPool = brand => secondaryBrandToPool.get(brand).pool; | ||
const getPoolHelper = brand => secondaryBrandToPool.get(brand).helper; | ||
const initPool = secondaryBrandToPool.init; | ||
|
@@ -146,6 +152,16 @@ const start = async (zcf, privateArgs) => { | |
|
||
const quoteIssuerKit = makeIssuerKit('Quote', AssetKind.SET); | ||
|
||
/** @type {SubscriptionRecord<MetricsNotification>} */ | ||
const { publication: metricsPublication, subscription: metricsSubscription } = | ||
makeSubscriptionKit(); | ||
const updateMetrics = () => { | ||
metricsPublication.updateState( | ||
harden({ XYK: Array.from(secondaryBrandToPool.keys()) }), | ||
); | ||
}; | ||
updateMetrics(); | ||
|
||
// For now, this seat collects protocol fees. It needs to be connected to | ||
// something that will extract the fees. | ||
const { zcfSeat: protocolSeat } = zcf.makeEmptySeatKit(); | ||
|
@@ -165,6 +181,7 @@ const start = async (zcf, privateArgs) => { | |
protocolSeat, | ||
reserveLiquidityTokenSeat, | ||
secondaryBrandToLiquidityMint, | ||
updateMetrics, | ||
); | ||
const addIssuer = makeAddIssuer( | ||
zcf, | ||
|
@@ -184,6 +201,9 @@ const start = async (zcf, privateArgs) => { | |
}; | ||
}; | ||
|
||
/** @param {Brand} brand */ | ||
const getPoolMetrics = brand => getPool(brand).getMetrics(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider inlining There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
/** | ||
* @param {Brand} brandIn | ||
* @param {Brand} [brandOut] | ||
|
@@ -266,6 +286,8 @@ const start = async (zcf, privateArgs) => { | |
getAllPoolBrands: () => | ||
Object.values(zcf.getTerms().brands).filter(isSecondary), | ||
getProtocolPoolBalance: () => protocolSeat.getCurrentAllocation(), | ||
getMetrics: () => metricsSubscription, | ||
getPoolMetrics, | ||
}), | ||
); | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||||
// @ts-check | ||||||||
|
||||||||
import { AmountMath, isNatValue } from '@agoric/ertp'; | ||||||||
import { makeNotifierKit } from '@agoric/notifier'; | ||||||||
import { makeNotifierKit, makeSubscriptionKit } from '@agoric/notifier'; | ||||||||
|
||||||||
import { | ||||||||
calcLiqValueToMint, | ||||||||
|
@@ -42,6 +42,8 @@ export const publicPrices = prices => { | |||||||
* @typedef {{ | ||||||||
* updater: IterationObserver<any>, | ||||||||
* notifier: Notifier<any>, | ||||||||
* metricsPublication: IterationObserver<PoolMetricsNotification>, | ||||||||
* metricsSubscription: Subscription<PoolMetricsNotification> | ||||||||
* poolSeat: ZCFSeat, | ||||||||
* liqTokenSupply: bigint, | ||||||||
* }} MutableState | ||||||||
|
@@ -54,6 +56,11 @@ export const publicPrices = prices => { | |||||||
* singlePool: VirtualPool, | ||||||||
* }, | ||||||||
* }} MethodContext | ||||||||
* | ||||||||
* @typedef {object} PoolMetricsNotification | ||||||||
* @property {Amount} centralAmount | ||||||||
* @property {Amount} secondaryAmount | ||||||||
* @property {NatValue} liquidityTokens - outstanding tokens | ||||||||
*/ | ||||||||
|
||||||||
export const updateUpdaterState = (updater, pool) => | ||||||||
|
@@ -131,8 +138,20 @@ const helperBehavior = { | |||||||
); | ||||||||
zcfSeat.exit(); | ||||||||
updateUpdaterState(updater, pool); | ||||||||
facets.helper.updateMetrics(); | ||||||||
return 'Added liquidity.'; | ||||||||
}, | ||||||||
/** @param {MethodContext} context */ | ||||||||
updateMetrics: context => { | ||||||||
const { state, facets } = context; | ||||||||
const payload = harden({ | ||||||||
centralAmount: facets.pool.getCentralAmount(), | ||||||||
secondaryAmount: facets.pool.getSecondaryAmount(), | ||||||||
liquidityTokens: state.liqTokenSupply, | ||||||||
}); | ||||||||
|
||||||||
state.metricsPublication.updateState(payload); | ||||||||
dckc marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
}, | ||||||||
}; | ||||||||
|
||||||||
const poolBehavior = { | ||||||||
|
@@ -233,6 +252,7 @@ const poolBehavior = { | |||||||
|
||||||||
userSeat.exit(); | ||||||||
updateUpdaterState(state.updater, facets.pool); | ||||||||
facets.helper.updateMetrics(); | ||||||||
return 'Liquidity successfully removed.'; | ||||||||
}, | ||||||||
getNotifier: ({ state: { notifier } }) => notifier, | ||||||||
|
@@ -242,6 +262,7 @@ const poolBehavior = { | |||||||
getToCentralPriceAuthority: ({ state }) => state.toCentralPriceAuthority, | ||||||||
getFromCentralPriceAuthority: ({ state }) => state.fromCentralPriceAuthority, | ||||||||
getVPool: ({ facets }) => facets.singlePool, | ||||||||
getMetrics: ({ state }) => state.metricsSubscription, | ||||||||
}; | ||||||||
|
||||||||
/** @param {MethodContext} context */ | ||||||||
|
@@ -290,6 +311,7 @@ const finish = context => { | |||||||
context.state.toCentralPriceAuthority = toCentralPriceAuthority; | ||||||||
// @ts-expect-error declared read-only, set value once | ||||||||
context.state.fromCentralPriceAuthority = fromCentralPriceAuthority; | ||||||||
context.facets.helper.updateMetrics(); | ||||||||
}; | ||||||||
|
||||||||
/** | ||||||||
|
@@ -312,6 +334,10 @@ export const definePoolKind = ( | |||||||
const { brand: liquidityBrand, issuer: liquidityIssuer } = | ||||||||
liquidityZcfMint.getIssuerRecord(); | ||||||||
const { notifier, updater } = makeNotifierKit(); | ||||||||
const { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please type
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, that's |
||||||||
publication: metricsPublication, | ||||||||
subscription: metricsSubscription, | ||||||||
} = makeSubscriptionKit(); | ||||||||
|
||||||||
// XXX why does the paramAccessor have to be repackaged as a Far object? | ||||||||
const params = Far('pool param accessor', { | ||||||||
|
@@ -335,6 +361,8 @@ export const definePoolKind = ( | |||||||
quoteIssuerKit, | ||||||||
timer, | ||||||||
paramAccessor: params, | ||||||||
metricsPublication, | ||||||||
metricsSubscription, | ||||||||
}; | ||||||||
}; | ||||||||
|
||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please type this so there is API documentation on what comes out of
getMetrics
.e.g. define a type up top,
then here would be,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done