@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,204 +0,0 @@
|
|
|
1
|
-
# Constant Product AMM
|
|
2
|
-
|
|
3
|
-
A constant product automatic market maker based on our Ratio library. It charges
|
|
4
|
-
two kinds of fees: a pool fee remains in the pool to reward the liquidity
|
|
5
|
-
providers and a protocol fee is extracted to fund the economy. The external
|
|
6
|
-
entry point is a call to `pricesForStatedInput()` or `pricesForStatedOutput()`.
|
|
7
|
-
|
|
8
|
-
This algorithm uses the x*y=k formula directly, without fees. Briefly, there are
|
|
9
|
-
two kinds of assets, whose values are kept roughly in balance through the
|
|
10
|
-
actions of arbitrageurs. At any time a trader can trade with the pool by
|
|
11
|
-
offering to deposit one of the two assets. They will receive an amount
|
|
12
|
-
of the complementary asset that will maintain the invariant that the product of
|
|
13
|
-
the balances doesn't decrease. (Rounding is done in favor of the
|
|
14
|
-
pool.)
|
|
15
|
-
|
|
16
|
-
The user can specify a maximum amount they want to pay or a minimum amount they
|
|
17
|
-
want to receive. Unlike Uniswap, this approach will charge less than the user
|
|
18
|
-
offered or pay more than they asked for when appropriate. By analogy, if a user
|
|
19
|
-
is willing to pay up to $20 when the price of soda is $3 per bottle, it would
|
|
20
|
-
give 6 bottles and only charge $18. (We refer to these as "improved" prices.)
|
|
21
|
-
Uniswap doesn't adjust the provided price, so it would charge $20 in that trade.
|
|
22
|
-
This matters whenever the values of the smallest unit of the currencies are
|
|
23
|
-
significantly different, which is common in DeFi.
|
|
24
|
-
|
|
25
|
-
The rules that drive the design include
|
|
26
|
-
|
|
27
|
-
* When the user specifies an input (or output) price, they shouldn't pay more
|
|
28
|
-
(or receive less) than they said.
|
|
29
|
-
* The pool fee is charged against the side not specified by the user (the
|
|
30
|
-
"computed side"). This increases the pool balance without impacting the amount
|
|
31
|
-
that the user specified.
|
|
32
|
-
* The protocol fee is always charged in IST.
|
|
33
|
-
* The fees are calculated based on the pool balances before the transaction.
|
|
34
|
-
* Computations are rounded in favor of the pool.
|
|
35
|
-
|
|
36
|
-
We start by estimating the exchange rate, and calculate fees based on that. Once
|
|
37
|
-
we know the fees, we add or subtract them directly to the amounts added to and
|
|
38
|
-
extracted from the pools to adhere to those rules.
|
|
39
|
-
|
|
40
|
-
## Calculating fees
|
|
41
|
-
|
|
42
|
-
In these tables BLD represents any collateral. The user can specify how much
|
|
43
|
-
they want or how much they're willing to pay. We'll call the value they
|
|
44
|
-
specified **sGive** or **sGet** and bold it. We'll always refer to the currency
|
|
45
|
-
being added as X and the currency the user gets as Y. X and Y are the amounts
|
|
46
|
-
used to maintain the constant product invariant. On every transaction the pool
|
|
47
|
-
balance will also increase on one side or the other by the pool fee, and the
|
|
48
|
-
protocol fee will be extracted outside the pool. So the amount produced is less
|
|
49
|
-
(or the amount paid is more) because the invariant is maintained on the amounts
|
|
50
|
-
remaining after fees have been charged.
|
|
51
|
-
|
|
52
|
-
In the final table, we'll see what the user pays or gets (sGet, sGive), how much
|
|
53
|
-
the pool balances change (xIncr, yDecr) and the changes that impact the constant
|
|
54
|
-
product calculation(ΔX, ΔY). The amount paid and received by the
|
|
55
|
-
trader and changes to the pool are calculated relative to ΔX and ΔY
|
|
56
|
-
so that the pool grows by the poolFee and the protocolFee can be paid from the
|
|
57
|
-
proceeds.
|
|
58
|
-
|
|
59
|
-
This table shows which brands the amounts each have, as well as what is computed
|
|
60
|
-
vs. given. The PoolFee is computed based on the calculated amount (BLD in rows 1
|
|
61
|
-
and 2; IST in rows 3 and 4). The Protocol fee is always in IST.
|
|
62
|
-
|
|
63
|
-
| | In (X) | Out (Y) | PoolFee | Protocol Fee | Specified | Computed |
|
|
64
|
-
|---------|-----|-----|--------|-----|------|-----|
|
|
65
|
-
| **IST in** | IST | BLD | BLD | IST | **sGive** | sGet |
|
|
66
|
-
| **IST out** | BLD | IST | BLD | IST | **sGet** | sGive |
|
|
67
|
-
| **BLD in** | BLD | IST | IST | IST | **sGive** | sGet |
|
|
68
|
-
| **BLD out** | IST | BLD | IST | IST | **sGet** | sGive |
|
|
69
|
-
|
|
70
|
-
We'll calculate how much the pool balances would change in the no-fee, improved
|
|
71
|
-
price case using the constant product formulas. We call these results δX,
|
|
72
|
-
and δY. This table uses lower case δ to distinguish estimates from
|
|
73
|
-
final values, which use capital Δ.
|
|
74
|
-
|
|
75
|
-
The fees are based on δX, and δY. ρ is the poolFee (e.g., 30
|
|
76
|
-
basis points). φ is the protocol fee (e.g., 6 basis points). The pool fee
|
|
77
|
-
will be ρ times whichever of δX and δY was calculated. The
|
|
78
|
-
protocol fee will be φ * δX when IST is paid in, and φ * δY
|
|
79
|
-
when BLD is paid in. (α and β in this table are the no-fee versions.)
|
|
80
|
-
|
|
81
|
-
| | δX | δY | PoolFee | Protocol Fee |
|
|
82
|
-
|---------|-----|-----|--------|-----|
|
|
83
|
-
| **IST in** | **sGive** | y * α / (1 + α) | ρ × δY | φ × **sGive** (= φ × δX) |
|
|
84
|
-
| **IST out** | x * β / (1 - β) | **sGet** | ρ × δX | φ × **sGet** (= φ × δY) |
|
|
85
|
-
| **BLD in** | **sGive** | y * α / (1 + α) | ρ × δY | φ × δY |
|
|
86
|
-
| **BLD out** | x * β / (1 - β) | **sGet** | ρ × δX | φ × δX |
|
|
87
|
-
|
|
88
|
-
In rows 1 and 3, **sGive** was specified and sGet will be calculated. In rows 2
|
|
89
|
-
and 4, **sGet** was specified and sGive will be calculated. Once we know the
|
|
90
|
-
fees, we can add or subtract the fees and calculate the pool changes.
|
|
91
|
-
|
|
92
|
-
The next table shows how the amount added to and subtracted from the pool (xIncr
|
|
93
|
-
and yIncr) differs from what the trader gives or gets and the change in the pool
|
|
94
|
-
values. While X' and Y' are the values resulting from the constant product
|
|
95
|
-
formula, xHat and yHat are the new values in the pool, reflecting the
|
|
96
|
-
contribution of the pool fee. From the diagram, xIncr is the difference between
|
|
97
|
-
X and xHat, while yIncr is the difference between Y and yHat.
|
|
98
|
-
|
|
99
|
-
The protocol fee (φ) is always charged on the IST side, and doesn't go in
|
|
100
|
-
the pool. The pool fee (ρ) is charged on the amount that is calculated
|
|
101
|
-
(ΔX or ΔY) and is included in yHat.
|
|
102
|
-
|
|
103
|
-
We use the estimate of the amount in or out to calculate improved values of
|
|
104
|
-
ΔX and ΔY. These values tell us how much the trader will pay, the
|
|
105
|
-
changes in pool balances, and what the trader will receive. As before, ΔX
|
|
106
|
-
reflects a balance that will be growing, and ΔY one that will be
|
|
107
|
-
shrinking.
|
|
108
|
-
|
|
109
|
-

