-
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(AMM)!: make amm.addPool() require minimum collateral #5377
Conversation
ff2ba9d
to
ae00101
Compare
34b0947
to
bbf019b
Compare
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.
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 |
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.
👍 updating related docs
export const makeAddIssuer = (zcf, isInSecondaries, brandToLiquidityMint) => { | ||
return async (secondaryIssuer, keyword) => { |
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.
param types, s'il vous plaît.
from the function signature isInSecondaries
looks like a boolean
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
X`${keyword} asset not fungible (must use NAT math)`, | ||
); | ||
const liquidityKeyword = `${keyword}Liquidity`; | ||
zcf.assertUniqueKeyword(liquidityKeyword); |
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.
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.)
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.
It's an early check so we don't make the mint if saveIssuer
will fail.
zcf.makeZCFMint( | ||
liquidityKeyword, | ||
AssetKind.NAT, | ||
harden({ decimalPlaces: 6 }), |
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.
magic number
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.
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 |
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.
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.
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.
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 |
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.
thanks for explaining this. any risk in something failing before that happens? (not atomic)
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.
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. |
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.
is this before MN-1? should have a ticket so we track it to release
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.
@@ -112,6 +108,23 @@ const helperBehavior = { | |||
} else { | |||
zcf.reallocate(poolSeat, zcfSeat); | |||
} | |||
}, | |||
addLiquidityActual: ( |
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.
can keep this, no?
addLiquidityActual: ( | |
/** @type {import('@agoric/vat-data/src/types').PlusContext<MethodContext, AddLiquidityActual>} */ | |
addLiquidityActual: ( |
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
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.
I pushed some other type fixes in a71f732
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.
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 |
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.
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 |
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.
the Invitation
can be typed with the offer args and result. I don't know it offhand but I'd be happy to help.
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.
nevermind, I tried a bit and it's more effort than I thought.
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.
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; |
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.
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?
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.
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 |
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.
👍
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 |
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.
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, |
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.
+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 |
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.
solved by 1a7c0a5
// await t.throwsAsync( | ||
// () => E(amm.ammPublicFacet).getPoolAllocation(moolaR.brand), | ||
// { message: /"secondaryBrand" not found: / }, | ||
// "The pool hasn't been created yet", | ||
// ); |
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.
💀
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.
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 () => { |
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.
import from test/supports.js
efc19a7
to
40d98d7
Compare
Blocked by #5397 [corrected] |
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.
40d98d7
to
2d536b8
Compare
I made relatively straightforward changes to integrate with #5397. I plan to merge this morning when everything is green. |
Handles the upcoming rename in Agoric/agoric-sdk#5377
@Mergifyio refresh |
✅ Pull request refreshed |
Handles the upcoming rename in Agoric/agoric-sdk#5377
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.