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(AMM)!: make amm.addPool() require minimum collateral #5377

Merged
merged 14 commits into from
May 24, 2022

Conversation

Chris-Hibbert
Copy link
Contributor

closes: #4643

Description

When creating a new pool for the AMM, there will be a minimum amount
of IST. The caller is expected to provide an equivalent value of the
collateral to balance the AMM pool. The liquidity tokens corresponding
to that minimum will be added to the AssetReserve. If the caller adds
more liquidity than the minimum, they get the extra liquidity tokens.

This required updating a number of tests to initialize their AMMs with
a minimal amount.

Security Considerations

This adds to the economic security of the INTER protocol, but doesn't have much to do with system security.

Documentation Considerations

MinInitialPoolLiquidity needs to be added to the doc for governance parameters, and the contract description.

Testing Considerations

updated existing tests.

@Chris-Hibbert Chris-Hibbert added Inter-protocol Overarching Inter Protocol AMM labels May 16, 2022
@Chris-Hibbert Chris-Hibbert added this to the Mainnet 1 milestone May 16, 2022
@Chris-Hibbert Chris-Hibbert requested a review from turadg as a code owner May 16, 2022 21:20
@Chris-Hibbert Chris-Hibbert self-assigned this May 16, 2022
@Chris-Hibbert Chris-Hibbert marked this pull request as draft May 16, 2022 21:20
@turadg turadg removed their request for review May 16, 2022 21:51
@Chris-Hibbert Chris-Hibbert marked this pull request as ready for review May 19, 2022 17:16
@Chris-Hibbert
Copy link
Contributor Author

@turadg this is now ready for review. #5397 should address the failing test.

Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

Took a pass through src/. Haven't reviewed test/ yet but have to get to a meeting.

@@ -18,11 +18,11 @@ liquidity providers to violate that expectation is a problem.
## Multiple Pools

`addPool` and `addLiquidity` are publicly available. That means someone could maliciously
create pools or provide insufficient liquidity. The ability to add liquidity in arbitrary
proportions should be enough to prevent misuse of these APIs from hurting us.
create pools or provide insufficient liquidity. The requirement of a minimum initial
Copy link
Member

Choose a reason for hiding this comment

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

👍 updating related docs

Comment on lines 11 to 21
export const makeAddIssuer = (zcf, isInSecondaries, brandToLiquidityMint) => {
return async (secondaryIssuer, keyword) => {
Copy link
Member

Choose a reason for hiding this comment

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

param types, s'il vous plaît.

from the function signature isInSecondaries looks like a boolean

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

X`${keyword} asset not fungible (must use NAT math)`,
);
const liquidityKeyword = `${keyword}Liquidity`;
zcf.assertUniqueKeyword(liquidityKeyword);
Copy link
Member

Choose a reason for hiding this comment

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

for my learning: is this giving earlier feedback or checking something that wouldn't be otherwise? (I assume makeZCFMint won't let you override a keyword.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's an early check so we don't make the mint if saveIssuer will fail.

zcf.makeZCFMint(
liquidityKeyword,
AssetKind.NAT,
harden({ decimalPlaces: 6 }),
Copy link
Member

Choose a reason for hiding this comment

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

magic number

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we have a canonical version of this number? Can I let it default?

]);
const { zcfSeat: poolSeat } = zcf.makeEmptySeatKit();
/** @type {PoolFacets} */
// @ts-expect-error cast
Copy link
Member

Choose a reason for hiding this comment

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

something still awry with singlePool.getPriceForInput type differing between PoolFacets and ReturnType<makePool>. Which one is correct? If it's PoolFacets let's move this cast over to makePool's signature. If it's makePool, let's define PoolFacets using it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed? Now the bad magic is concentrated around helper in pool.js. help?

return liquidityZCFMint.getIssuerRecord().issuer;

// in addLiquidityInternal, funder provides centralAmount & secondaryAmount,
// and receives liquidity tokens equal to centralAmount. Afterward, we'll
Copy link
Member

Choose a reason for hiding this comment

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

thanks for explaining this. any risk in something failing before that happens? (not atomic)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a valid question, but I think I've covered all the cases.

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

// For now, this seat collects protocol fees. It needs to be connected to
// something that will extract the fees.
const { zcfSeat: protocolSeat } = zcf.makeEmptySeatKit();

// todo(hibbert): give reserve the abilty to collect this.
Copy link
Member

Choose a reason for hiding this comment

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

