From e4782973fbf78440e776558df27fed7cfc905baa Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Thu, 17 Jun 2021 15:17:05 -0700 Subject: [PATCH] chore: integrate with changes to paramManager extracted params to a separate file --- package.json | 3 +- packages/governance/src/param-manager.js | 102 ------------------ packages/governance/src/types.js | 7 +- packages/treasury/package.json | 2 +- packages/treasury/src/paramKeys.js | 13 --- packages/treasury/src/params.js | 81 ++++++++++++++ packages/treasury/src/stablecoinMachine.js | 95 +++------------- packages/treasury/src/types.js | 28 ++++- packages/treasury/src/vaultManager.js | 23 ++-- .../treasury/test/vault-contract-wrapper.js | 2 +- yarn.lock | 20 ++-- 11 files changed, 152 insertions(+), 224 deletions(-) delete mode 100644 packages/governance/src/param-manager.js delete mode 100644 packages/treasury/src/paramKeys.js create mode 100644 packages/treasury/src/params.js diff --git a/package.json b/package.json index 633debfc2f2f..c665c084ae77 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,8 @@ "timeout": "30m" }, "dependencies": { - "@endo/eslint-config": "^0.3.9", + "@endo/eslint-config": "^0.3.10", + "@endo/eslint-plugin": "^0.3.6", "patch-package": "^6.2.2" } } diff --git a/packages/governance/src/param-manager.js b/packages/governance/src/param-manager.js deleted file mode 100644 index f57b766a8c49..000000000000 --- a/packages/governance/src/param-manager.js +++ /dev/null @@ -1,102 +0,0 @@ -// @ts-check - -import { makeStore } from '@agoric/store'; -import { assert, details as X } from '@agoric/assert'; -import { Nat } from '@agoric/nat'; -import { assertIsRatio } from '@agoric/zoe/src/contractSupport'; -import { AmountMath, looksLikeBrand } from '@agoric/ertp'; - -const ParamType = { - AMOUNT: 'amount', - ANY: 'any', - BIGINT: 'bigint', - BRAND: 'brand', - HANDLE: 'handle', - NAT: 'nat', - RATIO: 'ratio', - STRING: 'string', -}; -harden(ParamType); - -const assertType = (type, value, name) => { - if (!type) { - // undefined type means don't verify. Did we omit an interesting type? - return; - } - - switch (type) { - case ParamType.AMOUNT: - // TODO(hibbert): is there a clean way to assert something is an amount? - // An alternate approach would be to say the contract knows the brand and - // the managed parameter only needs to supply the value. - assert( - AmountMath.isEqual(value, value), - X`value for ${name} must be an Amount, was ${value}`, - ); - break; - case ParamType.ANY: - break; - case ParamType.BIGINT: - assert.typeof(value, 'bigint'); - break; - case ParamType.BRAND: - assert( - looksLikeBrand(value), - X`value for ${name} must be a brand, was ${value}`, - ); - break; - case ParamType.HANDLE: - assert( - typeof value === 'object' && !Object.getOwnPropertyNames(value).length, - X`value for ${name} must be an empty object, was ${value}`, - ); - break; - case ParamType.NAT: - Nat(value); - break; - case ParamType.RATIO: - assertIsRatio(value); - break; - case ParamType.STRING: - assert.typeof(value, 'string'); - break; - default: - assert.fail(X`unknown type guard ${type}`); - } -}; - -const parse = paramDesc => { - const bindings = makeStore('name'); - const types = makeStore('name'); - - paramDesc.forEach(({ name, value, type }) => { - assertType(type, value, name); - bindings.init(name, value); - types.init(name, type); - }); - - return { bindings, types }; -}; - -/** @type {BuildParamManager} */ -const buildParamManager = paramDesc => { - const { bindings, types } = parse(paramDesc); - - const publicFacet = { - lookup(name) { - return bindings.get(name); - }, - }; - - const manager = { - update(name, value) { - assertType(types.get(name), value, name); - bindings.set(name, value); - }, - }; - - return { publicFacet, manager }; -}; -harden(buildParamManager); - -export { ParamType, buildParamManager }; diff --git a/packages/governance/src/types.js b/packages/governance/src/types.js index a760d9ce05eb..c04c910b2f9b 100644 --- a/packages/governance/src/types.js +++ b/packages/governance/src/types.js @@ -19,9 +19,14 @@ * @property {ParamType} type */ +/** + * @callback GetParams + * @returns {Record} + */ + /** * @typedef {Object} ParamManagerBase - * @property {() => Record} getParams + * @property {GetParams} getParams * * @typedef {{ [updater: string]: (arg: ParamValue) => void }} ParamManagerUpdaters * @typedef {ParamManagerBase & ParamManagerUpdaters} ParamManagerFull diff --git a/packages/treasury/package.json b/packages/treasury/package.json index fd6dbd513499..c5760c1c9bb0 100644 --- a/packages/treasury/package.json +++ b/packages/treasury/package.json @@ -70,7 +70,7 @@ }, "eslintConfig": { "extends": [ - "@endo" + "@agoric" ] }, "eslintIgnore": [ diff --git a/packages/treasury/src/paramKeys.js b/packages/treasury/src/paramKeys.js deleted file mode 100644 index 9fb3e85449cb..000000000000 --- a/packages/treasury/src/paramKeys.js +++ /dev/null @@ -1,13 +0,0 @@ -// @ts-check - -export const POOL_FEE_KEY = 'poolFee'; -export const PROTOCOL_FEE_KEY = 'protocolFee'; - -export const CHARGING_PERIOD_KEY = 'chargingPeriod'; -export const RECORDING_PERIOD_KEY = 'recordingPeriod'; - -export const INITIAL_MARGIN_KEY = 'initialMargin'; -export const LIQUIDATION_MARGIN_KEY = 'liquidationMargin'; -export const INITIAL_PRICE_KEY = 'initialPrice'; -export const INTEREST_RATE_KEY = 'interestRate'; -export const LOAN_FEE_KEY = 'loanFee'; diff --git a/packages/treasury/src/params.js b/packages/treasury/src/params.js new file mode 100644 index 000000000000..d65e772a2ac1 --- /dev/null +++ b/packages/treasury/src/params.js @@ -0,0 +1,81 @@ +// @ts-check + +import { buildParamManager, ParamType } from '@agoric/governance'; + +export const POOL_FEE_KEY = 'PoolFee'; +export const PROTOCOL_FEE_KEY = 'ProtocolFee'; + +export const CHARGING_PERIOD_KEY = 'ChargingPeriod'; +export const RECORDING_PERIOD_KEY = 'RecordingPeriod'; + +export const INITIAL_MARGIN_KEY = 'InitialMargin'; +export const LIQUIDATION_MARGIN_KEY = 'LiquidationMargin'; +export const INTEREST_RATE_KEY = 'InterestRate'; +export const LOAN_FEE_KEY = 'LoanFee'; + +export const governedParameterTerms = () => ({ + loanParams: { + POOL_FEE_KEY, + PROTOCOL_FEE_KEY, + }, + poolParams: { + CHARGING_PERIOD_KEY, + RECORDING_PERIOD_KEY, + INITIAL_MARGIN_KEY, + LIQUIDATION_MARGIN_KEY, + INTEREST_RATE_KEY, + LOAN_FEE_KEY, + }, +}); + +export const makeFeeGovernor = loanParams => { + /** @type {FeeGovernor} */ + return buildParamManager([ + { + name: POOL_FEE_KEY, + value: loanParams.poolFee, + type: ParamType.NAT, + }, + { + name: PROTOCOL_FEE_KEY, + value: loanParams.protocolFee, + type: ParamType.NAT, + }, + ]); +}; + +export const makePoolGovernor = (loanParams, rates) => { + /** @type {PoolGovernor} */ + return buildParamManager([ + { + name: CHARGING_PERIOD_KEY, + value: loanParams.chargingPeriod, + type: ParamType.NAT, + }, + { + name: RECORDING_PERIOD_KEY, + value: loanParams.recordingPeriod, + type: ParamType.NAT, + }, + { + name: INITIAL_MARGIN_KEY, + value: rates.initialMargin, + type: ParamType.RATIO, + }, + { + name: LIQUIDATION_MARGIN_KEY, + value: rates.liquidationMargin, + type: ParamType.RATIO, + }, + { + name: INTEREST_RATE_KEY, + value: rates.interestRate, + type: ParamType.RATIO, + }, + { + name: LOAN_FEE_KEY, + value: rates.loanFee, + type: ParamType.RATIO, + }, + ]); +}; diff --git a/packages/treasury/src/stablecoinMachine.js b/packages/treasury/src/stablecoinMachine.js index c8b22a7281e5..d383842aa0e6 100644 --- a/packages/treasury/src/stablecoinMachine.js +++ b/packages/treasury/src/stablecoinMachine.js @@ -33,26 +33,17 @@ import { makeRatioFromAmounts, } from '@agoric/zoe/src/contractSupport/ratio'; import { AmountMath } from '@agoric/ertp'; -import { - buildParamManager, - ParamType, -} from '@agoric/governance/src/param-manager'; import { makeTracer } from './makeTracer'; import { makeVaultManager } from './vaultManager'; import { makeLiquidationStrategy } from './liquidateMinimum'; import { makeMakeCollectFeesInvitation } from './collectRewardFees'; import { + makePoolGovernor, + makeFeeGovernor, PROTOCOL_FEE_KEY, POOL_FEE_KEY, - RECORDING_PERIOD_KEY, - CHARGING_PERIOD_KEY, - INITIAL_MARGIN_KEY, - LIQUIDATION_MARGIN_KEY, - INITIAL_PRICE_KEY, - INTEREST_RATE_KEY, - LOAN_FEE_KEY, -} from './paramKeys'; +} from './params'; const trace = makeTracer('ST'); @@ -81,21 +72,7 @@ export async function start(zcf) { )}) must be a BigInt`, ); - const { - publicFacet: paramManagerPublic, - manager: paramManager, - } = buildParamManager([ - { - name: POOL_FEE_KEY, - value: loanParams.poolFee, - type: ParamType.BIGINT, - }, - { - name: PROTOCOL_FEE_KEY, - value: loanParams.protocolFee, - type: ParamType.BIGINT, - }, - ]); + const feeGovernor = makeFeeGovernor(loanParams); const [runMint, govMint] = await Promise.all([ zcf.makeZCFMint('RUN', undefined, harden({ decimalPlaces: 6 })), @@ -149,12 +126,12 @@ export async function start(zcf) { timer: timerService, // TODO(hibbert): make the AMM use a paramManager. For now, the values // are fixed after creation of an autoswap instance. - poolFee: paramManagerPublic.lookup(POOL_FEE_KEY), - protocolFee: paramManagerPublic.lookup(PROTOCOL_FEE_KEY), + poolFee: feeGovernor.getParams()[POOL_FEE_KEY].value, + protocolFee: feeGovernor.getParams()[PROTOCOL_FEE_KEY].value, }, ); - const rateManagers = makeStore('brand'); // Brand -> rateManager + const poolGovernors = makeStore('brand'); // Brand -> poolGovernor // We process only one offer per collateralType. They must tell us the // dollar value of their collateral, and we create that many RUN. @@ -168,48 +145,9 @@ export async function start(zcf) { const collateralBrand = zcf.getBrandForIssuer(collateralIssuer); assert(!collateralTypes.has(collateralBrand)); - const { - publicFacet: rateManagerPublic, - manager: rateManager, - } = buildParamManager([ - { - name: CHARGING_PERIOD_KEY, - value: loanParams.chargingPeriod, - type: ParamType.BIGINT, - }, - { - name: RECORDING_PERIOD_KEY, - value: loanParams.recordingPeriod, - type: ParamType.BIGINT, - }, - { - name: INITIAL_MARGIN_KEY, - value: rates.initialMargin, - type: ParamType.RATIO, - }, - { - name: LIQUIDATION_MARGIN_KEY, - value: rates.liquidationMargin, - type: ParamType.RATIO, - }, - { - name: INITIAL_PRICE_KEY, - value: rates.initialPrice, - type: ParamType.RATIO, - }, - { - name: INTEREST_RATE_KEY, - value: rates.interestRate, - type: ParamType.RATIO, - }, - { - name: LOAN_FEE_KEY, - value: rates.loanFee, - type: ParamType.RATIO, - }, - ]); - assert(!rateManagers.has(collateralBrand)); - rateManagers.init(collateralBrand, rateManager); + const poolGovernor = makePoolGovernor(loanParams, rates); + assert(!poolGovernors.has(collateralBrand)); + poolGovernors.init(collateralBrand, poolGovernor); const { creatorFacet: liquidationFacet } = await E(zoe).startInstance( liquidationInstall, @@ -227,8 +165,8 @@ export async function start(zcf) { want: { Governance: _govOut }, // ownership of the whole stablecoin machine } = seat.getProposal(); assert(!collateralTypes.has(collateralBrand)); - const initialPrice = rateManagerPublic.lookup(INITIAL_PRICE_KEY); - const runAmount = multiplyBy(collateralIn, initialPrice); + // initialPrice is in rates, but only used at creation, so not in governor + const runAmount = multiplyBy(collateralIn, rates.initialPrice); // arbitrarily, give governance tokens equal to RUN tokens const govAmount = AmountMath.make(runAmount.value, govBrand); @@ -304,10 +242,9 @@ export async function start(zcf) { runMint, collateralBrand, priceAuthority, - rateManagerPublic, + poolGovernor.getParams, reallocateReward, timerService, - paramManagerPublic, liquidationStrategy, ); collateralTypes.init(collateralBrand, vm); @@ -410,7 +347,7 @@ export async function start(zcf) { getRunIssuer() { return runIssuer; }, - getParamManager: () => paramManagerPublic, + getFeeParams: feeGovernor.getParams, }); const { makeCollectFeesInvitation } = makeMakeCollectFeesInvitation( @@ -430,8 +367,8 @@ export async function start(zcf) { getRewardAllocation, getBootstrapPayment: mintBootstrapPayment(), makeCollectFeesInvitation, - getParamManager: () => paramManager, - getRateManager: rateManagers.get, + getFeeGovernor: () => feeGovernor, + getPoolGovernor: poolGovernors.get, }); return harden({ creatorFacet: stablecoinMachine, publicFacet }); diff --git a/packages/treasury/src/types.js b/packages/treasury/src/types.js index 02cf73845c3a..51cbb49b1167 100644 --- a/packages/treasury/src/types.js +++ b/packages/treasury/src/types.js @@ -33,8 +33,8 @@ * @property {() => Instance} getAMM * @property {() => Promise>} getCollaterals * @property {() => Payment} getBootstrapPayment - * @property {() => ParamManager} paramManager - * @property {() => ParamManager} getRateManager + * @property {() => ParamManagerFull} getFeeGovernor + * @property {() => ParamManagerFull} getPoolGovernor */ /** @@ -140,10 +140,9 @@ * @param {ZCFMint} runMint * @param {Brand} collateralBrand * @param {ERef} priceAuthority - * @param {ParamManagerPublic} rateManager + * @param {GetParams} getLoanParams * @param {ReallocateReward} reallocateReward * @param {TimerService} timerService - * @param {ParamManagerPublic} paramManager * @param {LiquidationStrategy} liquidationStrategy * @returns {VaultManager} */ @@ -155,7 +154,7 @@ * @param {ZCFMint} runMint * @param {ERef} autoswap * @param {ERef} priceAuthority - * @param {ParamManagerPublic} paramManager + * @param {GetParams} paramManager * @param {Timestamp} startTimeStamp * @returns {VaultKit} */ @@ -192,3 +191,22 @@ * @param {RelativeTime} recordingPeriod * @returns {CalculatorKit} */ + +/** + * @typedef {Object} FeeGovernor + * @property {() => Record} getParams + * @property {(bigint) => void} updateProtocolFee + * @property {(bigint) => void} updatePoolFee + */ + +/** + * @typedef {Object} PoolGovernor + * @property {() => Record} getParams + * @property {(bigint) => void} updateChargingPeriod + * @property {(bigint) => void} updateRecordingPeriod + * @property {(Ratio) => void} updateInitialMargin + * @property {(Ratio) => void} updateLiquidationMargin + * @property {(Ratio) => void} updateInitialPrice + * @property {(Ratio) => void} updateInterestRate + * @property {(Ratio) => void} updateLoanFee + */ diff --git a/packages/treasury/src/vaultManager.js b/packages/treasury/src/vaultManager.js index 6a4cee43c8ea..60434feff6e6 100644 --- a/packages/treasury/src/vaultManager.js +++ b/packages/treasury/src/vaultManager.js @@ -24,7 +24,7 @@ import { LOAN_FEE_KEY, INTEREST_RATE_KEY, CHARGING_PERIOD_KEY, -} from './paramKeys'; +} from './params'; const trace = makeTracer(' VM '); @@ -40,34 +40,35 @@ export function makeVaultManager( runMint, collateralBrand, priceAuthority, - rateManager, + getLoanParams, reallocateReward, timerService, - loanParamManager, liquidationStrategy, ) { const { brand: runBrand } = runMint.getIssuerRecord(); + const getLoanParamValue = key => getLoanParams()[key].value; + const shared = { // loans below this margin may be liquidated getLiquidationMargin() { - return rateManager.lookup(LIQUIDATION_MARGIN_KEY); + return getLoanParamValue(LIQUIDATION_MARGIN_KEY); }, // loans must initially have at least 1.2x collateralization getInitialMargin() { - return rateManager.lookup(INITIAL_MARGIN_KEY); + return getLoanParamValue(INITIAL_MARGIN_KEY); }, getLoanFee() { - return rateManager.lookup(LOAN_FEE_KEY); + return getLoanParamValue(LOAN_FEE_KEY); }, getInterestRate() { - return rateManager.lookup(INTEREST_RATE_KEY); + return getLoanParamValue(INTEREST_RATE_KEY); }, getChargingPeriod() { - return rateManager.lookup(CHARGING_PERIOD_KEY); + return getLoanParamValue(CHARGING_PERIOD_KEY); }, getRecordingPeriod() { - return rateManager.lookup(RECORDING_PERIOD_KEY); + return getLoanParamValue(RECORDING_PERIOD_KEY); }, async getCollateralQuote() { // get a quote for one unit of the collateral @@ -188,7 +189,7 @@ export function makeVaultManager( const periodNotifier = E(timerService).makeNotifier( 0n, - rateManager.lookup(RECORDING_PERIOD_KEY), + /** @type {bigint} */ (getLoanParamValue(RECORDING_PERIOD_KEY)), ); const { zcfSeat: poolIncrementSeat } = zcf.makeEmptySeatKit(); @@ -225,7 +226,7 @@ export function makeVaultManager( runMint, autoswap, priceAuthority, - loanParamManager, + getLoanParams, startTimeStamp, ); diff --git a/packages/treasury/test/vault-contract-wrapper.js b/packages/treasury/test/vault-contract-wrapper.js index 6bb85badf34d..71c17ced7dba 100644 --- a/packages/treasury/test/vault-contract-wrapper.js +++ b/packages/treasury/test/vault-contract-wrapper.js @@ -11,7 +11,7 @@ import { makeFakePriceAuthority } from '@agoric/zoe/tools/fakePriceAuthority'; import { makeRatio } from '@agoric/zoe/src/contractSupport/ratio'; import { Far } from '@agoric/marshal'; -import { buildParamManager } from '@agoric/governance/src/param-manager'; +import { buildParamManager } from '@agoric/governance/src/paramManager'; import { makeVaultKit } from '../src/vault'; import { paymentFromZCFMint } from '../src/burn'; diff --git a/yarn.lock b/yarn.lock index 55d2c448c8e1..897b4a007e4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,7 +12,7 @@ resolved "https://registry.yarnpkg.com/@agoric/babel-standalone/-/babel-standalone-7.14.3.tgz#1bf201417481d37d2797dd3283590dcbef775b4d" integrity sha512-Rdlxts19kvxHsqTjTrhGJv0yKgCyjCSVgXoLBZf9dZ7lyo/j+6xFQBiWjP03bXve3X74wUvA1QU55wVey8DEiQ== -"@agoric/nat@^4.1.0": +"@agoric/nat@^4.0.0", "@agoric/nat@^4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@agoric/nat/-/nat-4.1.0.tgz#102794e033ffc183a20b0f86031a2e76d204b9f6" integrity sha512-2oMoh3DMn0Fx8HChPPiH8irBNdT/33ttxAZJohhd3nU3gyBRQ1u+eEoOQWfSkrE6M02iMkQM7GE9MzGmjQ6bHg== @@ -1279,17 +1279,17 @@ "@endo/zip" "^0.2.2" ses "^0.13.2" -"@endo/eslint-config@^0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@endo/eslint-config/-/eslint-config-0.3.9.tgz#157ab2e64ddca73c65c7cf0762cfb04c573c3722" - integrity sha512-nL3y1ncAC52PGLaZDr2u+/r5jjiLZ295wWGNpa+g0yOhzOuAaZ6PvEs8r7qIXJ7YrzdzRKJcEdC+RBjRLRo8Tg== +"@endo/eslint-config@^0.3.10": + version "0.3.10" + resolved "https://registry.yarnpkg.com/@endo/eslint-config/-/eslint-config-0.3.10.tgz#ce6e90ca7a36e2434ac4b9f53b4d3450b148acf3" + integrity sha512-hvlFAHf409ZYmSXyzZMGG2QjkfYFf0uiA/WgQ7VpvnHyRHuza2cX4gOeq6QlIlneLF2/UuxYmHTuwL/bEJSdbA== dependencies: - "@endo/eslint-plugin" "^0.3.5" + "@endo/eslint-plugin" "^0.3.6" -"@endo/eslint-plugin@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@endo/eslint-plugin/-/eslint-plugin-0.3.5.tgz#13c9c5e3f11ee147698af4f81b0cf03cea155bb1" - integrity sha512-qmkCgasPlzQhY/1gstz67RnakLmjc/MRSyNFzmvCmLw9NOCP4DEtsq9O6Af4wimfeqGwYOBvGOGT/FzfydQvlA== +"@endo/eslint-plugin@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@endo/eslint-plugin/-/eslint-plugin-0.3.6.tgz#a6ee8eaf6796ef3ea3133224e25827252447e806" + integrity sha512-kg/+17vdwcOTFknE4uqYGSrQvdvMCjnT1rTtJTjzstHDJHgFlQ9FalpwxOPBNZMqZi7wAB3XubvqeiE3B5dmmg== dependencies: requireindex "~1.1.0"