@agoric/inter-protocol 0.13.3 → 0.13.4-dev-800c2bb.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +26 -20
  2. package/bundles/bundle-auctioneer-js-meta.json +722 -0
  3. package/bundles/bundle-auctioneer.js +1 -0
  4. package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
  5. package/bundles/bundle-econCommitteeCharter.js +1 -0
  6. package/bundles/bundle-feeDistributor-js-meta.json +458 -0
  7. package/bundles/bundle-feeDistributor.js +1 -1
  8. package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
  9. package/bundles/bundle-fluxAggregatorKit.js +1 -0
  10. package/bundles/bundle-psm-js-meta.json +666 -0
  11. package/bundles/bundle-psm.js +1 -1
  12. package/bundles/bundle-reserve-js-meta.json +662 -0
  13. package/bundles/bundle-reserve.js +1 -1
  14. package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
  15. package/bundles/bundle-scaledPriceAuthority.js +1 -1
  16. package/bundles/bundle-vaultFactory-js-meta.json +786 -0
  17. package/bundles/bundle-vaultFactory.js +1 -1
  18. package/exported.js +0 -2
  19. package/package.json +34 -31
  20. package/scripts/add-collateral-core.js +14 -4
  21. package/scripts/build-bundles.js +9 -2
  22. package/scripts/deploy-contracts.js +1 -4
  23. package/scripts/init-core.js +20 -38
  24. package/scripts/invite-committee-core.js +1 -1
  25. package/scripts/manual-price-feed.js +2 -2
  26. package/scripts/price-feed-core.js +7 -6
  27. package/scripts/start-local-chain.sh +84 -0
  28. package/src/auction/auctionBook.js +755 -0
  29. package/src/auction/auctioneer.js +720 -0
  30. package/src/auction/offerBook.js +221 -0
  31. package/src/auction/params.js +174 -0
  32. package/src/auction/scheduleMath.js +167 -0
  33. package/src/auction/scheduler.js +370 -0
  34. package/src/auction/sortedOffers.js +136 -0
  35. package/src/auction/util.js +55 -0
  36. package/src/clientSupport.js +324 -0
  37. package/src/collectFees.js +8 -14
  38. package/src/contractSupport.js +24 -68
  39. package/src/econCommitteeCharter.js +161 -77
  40. package/src/feeDistributor.js +60 -20
  41. package/src/index.js +2 -0
  42. package/src/interest-math.js +1 -4
  43. package/src/interest.js +20 -13
  44. package/src/price/README.md +57 -0
  45. package/src/price/fluxAggregatorContract.js +190 -0
  46. package/src/price/fluxAggregatorKit.js +375 -0
  47. package/src/price/priceOracleKit.js +127 -0
  48. package/src/price/roundsManager.js +726 -0
  49. package/src/proposals/addAssetToVault.js +89 -94
  50. package/src/proposals/committee-proposal.js +141 -40
  51. package/src/proposals/core-proposal.js +100 -167
  52. package/src/proposals/econ-behaviors.js +320 -564
  53. package/src/proposals/price-feed-proposal.js +175 -78
  54. package/src/proposals/startEconCommittee.js +25 -12
  55. package/src/proposals/startPSM.js +231 -211
  56. package/src/proposals/utils.js +31 -17
  57. package/src/psm/README.md +71 -0
  58. package/src/psm/psm.js +272 -160
  59. package/src/psm/types.js +2 -0
  60. package/src/reserve/assetReserve.js +56 -413
  61. package/src/reserve/assetReserveKit.js +303 -0
  62. package/src/reserve/doc.md +1 -3
  63. package/src/reserve/params.js +2 -5
  64. package/src/typeGuards.js +13 -0
  65. package/src/vaultFactory/Liquidation.md +100 -0
  66. package/src/vaultFactory/burn.js +2 -1
  67. package/src/vaultFactory/liquidation.js +270 -108
  68. package/src/vaultFactory/math.js +95 -0
  69. package/src/vaultFactory/orderedVaultStore.js +0 -1
  70. package/src/vaultFactory/params.js +133 -112
  71. package/src/vaultFactory/prioritizedVaults.js +36 -79
  72. package/src/vaultFactory/storeUtils.js +67 -9
  73. package/src/vaultFactory/type-imports.js +2 -0
  74. package/src/vaultFactory/types.js +22 -26
  75. package/src/vaultFactory/vault.js +772 -709
  76. package/src/vaultFactory/vaultDirector.js +480 -483
  77. package/src/vaultFactory/vaultFactory.js +99 -60
  78. package/src/vaultFactory/vaultHolder.js +121 -95
  79. package/src/vaultFactory/vaultKit.js +39 -31
  80. package/src/vaultFactory/vaultManager.js +1249 -868
  81. package/bundles/bundle-amm-meta.js +0 -618
  82. package/bundles/bundle-amm.js +0 -1
  83. package/bundles/bundle-feeDistributor-meta.js +0 -346
  84. package/bundles/bundle-interchainPool-meta.js +0 -534
  85. package/bundles/bundle-interchainPool.js +0 -1
  86. package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
  87. package/bundles/bundle-liquidateIncrementally.js +0 -1
  88. package/bundles/bundle-liquidateMinimum-meta.js +0 -442
  89. package/bundles/bundle-liquidateMinimum.js +0 -1
  90. package/bundles/bundle-psm-meta.js +0 -538
  91. package/bundles/bundle-psmCharter-meta.js +0 -418
  92. package/bundles/bundle-psmCharter.js +0 -1
  93. package/bundles/bundle-reserve-meta.js +0 -542
  94. package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
  95. package/bundles/bundle-stakeFactory-meta.js +0 -574
  96. package/bundles/bundle-stakeFactory.js +0 -1
  97. package/bundles/bundle-vaultFactory-meta.js +0 -598
  98. package/scripts/add-initial-liquidity.js +0 -180
  99. package/src/collect.js +0 -13
  100. package/src/interchainPool.js +0 -135
  101. package/src/makeTracer.js +0 -36
  102. package/src/my-lien.js +0 -85
  103. package/src/proposals/demoIssuers.js +0 -685
  104. package/src/proposals/sim-behaviors.js +0 -40
  105. package/src/psm/psmCharter.js +0 -139
  106. package/src/stakeFactory/README.md +0 -62
  107. package/src/stakeFactory/attestation.js +0 -267
  108. package/src/stakeFactory/attestationTool.js +0 -66
  109. package/src/stakeFactory/constants.js +0 -16
  110. package/src/stakeFactory/params.js +0 -31
  111. package/src/stakeFactory/stakeFactory.js +0 -236
  112. package/src/stakeFactory/stakeFactoryKit.js +0 -455
  113. package/src/stakeFactory/stakeFactoryManager.js +0 -296
  114. package/src/stakeFactory/types.js +0 -42
  115. package/src/vaultFactory/liquidateIncrementally.js +0 -350
  116. package/src/vaultFactory/liquidateMinimum.js +0 -100
  117. package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
  118. package/src/vpool-xyk-amm/addLiquidity.js +0 -222
  119. package/src/vpool-xyk-amm/addPool.js +0 -197
  120. package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
  121. package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
  122. package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
  123. package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
  124. package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
  125. package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
  126. package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
  127. package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
  128. package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
  129. package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
  130. package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
  131. package/src/vpool-xyk-amm/doublePool.js +0 -194
  132. package/src/vpool-xyk-amm/estimate.js +0 -155
  133. package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
  134. package/src/vpool-xyk-amm/params.js +0 -61
  135. package/src/vpool-xyk-amm/pool.js +0 -396
  136. package/src/vpool-xyk-amm/priceAuthority.js +0 -94
  137. package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
  138. package/src/vpool-xyk-amm/singlePool.js +0 -73
  139. package/src/vpool-xyk-amm/swap.js +0 -69
  140. package/src/vpool-xyk-amm/types.js +0 -154