is this before MN-1? should have a ticket so we track it to release

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -112,6 +108,23 @@ const helperBehavior = {
} else {
zcf.reallocate(poolSeat, zcfSeat);
}
},
addLiquidityActual: (
Copy link
Member

Choose a reason for hiding this comment

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

can keep this, no?

Suggested change
addLiquidityActual: (
/** @type {import('@agoric/vat-data/src/types').PlusContext<MethodContext, AddLiquidityActual>} */
addLiquidityActual: (

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

Copy link
Member

Choose a reason for hiding this comment

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

I pushed some other type fixes in a71f732

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks

@@ -140,6 +153,7 @@ const poolBehavior = {
assert(isNatValue(secondaryIn.value), 'User Secondary');

if (state.liqTokenSupply === 0n) {
// @ts-expect-error TS confused about parameter count
Copy link
Member

Choose a reason for hiding this comment

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

without an annotation it doesn't know that feeSeat is optional

@@ -83,8 +91,9 @@
*/
/**
* @typedef {object} XYKAMMPublicFacet
* @property {(issuer: ERef<Issuer>, keyword: Keyword) => Promise<Issuer>} addPool
* @property {() => Promise<Invitation>} addPoolInvitation
Copy link
Member

Choose a reason for hiding this comment

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

the Invitation can be typed with the offer args and result. I don't know it offhand but I'd be happy to help.

Copy link
Member

Choose a reason for hiding this comment

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

nevermind, I tried a bit and it's more effort than I thought.

Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

Code LGTM. I pushed a few types fix commits.

I see the tests aren't passing yet but assume it's a matter of tweaking. Please re-request review if more substantial changes are pushed.

feeSeat,
) => {
const { updater } = state;
const { helper } = facets;
Copy link
Member

Choose a reason for hiding this comment

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

this is a work-around for the cyclic typedef error that happens when a method destructures a facet that it's part of defining. that's a bit of a gotcha. thoughts on how/where to raise awareness?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't have an idea other than spreading it through code reviews. I get bitten by this while trying to make the types work, and understanding these common workarounds will help me get past that.

* @property {{addLiquidityActual: AddLiquidityActual}} helper
* @property {VirtualPool} singlePool
* @property {{addLiquidityActual: AddLiquidityActual, addLiquidityInternal: AddLiquidityInternal}} helper
* @property {SinglePool} singlePool
Copy link
Member

@turadg turadg May 20, 2022

Choose a reason for hiding this comment

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

👍

I think the VirtualPool types will be all sorted out with 856aef

@@ -83,8 +91,9 @@
*/
/**
* @typedef {object} XYKAMMPublicFacet
* @property {(issuer: ERef<Issuer>, keyword: Keyword) => Promise<Issuer>} addPool
* @property {() => Promise<Invitation>} addPoolInvitation
Copy link
Member

Choose a reason for hiding this comment

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

nevermind, I tried a bit and it's more effort than I thought.

@@ -196,7 +236,11 @@ test('amm add and remove liquidity', async t => {
await assertPayouts(l1, 50_000n, c1, 0n, s1, 0n);
t.deepEqual(
await E(amm.ammPublicFacet).getPoolAllocation(moolaR.brand),
allocation(50_000n, 0n, 10000n),
allocation(
centralLiquidityValue + 50_000n,
Copy link
Member

Choose a reason for hiding this comment

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

+1 to regular arithmetic in tests

`bob gets the same price as when he called the getInputPrice method`,
);

// @ts-ignore it doesn't know both are Nat
Copy link
Member

Choose a reason for hiding this comment

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

solved by 1a7c0a5

Comment on lines 1029 to 1033
// await t.throwsAsync(
// () => E(amm.ammPublicFacet).getPoolAllocation(moolaR.brand),
// { message: /"secondaryBrand" not found: / },
// "The pool hasn't been created yet",
// );
Copy link
Member

Choose a reason for hiding this comment

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

💀

Copy link
Contributor Author

Choose a reason for hiding this comment

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

uncommented. This is valid at this point in the test .

@@ -15,11 +15,71 @@ import { unsafeMakeBundleCache } from '../bundleTool.js';
// Some notifier updates aren't propogating sufficiently quickly for the tests.
// This invocation (thanks to Warner) waits for all promises that can fire to
// have all their callbacks run
async function waitForPromisesToSettle() {
const waitForPromisesToSettle = async () => {
Copy link
Member

Choose a reason for hiding this comment

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

import from test/supports.js

@Chris-Hibbert
Copy link
Contributor Author

Chris-Hibbert commented May 20, 2022

Blocked by #5397

[corrected]

Chris-Hibbert and others added 10 commits May 23, 2022 17:19
When creating a new pool for the AMM, there will be a minimum amount
of IST. The caller is expected to provide an equivalent value of the
collateral to balance the AMM pool. The liquidity tokens corresponding
to that minimum will be added to the AssetReserve. If the caller adds
more liquidity than the minimum, they get the extra liquidity tokens.

Closes: #4643

This required updating a number of tests to initialize their AMMs with
a minimal amount.
update interchainPool tests

switch minInitialPoolLiquidity back to Nat in startupAmm since it has
to be driven from text values in environment variables.
@Chris-Hibbert
Copy link
Contributor Author

I made relatively straightforward changes to integrate with #5397. I plan to merge this morning when everything is green.

@Chris-Hibbert Chris-Hibbert added the automerge:squash Automatically squash merge label May 24, 2022
mhofman added a commit to Agoric/testnet-load-generator that referenced this pull request May 24, 2022
mhofman added a commit to Agoric/testnet-load-generator that referenced this pull request May 24, 2022
@mhofman
Copy link
Member

mhofman commented May 24, 2022

@Mergifyio refresh

@mergify
Copy link
Contributor

mergify bot commented May 24, 2022

refresh

✅ Pull request refreshed

@mergify mergify bot merged commit 2fedea6 into master May 24, 2022
@mergify mergify bot deleted the 4643-gateAddPool branch May 24, 2022 19:02
mhofman added a commit to Agoric/testnet-load-generator that referenced this pull request May 24, 2022
mergify bot added a commit that referenced this pull request May 24, 2022
* feat: public econ stats from AMM

closes: #4648

add notifier and subscription to state

* test: integrate tests with changes from #5377

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AMM automerge:squash Automatically squash merge Inter-protocol Overarching Inter Protocol
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make amm.addPool require initial assets
3 participants