@agoric/inter-protocol 0.13.3 → 0.13.4-dev-d32a66a.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.
- package/README.md +26 -20
- package/bundles/bundle-auctioneer-js-meta.json +722 -0
- package/bundles/bundle-auctioneer.js +1 -0
- package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
- package/bundles/bundle-econCommitteeCharter.js +1 -0
- package/bundles/bundle-feeDistributor-js-meta.json +458 -0
- package/bundles/bundle-feeDistributor.js +1 -1
- package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
- package/bundles/bundle-fluxAggregatorKit.js +1 -0
- package/bundles/bundle-psm-js-meta.json +666 -0
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-js-meta.json +662 -0
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
- package/bundles/bundle-scaledPriceAuthority.js +1 -1
- package/bundles/bundle-vaultFactory-js-meta.json +786 -0
- package/bundles/bundle-vaultFactory.js +1 -1
- package/exported.js +0 -2
- package/package.json +34 -31
- package/scripts/add-collateral-core.js +14 -4
- package/scripts/build-bundles.js +9 -2
- package/scripts/deploy-contracts.js +1 -4
- package/scripts/init-core.js +20 -38
- package/scripts/invite-committee-core.js +1 -1
- package/scripts/manual-price-feed.js +2 -2
- package/scripts/price-feed-core.js +7 -6
- package/scripts/start-local-chain.sh +84 -0
- package/src/auction/auctionBook.js +755 -0
- package/src/auction/auctioneer.js +720 -0
- package/src/auction/offerBook.js +221 -0
- package/src/auction/params.js +174 -0
- package/src/auction/scheduleMath.js +167 -0
- package/src/auction/scheduler.js +370 -0
- package/src/auction/sortedOffers.js +136 -0
- package/src/auction/util.js +55 -0
- package/src/clientSupport.js +324 -0
- package/src/collectFees.js +8 -14
- package/src/contractSupport.js +24 -68
- package/src/econCommitteeCharter.js +161 -77
- package/src/feeDistributor.js +60 -20
- package/src/index.js +2 -0
- package/src/interest-math.js +1 -4
- package/src/interest.js +20 -13
- package/src/price/README.md +57 -0
- package/src/price/fluxAggregatorContract.js +190 -0
- package/src/price/fluxAggregatorKit.js +375 -0
- package/src/price/priceOracleKit.js +127 -0
- package/src/price/roundsManager.js +726 -0
- package/src/proposals/addAssetToVault.js +89 -94
- package/src/proposals/committee-proposal.js +141 -40
- package/src/proposals/core-proposal.js +100 -167
- package/src/proposals/econ-behaviors.js +320 -564
- package/src/proposals/price-feed-proposal.js +175 -78
- package/src/proposals/startEconCommittee.js +25 -12
- package/src/proposals/startPSM.js +231 -211
- package/src/proposals/utils.js +31 -17
- package/src/psm/README.md +71 -0
- package/src/psm/psm.js +272 -160
- package/src/psm/types.js +2 -0
- package/src/reserve/assetReserve.js +56 -413
- package/src/reserve/assetReserveKit.js +303 -0
- package/src/reserve/doc.md +1 -3
- package/src/reserve/params.js +2 -5
- package/src/typeGuards.js +13 -0
- package/src/vaultFactory/Liquidation.md +100 -0
- package/src/vaultFactory/burn.js +2 -1
- package/src/vaultFactory/liquidation.js +270 -108
- package/src/vaultFactory/math.js +95 -0
- package/src/vaultFactory/orderedVaultStore.js +0 -1
- package/src/vaultFactory/params.js +133 -112
- package/src/vaultFactory/prioritizedVaults.js +36 -79
- package/src/vaultFactory/storeUtils.js +67 -9
- package/src/vaultFactory/type-imports.js +2 -0
- package/src/vaultFactory/types.js +22 -26
- package/src/vaultFactory/vault.js +772 -709
- package/src/vaultFactory/vaultDirector.js +480 -483
- package/src/vaultFactory/vaultFactory.js +99 -60
- package/src/vaultFactory/vaultHolder.js +121 -95
- package/src/vaultFactory/vaultKit.js +39 -31
- package/src/vaultFactory/vaultManager.js +1249 -868
- package/bundles/bundle-amm-meta.js +0 -618
- package/bundles/bundle-amm.js +0 -1
- package/bundles/bundle-feeDistributor-meta.js +0 -346
- package/bundles/bundle-interchainPool-meta.js +0 -534
- package/bundles/bundle-interchainPool.js +0 -1
- package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
- package/bundles/bundle-liquidateIncrementally.js +0 -1
- package/bundles/bundle-liquidateMinimum-meta.js +0 -442
- package/bundles/bundle-liquidateMinimum.js +0 -1
- package/bundles/bundle-psm-meta.js +0 -538
- package/bundles/bundle-psmCharter-meta.js +0 -418
- package/bundles/bundle-psmCharter.js +0 -1
- package/bundles/bundle-reserve-meta.js +0 -542
- package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
- package/bundles/bundle-stakeFactory-meta.js +0 -574
- package/bundles/bundle-stakeFactory.js +0 -1
- package/bundles/bundle-vaultFactory-meta.js +0 -598
- package/scripts/add-initial-liquidity.js +0 -180
- package/src/collect.js +0 -13
- package/src/interchainPool.js +0 -135
- package/src/makeTracer.js +0 -36
- package/src/my-lien.js +0 -85
- package/src/proposals/demoIssuers.js +0 -685
- package/src/proposals/sim-behaviors.js +0 -40
- package/src/psm/psmCharter.js +0 -139
- package/src/stakeFactory/README.md +0 -62
- package/src/stakeFactory/attestation.js +0 -267
- package/src/stakeFactory/attestationTool.js +0 -66
- package/src/stakeFactory/constants.js +0 -16
- package/src/stakeFactory/params.js +0 -31
- package/src/stakeFactory/stakeFactory.js +0 -236
- package/src/stakeFactory/stakeFactoryKit.js +0 -455
- package/src/stakeFactory/stakeFactoryManager.js +0 -296
- package/src/stakeFactory/types.js +0 -42
- package/src/vaultFactory/liquidateIncrementally.js +0 -350
- package/src/vaultFactory/liquidateMinimum.js +0 -100
- package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
- package/src/vpool-xyk-amm/addLiquidity.js +0 -222
- package/src/vpool-xyk-amm/addPool.js +0 -197
- package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
- package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
- package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
- package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
- package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
- package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
- package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
- package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
- package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
- package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
- package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
- package/src/vpool-xyk-amm/doublePool.js +0 -194
- package/src/vpool-xyk-amm/estimate.js +0 -155
- package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
- package/src/vpool-xyk-amm/params.js +0 -61
- package/src/vpool-xyk-amm/pool.js +0 -396
- package/src/vpool-xyk-amm/priceAuthority.js +0 -94
- package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
- package/src/vpool-xyk-amm/singlePool.js +0 -73
- package/src/vpool-xyk-amm/swap.js +0 -69
- package/src/vpool-xyk-amm/types.js +0 -154
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { natSafeMath } from '@agoric/zoe/src/contractSupport/index.js';
|
|
4
|
-
import { AmountMath } from '@agoric/ertp';
|
|
5
|
-
import { BASIS_POINTS } from './constantProduct/defaults.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @file support the UI in calculating how much to offer, taking slippage
|
|
9
|
-
* into account, and not requiring a round trip to the chain.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { ceilDivide, floorDivide } = natSafeMath;
|
|
13
|
-
|
|
14
|
-
export const charge = (chargeBP, amount) => {
|
|
15
|
-
return AmountMath.make(
|
|
16
|
-
amount.brand,
|
|
17
|
-
ceilDivide(amount.value * chargeBP, BASIS_POINTS),
|
|
18
|
-
);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const chargeFloor = (chargeBP, amount) => {
|
|
22
|
-
return AmountMath.make(
|
|
23
|
-
amount.brand,
|
|
24
|
-
floorDivide(amount.value * chargeBP, BASIS_POINTS),
|
|
25
|
-
);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const makeEstimator = (centralBrand, rates) => {
|
|
29
|
-
const { poolFeeBP, protocolFeeBP, slippageBP } = rates;
|
|
30
|
-
|
|
31
|
-
// Proceeds less slippage when specifying the amount to add to a single pool
|
|
32
|
-
function estimateSinglePoolProceeds(amountIn, brandOut, pools) {
|
|
33
|
-
const isCentralIn = amountIn.brand === centralBrand;
|
|
34
|
-
const pool = isCentralIn ? pools.get(brandOut) : pools.get(amountIn.brand);
|
|
35
|
-
const kPre = pool.secondaryAmount.value * pool.centralAmount.value;
|
|
36
|
-
|
|
37
|
-
function calcYFromX(X) {
|
|
38
|
-
const denom = isCentralIn
|
|
39
|
-
? AmountMath.add(pool.centralAmount, X)
|
|
40
|
-
: AmountMath.add(pool.secondaryAmount, X);
|
|
41
|
-
const finalOutBalance = AmountMath.make(
|
|
42
|
-
brandOut,
|
|
43
|
-
ceilDivide(kPre, denom.value),
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
return isCentralIn
|
|
47
|
-
? AmountMath.subtract(pool.secondaryAmount, finalOutBalance)
|
|
48
|
-
: AmountMath.subtract(pool.centralAmount, finalOutBalance);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const amountAdded = isCentralIn
|
|
52
|
-
? AmountMath.subtract(amountIn, charge(protocolFeeBP, amountIn))
|
|
53
|
-
: amountIn;
|
|
54
|
-
const amountOutForFees = calcYFromX(amountIn);
|
|
55
|
-
const amountOut = calcYFromX(amountAdded);
|
|
56
|
-
const amountRemoved = AmountMath.subtract(
|
|
57
|
-
amountOut,
|
|
58
|
-
charge(poolFeeBP, amountOutForFees),
|
|
59
|
-
);
|
|
60
|
-
const amountReturned = isCentralIn
|
|
61
|
-
? amountRemoved
|
|
62
|
-
: AmountMath.subtract(
|
|
63
|
-
amountRemoved,
|
|
64
|
-
charge(protocolFeeBP, amountOutForFees),
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
return amountReturned;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Payment w/slippage when specifying the amount to receive from a single pool
|
|
71
|
-
function estimateSinglePoolRequired(brandIn, amountOut, pools) {
|
|
72
|
-
const isCentralIn = brandIn === centralBrand;
|
|
73
|
-
const pool = isCentralIn ? pools.get(amountOut.brand) : pools.get(brandIn);
|
|
74
|
-
const kPre = pool.secondaryAmount.value * pool.centralAmount.value;
|
|
75
|
-
const amountWithdrawn = isCentralIn
|
|
76
|
-
? AmountMath.add(amountOut, charge(protocolFeeBP, amountOut))
|
|
77
|
-
: amountOut;
|
|
78
|
-
|
|
79
|
-
const calcXFromY = y => {
|
|
80
|
-
const denom = isCentralIn
|
|
81
|
-
? AmountMath.subtract(pool.secondaryAmount, y)
|
|
82
|
-
: AmountMath.subtract(pool.centralAmount, y);
|
|
83
|
-
const finalInBalance = AmountMath.make(
|
|
84
|
-
brandIn,
|
|
85
|
-
ceilDivide(kPre, denom.value),
|
|
86
|
-
);
|
|
87
|
-
return isCentralIn
|
|
88
|
-
? AmountMath.subtract(finalInBalance, pool.centralAmount)
|
|
89
|
-
: AmountMath.subtract(finalInBalance, pool.secondaryAmount);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const amountInForFees = calcXFromY(amountOut);
|
|
93
|
-
const amountIn = calcXFromY(amountWithdrawn);
|
|
94
|
-
const amountAddToPool = AmountMath.add(
|
|
95
|
-
amountIn,
|
|
96
|
-
charge(poolFeeBP, amountInForFees),
|
|
97
|
-
);
|
|
98
|
-
const amountToBePaid = isCentralIn
|
|
99
|
-
? amountAddToPool
|
|
100
|
-
: AmountMath.add(
|
|
101
|
-
amountAddToPool,
|
|
102
|
-
chargeFloor(protocolFeeBP, amountInForFees),
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
return amountToBePaid;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ignores price improvement
|
|
109
|
-
function estimateDoublePoolProceeds(amountIn, brandOut, pools) {
|
|
110
|
-
const inProceeds = estimateSinglePoolProceeds(
|
|
111
|
-
amountIn,
|
|
112
|
-
centralBrand,
|
|
113
|
-
pools,
|
|
114
|
-
);
|
|
115
|
-
const outProceeds = estimateSinglePoolProceeds(inProceeds, brandOut, pools);
|
|
116
|
-
return outProceeds;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ignores price improvement
|
|
120
|
-
function estimateDoublePoolRequired(brandIn, amountOut, pools) {
|
|
121
|
-
const outRequired = estimateSinglePoolRequired(
|
|
122
|
-
centralBrand,
|
|
123
|
-
amountOut,
|
|
124
|
-
pools,
|
|
125
|
-
);
|
|
126
|
-
const inRequired = estimateSinglePoolRequired(brandIn, outRequired, pools);
|
|
127
|
-
return inRequired;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const estimateProceeds = (amountIn, brandOut, pools) => {
|
|
131
|
-
let proceeds;
|
|
132
|
-
if (amountIn.brand === centralBrand || brandOut === centralBrand) {
|
|
133
|
-
proceeds = estimateSinglePoolProceeds(amountIn, brandOut, pools);
|
|
134
|
-
} else {
|
|
135
|
-
proceeds = estimateDoublePoolProceeds(amountIn, brandOut, pools);
|
|
136
|
-
}
|
|
137
|
-
return AmountMath.subtract(proceeds, charge(slippageBP, proceeds));
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const estimateRequired = (brandIn, amountOut, pools) => {
|
|
141
|
-
let required;
|
|
142
|
-
if (brandIn === centralBrand || amountOut.brand === centralBrand) {
|
|
143
|
-
required = estimateSinglePoolRequired(brandIn, amountOut, pools);
|
|
144
|
-
} else {
|
|
145
|
-
required = estimateDoublePoolRequired(brandIn, amountOut, pools);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return AmountMath.add(required, charge(slippageBP, required));
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
return { estimateProceeds, estimateRequired };
|
|
152
|
-
};
|
|
153
|
-
harden(makeEstimator);
|
|
154
|
-
|
|
155
|
-
export { makeEstimator };
|
|
@@ -1,520 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import '@agoric/zoe/exported.js';
|
|
4
|
-
|
|
5
|
-
import { AssetKind, makeIssuerKit } from '@agoric/ertp';
|
|
6
|
-
import { handleParamGovernance, ParamTypes } from '@agoric/governance';
|
|
7
|
-
import { makeAtomicProvider } from '@agoric/store/src/stores/store-utils.js';
|
|
8
|
-
import {
|
|
9
|
-
assertIssuerKeywords,
|
|
10
|
-
offerTo,
|
|
11
|
-
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
12
|
-
import { E } from '@endo/far';
|
|
13
|
-
import { Far } from '@endo/marshal';
|
|
14
|
-
import { initEmpty } from '@agoric/store';
|
|
15
|
-
import {
|
|
16
|
-
provideDurableMapStore,
|
|
17
|
-
provideDurableWeakMapStore,
|
|
18
|
-
provide,
|
|
19
|
-
vivifyKindMulti,
|
|
20
|
-
} from '@agoric/vat-data';
|
|
21
|
-
import { makeMakeCollectFeesInvitation } from '../collectFees.js';
|
|
22
|
-
import { makeMetricsPublisherKit } from '../contractSupport.js';
|
|
23
|
-
import { makeTracer } from '../makeTracer.js';
|
|
24
|
-
import {
|
|
25
|
-
makeMakeAddLiquidityAtRateInvitation,
|
|
26
|
-
makeMakeAddLiquidityInvitation,
|
|
27
|
-
} from './addLiquidity.js';
|
|
28
|
-
import { makeAddIssuer, makeAddPoolInvitation } from './addPool.js';
|
|
29
|
-
import { makeDoublePool } from './doublePool.js';
|
|
30
|
-
import {
|
|
31
|
-
MIN_INITIAL_POOL_LIQUIDITY_KEY,
|
|
32
|
-
POOL_FEE_KEY,
|
|
33
|
-
PROTOCOL_FEE_KEY,
|
|
34
|
-
} from './params.js';
|
|
35
|
-
import { publicPrices } from './pool.js';
|
|
36
|
-
import { makeMakeRemoveLiquidityInvitation } from './removeLiquidity.js';
|
|
37
|
-
import { makeMakeSwapInvitation } from './swap.js';
|
|
38
|
-
|
|
39
|
-
import '@agoric/governance/src/exported.js';
|
|
40
|
-
|
|
41
|
-
const { quote: q, details: X } = assert;
|
|
42
|
-
|
|
43
|
-
const trace = makeTracer('XykAmm', false);
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @typedef {object} MetricsNotification
|
|
47
|
-
* @property {Brand[]} XYK brands of pools that use an X*Y=K pricing policy
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
/** @typedef {GovernanceTerms< {MinInitialPoolLiquidity: 'amount'} & {ProtocolFee: 'amount'} & {PoolFee: 'amount'}>} AmmGovernanceParams */
|
|
51
|
-
|
|
52
|
-
/** @typedef {{brands:BrandKeywordRecord,timer:TimerService}} AmmTerms */
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @typedef {Readonly<{
|
|
56
|
-
* zcf: ZCF<AmmTerms>,
|
|
57
|
-
* secondaryBrandToPool: WeakMapStore<Brand,PoolFacets>,
|
|
58
|
-
* secondaryBrandToLiquidityMint: WeakMapStore<Brand,ZCFMint<'nat'>>,
|
|
59
|
-
* centralBrand: Brand,
|
|
60
|
-
* timer: TimerService,
|
|
61
|
-
* quoteIssuerKit: IssuerKit,
|
|
62
|
-
* params: import('@agoric/governance/src/contractGovernance/typedParamManager').Getters<import('./params.js').AmmParams>,
|
|
63
|
-
* protocolSeat: ZCFSeat,
|
|
64
|
-
* }>} AmmPowers
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
// All the state at the AMM level is shared lexically. Some functions here have
|
|
68
|
-
// to ignore their first parameter since they have other parameters and are
|
|
69
|
-
// included in virtual/durable facets.
|
|
70
|
-
/** @typedef {{}} MethodContext */
|
|
71
|
-
|
|
72
|
-
/** @typedef {import('@agoric/vat-data').Baggage} Baggage */
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Multipool AMM is a rewrite of Uniswap that supports multiple liquidity pools,
|
|
76
|
-
* and direct exchanges across pools. Please see the documentation for more:
|
|
77
|
-
* https://agoric.com/documentation/zoe/guide/contracts/multipoolAMM.html It
|
|
78
|
-
* also uses a unique approach to charging fees. Each pool grows on every trade,
|
|
79
|
-
* and a protocolFee is extracted.
|
|
80
|
-
*
|
|
81
|
-
* We expect that this contract will have tens to hundreds of issuers. Each
|
|
82
|
-
* liquidity pool is between the central token and a secondary token. Secondary
|
|
83
|
-
* tokens can be exchanged with each other, but only through the central
|
|
84
|
-
* token. For example, if X and Y are two token types and C is the central
|
|
85
|
-
* token, a swap giving X and wanting Y would first use the pool (X, C) then the
|
|
86
|
-
* pool (Y, C). There are no liquidity pools directly between two secondary
|
|
87
|
-
* tokens.
|
|
88
|
-
*
|
|
89
|
-
* There should only need to be one instance of this contract, so liquidity can
|
|
90
|
-
* be shared as much as possible.
|
|
91
|
-
*
|
|
92
|
-
* When the contract is instantiated, the central token is specified in the
|
|
93
|
-
* terms. Separate invitations are available by calling methods on the
|
|
94
|
-
* publicFacet for adding and removing liquidity and for making trades. Other
|
|
95
|
-
* publicFacet operations support querying prices and the sizes of pools. New
|
|
96
|
-
* Pools can be created by first calling addIssuer() and then exercising an
|
|
97
|
-
* invitation from addPoolInvitation().
|
|
98
|
-
*
|
|
99
|
-
* When making trades or requesting prices, the caller must specify either a
|
|
100
|
-
* maximum input amount (swapIn, getInputPrice) or a minimum output amount
|
|
101
|
-
* (swapOut, getOutPutPrice) or both. For swaps, the required keywords are `In`
|
|
102
|
-
* for the trader's `give` amount, and `Out` for the trader's `want` amount.
|
|
103
|
-
* getInputPrice and getOutputPrice each take two Amounts. The price functions
|
|
104
|
-
* return both amountIn (which may be lower than the original amount) and
|
|
105
|
-
* amountOut (which may be higher). When both prices are specified, no swap will
|
|
106
|
-
* be made (and no price provided) if both restrictions can't be honored.
|
|
107
|
-
*
|
|
108
|
-
* When adding and removing liquidity, the keywords are Central, Secondary, and
|
|
109
|
-
* Liquidity. adding liquidity has Central and Secondary in the `give` section,
|
|
110
|
-
* while removing liquidity has `want` and `give` swapped.
|
|
111
|
-
*
|
|
112
|
-
* Transactions that don't require an invitation include addPool and the
|
|
113
|
-
* queries: getInputPrice, getOutputPrice, getPoolAllocation,
|
|
114
|
-
* getLiquidityIssuer, and getLiquiditySupply.
|
|
115
|
-
*
|
|
116
|
-
* This contract has two parameters (poolFee and protocolFee) that are
|
|
117
|
-
* managed by governance. The contract calls `handleParamGovernance()` at
|
|
118
|
-
* startup, which allows a contractManager to call for votes that would change
|
|
119
|
-
* the parameter values in a transparent way. When correctly set up, customers
|
|
120
|
-
* with access to this contract's publicFacet can verify the connectivity, and
|
|
121
|
-
* see which Electorate has the ability to vote on changes, and which votes are
|
|
122
|
-
* ongoing or have taken place. If not correctly set up, the validation checks
|
|
123
|
-
* will fail visibly.
|
|
124
|
-
*
|
|
125
|
-
* The initial values of the parameters are provided as poolFeeBP and
|
|
126
|
-
* protocolFeeBP in terms. The poolFee is charged in {Central} and each collateral, so
|
|
127
|
-
* it is provided as a bigint. The protocolFee is always charged in {Fee}, but the
|
|
128
|
-
* initial value is specified as a bigint for consistency.
|
|
129
|
-
*
|
|
130
|
-
* The contract gets the initial values for those parameters from its terms, and
|
|
131
|
-
* thereafter can be seen to only use the values provided by the
|
|
132
|
-
* getter method returned by the paramManager.
|
|
133
|
-
*
|
|
134
|
-
* `handleParamGovernance()` adds several methods to the publicFacet of the
|
|
135
|
-
* contract, and bundles the privateFacet to ensure that governance
|
|
136
|
-
* functionality is only accessible to the contractGovernor.
|
|
137
|
-
*
|
|
138
|
-
* The creatorFacet has one method (makeCollectFeesInvitation, which returns
|
|
139
|
-
* collected fees to the creator). `handleParamGovernance()` adds internal
|
|
140
|
-
* methods used by the contractGovernor. The contractGovernor then has access to
|
|
141
|
-
* those internal methods, and reveals the original AMM creatorFacet to its own
|
|
142
|
-
* creator.
|
|
143
|
-
*
|
|
144
|
-
* @param {ZCF<AMMTerms>} zcf
|
|
145
|
-
* @param {{
|
|
146
|
-
* initialPoserInvitation: Invitation,
|
|
147
|
-
* storageNode: ERef<StorageNode>,
|
|
148
|
-
* marshaller: ERef<Marshaller>,
|
|
149
|
-
* }} privateArgs
|
|
150
|
-
* @param {Baggage} baggage
|
|
151
|
-
*/
|
|
152
|
-
const start = async (zcf, privateArgs, baggage) => {
|
|
153
|
-
/**
|
|
154
|
-
* This contract must have a "Central" keyword and issuer in the
|
|
155
|
-
* IssuerKeywordRecord.
|
|
156
|
-
*/
|
|
157
|
-
const {
|
|
158
|
-
brands: { Central: centralBrand },
|
|
159
|
-
timer,
|
|
160
|
-
} = zcf.getTerms();
|
|
161
|
-
assertIssuerKeywords(zcf, ['Central']);
|
|
162
|
-
assert(centralBrand !== undefined, 'centralBrand must be present');
|
|
163
|
-
|
|
164
|
-
const [
|
|
165
|
-
{ augmentVirtualPublicFacet, makeVirtualGovernorFacet, params },
|
|
166
|
-
centralDisplayInfo,
|
|
167
|
-
] = await Promise.all([
|
|
168
|
-
handleParamGovernance(
|
|
169
|
-
zcf,
|
|
170
|
-
privateArgs.initialPoserInvitation,
|
|
171
|
-
{
|
|
172
|
-
[POOL_FEE_KEY]: ParamTypes.NAT,
|
|
173
|
-
[PROTOCOL_FEE_KEY]: ParamTypes.NAT,
|
|
174
|
-
[MIN_INITIAL_POOL_LIQUIDITY_KEY]: ParamTypes.AMOUNT,
|
|
175
|
-
},
|
|
176
|
-
privateArgs.storageNode,
|
|
177
|
-
privateArgs.marshaller,
|
|
178
|
-
),
|
|
179
|
-
E(centralBrand).getDisplayInfo(),
|
|
180
|
-
privateArgs.storageNode,
|
|
181
|
-
privateArgs.marshaller,
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
assert.equal(
|
|
185
|
-
centralDisplayInfo.assetKind,
|
|
186
|
-
AssetKind.NAT,
|
|
187
|
-
X`Central must be of kind ${q(AssetKind.NAT)}, not ${q(
|
|
188
|
-
centralDisplayInfo.assetKind,
|
|
189
|
-
)}`,
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
/** @type {Store<Brand,PoolFacets>} */
|
|
193
|
-
const secondaryBrandToPool = provideDurableMapStore(
|
|
194
|
-
baggage,
|
|
195
|
-
'secondaryBrandToPool',
|
|
196
|
-
);
|
|
197
|
-
const getPool = brand => {
|
|
198
|
-
// TODO: https://github.com/Agoric/agoric-sdk/issues/5776
|
|
199
|
-
assert(
|
|
200
|
-
secondaryBrandToPool.has(brand),
|
|
201
|
-
`"secondaryBrandToPool" not found: ${q(brand)}`,
|
|
202
|
-
);
|
|
203
|
-
return secondaryBrandToPool.get(brand).pool;
|
|
204
|
-
};
|
|
205
|
-
const getPoolHelper = brand => secondaryBrandToPool.get(brand).helper;
|
|
206
|
-
// XXX a brand can be in secondaryBrandToLiquidityMint and return false for this check
|
|
207
|
-
// if it's called between addIssuer and addPool
|
|
208
|
-
const isSecondary = secondaryBrandToPool.has;
|
|
209
|
-
|
|
210
|
-
// The liquidityBrand has to exist to allow the addPool Offer to specify want
|
|
211
|
-
/** @type {WeakMapStore<Brand,ZCFMint<'nat'>>} */
|
|
212
|
-
const secondaryBrandToLiquidityMint = provideDurableWeakMapStore(
|
|
213
|
-
baggage,
|
|
214
|
-
'secondaryBrandToLiquidityMint',
|
|
215
|
-
);
|
|
216
|
-
const secondaryBrandToLiquidityMintProvider = makeAtomicProvider(
|
|
217
|
-
secondaryBrandToLiquidityMint,
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
const quoteIssuerKit = provide(baggage, 'quoteIssuerKit', () =>
|
|
221
|
-
makeIssuerKit('Quote', AssetKind.SET),
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
const { metricsPublication, metricsSubscription } = makeMetricsPublisherKit(
|
|
225
|
-
privateArgs.storageNode,
|
|
226
|
-
privateArgs.marshaller,
|
|
227
|
-
);
|
|
228
|
-
const updateMetrics = () => {
|
|
229
|
-
metricsPublication.updateState(
|
|
230
|
-
harden({ XYK: Array.from(secondaryBrandToPool.keys()) }),
|
|
231
|
-
);
|
|
232
|
-
};
|
|
233
|
-
updateMetrics();
|
|
234
|
-
|
|
235
|
-
// For now, this seat collects protocol fees. It needs to be connected to
|
|
236
|
-
// something that will extract the fees.
|
|
237
|
-
const protocolSeat = provide(
|
|
238
|
-
baggage,
|
|
239
|
-
'protocolSeat',
|
|
240
|
-
() => zcf.makeEmptySeatKit().zcfSeat,
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
/** @type {AssetReservePublicFacet=} */
|
|
244
|
-
let reserveFacet = baggage.has('reserveFacet')
|
|
245
|
-
? baggage.get('reserveFacet')
|
|
246
|
-
: undefined;
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* @param {Brand} secondaryBrand
|
|
250
|
-
* @param {ZCFSeat} reserveLiquidityTokenSeat
|
|
251
|
-
* @param {Keyword} liquidityKeyword
|
|
252
|
-
* @returns {Promise<void>} up to caller whether to await or handle rejections
|
|
253
|
-
*/
|
|
254
|
-
const handlePoolAdded = async (
|
|
255
|
-
secondaryBrand,
|
|
256
|
-
reserveLiquidityTokenSeat,
|
|
257
|
-
liquidityKeyword,
|
|
258
|
-
) => {
|
|
259
|
-
trace('handlePoolAdded', { secondaryBrand, liquidityKeyword });
|
|
260
|
-
updateMetrics();
|
|
261
|
-
|
|
262
|
-
assert(reserveFacet, 'Missing reserveFacet');
|
|
263
|
-
assert(reserveLiquidityTokenSeat, 'Missing reserveLiquidityTokenSeat');
|
|
264
|
-
|
|
265
|
-
const secondaryIssuer = await zcf.getIssuerForBrand(secondaryBrand);
|
|
266
|
-
trace('ensuring reserve has the liquidity issuer', {
|
|
267
|
-
secondaryBrand,
|
|
268
|
-
secondaryIssuer,
|
|
269
|
-
});
|
|
270
|
-
await E(reserveFacet).addLiquidityIssuer(secondaryIssuer);
|
|
271
|
-
|
|
272
|
-
trace(
|
|
273
|
-
`move ${liquidityKeyword} to the reserve`,
|
|
274
|
-
reserveLiquidityTokenSeat.getCurrentAllocation(),
|
|
275
|
-
);
|
|
276
|
-
const addCollateral = await E(reserveFacet).makeAddCollateralInvitation();
|
|
277
|
-
const proposal = harden({
|
|
278
|
-
give: {
|
|
279
|
-
Collateral:
|
|
280
|
-
reserveLiquidityTokenSeat.getCurrentAllocation()[liquidityKeyword],
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
|
-
const { deposited, userSeatPromise } = await offerTo(
|
|
284
|
-
zcf,
|
|
285
|
-
addCollateral,
|
|
286
|
-
harden({ [liquidityKeyword]: 'Collateral' }),
|
|
287
|
-
proposal,
|
|
288
|
-
reserveLiquidityTokenSeat,
|
|
289
|
-
);
|
|
290
|
-
const deposits = await deposited;
|
|
291
|
-
trace('handlePoolAdded deposited', deposits);
|
|
292
|
-
await E(userSeatPromise).getOfferResult();
|
|
293
|
-
reserveLiquidityTokenSeat.exit();
|
|
294
|
-
trace('handlePoolAdded done');
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* @param {MethodContext} _context
|
|
299
|
-
* @param {Brand} brand
|
|
300
|
-
*/
|
|
301
|
-
const getLiquidityIssuer = (_context, brand) =>
|
|
302
|
-
secondaryBrandToLiquidityMint.get(brand).getIssuerRecord().issuer;
|
|
303
|
-
/**
|
|
304
|
-
* @param {MethodContext} _context
|
|
305
|
-
* @param {Brand} brand
|
|
306
|
-
*/
|
|
307
|
-
const getLiquiditySupply = (_context, brand) =>
|
|
308
|
-
getPool(brand).getLiquiditySupply();
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* @param {MethodContext} _context
|
|
312
|
-
* @param {Brand} brand
|
|
313
|
-
*/
|
|
314
|
-
const getSecondaryIssuer = (_context, brand) => {
|
|
315
|
-
assert(
|
|
316
|
-
secondaryBrandToLiquidityMint.has(brand),
|
|
317
|
-
'Brand not a secondary of the AMM',
|
|
318
|
-
);
|
|
319
|
-
return zcf.getIssuerForBrand(brand);
|
|
320
|
-
};
|
|
321
|
-
const poolStorageNode = await (privateArgs.storageNode &&
|
|
322
|
-
E(privateArgs.storageNode).makeChildNode(
|
|
323
|
-
// NB: the set of pools grows monotonically
|
|
324
|
-
`pool${secondaryBrandToPool.getSize()}`,
|
|
325
|
-
));
|
|
326
|
-
|
|
327
|
-
// shared AMM state that will be lexically accessible to all pools
|
|
328
|
-
/** @type {AmmPowers} */
|
|
329
|
-
const ammPowers = harden({
|
|
330
|
-
zcf,
|
|
331
|
-
secondaryBrandToPool,
|
|
332
|
-
secondaryBrandToLiquidityMint,
|
|
333
|
-
centralBrand,
|
|
334
|
-
timer,
|
|
335
|
-
quoteIssuerKit,
|
|
336
|
-
params,
|
|
337
|
-
protocolSeat,
|
|
338
|
-
});
|
|
339
|
-
const addPoolInvitation = makeAddPoolInvitation(
|
|
340
|
-
baggage,
|
|
341
|
-
ammPowers,
|
|
342
|
-
handlePoolAdded,
|
|
343
|
-
poolStorageNode,
|
|
344
|
-
privateArgs.marshaller,
|
|
345
|
-
);
|
|
346
|
-
const addIssuer = makeAddIssuer(
|
|
347
|
-
zcf,
|
|
348
|
-
isSecondary,
|
|
349
|
-
secondaryBrandToLiquidityMintProvider,
|
|
350
|
-
() => {
|
|
351
|
-
assert(reserveFacet, 'Must first resolveReserveFacet');
|
|
352
|
-
return secondaryBrand =>
|
|
353
|
-
E(
|
|
354
|
-
/** @type {AssetReservePublicFacet} */ (reserveFacet),
|
|
355
|
-
).addIssuerFromAmm(secondaryBrand);
|
|
356
|
-
},
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* @param {unknown} _context
|
|
361
|
-
* @param {Brand} brand
|
|
362
|
-
*/
|
|
363
|
-
const getPoolAllocation = (_context, brand) =>
|
|
364
|
-
getPool(brand).getPoolSeat().getCurrentAllocation();
|
|
365
|
-
|
|
366
|
-
const getPriceAuthorities = (_context, brand) => {
|
|
367
|
-
const pool = getPool(brand);
|
|
368
|
-
return {
|
|
369
|
-
toCentral: pool.getToCentralPriceAuthority(),
|
|
370
|
-
fromCentral: pool.getFromCentralPriceAuthority(),
|
|
371
|
-
};
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* @param {MethodContext} _context
|
|
376
|
-
* @param {Brand} brand
|
|
377
|
-
*/
|
|
378
|
-
const getPoolMetrics = (_context, brand) => getPool(brand).getMetrics();
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* @param {Brand} brandIn
|
|
382
|
-
* @param {Brand} [brandOut]
|
|
383
|
-
* @returns {VirtualPool}
|
|
384
|
-
*/
|
|
385
|
-
const provideVPool = (brandIn, brandOut) => {
|
|
386
|
-
if (!brandOut) {
|
|
387
|
-
return getPool(brandIn).getVPool();
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (isSecondary(brandIn) && isSecondary(brandOut)) {
|
|
391
|
-
return makeDoublePool(
|
|
392
|
-
zcf,
|
|
393
|
-
getPool(brandIn),
|
|
394
|
-
getPool(brandOut),
|
|
395
|
-
params.getProtocolFee,
|
|
396
|
-
params.getPoolFee,
|
|
397
|
-
protocolSeat,
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const pool = isSecondary(brandOut) ? getPool(brandOut) : getPool(brandIn);
|
|
402
|
-
return pool.getVPool();
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
const getInputPrice = (_context, amountIn, amountOut) => {
|
|
406
|
-
const pool = provideVPool(amountIn.brand, amountOut.brand);
|
|
407
|
-
return publicPrices(pool.getPriceForInput(amountIn, amountOut));
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
const getOutputPrice = (_context, amountIn, amountOut) => {
|
|
411
|
-
const pool = provideVPool(amountIn.brand, amountOut.brand);
|
|
412
|
-
return publicPrices(pool.getPriceForOutput(amountIn, amountOut));
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
const { makeSwapInInvitation, makeSwapOutInvitation } =
|
|
416
|
-
makeMakeSwapInvitation(zcf, provideVPool);
|
|
417
|
-
const makeAddLiquidityInvitation = makeMakeAddLiquidityInvitation(
|
|
418
|
-
zcf,
|
|
419
|
-
getPool,
|
|
420
|
-
);
|
|
421
|
-
const makeAddLiquidityAtRateInvitation = makeMakeAddLiquidityAtRateInvitation(
|
|
422
|
-
zcf,
|
|
423
|
-
getPool,
|
|
424
|
-
provideVPool,
|
|
425
|
-
protocolSeat,
|
|
426
|
-
getPoolHelper,
|
|
427
|
-
);
|
|
428
|
-
|
|
429
|
-
const makeRemoveLiquidityInvitation = makeMakeRemoveLiquidityInvitation(
|
|
430
|
-
zcf,
|
|
431
|
-
getPool,
|
|
432
|
-
);
|
|
433
|
-
|
|
434
|
-
const { makeCollectFeesInvitation } = makeMakeCollectFeesInvitation(
|
|
435
|
-
zcf,
|
|
436
|
-
protocolSeat,
|
|
437
|
-
centralBrand,
|
|
438
|
-
'Fee',
|
|
439
|
-
);
|
|
440
|
-
|
|
441
|
-
const publicFacet = augmentVirtualPublicFacet(
|
|
442
|
-
Far('AMM public facet', {
|
|
443
|
-
addPoolInvitation,
|
|
444
|
-
addIssuer,
|
|
445
|
-
getPoolAllocation,
|
|
446
|
-
getLiquidityIssuer,
|
|
447
|
-
getLiquiditySupply,
|
|
448
|
-
getInputPrice,
|
|
449
|
-
getOutputPrice,
|
|
450
|
-
getSecondaryIssuer,
|
|
451
|
-
makeSwapInvitation: makeSwapInInvitation,
|
|
452
|
-
makeSwapInInvitation,
|
|
453
|
-
makeSwapOutInvitation,
|
|
454
|
-
makeAddLiquidityInvitation,
|
|
455
|
-
makeAddLiquidityAtRateInvitation,
|
|
456
|
-
makeRemoveLiquidityInvitation,
|
|
457
|
-
getQuoteIssuer: () => quoteIssuerKit.issuer,
|
|
458
|
-
getPriceAuthorities,
|
|
459
|
-
getAllPoolBrands: () =>
|
|
460
|
-
Object.values(zcf.getTerms().brands).filter(isSecondary),
|
|
461
|
-
getProtocolPoolBalance: () => protocolSeat.getCurrentAllocation(),
|
|
462
|
-
getMetrics: () => metricsSubscription,
|
|
463
|
-
getPoolMetrics,
|
|
464
|
-
...params,
|
|
465
|
-
}),
|
|
466
|
-
);
|
|
467
|
-
|
|
468
|
-
const { governorFacet, limitedCreatorFacet } = makeVirtualGovernorFacet(
|
|
469
|
-
harden({
|
|
470
|
-
makeCollectFeesInvitation,
|
|
471
|
-
/**
|
|
472
|
-
* Must be called before adding pools. Not provided at contract start time
|
|
473
|
-
* due to cyclic dependency.
|
|
474
|
-
*
|
|
475
|
-
* @param {MethodContext} _context
|
|
476
|
-
* @param {AssetReservePublicFacet} facet
|
|
477
|
-
*/
|
|
478
|
-
resolveReserveFacet: (_context, facet) => {
|
|
479
|
-
assert(!reserveFacet, 'reserveFacet already resolved');
|
|
480
|
-
reserveFacet = facet;
|
|
481
|
-
baggage.init('reserveFacet', facet);
|
|
482
|
-
},
|
|
483
|
-
}),
|
|
484
|
-
);
|
|
485
|
-
|
|
486
|
-
const makeAMM = vivifyKindMulti(baggage, 'AMM', initEmpty, {
|
|
487
|
-
publicFacet,
|
|
488
|
-
creatorFacet: governorFacet,
|
|
489
|
-
limitedCreatorFacet,
|
|
490
|
-
});
|
|
491
|
-
const { creatorFacet, publicFacet: pFacet } = makeAMM();
|
|
492
|
-
return { creatorFacet, publicFacet: pFacet };
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
harden(start);
|
|
496
|
-
export { start };
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* @typedef {object} AMMParamGetters
|
|
500
|
-
* @property {() => NatValue} getPoolFee
|
|
501
|
-
* @property {() => NatValue} getProtocolFee
|
|
502
|
-
* @property {() => Amount<'nat'>} getMinInitialPoolLiquidity
|
|
503
|
-
* @property {() => Amount} getElectorate
|
|
504
|
-
*/
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* @typedef { bigint } BasisPoints -- hundredths of a percent
|
|
508
|
-
*
|
|
509
|
-
* @typedef {GovernanceTerms<{
|
|
510
|
-
* PoolFee: 'nat',
|
|
511
|
-
* ProtocolFee: 'nat',
|
|
512
|
-
* MinInitialPoolLiquidity: 'amount',
|
|
513
|
-
* }> & {
|
|
514
|
-
* brands: { Central: Brand },
|
|
515
|
-
* issuers: {},
|
|
516
|
-
* timer: TimerService,
|
|
517
|
-
* poolFeeBP: BasisPoints, // portion of the fees that go into the pool
|
|
518
|
-
* protocolFeeBP: BasisPoints, // portion of the fees that are shared with validators
|
|
519
|
-
* }} AMMTerms
|
|
520
|
-
*/
|