@@ -1,100 +0,0 @@
1
- // @ts-check
2
-
3
- import { E } from '@endo/eventual-send';
4
- import {
5
- ceilMultiplyBy,
6
- offerTo,
7
- } from '@agoric/zoe/src/contractSupport/index.js';
8
- import { AmountMath } from '@agoric/ertp';
9
- import { Far } from '@endo/marshal';
10
-
11
- import { makeTracer } from '../makeTracer.js';
12
-
13
- const trace = makeTracer('LiqMin', false);
14
-
15
- /**
16
- * This contract liquidates the minimum amount of vault's collateral necessary
17
- * to satisfy the debt. It uses the AMM's swapOut, which sells no more than
18
- * necessary. Because it has offer safety, it can refuse the trade. When that
19
- * happens, we fall back to selling using the default strategy, which currently
20
- * uses the AMM's swapIn instead.
21
- *
22
- * @param {ZCF<{
23
- * amm: XYKAMMPublicFacet,
24
- * }>} zcf
25
- */
26
- const start = async zcf => {
27
- const { amm } = zcf.getTerms();
28
- trace('start', zcf.getTerms());
29
-
30
- /**
31
- * @param {ZCFSeat} debtorSeat
32
- * @param {object} options
33
- * @param {Amount<'nat'>} options.debt Debt before penalties
34
- * @param {Ratio} options.penaltyRate
35
- */
36
- const handleLiquidationOffer = async (
37
- debtorSeat,
38
- { debt: originalDebt, penaltyRate },
39
- ) => {
40
- // XXX does not distribute penalties anywhere
41
- const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit();
42
- const penalty = ceilMultiplyBy(originalDebt, penaltyRate);
43
- const debtWithPenalty = AmountMath.add(originalDebt, penalty);
44
- const debtBrand = originalDebt.brand;
45
- const {
46
- give: { In: amountIn },
47
- } = debtorSeat.getProposal();
48
-
49
- const swapInvitation = E(amm).makeSwapInvitation();
50
- const liqProposal = harden({
51
- give: { In: amountIn },
52
- want: { Out: AmountMath.makeEmpty(debtBrand) },
53
- });
54
- trace(`OFFER TO DEBT: `, debtWithPenalty, amountIn);
55
- const { deposited } = await offerTo(
56
- zcf,
57
- swapInvitation,
58
- undefined, // The keywords were mapped already
59
- liqProposal,
60
- debtorSeat,
61
- debtorSeat,
62
- { stopAfter: debtWithPenalty },
63
- );
64
- const amounts = await deposited;
65
- trace(`Liq results`, {
66
- debtWithPenalty,
67
- amountIn,
68
- paid: debtorSeat.getCurrentAllocation(),
69
- amounts,
70
- });
71
-
72
- // Now we need to know how much was sold so we can pay off the debt.
73
- // We can use this seat because only liquidation adds debt brand to it..
74
- const debtPaid = debtorSeat.getAmountAllocated('Out', debtBrand);
75
- const penaltyPaid = AmountMath.min(penalty, debtPaid);
76
-
77
- // Allocate penalty portion of proceeds to a seat that will hold it for transfer to reserve
78
- penaltyPoolSeat.incrementBy(
79
- debtorSeat.decrementBy(harden({ Out: penaltyPaid })),
80
- );
81
- zcf.reallocate(penaltyPoolSeat, debtorSeat);
82
-
83
- debtorSeat.exit();
84
- };
85
-
86
- /**
87
- * @type {ERef<Liquidator>}
88
- */
89
- const creatorFacet = Far('debtorInvitationCreator (minimum)', {
90
- makeLiquidateInvitation: () =>
91
- zcf.makeInvitation(handleLiquidationOffer, 'Liquidate'),
92
- });
93
-
94
- return harden({ creatorFacet });
95
- };
96
-
97
- /** @typedef {ContractOf<typeof start>} LiquidationContract */
98
-
99
- harden(start);
100
- export { start };
@@ -1,89 +0,0 @@
1
- # An Attacker's guide to the Constant Product AMM
2
-
3
- This is an incomplete list of potential weak points that an attacker might want to focus
4
- on when looking for ways to violate the integrity of the AMM. It's here to help defenders,
5
- as "attacker's mindset" is a good way to focus attention for the defender. The list should
6
- correspond pretty closely to the set of assurances that the AMM aims to support.
7
-
8
- The main guarantee that an
9
- [Automated Market Maker](https://mason.gmu.edu/~rhanson/mktscore.pdf) makes is that
10
- sufficiently liquid pools will always retain enough collateral through any sequence of
11
- trades to be able to continue trading. The caveat just means that when the amount of
12
- liquidity in the pool is quite small with respect to desired trades, trades will quickly
13
- push the balance to extreme enough prices that no further trading will take place. If the
14
- pool is liquid enough, trades will push the price enough out of equilibrium that it will
15
- be very attractive for arbitrageurs to restore the price. Anything that allows traders or
16
- liquidity providers to violate that expectation is a problem.
17
-
18
- ## Multiple Pools
19
-
20
- `addPool` and `addLiquidity` are publicly available. That means someone could maliciously
21
- create pools or provide insufficient liquidity. The requirement of a minimum initial
22
- liquidity should be enough to prevent misuse of these APIs from hurting us.
23
-
24
- Since `addPool` is public, someone could add a look-alike issuer for a well-known
25
- currency and make it harder for people to find the pool they intend to trade with. As
26
- long as people are dealing wiht Brands and Issuers, they shouldn't be confused by
27
- this. Does the Wallet UI provide enough clarity in the face of this?
28
-
29
- Zoe holds the collaterral for all the pools in common. We segragate it by Pool, so each
30
- pool's allocation includes some IST (the central currency) and some of another
31
- collateral. The doublePool trades move IST between pools, but Zoe's rights conservation
32
- enforcement ensure that none is ever gained or lost.
33
-
34
- ## Fees
35
-
36
- Fees are collected as trading takes place, and kept in a distinct Zoe seat. The creator of
37
- the AMM should be the only one who can collect the fees. Can that invitation be hijacked
38
- from whoever gets that facet during bootstrap? Is there another way to steal fees?
39
-
40
- Can users structure trades so they can pay less in fees than intended?
41
-
42
- ## Providing Liquidity
43
-
44
- Traders can provide liquidity and get liquidity tokens for a particular pool. The goal is
45
- that they earn a share of the fees that were collected while their liquidity remained in
46
- the pool. Can liquidity providers gain extra fees over other providers, or can they cause
47
- traders to be disadvantaged?
48
-
49
- Can liquidity providers extact more from the pool than they should be able to?
50
-
51
- ## Math
52
-
53
- The whole design is predicated on the X*Y=K invariant. That invariant says that trading
54
- should not change the product of X and Y, but in actuality, roundoff and fees are both
55
- allowed to change the product. Roundoff should increase it ever so slightly, except in
56
- cases where there are small amounts in the pool, where it can be significant. Fees are
57
- added to the pool, so they change the size of the pool, but should be interpreted as
58
- taking place after the trade rebalances the amounts. The equations are explained in detail
59
- in `constantProduct/README.md`.
60
-
61
- Adding liquidity adds funds to both pools so, of course, it changes X and Y. But (except
62
- in the case of `AddLiquidityAtRate`), it should keep X and Y in the same proportion.
63
-
64
- I don't know whether anyone else has done an implementation of the multi-pool swap that
65
- works like ours. If neither X nor Y is IST, then we trade X for IST and IST for
66
- Y. Attributing fees in this case took some art. This is also addressed in
67
- `constantProduct/README.md`.
68
-
69
- Adding liquidity while changing the ratio of assets is done in two steps in order to
70
- prevent people from using a single step as a way to avoid fees on trades. Users shouldn't
71
- be able to use `AddLiquidityAtRate` to avoid paying fees on what is effectively a trade.
72
-
73
-
74
- ## Economics
75
-
76
- The Inter Protocol mechanism is envisioned as a major provider of liquidity. It may leave
77
- its liquidity in the pool over the long term, and never or seldom collect earnings. Does
78
- this affect prices or trading volumes adverselyj? (More liquidity is expected to provide
79
- better prices for traders, so this would be a surprise.)
80
-
81
- Other constant product markets have performed reasonably well through periods of high
82
- volatillity. Is there any reason to expect the design variations we've introduced to have
83
- trouble where others did not?
84
-
85
- ## Governance
86
-
87
- The poolFee and protocolFee can be changed by governance. Can unauthorized parties
88
- interfere with this? Is there any hazard here beyond the possibility that the holders of
89
- this power might raise rates more than some users would be happy with?
@@ -1,222 +0,0 @@
1
- // @ts-check
2
-
3
- import {
4
- assertProposalShape,
5
- calcSecondaryRequired,
6
- natSafeMath,
7
- } from '@agoric/zoe/src/contractSupport/index.js';
8
- import { AmountMath } from '@agoric/ertp';
9
-
10
- import '@agoric/zoe/exported.js';
11
-
12
- const { details: X, quote: q } = assert;
13
-
14
- const { add, multiply } = natSafeMath;
15
- /**
16
- * @param {ZCF} zcf
17
- * @param {(brand: Brand) => XYKPool} getPool
18
- */
19
- const makeMakeAddLiquidityInvitation = (zcf, getPool) => {
20
- const addLiquidity = seat => {
21
- assertProposalShape(seat, {
22
- give: {
23
- Central: null,
24
- Secondary: null,
25
- },
26
- });
27
-
28
- // Get the brand of the secondary token so we can identify the liquidity pool.
29
- const secondaryBrand = seat.getProposal().give.Secondary.brand;
30
- const pool = getPool(secondaryBrand);
31
- const liquidityIssuer = pool.getLiquidityIssuer();
32
- const liquidityBrand = zcf.getBrandForIssuer(liquidityIssuer);
33
- seat.getProposal().want.Liquidity.brand === liquidityBrand ||
34
- assert.fail(X`liquidity brand must be ${q(liquidityBrand)}`);
35
-
36
- return pool.addLiquidity(seat);
37
- };
38
-
39
- const makeAddLiquidityInvitation = () =>
40
- zcf.makeInvitation(addLiquidity, 'multipool amm add liquidity');
41
-
42
- return makeAddLiquidityInvitation;
43
- };
44
-
45
- // The desired ratio requires a wider range than K would support.
46
- const imbalancedRequest = (desiredRatio, startK) => {
47
- if (desiredRatio > 1.0) {
48
- return desiredRatio > Number(startK);
49
- } else {
50
- return Number(startK) * desiredRatio < 1n;
51
- }
52
- };
53
- harden(imbalancedRequest);
54
- // exported for testing only
55
- export { imbalancedRequest };
56
-
57
- /**
58
- * The pool has poolX and poolY currently. The user wants to add liquidity of
59
- * giveX and giveY, but the ratios are probably not the same. We want to adjust
60
- * the pool to have the ratio (poolX + giveX) / (poolY + giveY), without
61
- * changing K, the product of the two sides.
62
- *
63
- * Calculate targetX and targetY, which multiply to the same product as
64
- * poolX * poolY, but are in the ratio we'll end at. From this we can produce
65
- * a proposed trade that maintains K, but changes the ratio, so we can add
66
- * liquidity at the desired ratio.
67
- *
68
- * endX = poolX + giveX; endY = poolY + giveY
69
- * desiredRatio = endX / endY
70
- * targetY = sqrt(startK / desiredRatio)
71
- * targetX = desiredRatio * targetY
72
- * so targetK equals startK because we square targetY
73
- * targetK = targetX * targetY = desiredRatio * (startK / desiredRatio)
74
- *
75
- * Since startK/endK is less than one, and we have to worry about early loss of
76
- * precision, we round and convert to bigint as the last step
77
- *
78
- * If the desired ratio (the ratio of the sums of contributed amounts and pool
79
- * balances) is larger than K (which most often happens when the pool balances
80
- * are small) we somewhat arbitrarily refuse the transaction.
81
- * For instance, if the desired ratio is 1000:1 because one currency uses 12
82
- * digits and the other 9, and the pool has single digits of liquidity, then
83
- * it would be better to manually adjust rather than using this approach.
84
- *
85
- * @param {Amount<'nat'>} poolX
86
- * @param {Amount<'nat'>} poolY
87
- * @param {Amount<'nat'>} giveX
88
- * @param {Amount<'nat'>} giveY
89
- * @returns {{targetX: Amount<'nat'>, targetY: Amount<'nat'> }}
90
- */
91
- export const balancesToReachRatio = (poolX, poolY, giveX, giveY) => {
92
- const startK = multiply(poolX.value, poolY.value);
93
- const endX = add(poolX.value, giveX.value);
94
- const endY = add(poolY.value, giveY.value);
95
- const desiredRatio = Number(endX) / Number(endY);
96
-
97
- if (imbalancedRequest(desiredRatio, startK)) {
98
- return {
99
- targetX: AmountMath.makeEmpty(poolX.brand),
100
- targetY: AmountMath.makeEmpty(poolY.brand),
101
- };
102
- }
103
- const targetY = Math.sqrt(Number(startK) / desiredRatio);
104
- const targetX = targetY * desiredRatio;
105
-
106
- return {
107
- targetX: AmountMath.make(poolX.brand, BigInt(Math.trunc(targetX))),
108
- targetY: AmountMath.make(poolY.brand, BigInt(Math.trunc(targetY))),
109
- };
110
- };
111
-
112
- /**
113
- * @param {ZCF} zcf
114
- * @param {(b: Brand) => XYKPool} getPool
115
- * @param {(i: Brand) => VirtualPool} provideVPool
116
- * @param {ZCFSeat} feeSeat
117
- * @param {(b: Brand) => PoolFacets['helper']} getPoolHelper
118
- */
119
- const makeMakeAddLiquidityAtRateInvitation = (
120
- zcf,
121
- getPool,
122
- provideVPool,
123
- feeSeat,
124
- getPoolHelper,
125
- ) => {
126
- const addLiquidityAtRate = seat => {
127
- assertProposalShape(seat, {
128
- give: {
129
- Central: null,
130
- Secondary: null,
131
- },
132
- want: { Liquidity: null },
133
- });
134
-
135
- const giveAlloc = seat.getProposal().give;
136
- const secondaryAmount = giveAlloc.Secondary;
137
- const secondaryBrand = secondaryAmount.brand;
138
- const centralBrand = giveAlloc.Central.brand;
139
- const pool = getPool(secondaryBrand);
140
- // Step 1: trade to adjust the pool's price
141
- // A figure out the ratio of the inputs
142
- // B figure out how X*Y changes to reach that ratio (ignoring fees)
143
- const centralPoolAmount = pool.getCentralAmount();
144
- const secondaryPoolAmount = pool.getSecondaryAmount();
145
-
146
- if (
147
- AmountMath.isEmpty(centralPoolAmount) &&
148
- AmountMath.isEmpty(secondaryPoolAmount)
149
- ) {
150
- return pool.addLiquidity(seat);
151
- }
152
-
153
- const { targetX: newCentral, targetY: newSecondary } = balancesToReachRatio(
154
- centralPoolAmount,
155
- secondaryPoolAmount,
156
- giveAlloc.Central,
157
- giveAlloc.Secondary,
158
- );
159
-
160
- const vPool = provideVPool(secondaryBrand);
161
- const poolSeat = pool.getPoolSeat();
162
- const transferForTrade = (prices, incrementKey, decrementKey) => {
163
- seat.decrementBy(harden({ [incrementKey]: prices.swapperGives }));
164
- poolSeat.decrementBy(harden({ [decrementKey]: prices.yDecrement }));
165
- seat.incrementBy(harden({ [decrementKey]: prices.swapperGets }));
166
- feeSeat.incrementBy(harden({ Fee: prices.protocolFee }));
167
- poolSeat.incrementBy(harden({ [incrementKey]: prices.xIncrement }));
168
- };
169
-
170
- // 1C Stage the changes for the trade
171
- if (AmountMath.isGTE(newCentral, centralPoolAmount)) {
172
- const prices = vPool.getPriceForOutput(
173
- AmountMath.makeEmpty(centralBrand),
174
- AmountMath.subtract(secondaryPoolAmount, newSecondary),
175
- );
176
- transferForTrade(prices, 'Central', 'Secondary');
177
- } else {
178
- const prices = vPool.getPriceForInput(
179
- AmountMath.subtract(newSecondary, secondaryPoolAmount),
180
- AmountMath.makeEmpty(centralBrand),
181
- );
182
- transferForTrade(prices, 'Secondary', 'Central');
183
- }
184
-
185
- // Step 2: add remaining liquidity
186
- const stagedAllocation = poolSeat.getStagedAllocation();
187
- const centralPoolAfterTrade = stagedAllocation.Central;
188
- const secondaryPoolAfterTrade = stagedAllocation.Secondary;
189
- const userAllocation = seat.getStagedAllocation();
190
-
191
- const secondaryRequired = AmountMath.make(
192
- secondaryBrand,
193
- calcSecondaryRequired(
194
- userAllocation.Central.value,
195
- centralPoolAfterTrade.value,
196
- secondaryPoolAfterTrade.value,
197
- userAllocation.Secondary.value,
198
- ),
199
- );
200
-
201
- return getPoolHelper(secondaryBrand).addLiquidityActual(
202
- pool,
203
- seat,
204
- secondaryRequired,
205
- poolSeat.getStagedAllocation().Central,
206
- feeSeat,
207
- );
208
- };
209
-
210
- const makeAddLiquidityInvitation = () =>
211
- zcf.makeInvitation(
212
- addLiquidityAtRate,
213
- 'multipool amm add liquidity at rate',
214
- );
215
-
216
- return makeAddLiquidityInvitation;
217
- };
218
-
219
- harden(makeMakeAddLiquidityInvitation);
220
- harden(makeMakeAddLiquidityAtRateInvitation);
221
-
222
- export { makeMakeAddLiquidityInvitation, makeMakeAddLiquidityAtRateInvitation };
@@ -1,197 +0,0 @@
1
- // @ts-check
2
-
3
- import { E } from '@endo/eventual-send';
4
- import { AmountMath, AssetKind } from '@agoric/ertp';
5
- import { assertProposalShape } from '@agoric/zoe/src/contractSupport/index.js';
6
-
7
- import { definePoolKind } from './pool.js';
8
-
9
- const { details: X, quote: q } = assert;
10
-
11
- const DISPLAY_INFO = harden({ decimalPlaces: 6 });
12
-
13
- /** @typedef {import('@agoric/vat-data').Baggage} Baggage */
14
-
15
- /**
16
- * @param {ZCF} zcf
17
- * @param {(Brand) => boolean} isInSecondaries
18
- * @param {import('@agoric/store/src/stores/store-utils.js').AtomicProvider<Brand, ZCFMint>} brandToLiquidityMintProvider
19
- * @param {() => (secondaryBrand: Brand) => Promise<void>} getAddIssuerToReserve
20
- */
21
- export const makeAddIssuer = (
22
- zcf,
23
- isInSecondaries,
24
- brandToLiquidityMintProvider,
25
- getAddIssuerToReserve,
26
- ) => {
27
- /**
28
- * Add a new issuer. If we previously received a request for the same issuer,
29
- * we'll return the issuer or a promise for it.
30
- *
31
- * @param {import('./pool.js').MethodContext} _context
32
- * @param {Issuer} secondaryIssuer
33
- * @param {string} keyword
34
- */
35
- const addIssuer = async (_context, secondaryIssuer, keyword) => {
36
- const [secondaryAssetKind, secondaryBrand] = await Promise.all([
37
- E(secondaryIssuer).getAssetKind(),
38
- E(secondaryIssuer).getBrand(),
39
- ]);
40
- // AWAIT ///////////////
41
- secondaryAssetKind === AssetKind.NAT ||
42
- assert.fail(X`${q(keyword)} asset not fungible (must use NAT math)`);
43
-
44
- /** @type {(brand: Brand) => Promise<ZCFMint>} */
45
- const makeLiquidityMint = brand => {
46
- !isInSecondaries(brand) ||
47
- assert.fail(X`issuer ${secondaryIssuer} already has a pool`);
48
-
49
- const liquidityKeyword = `${keyword}Liquidity`;
50
- zcf.assertUniqueKeyword(liquidityKeyword);
51
-
52
- return E.when(
53
- Promise.all([
54
- zcf.saveIssuer(secondaryIssuer, keyword),
55
- zcf.makeZCFMint(liquidityKeyword, AssetKind.NAT, DISPLAY_INFO),
56
- ]),
57
- ([issuer, mint]) => {
58
- console.log(
59
- X`Saved issuer ${secondaryIssuer} to keyword ${keyword} and got back ${issuer}`,
60
- );
61
- return mint;
62
- },
63
- ).catch(e => {
64
- console.error(
65
- X`Failure Saving issuer ${secondaryIssuer}. Not added to Reserve`,
66
- );
67
- throw e;
68
- });
69
- };
70
-
71
- /** @type {(brand: Brand) => Promise<void>} */
72
- const finish = brand => {
73
- // defer lookup until necessary. more aligned with governed
74
- // param we expect this to be eventually.
75
- const addIssuerToReserve = getAddIssuerToReserve();
76
-
77
- // tell the reserve about this brand, which it will validate by
78
- // calling back to AMM for the issuer
79
- return addIssuerToReserve(brand);
80
- };
81
-
82
- return brandToLiquidityMintProvider
83
- .provideAsync(secondaryBrand, makeLiquidityMint, finish)
84
- .then(mint => mint.getIssuerRecord().issuer);
85
- };
86
-
87
- return addIssuer;
88
- };
89
-
90
- /**
91
- * @param {Baggage} baggage
92
- * @param {import('./multipoolMarketMaker.js').AmmPowers} ammPowers
93
- * @param {(secondaryBrand: Brand, reserveLiquidityTokenSeat: ZCFSeat, liquidityKeyword: Keyword) => Promise<void>} onOfferHandled
94
- * @param {ERef<StorageNode>} storageNode
95
- * @param {ERef<Marshaller>} marshaller
96
- */
97
- export const makeAddPoolInvitation = (
98
- baggage,
99
- ammPowers,
100
- onOfferHandled,
101
- storageNode,
102
- marshaller,
103
- ) => {
104
- const { zcf } = ammPowers;
105
- const makePool = definePoolKind(baggage, ammPowers, storageNode, marshaller);
106
-
107
- /** @type {(Brand) => Promise<{poolFacets: PoolFacets, liquidityZcfMint: ZCFMint}>} */
108
- const addPool = async secondaryBrand => {
109
- const liquidityZcfMint =
110
- ammPowers.secondaryBrandToLiquidityMint.get(secondaryBrand);
111
-
112
- const { zcfSeat: poolSeat } = ammPowers.zcf.makeEmptySeatKit();
113
- const poolFacets = makePool(liquidityZcfMint, poolSeat, secondaryBrand);
114
-
115
- ammPowers.secondaryBrandToPool.init(secondaryBrand, poolFacets);
116
- return { liquidityZcfMint, poolFacets };
117
- };
118
-
119
- /** @param {ZCFSeat} seat */
120
- const handleAddPoolOffer = async seat => {
121
- assertProposalShape(seat, {
122
- give: { Central: null, Secondary: null },
123
- });
124
-
125
- const {
126
- give: { Central: centralAmount, Secondary: secondaryAmount },
127
- want: proposalWant,
128
- } = seat.getProposal();
129
- const secondaryBrand = secondaryAmount.brand;
130
-
131
- const { brand: liquidityBrand, issuer } =
132
- ammPowers.secondaryBrandToLiquidityMint
133
- .get(secondaryBrand)
134
- .getIssuerRecord();
135
-
136
- const minPoolLiquidity = ammPowers.params.getMinInitialPoolLiquidity();
137
-
138
- if (proposalWant.Liquidity) {
139
- const { Liquidity: wantLiquidityAmount } = proposalWant;
140
- const centralAboveMinimum =
141
- // @ts-expect-error central is NAT
142
- centralAmount.value - minPoolLiquidity.value;
143
- // when providing initial liquidity, the liquidity tokens issued will be
144
- // equal to the central provided. Here, the reserve gets the minimum
145
- const funderLiquidityAmount = AmountMath.make(
146
- liquidityBrand,
147
- centralAboveMinimum,
148
- );
149
- AmountMath.isGTE(funderLiquidityAmount, wantLiquidityAmount) ||
150
- assert.fail(
151
- X`Requested too many liquidity tokens (${wantLiquidityAmount}, max: ${funderLiquidityAmount}`,
152
- );
153
- }
154
- AmountMath.isGTE(centralAmount, minPoolLiquidity) ||
155
- assert.fail(
156
- X`The minimum initial liquidity is ${minPoolLiquidity}, rejecting ${centralAmount}`,
157
- );
158
- const minLiqAmount = AmountMath.make(
159
- liquidityBrand,
160
- // @ts-expect-error known nat
161
- minPoolLiquidity.value,
162
- );
163
-
164
- // @ts-expect-error find might return undefined
165
- const [liquidityKeyword] = Object.entries(zcf.getTerms().issuers).find(
166
- ([_, i]) => i === issuer,
167
- );
168
- assert(liquidityKeyword, 'liquidity brand required');
169
-
170
- // COMMIT POINT /////////////////////
171
-
172
- const {
173
- poolFacets: { pool, helper },
174
- } = await addPool(secondaryBrand);
175
-
176
- // in addLiquidityInternal, funder provides centralAmount & secondaryAmount,
177
- // and receives liquidity tokens equal to centralAmount. Afterward, we'll
178
- // transfer minPoolLiquidity in tokens from the funder to the reserve.
179
- helper.addLiquidityInternal(seat, secondaryAmount, centralAmount);
180
-
181
- seat.decrementBy({ Liquidity: minLiqAmount });
182
- const { zcfSeat: reserveLiquidityTokenSeat } = zcf.makeEmptySeatKit();
183
- reserveLiquidityTokenSeat.incrementBy({ [liquidityKeyword]: minLiqAmount });
184
- zcf.reallocate(reserveLiquidityTokenSeat, seat);
185
- seat.exit();
186
- pool.updateState();
187
-
188
- await onOfferHandled(
189
- secondaryBrand,
190
- reserveLiquidityTokenSeat,
191
- liquidityKeyword,
192
- );
193
- return 'Added liquidity.';
194
- };
195
-
196
- return () => zcf.makeInvitation(handleAddPoolOffer, 'Add Pool and Liquidity');
197
- };