diff --git a/packages/run-protocol/src/proposals/addAssetToVault.js b/packages/run-protocol/src/proposals/addAssetToVault.js index a95539f6217b..9b9911c6f90c 100644 --- a/packages/run-protocol/src/proposals/addAssetToVault.js +++ b/packages/run-protocol/src/proposals/addAssetToVault.js @@ -195,6 +195,7 @@ export const getManifestForAddAssetToVault = ( manifest: { [addInterchainAsset.name]: { consume: { + zoe: true, bankManager: true, agoricNamesAdmin: true, interchainMints: true, diff --git a/packages/run-protocol/src/proposals/core-proposal.js b/packages/run-protocol/src/proposals/core-proposal.js index 1e799f79802d..b5b1fff81951 100644 --- a/packages/run-protocol/src/proposals/core-proposal.js +++ b/packages/run-protocol/src/proposals/core-proposal.js @@ -35,6 +35,7 @@ const SHARED_MAIN_MANIFEST = harden({ ammGovernorCreatorFacet: 'amm', }, issuer: { consume: { RUN: 'zoe' } }, + brand: { consume: { RUN: 'zoe' } }, installation: { consume: { contractGovernor: 'zoe', amm: 'zoe' }, }, diff --git a/packages/run-protocol/src/proposals/econ-behaviors.js b/packages/run-protocol/src/proposals/econ-behaviors.js index 577fa837baae..b0a81f27fee7 100644 --- a/packages/run-protocol/src/proposals/econ-behaviors.js +++ b/packages/run-protocol/src/proposals/econ-behaviors.js @@ -103,8 +103,8 @@ export const startEconomicCommittee = async ( harden(startEconomicCommittee); /** - * @param { EconomyBootstrapPowers } powers - * @param { bigint } minInitialPoolLiquidity + * @param {EconomyBootstrapPowers} powers + * @param {object} opts */ export const setupAmm = async ( { @@ -114,6 +114,9 @@ export const setupAmm = async ( economicCommitteeCreatorFacet: committeeCreator, }, produce: { ammCreatorFacet, ammGovernorCreatorFacet }, + brand: { + consume: { RUN: runBrandP }, + }, issuer: { consume: { [CENTRAL_ISSUER_NAME]: centralIssuer }, }, @@ -125,13 +128,17 @@ export const setupAmm = async ( consume: { contractGovernor: governorInstallation, amm: ammInstallation }, }, }, - minInitialPoolLiquidity = 1_000_000_000n, + opts, ) => { const poserInvitationP = E(committeeCreator).getPoserInvitation(); - const [poserInvitation, poserInvitationAmount] = await Promise.all([ + const [poserInvitation, poserInvitationAmount, runBrand] = await Promise.all([ poserInvitationP, E(E(zoe).getInvitationIssuer()).getAmountOf(poserInvitationP), + runBrandP, ]); + const { + minInitialPoolLiquidity = AmountMath.make(runBrand, 1_000_000_000n), + } = opts; const timer = await chainTimerService; // avoid promise for legibility diff --git a/packages/run-protocol/src/vpool-xyk-amm/addPool.js b/packages/run-protocol/src/vpool-xyk-amm/addPool.js index 3ec3c6852dd5..251142be79c2 100644 --- a/packages/run-protocol/src/vpool-xyk-amm/addPool.js +++ b/packages/run-protocol/src/vpool-xyk-amm/addPool.js @@ -107,8 +107,9 @@ export const makeAddPoolInvitation = ( if (proposalWant.Liquidity) { const { Liquidity: wantLiquidityAmount } = proposalWant; - // @ts-expect-error central is NAT - const liquidityTokensForFunder = centralAmount.value - minPoolLiquidity; + const liquidityTokensForFunder = + // @ts-expect-error central is NAT + centralAmount.value - minPoolLiquidity.value; const funderLiquidityAmount = AmountMath.make( liquidityBrand, liquidityTokensForFunder, @@ -125,16 +126,12 @@ export const makeAddPoolInvitation = ( } = await addPool(secondaryBrand); assert( - centralAmount.value >= minPoolLiquidity, + AmountMath.isGTE(centralAmount, minPoolLiquidity), `The minimum initial liquidity is ${minPoolLiquidity}, rejecting ${centralAmount}`, ); - - helper.addLiquidityInternal(seat, secondaryAmount, centralAmount); - - const totalNewLiquidity = seat.getAmountAllocated('Liquidity'); const minLiqAmount = AmountMath.make( - totalNewLiquidity.brand, - minPoolLiquidity, + liquidityBrand, + minPoolLiquidity.value, ); // @ts-ignore TS unhappy about issuers @@ -142,6 +139,11 @@ export const makeAddPoolInvitation = ( ([_, i]) => i === issuer, ); + // in addLiquidityInternal, funder provides centralAmount & secondaryAmount, + // and receives liquidity tokens equal to centralAmount. Afterward, we'll + // transfer minPoolLiquidity in tokens from the funder to the reserve. + helper.addLiquidityInternal(seat, secondaryAmount, centralAmount); + seat.decrementBy({ Liquidity: minLiqAmount }); reserveLiquidityTokenSeat.incrementBy({ [liquidityKeyword]: minLiqAmount }); zcf.reallocate(reserveLiquidityTokenSeat, seat); diff --git a/packages/run-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js b/packages/run-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js index 97f797dc4d73..16375b6db49c 100644 --- a/packages/run-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js +++ b/packages/run-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js @@ -109,7 +109,7 @@ const start = async (zcf, privateArgs) => { * @typedef {GovernanceTerms<{ * PoolFee: 'nat', * ProtocolFee: 'nat', - * MinInitialPoolLiquidity: 'nat', + * MinInitialPoolLiquidity: 'amount', * }> & { * brands: { Central: Brand }, * issuers: {}, @@ -134,7 +134,7 @@ const start = async (zcf, privateArgs) => { handleParamGovernance(zcf, privateArgs.initialPoserInvitation, { [POOL_FEE_KEY]: ParamTypes.NAT, [PROTOCOL_FEE_KEY]: ParamTypes.NAT, - [MIN_INITIAL_POOL_LIQUIDITY_KEY]: ParamTypes.NAT, + [MIN_INITIAL_POOL_LIQUIDITY_KEY]: ParamTypes.AMOUNT, }), E(centralBrand).getDisplayInfo(), ]); @@ -298,6 +298,6 @@ export { start }; * @typedef {object} AMMParamGetters * @property {() => NatValue} getPoolFee * @property {() => NatValue} getProtocolFee - * @property {() => NatValue} getMinInitialPoolLiquidity + * @property {() => Amount} getMinInitialPoolLiquidity * @property {() => Amount} getElectorate */ diff --git a/packages/run-protocol/src/vpool-xyk-amm/params.js b/packages/run-protocol/src/vpool-xyk-amm/params.js index 084785bf2d8d..7317bb6af8e7 100644 --- a/packages/run-protocol/src/vpool-xyk-amm/params.js +++ b/packages/run-protocol/src/vpool-xyk-amm/params.js @@ -17,21 +17,24 @@ const DEFAULT_PROTOCOL_FEE_BP = 6n; * @param {ERef} zoe * @param {bigint} poolFeeBP * @param {bigint} protocolFeeBP - * @param {bigint} mintInitialLiquidity + * @param {Amount} minInitialLiquidity * @param {Invitation} poserInvitation - invitation for the question poser */ const makeAmmParamManager = async ( zoe, poolFeeBP, protocolFeeBP, - mintInitialLiquidity, + minInitialLiquidity, poserInvitation, ) => { return makeParamManager( { [POOL_FEE_KEY]: [ParamTypes.NAT, poolFeeBP], [PROTOCOL_FEE_KEY]: [ParamTypes.NAT, protocolFeeBP], - [MIN_INITIAL_POOL_LIQUIDITY_KEY]: [ParamTypes.NAT, mintInitialLiquidity], + [MIN_INITIAL_POOL_LIQUIDITY_KEY]: [ + ParamTypes.AMOUNT, + minInitialLiquidity, + ], [CONTRACT_ELECTORATE]: [ParamTypes.INVITATION, poserInvitation], }, zoe, @@ -42,14 +45,14 @@ const makeAmmParams = ( electorateInvitationAmount, protocolFeeBP, poolFeeBP, - mintInitialLiquidity, + minInitialLiquidity, ) => { return harden({ [POOL_FEE_KEY]: { type: ParamTypes.NAT, value: poolFeeBP }, [PROTOCOL_FEE_KEY]: { type: ParamTypes.NAT, value: protocolFeeBP }, [MIN_INITIAL_POOL_LIQUIDITY_KEY]: { - type: ParamTypes.NAT, - value: mintInitialLiquidity, + type: ParamTypes.AMOUNT, + value: minInitialLiquidity, }, [CONTRACT_ELECTORATE]: { type: ParamTypes.INVITATION, @@ -61,7 +64,7 @@ const makeAmmParams = ( const makeAmmTerms = ( timer, poserInvitationAmount, - mintInitialLiquidity, + minInitialLiquidity, protocolFeeBP = DEFAULT_PROTOCOL_FEE_BP, poolFeeBP = DEFAULT_POOL_FEE_BP, ) => ({ @@ -72,7 +75,7 @@ const makeAmmTerms = ( poserInvitationAmount, protocolFeeBP, poolFeeBP, - mintInitialLiquidity, + minInitialLiquidity, ), }); diff --git a/packages/run-protocol/test/amm/vpool-xyk-amm/setup.js b/packages/run-protocol/test/amm/vpool-xyk-amm/setup.js index b0fc88a3ee96..d7d6f1bfbfc8 100644 --- a/packages/run-protocol/test/amm/vpool-xyk-amm/setup.js +++ b/packages/run-protocol/test/amm/vpool-xyk-amm/setup.js @@ -3,7 +3,7 @@ import { E } from '@endo/eventual-send'; import { makeLoopback } from '@endo/captp'; import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin.js'; - +import { AmountMath } from '@agoric/ertp'; import { makeZoeKit } from '@agoric/zoe'; import buildManualTimer from '@agoric/zoe/tools/manualTimer.js'; import { @@ -92,7 +92,9 @@ export const setupAmmServices = async ( startEconomicCommittee(space, { options: { econCommitteeOptions: electorateTerms }, }), - setupAmm(space, 1000n), + setupAmm(space, { + minInitialPoolLiquidity: AmountMath.make(centralR.brand, 1000n), + }), ]); const installs = await Collect.allValues({ diff --git a/packages/run-protocol/test/amm/vpool-xyk-amm/test-amm-governance.js b/packages/run-protocol/test/amm/vpool-xyk-amm/test-amm-governance.js index e18ad366f642..80b5d2f0dad1 100644 --- a/packages/run-protocol/test/amm/vpool-xyk-amm/test-amm-governance.js +++ b/packages/run-protocol/test/amm/vpool-xyk-amm/test-amm-governance.js @@ -59,8 +59,8 @@ test('amm change param via Governance', async t => { value: 24n, }, [MIN_INITIAL_POOL_LIQUIDITY_KEY]: { - type: 'nat', - value: 1000n, + type: 'amount', + value: AmountMath.make(centralR.brand, 1000n), }, [PROTOCOL_FEE_KEY]: { type: 'nat', @@ -168,8 +168,8 @@ test('price check after Governance param change', async t => { value: 6n, }, MinInitialPoolLiquidity: { - type: 'nat', - value: 1000n, + type: 'amount', + value: AmountMath.make(centralR.brand, 1000n), }, Electorate: { type: 'invitation', diff --git a/packages/run-protocol/test/test-voPool.js b/packages/run-protocol/test/test-voPool.js index 403ed96009b6..bd0510bb06cf 100644 --- a/packages/run-protocol/test/test-voPool.js +++ b/packages/run-protocol/test/test-voPool.js @@ -3,7 +3,7 @@ import { runVOTest, test } from '@agoric/swingset-vat/tools/vo-test-harness.js'; import { setupZCFTest } from '@agoric/zoe/test/unitTests/zcf/setupZcfTest.js'; import buildManualTimer from '@agoric/zoe/tools/manualTimer.js'; -import { makeIssuerKit } from '@agoric/ertp'; +import { makeIssuerKit, AmountMath } from '@agoric/ertp'; import { definePoolKind } from '../src/vpool-xyk-amm/pool.js'; import { makeAmmParamManager } from '../src/vpool-xyk-amm/params.js'; @@ -12,14 +12,14 @@ const voPoolTest = async (t, mutation, postTest) => { let makePool; const { zoe, zcf } = await setupZCFTest(); const invitation = await zcf.makeInvitation(() => {}, 'fake invitation'); + const { brand: centralBrand } = makeIssuerKit('central'); const paramManager = await makeAmmParamManager( zoe, 25n, 5n, - 100n, + AmountMath.make(centralBrand, 100n), invitation, ); - const { brand: centralBrand } = makeIssuerKit('central'); const { brand: secondaryBrand } = makeIssuerKit('secondary'); const quoteIssuerKit = makeIssuerKit('Quotes'); const liquidityZcfMint = await zcf.makeZCFMint('Liquidity'); diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index 54e4eab8481d..c58865318d1f 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -127,6 +127,7 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { const { zoe, aethKit: { issuer: aethIssuer }, + runKit: { brand: runBrand }, electorateTerms = { committeeName: 'The Cabal', committeeSize: 1 }, timer, } = t.context; @@ -138,7 +139,9 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { startEconomicCommittee(space, { options: { econCommitteeOptions: electorateTerms }, }); - setupAmm(space, 1000n); + setupAmm(space, { + minInitialPoolLiquidity: AmountMath.make(runBrand, 1000n), + }); const governorCreatorFacet = consume.ammGovernorCreatorFacet; const governorInstance = await instance.consume.ammGovernor; diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index da43dc1b7daf..23d636fde695 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -135,6 +135,7 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { const { zoe, aethKit: { issuer: aethIssuer }, + runKit: { brand: runBrand }, electorateTerms = { committeeName: 'The Cabal', committeeSize: 1 }, timer, } = t.context; @@ -144,7 +145,9 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { installGovernance(zoe, space.installation.produce); space.installation.produce.amm.resolve(t.context.installation.amm); await startEconomicCommittee(space, electorateTerms); - await setupAmm(space, 300n); + await setupAmm(space, { + minInitialPoolLiquidity: AmountMath.make(runBrand, 300n), + }); const governorCreatorFacet = consume.ammGovernorCreatorFacet; const governorInstance = await instance.consume.ammGovernor;