Skip to content
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

Merged
merged 3 commits into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/run-protocol/src/vpool-xyk-amm/addPool.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const makeAddIssuer = (zcf, isInSecondaries, brandToLiquidityMint) => {
* @param {ZCFSeat} reserveLiquidityTokenSeat seat that holds liquidity tokens
* from adding pool liquidity. It is expected to be collected by the Reserve.
* @param {WeakStore<Brand,ZCFMint>} brandToLiquidityMint
* @param {() => void} updateMetrics
*/
export const makeAddPoolInvitation = (
zcf,
Expand All @@ -73,6 +74,7 @@ export const makeAddPoolInvitation = (
protocolSeat,
reserveLiquidityTokenSeat,
brandToLiquidityMint,
updateMetrics,
) => {
const makePool = definePoolKind(
zcf,
Expand All @@ -92,6 +94,7 @@ export const makeAddPoolInvitation = (
const poolFacets = makePool(liquidityZcfMint, poolSeat, secondaryBrand);

initPool(secondaryBrand, poolFacets);
updateMetrics();
return { liquidityZcfMint, poolFacets };
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {
makeRatio,
} from '@agoric/zoe/src/contractSupport/ratio.js';

import './types.js';
import './internal-types.js';

import { BASIS_POINTS } from './defaults.js';

const { details: X } = assert;
Expand Down
30 changes: 26 additions & 4 deletions packages/run-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js
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';

Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -146,6 +152,16 @@ const start = async (zcf, privateArgs) => {

const quoteIssuerKit = makeIssuerKit('Quote', AssetKind.SET);

/** @type {SubscriptionRecord<MetricsNotification>} */
const { publication: metricsPublication, subscription: metricsSubscription } =
Copy link
Member

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,

/**
 * @typedef {object} MetricsNotification
 * @property {Brand[]} XYK brands
 */

then here would be,

Suggested change
const { publication: metricsPublication, subscription: metricsSubscription } =
/** @type {SubscriptonKit<MetricsNotification> */
const { publication: metricsPublication, subscription: metricsSubscription } =

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

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();
Expand All @@ -165,6 +181,7 @@ const start = async (zcf, privateArgs) => {
protocolSeat,
reserveLiquidityTokenSeat,
secondaryBrandToLiquidityMint,
updateMetrics,
);
const addIssuer = makeAddIssuer(
zcf,
Expand All @@ -184,6 +201,9 @@ const start = async (zcf, privateArgs) => {
};
};

/** @param {Brand} brand */
const getPoolMetrics = brand => getPool(brand).getMetrics();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


/**
* @param {Brand} brandIn
* @param {Brand} [brandOut]
Expand Down Expand Up @@ -266,6 +286,8 @@ const start = async (zcf, privateArgs) => {
getAllPoolBrands: () =>
Object.values(zcf.getTerms().brands).filter(isSecondary),
getProtocolPoolBalance: () => protocolSeat.getCurrentAllocation(),
getMetrics: () => metricsSubscription,
getPoolMetrics,
}),
);

Expand Down
30 changes: 29 additions & 1 deletion packages/run-protocol/src/vpool-xyk-amm/pool.js
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,
Expand Down Expand Up @@ -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
Expand All @@ -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) =>
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -233,6 +252,7 @@ const poolBehavior = {

userSeat.exit();
updateUpdaterState(state.updater, facets.pool);
facets.helper.updateMetrics();
return 'Liquidity successfully removed.';
},
getNotifier: ({ state: { notifier } }) => notifier,
Expand All @@ -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 */
Expand Down Expand Up @@ -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();
};

/**
Expand All @@ -312,6 +334,10 @@ export const definePoolKind = (
const { brand: liquidityBrand, issuer: liquidityIssuer } =
liquidityZcfMint.getIssuerRecord();
const { notifier, updater } = makeNotifierKit();
const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please type

Suggested change
const {
/** @type {SubscriptionKit<MetricsNotification> */
const {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, that's SubscriptionRecord<>. Took me a bit to find it.

publication: metricsPublication,
subscription: metricsSubscription,
} = makeSubscriptionKit();

// XXX why does the paramAccessor have to be repackaged as a Far object?
const params = Far('pool param accessor', {
Expand All @@ -335,6 +361,8 @@ export const definePoolKind = (
quoteIssuerKit,
timer,
paramAccessor: params,
metricsPublication,
metricsSubscription,
};
};

Expand Down
3 changes: 2 additions & 1 deletion packages/run-protocol/src/vpool-xyk-amm/singlePool.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const getPools = pool => ({

export const singlePool = {
allocateGainsAndLosses: (context, seat, prices) => {
const { pool } = context.facets;
const { pool, helper } = context.facets;
const { poolSeat, zcf, protocolSeat } = context.state;
seat.decrementBy(harden({ In: prices.swapperGives }));
seat.incrementBy(harden({ Out: prices.swapperGets }));
Expand All @@ -34,6 +34,7 @@ export const singlePool = {
zcf.reallocate(poolSeat, seat, protocolSeat);
seat.exit();
pool.updateState();
helper.updateMetrics();
return `Swap successfully completed.`;
},

Expand Down
8 changes: 8 additions & 0 deletions packages/run-protocol/src/vpool-xyk-amm/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
* @property {Amount<'nat'>} newX
*/

/**
* @typedef {import('./multipoolMarketMaker.js').MetricsNotification} MetricsNotification
* @typedef {import('./pool.js').PoolMetricsNotification} PoolMetricsNotification
*/

/**
* @typedef {object} DoublePoolSwapResult
* @property {Amount<'nat'>} swapperGives
Expand Down Expand Up @@ -77,6 +82,7 @@
* @property {() => PriceAuthority} getToCentralPriceAuthority
* @property {() => PriceAuthority} getFromCentralPriceAuthority
* @property {() => VirtualPool} getVPool
* @property {() => Subscription<PoolMetricsNotification>} getMetrics
*/

/**
Expand Down Expand Up @@ -128,6 +134,8 @@
* Prices and notifications about changing prices.
* @property {() => Brand[]} getAllPoolBrands
* @property {() => Allocation} getProtocolPoolBalance
* @property {() => Subscription<MetricsNotification>} getMetrics
* @property {(brand: Brand) => Subscription<PoolMetricsNotification>} getPoolMetrics
*/

/**
Expand Down
Loading