|
|
110
|
-
|
|
111
|
-
When IST is specified (in or out), we adjust by the protocol Fee to get the
|
|
112
|
-
change to the IST balance (which gives X' or Y'); use that to calculate the
|
|
113
|
-
BLD component of the constant product, and then adjust δ by the pool fee.
|
|
114
|
-
When BLD is specified, the entire amount will affect the pool balance (so the
|
|
115
|
-
value in the constant product formula is the final BLD balance.) Both the pool
|
|
116
|
-
and protocol fees are charged in IST so they respectively reduce sGet or
|
|
117
|
-
increase sGive.
|
|
118
|
-
|
|
119
|
-
This table shows how the pool's growth and trader's values differ from the
|
|
120
|
-
amounts that match the constant product formula. X is in IST on lines 1 and 4,
|
|
121
|
-
and BLD on lines 2 and 3.
|
|
122
|
-
|
|
123
|
-
| | xIncr | yDecr | pay In (sGive) | pay Out (sGet) |
|
|
124
|
-
|---------|-----|-----|-----|-----|
|
|
125
|
-
| **IST in** | ΔX | ΔY - PoolFee | ΔX + protocolFee | ΔY - PoolFee |
|
|
126
|
-
| **IST out** | ΔX + PoolFee | ΔY | ΔX + protocolFee + PoolFee | ΔY |
|
|
127
|
-
| **BLD in** | ΔX | ΔY - PoolFee | ΔX + ProtocolFee | ΔY - PoolFee |
|
|
128
|
-
| **BLD out** | ΔX + PoolFee | ΔY | ΔX + PoolFee + ProtocolFee | ΔY |
|
|
129
|
-
|
|
130
|
-
In the two right columns the protocolFee is either added to the amount the
|
|
131
|
-
trader pays, or subtracted from the proceeds. The poolFee does the same on the
|
|
132
|
-
left side, and it is either added to the amount deposited in the pool (xIncr)
|
|
133
|
-
or deducted from the amount removed from the pool (yDecr).
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
* line 1: the trader provides **sGive** IST; the pool will gain that minus
|
|
137
|
-
the protocol fee in IST. The value in the IST pool after (X') will be used to
|
|
138
|
-
calculate Y'. The pool fee is calculated from δY and the trader gets
|
|
139
|
-
&deltaY; - poolFee
|
|
140
|
-
* line 2: the trader asked for **sGet** IST; the pool will be reduced by that
|
|
141
|
-
amount plus the protocol fee. Y' will be used to calculate X'. The trader
|
|
142
|
-
must provide &deltaX; plus poolFee
|
|
143
|
-
* Line 3: the trader pays **sGive** BLD; the pool will increase by that minus
|
|
144
|
-
both fees
|
|
145
|
-
* line 4: the trader specified **sGet** BLD; the pool will be reduced by that
|
|
146
|
-
plus the protocol fee.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
## Example
|
|
150
|
-
|
|
151
|
-
For example, let's say the pool has 40,000,000 IST and 3,000,000 BLD. Alice
|
|
152
|
-
requests a swapIn with inputAmount of 30,000 IST, and outputAmount of 2000 BLD.
|
|
153
|
-
(SwapIn means the inputValue is the basis of the computation, while outputAmount
|
|
154
|
-
is treated as a minimum). To make the numbers concrete, we'll say the pool fee
|
|
155
|
-
is 25 Basis Points, and the protocol fee is 5 Basis Points.
|
|
156
|
-
|
|
157
|
-
The first step is to compute the trade that would take place with no fees. 30K
|
|
158
|
-
will be added to 40M IST. To keep the product just above 120MM, the BLD will be
|
|
159
|
-
reduced to 2,997,752.
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
40,030,000 * 2,997,752 > 40,000,000 * 3,000,000 > 40,030,000 * 2,997,751
|
|
163
|
-
120000012560000 > 120000000000000 > 119999972530000
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
But we get an even tighter bound by reducing the amount Alice has to spend
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
40,029,996 * 2,997,752 > 40,000,000 * 3,000,000 > 40,029,995 * 2,997,752
|
|
170
|
-
120000000568992 > 120000000000000 > 119999997571240
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
The initial price estimate is that 29,996 IST would get 2248 BLD in a no-fee
|
|
174
|
-
pool. We base fees on this estimate, so the **protocol Fee will be 15 IST**
|
|
175
|
-
(always in IST, ⌈29,996 * 0.0005⌉) and the **pool fee will be 6 BLD**
|
|
176
|
-
(in the computed side, ⌈2248 * 0.0025⌉). The "computed side" for
|
|
177
|
-
`swapIn` is output and for `swapOut` is input.
|
|
178
|
-
|
|
179
|
-
Now we calculate the actual ΔX and ΔY, since the fees affect the
|
|
180
|
-
size of the changes to the pool. From the first row of the third table we see
|
|
181
|
-
that the calculation starts from ΔX of
|
|
182
|
-
`sGive - ProtocolFee (i.e. 30,000 - 15 = 29,985)`
|
|
183
|
-
|
|
184
|
-
```
|
|
185
|
-
40,029,985 * 2,997,753 > 40,000,000 * 3,000,000 > 40,029,985 * 2,997,752
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
and knowing that 2,997,753 BLD must remain in the pool, we refine the required
|
|
189
|
-
amount of IST:
|
|
190
|
-
|
|
191
|
-
```
|
|
192
|
-
40,029,983 * 2,997,753 > 40,000,000 * 3,000,000 > 40,029,982 * 2,997,753
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
**ΔX is 29,983, and ΔY is 2247**.
|
|
196
|
-
|
|
197
|
-
* Alice pays ΔX + protocolFee, which is 29,983 + 15 (29998 IST)
|
|
198
|
-
* Alice will receive ΔY - PoolFee which is 2247 - 6 (2241 BLD)
|
|
199
|
-
* The IST in the pool will increase by ΔX (29983 IST)
|
|
200
|
-
* The BLD in the pool will decrease by ΔY (2247 BLD)
|
|
201
|
-
|
|
202
|
-
The Pool grew by 6 BLD more than was required to maintain the constant product
|
|
203
|
-
invariant. 15 IST were extracted for the protocol fee.
|
|
204
|
-
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { AmountMath } from '@agoric/ertp';
|
|
4
|
-
import {
|
|
5
|
-
ceilMultiplyBy,
|
|
6
|
-
makeRatio,
|
|
7
|
-
} from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
8
|
-
|
|
9
|
-
import './types.js';
|
|
10
|
-
import './internal-types.js';
|
|
11
|
-
|
|
12
|
-
import { BASIS_POINTS } from './defaults.js';
|
|
13
|
-
|
|
14
|
-
const { details: X } = assert;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Make a ratio given a nat representing basis points and a brand.
|
|
18
|
-
*
|
|
19
|
-
* @type {MakeFeeRatio}
|
|
20
|
-
*/
|
|
21
|
-
const makeFeeRatio = (feeBP, brandOfFee) =>
|
|
22
|
-
makeRatio(feeBP, brandOfFee, BASIS_POINTS);
|
|
23
|
-
|
|
24
|
-
/** @type {Maximum} */
|
|
25
|
-
const maximum = (left, right) => {
|
|
26
|
-
// If left is greater or equal, return left. Otherwise return right.
|
|
27
|
-
return AmountMath.isGTE(left, right) ? left : right;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/** @type {AmountGT} */
|
|
31
|
-
const amountGT = (left, right) =>
|
|
32
|
-
AmountMath.isGTE(left, right) && !AmountMath.isEqual(left, right);
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Apply the feeRatio to the amount that has a matching brand. This used to
|
|
36
|
-
* calculate fees in the single pool case.
|
|
37
|
-
*
|
|
38
|
-
* @param {{ amountIn: Amount, amountOut: Amount}} amounts - a record with two
|
|
39
|
-
* amounts in different brands.
|
|
40
|
-
* @param {Ratio} feeRatio
|
|
41
|
-
* @returns {Amount}
|
|
42
|
-
*/
|
|
43
|
-
const calcFee = ({ amountIn, amountOut }, feeRatio) => {
|
|
44
|
-
feeRatio.numerator.brand === feeRatio.denominator.brand ||
|
|
45
|
-
assert.fail(
|
|
46
|
-
X`feeRatio numerator and denominator must use the same brand ${feeRatio}`,
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
let sameBrandAmount;
|
|
50
|
-
if (amountIn.brand === feeRatio.numerator.brand) {
|
|
51
|
-
sameBrandAmount = amountIn;
|
|
52
|
-
} else if (amountOut.brand === feeRatio.numerator.brand) {
|
|
53
|
-
sameBrandAmount = amountOut;
|
|
54
|
-
} else {
|
|
55
|
-
assert.fail(
|
|
56
|
-
X`feeRatio's brand (${feeRatio.numerator.brand}) must match one of the amounts [${amountIn}, ${amountOut}].`,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Always round fees up
|
|
61
|
-
const fee = ceilMultiplyBy(sameBrandAmount, feeRatio);
|
|
62
|
-
|
|
63
|
-
// Fee cannot exceed the amount on which it is levied
|
|
64
|
-
AmountMath.isGTE(sameBrandAmount, fee) ||
|
|
65
|
-
assert.fail(X`The feeRatio can't be greater than 1 ${feeRatio}`);
|
|
66
|
-
|
|
67
|
-
return fee;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Estimate the swap values, then calculate fees. The swapFn provided by the
|
|
72
|
-
* caller will be swapInNoFees or swapOutNoFees.
|
|
73
|
-
* SwapOut.
|
|
74
|
-
*
|
|
75
|
-
* @type {CalculateFees}
|
|
76
|
-
*/
|
|
77
|
-
const calculateFees = (
|
|
78
|
-
amountGiven,
|
|
79
|
-
poolAllocation,
|
|
80
|
-
amountWanted,
|
|
81
|
-
protocolFeeRatio,
|
|
82
|
-
poolFeeRatio,
|
|
83
|
-
swapFn,
|
|
84
|
-
) => {
|
|
85
|
-
// Get a rough estimation in both brands of the amount to be swapped
|
|
86
|
-
const estimation = swapFn({ amountGiven, poolAllocation, amountWanted });
|
|
87
|
-
|
|
88
|
-
const protocolFee = calcFee(estimation, protocolFeeRatio);
|
|
89
|
-
const poolFee = calcFee(estimation, poolFeeRatio);
|
|
90
|
-
|
|
91
|
-
return harden({ protocolFee, poolFee, ...estimation });
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
harden(amountGT);
|
|
95
|
-
harden(maximum);
|
|
96
|
-
harden(makeFeeRatio);
|
|
97
|
-
harden(calculateFees);
|
|
98
|
-
|
|
99
|
-
export { amountGT, maximum, makeFeeRatio, calculateFees };
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { Far } from '@endo/marshal';
|
|
4
|
-
|
|
5
|
-
import { swap } from './swap.js';
|
|
6
|
-
import { assertKInvariantSellingX } from './invariants.js';
|
|
7
|
-
import { getXY } from './getXY.js';
|
|
8
|
-
import { swapInNoFees, swapOutNoFees } from './core.js';
|
|
9
|
-
|
|
10
|
-
// pricesForStatedOutput() and pricesForStatedInput are the external entrypoints
|
|
11
|
-
// to the constantProduct module. The amountWanted is optional for
|
|
12
|
-
// pricesForStatedInput and amountgiven is optional for pricesForStatedOutput.
|
|
13
|
-
|
|
14
|
-
// The two methods call swap, passing in different functions for noFeeSwap.
|
|
15
|
-
// pricesForStatedInput uses swapInNoFees, while pricesForStatedOutput uses
|
|
16
|
-
// swapOutNoFees. the noFeesSwap functions
|
|
17
|
-
const makeCalcSwapPrices = noFeesSwap => {
|
|
18
|
-
return Far(
|
|
19
|
-
'calcSwapPrices',
|
|
20
|
-
(
|
|
21
|
-
amountGiven,
|
|
22
|
-
poolAllocation,
|
|
23
|
-
amountWanted,
|
|
24
|
-
protocolFeeRatio,
|
|
25
|
-
poolFeeRatio,
|
|
26
|
-
) => {
|
|
27
|
-
const result = swap(
|
|
28
|
-
amountGiven,
|
|
29
|
-
poolAllocation,
|
|
30
|
-
amountWanted,
|
|
31
|
-
protocolFeeRatio,
|
|
32
|
-
poolFeeRatio,
|
|
33
|
-
noFeesSwap,
|
|
34
|
-
);
|
|
35
|
-
const { x, y } = getXY({
|
|
36
|
-
amountGiven,
|
|
37
|
-
poolAllocation,
|
|
38
|
-
amountWanted,
|
|
39
|
-
});
|
|
40
|
-
assertKInvariantSellingX(x, y, result.xIncrement, result.yDecrement);
|
|
41
|
-
return result;
|
|
42
|
-
},
|
|
43
|
-
);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/** @type {CalcSwapInPrices} */
|
|
47
|
-
const pricesForStatedInput = (
|
|
48
|
-
amountGiven,
|
|
49
|
-
poolAllocation,
|
|
50
|
-
amountWanted,
|
|
51
|
-
protocolFeeRatio,
|
|
52
|
-
poolFeeRatio,
|
|
53
|
-
) => {
|
|
54
|
-
const calcSwapPrices = makeCalcSwapPrices(swapInNoFees);
|
|
55
|
-
return calcSwapPrices(
|
|
56
|
-
amountGiven,
|
|
57
|
-
poolAllocation,
|
|
58
|
-
amountWanted,
|
|
59
|
-
protocolFeeRatio,
|
|
60
|
-
poolFeeRatio,
|
|
61
|
-
);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
/** @type {CalcSwapOutPrices} */
|
|
65
|
-
const pricesForStatedOutput = (
|
|
66
|
-
amountGiven,
|
|
67
|
-
poolAllocation,
|
|
68
|
-
amountWanted,
|
|
69
|
-
protocolFeeRatio,
|
|
70
|
-
poolFeeRatio,
|
|
71
|
-
) => {
|
|
72
|
-
const calcSwapPrices = makeCalcSwapPrices(swapOutNoFees);
|
|
73
|
-
return calcSwapPrices(
|
|
74
|
-
amountGiven,
|
|
75
|
-
poolAllocation,
|
|
76
|
-
amountWanted,
|
|
77
|
-
protocolFeeRatio,
|
|
78
|
-
poolFeeRatio,
|
|
79
|
-
);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
harden(pricesForStatedInput);
|
|
83
|
-
harden(pricesForStatedOutput);
|
|
84
|
-
|
|
85
|
-
export { pricesForStatedOutput, pricesForStatedInput };
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { AmountMath } from '@agoric/ertp';
|
|
4
|
-
|
|
5
|
-
import { natSafeMath } from '@agoric/zoe/src/contractSupport/index.js';
|
|
6
|
-
import { makeRatioFromAmounts } from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
7
|
-
import { getXY } from './getXY.js';
|
|
8
|
-
|
|
9
|
-
const { details: X } = assert;
|
|
10
|
-
|
|
11
|
-
const assertSingleBrand = ratio => {
|
|
12
|
-
ratio.numerator.brand === ratio.denominator.brand ||
|
|
13
|
-
assert.fail(
|
|
14
|
-
X`Ratio was expected to have same brand in numerator ${ratio.numerator.brand} and denominator ${ratio.denominator.brand}`,
|
|
15
|
-
);
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Multiply an amount by a ratio using floorDivide, ignoring the ratio's brands
|
|
20
|
-
* in favor of the amount brand. This is necessary because the ratio is produced
|
|
21
|
-
* by dividing assets of the opposite brand.
|
|
22
|
-
*
|
|
23
|
-
* @param {Amount} amount
|
|
24
|
-
* @param {Ratio} ratio
|
|
25
|
-
* @returns {Amount}
|
|
26
|
-
*/
|
|
27
|
-
const floorMultiplyKeepBrand = (amount, ratio) => {
|
|
28
|
-
assertSingleBrand(ratio);
|
|
29
|
-
const value = natSafeMath.floorDivide(
|
|
30
|
-
natSafeMath.multiply(amount.value, ratio.numerator.value),
|
|
31
|
-
ratio.denominator.value,
|
|
32
|
-
);
|
|
33
|
-
return AmountMath.make(amount.brand, value);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Multiply an amount and a ratio using ceilDivide, ignoring the ratio's brands
|
|
38
|
-
* in favor of the amount brand. This is necessary because the ratio is produced
|
|
39
|
-
* by dividing assets of the opposite brand.
|
|
40
|
-
*
|
|
41
|
-
* @param {Amount} amount
|
|
42
|
-
* @param {Ratio} ratio
|
|
43
|
-
* @returns {Amount}
|
|
44
|
-
*/
|
|
45
|
-
const ceilMultiplyKeepBrand = (amount, ratio) => {
|
|
46
|
-
assertSingleBrand(ratio);
|
|
47
|
-
const value = natSafeMath.ceilDivide(
|
|
48
|
-
natSafeMath.multiply(amount.value, ratio.numerator.value),
|
|
49
|
-
ratio.denominator.value,
|
|
50
|
-
);
|
|
51
|
-
return AmountMath.make(amount.brand, value);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Calculate deltaY when the user is selling brand X. That is, whichever asset
|
|
56
|
-
* the user is selling, this function is used to calculate the change in the
|
|
57
|
-
* other asset, i.e. how much of brand Y to give the user in return.
|
|
58
|
-
* swapOutImproved calls this function with the calculated amountIn to find out
|
|
59
|
-
* if more than the wantedAmountOut can be gained for the necessary amountIn.
|
|
60
|
-
*
|
|
61
|
-
* deltaY = (deltaXOverX/(1 + deltaXOverX))*y
|
|
62
|
-
* Equivalently: (deltaX / (deltaX + x)) * y
|
|
63
|
-
*
|
|
64
|
-
* @param {Amount} x - the amount of Brand X in pool
|
|
65
|
-
* @param {Amount} y - the amount of Brand Y the pool
|
|
66
|
-
* @param {Amount} deltaX - the amount of Brand X to be added
|
|
67
|
-
* @returns {Amount} deltaY - the amount of Brand Y to be taken out
|
|
68
|
-
*/
|
|
69
|
-
export const calcDeltaYSellingX = (x, y, deltaX) => {
|
|
70
|
-
const deltaXPlusX = AmountMath.add(deltaX, x);
|
|
71
|
-
const xRatio = makeRatioFromAmounts(deltaX, deltaXPlusX);
|
|
72
|
-
// We want to err on the side of the pool, so this will use floorDivide to
|
|
73
|
-
// round down the amount paid out.
|
|
74
|
-
return floorMultiplyKeepBrand(y, xRatio);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Calculate deltaX when the user is selling brand X. That is, whichever asset
|
|
79
|
-
* the user is selling, this function is used to calculate the change to the
|
|
80
|
-
* pool for that asset. swapInReduced calls this with the calculated amountOut
|
|
81
|
-
* to find out if less than the offeredAmountIn would be sufficient.
|
|
82
|
-
*
|
|
83
|
-
* deltaX = (deltaYOverY/(1 - deltaYOverY))*x
|
|
84
|
-
* Equivalently: (deltaY / (Y - deltaY )) * x
|
|
85
|
-
*
|
|
86
|
-
* @param {Amount} x - the amount of Brand X in the pool
|
|
87
|
-
* @param {Amount} y - the amount of Brand Y in the pool
|
|
88
|
-
* @param {Amount} deltaY - the amount of Brand Y to be taken out
|
|
89
|
-
* @returns {Amount} deltaX - the amount of Brand X to be added
|
|
90
|
-
*/
|
|
91
|
-
export const calcDeltaXSellingX = (x, y, deltaY) => {
|
|
92
|
-
const yMinusDeltaY = AmountMath.subtract(y, deltaY);
|
|
93
|
-
const yRatio = makeRatioFromAmounts(deltaY, yMinusDeltaY);
|
|
94
|
-
// We want to err on the side of the pool, so this will use ceilMultiply to
|
|
95
|
-
// round up the amount required.
|
|
96
|
-
return ceilMultiplyKeepBrand(x, yRatio);
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* The input contains the amounts in the pool and a maximum amount offered.
|
|
101
|
-
* Calculate the most beneficial trade that satisfies the constant product
|
|
102
|
-
* invariant.
|
|
103
|
-
*
|
|
104
|
-
* @param {GetXYResultDeltaX} obj
|
|
105
|
-
* @returns {ImprovedNoFeeSwapResult}
|
|
106
|
-
*/
|
|
107
|
-
const swapInReduced = ({ x, y, deltaX: offeredAmountIn }) => {
|
|
108
|
-
const amountOut = calcDeltaYSellingX(x, y, offeredAmountIn);
|
|
109
|
-
const reducedAmountIn = calcDeltaXSellingX(x, y, amountOut);
|
|
110
|
-
AmountMath.isGTE(offeredAmountIn, reducedAmountIn) ||
|
|
111
|
-
assert.fail(
|
|
112
|
-
X`The trade would have required ${reducedAmountIn} more than was offered ${offeredAmountIn}`,
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
return harden({
|
|
116
|
-
amountIn: reducedAmountIn,
|
|
117
|
-
amountOut,
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* The input contains the amounts in the pool and the minimum amount requested.
|
|
123
|
-
* Calculate the most beneficial trade that satisfies the constant product
|
|
124
|
-
* invariant.
|
|
125
|
-
*
|
|
126
|
-
* @param {GetXYResultDeltaY} obj
|
|
127
|
-
* @returns {ImprovedNoFeeSwapResult}
|
|
128
|
-
*/
|
|
129
|
-
const swapOutImproved = ({ x, y, deltaY: wantedAmountOut }) => {
|
|
130
|
-
const amountIn = calcDeltaXSellingX(x, y, wantedAmountOut);
|
|
131
|
-
const improvedAmountOut = calcDeltaYSellingX(x, y, amountIn);
|
|
132
|
-
AmountMath.isGTE(improvedAmountOut, wantedAmountOut) ||
|
|
133
|
-
assert.fail(
|
|
134
|
-
X`The trade would have returned ${improvedAmountOut} less than was wanted ${wantedAmountOut}`,
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return harden({
|
|
138
|
-
amountIn,
|
|
139
|
-
amountOut: improvedAmountOut,
|
|
140
|
-
});
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
/** @type {NoFeeSwapFn} */
|
|
144
|
-
export const swapInNoFees = ({ amountGiven, poolAllocation }) => {
|
|
145
|
-
const XY = getXY({ amountGiven, poolAllocation });
|
|
146
|
-
return swapInReduced(XY);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
/** @type {NoFeeSwapFn} */
|
|
150
|
-
export const swapOutNoFees = ({ poolAllocation, amountWanted }) => {
|
|
151
|
-
const XY = getXY({ poolAllocation, amountWanted });
|
|
152
|
-
return swapOutImproved(XY);
|
|
153
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
// This does not support secondary to secondary. That has to happen at
|
|
4
|
-
// a higher abstraction
|
|
5
|
-
|
|
6
|
-
const { details: X } = assert;
|
|
7
|
-
/**
|
|
8
|
-
* The caller provides poolAllocation, which has balances for both Central and
|
|
9
|
-
* Secondary, and at least one of amountGiven and amountWanted. getXY treats
|
|
10
|
-
* the amountGiven as the X pool, and amountWanted as Y. It figures out which
|
|
11
|
-
* way to pair up X and Y with Central and Secondary, and returns the pool
|
|
12
|
-
* balances as X and Y and given and wanted as deltaX and deltaY
|
|
13
|
-
* { X, Y, deltaX, deltaY }.
|
|
14
|
-
*
|
|
15
|
-
* @type {GetXY}
|
|
16
|
-
*/
|
|
17
|
-
export const getXY = ({ amountGiven, poolAllocation, amountWanted }) => {
|
|
18
|
-
// Regardless of whether we are specifying the amountIn or the
|
|
19
|
-
// amountOut, the xBrand is the brand of the amountIn.
|
|
20
|
-
const xBrand = amountGiven && amountGiven.brand;
|
|
21
|
-
const yBrand = amountWanted && amountWanted.brand;
|
|
22
|
-
const secondaryBrand = poolAllocation.Secondary.brand;
|
|
23
|
-
const centralBrand = poolAllocation.Central.brand;
|
|
24
|
-
amountGiven ||
|
|
25
|
-
amountWanted ||
|
|
26
|
-
assert.fail(
|
|
27
|
-
X`At least one of ${amountGiven} and ${amountWanted} must be specified`,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const deltas = {
|
|
31
|
-
deltaX: amountGiven,
|
|
32
|
-
deltaY: amountWanted,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (secondaryBrand === xBrand || centralBrand === yBrand) {
|
|
36
|
-
// @ts-expect-error at least one of amountGiven and amountWanted is non-null
|
|
37
|
-
return harden({
|
|
38
|
-
x: poolAllocation.Secondary,
|
|
39
|
-
y: poolAllocation.Central,
|
|
40
|
-
...deltas,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
if (centralBrand === xBrand || secondaryBrand === yBrand) {
|
|
44
|
-
// @ts-expect-error at least one of amountGiven and amountWanted is non-null
|
|
45
|
-
return harden({
|
|
46
|
-
x: poolAllocation.Central,
|
|
47
|
-
y: poolAllocation.Secondary,
|
|
48
|
-
...deltas,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
assert.fail(`brand ${xBrand} was not recognized as Central or Secondary`);
|
|
52
|
-
};
|