@agoric/inter-protocol 0.13.2-dev-70ba9b0.0 → 0.13.2-dev-ed5ee58.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/bundles/bundle-econCommitteeCharter-meta.js +78 -78
- package/bundles/bundle-econCommitteeCharter.js +1 -1
- package/bundles/bundle-feeDistributor-meta.js +61 -61
- package/bundles/bundle-feeDistributor.js +1 -1
- package/bundles/bundle-fluxAggregator-meta.js +188 -188
- package/bundles/bundle-fluxAggregator.js +1 -1
- package/bundles/bundle-psm-meta.js +112 -112
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-meta.js +110 -114
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-meta.js +78 -78
- package/bundles/bundle-stakeFactory-meta.js +118 -118
- package/bundles/bundle-stakeFactory.js +1 -1
- package/bundles/bundle-vaultFactory-meta.js +130 -130
- package/bundles/bundle-vaultFactory.js +1 -1
- package/exported.js +0 -1
- package/package.json +16 -16
- package/scripts/deploy-contracts.js +0 -2
- package/scripts/init-core.js +0 -16
- package/src/feeDistributor.js +1 -1
- package/src/proposals/addAssetToVault.js +4 -57
- package/src/proposals/committee-proposal.js +3 -6
- package/src/proposals/core-proposal.js +1 -73
- package/src/proposals/demoIssuers.js +1 -232
- package/src/proposals/econ-behaviors.js +10 -193
- package/src/proposals/sim-behaviors.js +1 -1
- package/src/reserve/assetReserve.js +9 -170
- package/src/reserve/params.js +1 -4
- package/src/vaultFactory/liquidateIncrementally.js +16 -141
- package/src/vaultFactory/liquidateMinimum.js +19 -21
- package/src/vaultFactory/params.js +0 -29
- package/src/vaultFactory/types.js +0 -6
- package/src/vaultFactory/vault.js +1 -3
- package/src/vaultFactory/vaultDirector.js +1 -33
- package/src/vaultFactory/vaultFactory.js +2 -12
- package/src/vaultFactory/vaultManager.js +10 -217
- package/bundles/bundle-amm-meta.js +0 -686
- package/bundles/bundle-amm.js +0 -1
- package/bundles/bundle-interchainPool-meta.js +0 -606
- package/bundles/bundle-interchainPool.js +0 -1
- package/bundles/bundle-liquidateIncrementally-meta.js +0 -470
- package/bundles/bundle-liquidateIncrementally.js +0 -1
- package/bundles/bundle-liquidateMinimum-meta.js +0 -470
- package/bundles/bundle-liquidateMinimum.js +0 -1
- package/scripts/add-initial-liquidity.js +0 -179
- package/src/interchainPool.js +0 -134
- package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
- package/src/vpool-xyk-amm/addLiquidity.js +0 -221
- package/src/vpool-xyk-amm/addPool.js +0 -200
- 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 -93
- package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -83
- package/src/vpool-xyk-amm/constantProduct/core.js +0 -145
- package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -3
- package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -48
- package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -114
- package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -39
- package/src/vpool-xyk-amm/constantProduct/swap.js +0 -270
- package/src/vpool-xyk-amm/constantProduct/types.js +0 -30
- package/src/vpool-xyk-amm/doublePool.js +0 -200
- package/src/vpool-xyk-amm/estimate.js +0 -175
- package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -530
- package/src/vpool-xyk-amm/params.js +0 -59
- package/src/vpool-xyk-amm/pool.js +0 -398
- package/src/vpool-xyk-amm/priceAuthority.js +0 -92
- package/src/vpool-xyk-amm/removeLiquidity.js +0 -29
- package/src/vpool-xyk-amm/singlePool.js +0 -88
- package/src/vpool-xyk-amm/swap.js +0 -68
- package/src/vpool-xyk-amm/types.js +0 -152
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { AmountMath } from '@agoric/ertp';
|
|
2
|
-
|
|
3
|
-
import { natSafeMath } from '@agoric/zoe/src/contractSupport/index.js';
|
|
4
|
-
import { makeRatioFromAmounts } from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
5
|
-
import { getXY } from './getXY.js';
|
|
6
|
-
|
|
7
|
-
const { Fail } = assert;
|
|
8
|
-
|
|
9
|
-
const assertSingleBrand = ratio => {
|
|
10
|
-
ratio.numerator.brand === ratio.denominator.brand ||
|
|
11
|
-
Fail`Ratio was expected to have same brand in numerator ${ratio.numerator.brand} and denominator ${ratio.denominator.brand}`;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Multiply an amount by a ratio using floorDivide, ignoring the ratio's brands
|
|
16
|
-
* in favor of the amount brand. This is necessary because the ratio is produced
|
|
17
|
-
* by dividing assets of the opposite brand.
|
|
18
|
-
*
|
|
19
|
-
* @param {Amount<'nat'>} amount
|
|
20
|
-
* @param {Ratio} ratio
|
|
21
|
-
* @returns {Amount<'nat'>}
|
|
22
|
-
*/
|
|
23
|
-
const floorMultiplyKeepBrand = (amount, ratio) => {
|
|
24
|
-
assertSingleBrand(ratio);
|
|
25
|
-
const value = natSafeMath.floorDivide(
|
|
26
|
-
natSafeMath.multiply(amount.value, ratio.numerator.value),
|
|
27
|
-
ratio.denominator.value,
|
|
28
|
-
);
|
|
29
|
-
return AmountMath.make(amount.brand, value);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Multiply an amount and a ratio using ceilDivide, ignoring the ratio's brands
|
|
34
|
-
* in favor of the amount brand. This is necessary because the ratio is produced
|
|
35
|
-
* by dividing assets of the opposite brand.
|
|
36
|
-
*
|
|
37
|
-
* @param {Amount<'nat'>} amount
|
|
38
|
-
* @param {Ratio} ratio
|
|
39
|
-
* @returns {Amount<'nat'>}
|
|
40
|
-
*/
|
|
41
|
-
const ceilMultiplyKeepBrand = (amount, ratio) => {
|
|
42
|
-
assertSingleBrand(ratio);
|
|
43
|
-
const value = natSafeMath.ceilDivide(
|
|
44
|
-
natSafeMath.multiply(amount.value, ratio.numerator.value),
|
|
45
|
-
ratio.denominator.value,
|
|
46
|
-
);
|
|
47
|
-
return AmountMath.make(amount.brand, value);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Calculate deltaY when the user is selling brand X. That is, whichever asset
|
|
52
|
-
* the user is selling, this function is used to calculate the change in the
|
|
53
|
-
* other asset, i.e. how much of brand Y to give the user in return.
|
|
54
|
-
* swapOutImproved calls this function with the calculated amountIn to find out
|
|
55
|
-
* if more than the wantedAmountOut can be gained for the necessary amountIn.
|
|
56
|
-
*
|
|
57
|
-
* deltaY = (deltaXOverX/(1 + deltaXOverX))*y
|
|
58
|
-
* Equivalently: (deltaX / (deltaX + x)) * y
|
|
59
|
-
*
|
|
60
|
-
* @param {Amount<'nat'>} x - the amount of Brand X in pool
|
|
61
|
-
* @param {Amount<'nat'>} y - the amount of Brand Y the pool
|
|
62
|
-
* @param {Amount<'nat'>} deltaX - the amount of Brand X to be added
|
|
63
|
-
* @returns {Amount<'nat'>} deltaY - the amount of Brand Y to be taken out
|
|
64
|
-
*/
|
|
65
|
-
export const calcDeltaYSellingX = (x, y, deltaX) => {
|
|
66
|
-
const deltaXPlusX = AmountMath.add(deltaX, x);
|
|
67
|
-
const xRatio = makeRatioFromAmounts(deltaX, deltaXPlusX);
|
|
68
|
-
// We want to err on the side of the pool, so this will use floorDivide to
|
|
69
|
-
// round down the amount paid out.
|
|
70
|
-
return floorMultiplyKeepBrand(y, xRatio);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Calculate deltaX when the user is selling brand X. That is, whichever asset
|
|
75
|
-
* the user is selling, this function is used to calculate the change to the
|
|
76
|
-
* pool for that asset. swapInReduced calls this with the calculated amountOut
|
|
77
|
-
* to find out if less than the offeredAmountIn would be sufficient.
|
|
78
|
-
*
|
|
79
|
-
* deltaX = (deltaYOverY/(1 - deltaYOverY))*x
|
|
80
|
-
* Equivalently: (deltaY / (Y - deltaY )) * x
|
|
81
|
-
*
|
|
82
|
-
* @param {Amount<'nat'>} x - the amount of Brand X in the pool
|
|
83
|
-
* @param {Amount<'nat'>} y - the amount of Brand Y in the pool
|
|
84
|
-
* @param {Amount<'nat'>} deltaY - the amount of Brand Y to be taken out
|
|
85
|
-
* @returns {Amount<'nat'>} deltaX - the amount of Brand X to be added
|
|
86
|
-
*/
|
|
87
|
-
export const calcDeltaXSellingX = (x, y, deltaY) => {
|
|
88
|
-
const yMinusDeltaY = AmountMath.subtract(y, deltaY);
|
|
89
|
-
const yRatio = makeRatioFromAmounts(deltaY, yMinusDeltaY);
|
|
90
|
-
// We want to err on the side of the pool, so this will use ceilMultiply to
|
|
91
|
-
// round up the amount required.
|
|
92
|
-
return ceilMultiplyKeepBrand(x, yRatio);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* The input contains the amounts in the pool and a maximum amount offered.
|
|
97
|
-
* Calculate the most beneficial trade that satisfies the constant product
|
|
98
|
-
* invariant.
|
|
99
|
-
*
|
|
100
|
-
* @param {GetXYResultDeltaX} obj
|
|
101
|
-
* @returns {ImprovedNoFeeSwapResult}
|
|
102
|
-
*/
|
|
103
|
-
const swapInReduced = ({ x, y, deltaX: offeredAmountIn }) => {
|
|
104
|
-
const amountOut = calcDeltaYSellingX(x, y, offeredAmountIn);
|
|
105
|
-
const reducedAmountIn = calcDeltaXSellingX(x, y, amountOut);
|
|
106
|
-
AmountMath.isGTE(offeredAmountIn, reducedAmountIn) ||
|
|
107
|
-
Fail`The trade would have required ${reducedAmountIn} more than was offered ${offeredAmountIn}`;
|
|
108
|
-
|
|
109
|
-
return harden({
|
|
110
|
-
amountIn: reducedAmountIn,
|
|
111
|
-
amountOut,
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* The input contains the amounts in the pool and the minimum amount requested.
|
|
117
|
-
* Calculate the most beneficial trade that satisfies the constant product
|
|
118
|
-
* invariant.
|
|
119
|
-
*
|
|
120
|
-
* @param {GetXYResultDeltaY} obj
|
|
121
|
-
* @returns {ImprovedNoFeeSwapResult}
|
|
122
|
-
*/
|
|
123
|
-
const swapOutImproved = ({ x, y, deltaY: wantedAmountOut }) => {
|
|
124
|
-
const amountIn = calcDeltaXSellingX(x, y, wantedAmountOut);
|
|
125
|
-
const improvedAmountOut = calcDeltaYSellingX(x, y, amountIn);
|
|
126
|
-
AmountMath.isGTE(improvedAmountOut, wantedAmountOut) ||
|
|
127
|
-
Fail`The trade would have returned ${improvedAmountOut} less than was wanted ${wantedAmountOut}`;
|
|
128
|
-
|
|
129
|
-
return harden({
|
|
130
|
-
amountIn,
|
|
131
|
-
amountOut: improvedAmountOut,
|
|
132
|
-
});
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
/** @type {NoFeeSwapFn} */
|
|
136
|
-
export const swapInNoFees = ({ amountGiven, poolAllocation }) => {
|
|
137
|
-
const XY = getXY({ amountGiven, poolAllocation });
|
|
138
|
-
return swapInReduced(XY);
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
/** @type {NoFeeSwapFn} */
|
|
142
|
-
export const swapOutNoFees = ({ poolAllocation, amountWanted }) => {
|
|
143
|
-
const XY = getXY({ poolAllocation, amountWanted });
|
|
144
|
-
return swapOutImproved(XY);
|
|
145
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// This does not support secondary to secondary. That has to happen at
|
|
2
|
-
// a higher abstraction
|
|
3
|
-
|
|
4
|
-
const { Fail } = assert;
|
|
5
|
-
/**
|
|
6
|
-
* The caller provides poolAllocation, which has balances for both Central and
|
|
7
|
-
* Secondary, and at least one of amountGiven and amountWanted. getXY treats
|
|
8
|
-
* the amountGiven as the X pool, and amountWanted as Y. It figures out which
|
|
9
|
-
* way to pair up X and Y with Central and Secondary, and returns the pool
|
|
10
|
-
* balances as X and Y and given and wanted as deltaX and deltaY
|
|
11
|
-
* { X, Y, deltaX, deltaY }.
|
|
12
|
-
*
|
|
13
|
-
* @type {GetXY}
|
|
14
|
-
*/
|
|
15
|
-
export const getXY = ({ amountGiven, poolAllocation, amountWanted }) => {
|
|
16
|
-
// Regardless of whether we are specifying the amountIn or the
|
|
17
|
-
// amountOut, the xBrand is the brand of the amountIn.
|
|
18
|
-
const xBrand = amountGiven && amountGiven.brand;
|
|
19
|
-
const yBrand = amountWanted && amountWanted.brand;
|
|
20
|
-
const secondaryBrand = poolAllocation.Secondary.brand;
|
|
21
|
-
const centralBrand = poolAllocation.Central.brand;
|
|
22
|
-
amountGiven ||
|
|
23
|
-
amountWanted ||
|
|
24
|
-
Fail`At least one of ${amountGiven} and ${amountWanted} must be specified`;
|
|
25
|
-
|
|
26
|
-
const deltas = {
|
|
27
|
-
deltaX: amountGiven,
|
|
28
|
-
deltaY: amountWanted,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
if (secondaryBrand === xBrand || centralBrand === yBrand) {
|
|
32
|
-
// @ts-expect-error at least one of amountGiven and amountWanted is non-null
|
|
33
|
-
return harden({
|
|
34
|
-
x: poolAllocation.Secondary,
|
|
35
|
-
y: poolAllocation.Central,
|
|
36
|
-
...deltas,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
if (centralBrand === xBrand || secondaryBrand === yBrand) {
|
|
40
|
-
// @ts-expect-error at least one of amountGiven and amountWanted is non-null
|
|
41
|
-
return harden({
|
|
42
|
-
x: poolAllocation.Central,
|
|
43
|
-
y: poolAllocation.Secondary,
|
|
44
|
-
...deltas,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
assert.fail(`brand ${xBrand} was not recognized as Central or Secondary`);
|
|
48
|
-
};
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {object} ImprovedNoFeeSwapResult
|
|
3
|
-
* @property {Amount<'nat'>} amountIn
|
|
4
|
-
* @property {Amount<'nat'>} amountOut
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {object} FeePair
|
|
9
|
-
*
|
|
10
|
-
* @property {Amount<'nat'>} poolFee
|
|
11
|
-
* @property {Amount<'nat'>} protocolFee
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {object} PoolAllocation
|
|
16
|
-
*
|
|
17
|
-
* @property {Amount<'nat'>} Central
|
|
18
|
-
* @property {Amount<'nat'>} Secondary
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef {object} NoFeeSwapFnInput
|
|
23
|
-
* @property {Amount} amountGiven
|
|
24
|
-
* @property {Amount} amountWanted
|
|
25
|
-
* @property {Brand} [brand]
|
|
26
|
-
* @property {PoolAllocation} poolAllocation
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* This is the type for swapInNoFees and swapOutNoFees. pricesForStatedInput()
|
|
31
|
-
* uses swapInNoFees, while pricesForStatedOutput() uses swapOutNoFees.
|
|
32
|
-
*
|
|
33
|
-
* @callback NoFeeSwapFn
|
|
34
|
-
* @param {NoFeeSwapFnInput} input
|
|
35
|
-
* @returns {ImprovedNoFeeSwapResult}
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @typedef {FeePair & ImprovedNoFeeSwapResult} FeeEstimate
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @callback CalculateFees
|
|
44
|
-
* @param {Amount<'nat'>} amountGiven
|
|
45
|
-
* @param {PoolAllocation} poolAllocation
|
|
46
|
-
* @param {Amount<'nat'>} amountWanted
|
|
47
|
-
* @param {Ratio} protocolFeeRatio
|
|
48
|
-
* @param {Ratio} poolFeeRatio
|
|
49
|
-
* @param {NoFeeSwapFn} swapFn
|
|
50
|
-
* @returns {FeeEstimate}
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @callback InternalSwap
|
|
55
|
-
* @param {Amount<'nat'>} amountGiven
|
|
56
|
-
* @param {PoolAllocation} poolAllocation
|
|
57
|
-
* @param {Amount<'nat'>} amountWanted
|
|
58
|
-
* @param {Ratio} protocolFeeRatio
|
|
59
|
-
* @param {Ratio} poolFeeRatio
|
|
60
|
-
* @param {NoFeeSwapFn} swapFn
|
|
61
|
-
* @returns {SinglePoolSwapResult}
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @callback CalcSwapInPrices
|
|
66
|
-
* @param {Amount} amountGiven
|
|
67
|
-
* @param {PoolAllocation} poolAllocation
|
|
68
|
-
* @param {Amount} [amountWanted]
|
|
69
|
-
* @param {Ratio} protocolFeeRatio
|
|
70
|
-
* @param {Ratio} poolFeeRatio
|
|
71
|
-
* @returns {SinglePoolSwapResult}
|
|
72
|
-
*/
|
|
73
|
-
/**
|
|
74
|
-
* @callback CalcSwapOutPrices
|
|
75
|
-
* @param {Amount} [amountGiven]
|
|
76
|
-
* @param {PoolAllocation} poolAllocation
|
|
77
|
-
* @param {Amount} amountWanted
|
|
78
|
-
* @param {Ratio} protocolFeeRatio
|
|
79
|
-
* @param {Ratio} poolFeeRatio
|
|
80
|
-
* @returns {SinglePoolSwapResult}
|
|
81
|
-
*/
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* @typedef {object} GetXYParam
|
|
85
|
-
* @property {Amount} [amountGiven]
|
|
86
|
-
* @property {PoolAllocation} poolAllocation
|
|
87
|
-
* @property {Amount} [amountWanted]
|
|
88
|
-
*/
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* @typedef {object} GetXYResultDeltaX
|
|
92
|
-
* @property {Amount<'nat'>} x
|
|
93
|
-
* @property {Amount<'nat'>} y
|
|
94
|
-
* @property {Amount<'nat'>} deltaX
|
|
95
|
-
* @property {Amount<'nat'>|undefined} deltaY
|
|
96
|
-
*/
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* @typedef {object} GetXYResultDeltaY
|
|
100
|
-
* @property {Amount<'nat'>} x
|
|
101
|
-
* @property {Amount<'nat'>} y
|
|
102
|
-
* @property {Amount<'nat'>} deltaY
|
|
103
|
-
* @property {Amount<'nat'>|undefined} deltaX
|
|
104
|
-
*/
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @typedef {GetXYResultDeltaX & GetXYResultDeltaY} GetXYResult
|
|
108
|
-
*/
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @callback GetXY
|
|
112
|
-
* @param {GetXYParam} obj
|
|
113
|
-
* @returns {GetXYResult}
|
|
114
|
-
*/
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Fail } from '@agoric/assert';
|
|
2
|
-
import { AmountMath } from '@agoric/ertp';
|
|
3
|
-
|
|
4
|
-
import { natSafeMath } from '@agoric/zoe/src/contractSupport/index.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* xy <= (x + deltaX)(y - deltaY)
|
|
8
|
-
*
|
|
9
|
-
* @param {Amount<'nat'>} x - the amount of Brand X in pool, xPoolAllocation
|
|
10
|
-
* @param {Amount<'nat'>} y - the amount of Brand Y in pool, yPoolAllocation
|
|
11
|
-
* @param {Amount<'nat'>} deltaX - the amount of Brand X to be added
|
|
12
|
-
* @param {Amount<'nat'>} deltaY - the amount of Brand Y to be taken out
|
|
13
|
-
*/
|
|
14
|
-
export const checkKInvariantSellingX = (x, y, deltaX, deltaY) => {
|
|
15
|
-
const oldK = natSafeMath.multiply(x.value, y.value);
|
|
16
|
-
const newX = AmountMath.add(x, deltaX);
|
|
17
|
-
const newY = AmountMath.subtract(y, deltaY);
|
|
18
|
-
const newK = natSafeMath.multiply(newX.value, newY.value);
|
|
19
|
-
return oldK <= newK;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* xy <= (x + deltaX)(y - deltaY)
|
|
24
|
-
*
|
|
25
|
-
* @param {Amount<'nat'>} x - the amount of Brand X in pool, xPoolAllocation
|
|
26
|
-
* @param {Amount<'nat'>} y - the amount of Brand Y in pool, yPoolAllocation
|
|
27
|
-
* @param {Amount<'nat'>} deltaX - the amount of Brand X to be added
|
|
28
|
-
* @param {Amount<'nat'>} deltaY - the amount of Brand Y to be taken out
|
|
29
|
-
*/
|
|
30
|
-
export const assertKInvariantSellingX = (x, y, deltaX, deltaY) => {
|
|
31
|
-
checkKInvariantSellingX(x, y, deltaX, deltaY) ||
|
|
32
|
-
Fail`the constant product invariant was violated, with x=${x}, y=${y}, deltaX=${deltaX}, deltaY=${deltaY}, oldK=${natSafeMath.multiply(
|
|
33
|
-
x.value,
|
|
34
|
-
y.value,
|
|
35
|
-
)}, newK=${natSafeMath.multiply(
|
|
36
|
-
AmountMath.add(x, deltaX).value,
|
|
37
|
-
AmountMath.subtract(y, deltaY).value,
|
|
38
|
-
)}`;
|
|
39
|
-
};
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { AmountMath } from '@agoric/ertp';
|
|
2
|
-
import { calculateFees, amountGT } from './calcFees.js';
|
|
3
|
-
|
|
4
|
-
const { Fail } = assert;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The fee might not be in the same brand as the amount. If they are the same,
|
|
8
|
-
* subtract the fee from the amount. Otherwise return the unadjusted amount.
|
|
9
|
-
*
|
|
10
|
-
* We return empty if the fee is larger because an empty amount indicates that
|
|
11
|
-
* the trader didn't place a limit on the inputAmount.
|
|
12
|
-
*
|
|
13
|
-
* @param {Amount<'nat'>} amount
|
|
14
|
-
* @param {Amount<'nat'>} fee
|
|
15
|
-
* @returns {Amount<'nat'>}
|
|
16
|
-
*/
|
|
17
|
-
const subtractRelevantFees = (amount, fee) => {
|
|
18
|
-
if (amount.brand === fee.brand) {
|
|
19
|
-
if (AmountMath.isGTE(fee, amount)) {
|
|
20
|
-
return AmountMath.makeEmptyFromAmount(amount);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return AmountMath.subtract(amount, fee);
|
|
24
|
-
}
|
|
25
|
-
return amount;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* PoolFee and ProtocolFee each identify their brand. If either (or both) match
|
|
30
|
-
* the brand of the Amount, subtract it/them from the amount.
|
|
31
|
-
*
|
|
32
|
-
* @param {Amount<'nat'>} amount
|
|
33
|
-
* @param {FeePair} fee
|
|
34
|
-
* @returns {Amount<'nat'>}
|
|
35
|
-
*/
|
|
36
|
-
const subtractFees = (amount, { poolFee, protocolFee }) => {
|
|
37
|
-
return subtractRelevantFees(
|
|
38
|
-
subtractRelevantFees(amount, protocolFee),
|
|
39
|
-
poolFee,
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The fee might not be in the same brand as the amount. If they are the same,
|
|
45
|
-
* add the fee to the amount. Otherwise return the unadjusted amount.
|
|
46
|
-
*
|
|
47
|
-
* @param {Amount<'nat'>} amount
|
|
48
|
-
* @param {Amount<'nat'>} fee
|
|
49
|
-
* @returns {Amount<'nat'>}
|
|
50
|
-
*/
|
|
51
|
-
const addRelevantFees = (amount, fee) => {
|
|
52
|
-
if (amount.brand === fee.brand) {
|
|
53
|
-
return AmountMath.add(amount, fee);
|
|
54
|
-
}
|
|
55
|
-
return amount;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* PoolFee and ProtocolFee each identify their brand. If either (or both) match
|
|
60
|
-
* the brand of the Amount, add it/them to the amount.
|
|
61
|
-
*
|
|
62
|
-
* @param {Amount<'nat'>} amount
|
|
63
|
-
* @param {FeePair} fee
|
|
64
|
-
* @returns {Amount<'nat'>}
|
|
65
|
-
*/
|
|
66
|
-
const addFees = (amount, { poolFee, protocolFee }) => {
|
|
67
|
-
return addRelevantFees(addRelevantFees(amount, protocolFee), poolFee);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Increment or decrement a pool balance by an amount. The amount's brand might
|
|
72
|
-
* match the Central or Secondary balance of the pool. Return the adjusted
|
|
73
|
-
* balance. The caller knows which amount they provided, so they're expecting a
|
|
74
|
-
* single Amount whose brand matches the amount parameter.
|
|
75
|
-
*
|
|
76
|
-
* The first parameter specifies whether we're incrementing or decrementing from the pool
|
|
77
|
-
*
|
|
78
|
-
* @param {(amountLeft: Amount<any>, amountRight: Amount<any>, brand?: Brand) => Amount<any>} addOrSub
|
|
79
|
-
* @param {PoolAllocation} poolAllocation
|
|
80
|
-
* @param {Amount<'nat'>} amount
|
|
81
|
-
* @returns {Amount<'nat'>}
|
|
82
|
-
*/
|
|
83
|
-
const addOrSubtractFromPool = (addOrSub, poolAllocation, amount) => {
|
|
84
|
-
if (poolAllocation.Central.brand === amount.brand) {
|
|
85
|
-
return addOrSub(poolAllocation.Central, amount);
|
|
86
|
-
} else {
|
|
87
|
-
return addOrSub(poolAllocation.Secondary, amount);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const isGreaterThanZero = amount => {
|
|
92
|
-
return amount && amountGT(amount, AmountMath.makeEmptyFromAmount(amount));
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const assertGreaterThanZero = (amount, name) => {
|
|
96
|
-
(amount && isGreaterThanZero(amount)) ||
|
|
97
|
-
Fail`${name} must be greater than 0: ${amount}`;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const isWantedAvailable = (poolAllocation, amountWanted) => {
|
|
101
|
-
// The question is about a poolAllocation. If it has exactly amountWanted,
|
|
102
|
-
// that's not sufficient, since it would leave the pool empty.
|
|
103
|
-
return amountWanted.brand === poolAllocation.Central.brand
|
|
104
|
-
? !AmountMath.isGTE(amountWanted, poolAllocation.Central)
|
|
105
|
-
: !AmountMath.isGTE(amountWanted, poolAllocation.Secondary);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* We've identified a violation of constraints that means we won't be able to
|
|
110
|
-
* satisfy the user's request. (Not enough funds in the pool, too much was
|
|
111
|
-
* requested, the proceeds would be empty, etc.) Return a result that says no
|
|
112
|
-
* trade will take place and the pool balances won't change.
|
|
113
|
-
*
|
|
114
|
-
* @param {Amount<'nat'>} amountGiven
|
|
115
|
-
* @param {Amount<'nat'>} amountWanted
|
|
116
|
-
* @param {PoolAllocation} poolAllocation
|
|
117
|
-
* @param {Ratio} poolFee
|
|
118
|
-
*/
|
|
119
|
-
const makeNoTransaction = (
|
|
120
|
-
amountGiven,
|
|
121
|
-
amountWanted,
|
|
122
|
-
poolAllocation,
|
|
123
|
-
poolFee,
|
|
124
|
-
) => {
|
|
125
|
-
const emptyGive = AmountMath.makeEmptyFromAmount(amountGiven);
|
|
126
|
-
const emptyWant = AmountMath.makeEmptyFromAmount(amountWanted);
|
|
127
|
-
|
|
128
|
-
let newX;
|
|
129
|
-
let newY;
|
|
130
|
-
if (poolAllocation.Central.brand === amountGiven.brand) {
|
|
131
|
-
newX = poolAllocation.Central;
|
|
132
|
-
newY = poolAllocation.Secondary;
|
|
133
|
-
} else {
|
|
134
|
-
newX = poolAllocation.Secondary;
|
|
135
|
-
newY = poolAllocation.Central;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const result = harden({
|
|
139
|
-
protocolFee: AmountMath.makeEmpty(poolAllocation.Central.brand),
|
|
140
|
-
poolFee: AmountMath.makeEmpty(poolFee.numerator.brand),
|
|
141
|
-
swapperGives: emptyGive,
|
|
142
|
-
swapperGets: emptyWant,
|
|
143
|
-
xIncrement: emptyGive,
|
|
144
|
-
yDecrement: emptyWant,
|
|
145
|
-
newX,
|
|
146
|
-
newY,
|
|
147
|
-
});
|
|
148
|
-
return result;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* This is the heart of the calculation. See README.md for the long explanation.
|
|
153
|
-
* calculate how much should be added to and removed from the pool, the fees,
|
|
154
|
-
* and what the user will pay and receive.
|
|
155
|
-
*
|
|
156
|
-
* As soon as we detect that we won't be able to satisfy the request, we return
|
|
157
|
-
* noTransaction, indicating that no trade should take place. This can be due to
|
|
158
|
-
* a request for more assets than the pool holds, a specified price the current
|
|
159
|
-
* assets won't support, or the trade would require more than the trader allowed,
|
|
160
|
-
* or provide less, or fees would eat up all the trader's proceeds.
|
|
161
|
-
*
|
|
162
|
-
* We start by calculating the amounts that would be traded if no fees were
|
|
163
|
-
* charged. The actual fees are based on these amounts. Once we know the actual
|
|
164
|
-
* fees, we calculate the deltaX and deltaY that will best maintain the
|
|
165
|
-
* constant product invariant.
|
|
166
|
-
*
|
|
167
|
-
* The amounts by which the pool will be adjusted, that the trader will pay and
|
|
168
|
-
* receive, and the fees are then computed based on deltaX and deltaY.
|
|
169
|
-
*
|
|
170
|
-
* @type {InternalSwap}
|
|
171
|
-
*/
|
|
172
|
-
export const swap = (
|
|
173
|
-
amountGiven,
|
|
174
|
-
poolAllocation,
|
|
175
|
-
amountWanted,
|
|
176
|
-
protocolFeeRatio,
|
|
177
|
-
poolFeeRatio,
|
|
178
|
-
swapFn,
|
|
179
|
-
) => {
|
|
180
|
-
const noTransaction = makeNoTransaction(
|
|
181
|
-
amountGiven,
|
|
182
|
-
amountWanted,
|
|
183
|
-
poolAllocation,
|
|
184
|
-
poolFeeRatio,
|
|
185
|
-
);
|
|
186
|
-
assertGreaterThanZero(poolAllocation.Central, 'poolAllocation.Central');
|
|
187
|
-
assertGreaterThanZero(poolAllocation.Secondary, 'poolAllocation.Secondary');
|
|
188
|
-
|
|
189
|
-
if (!isGreaterThanZero(amountGiven) && !isGreaterThanZero(amountWanted)) {
|
|
190
|
-
return noTransaction;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (!isWantedAvailable(poolAllocation, amountWanted)) {
|
|
194
|
-
return noTransaction;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// The protocol fee must always be collected in `Fee`, but the pool
|
|
198
|
-
// fee is collected in the amount opposite of what is specified.
|
|
199
|
-
// This call gives us improved amountIn or amountOut
|
|
200
|
-
const fees = calculateFees(
|
|
201
|
-
amountGiven,
|
|
202
|
-
poolAllocation,
|
|
203
|
-
amountWanted,
|
|
204
|
-
protocolFeeRatio,
|
|
205
|
-
poolFeeRatio,
|
|
206
|
-
swapFn,
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
if (!isWantedAvailable(poolAllocation, addFees(amountWanted, fees))) {
|
|
210
|
-
return noTransaction;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Calculate no-fee amounts. swapFn will only pay attention to the `specified`
|
|
214
|
-
// value. The pool fee is always charged on the unspecified side, so it is an
|
|
215
|
-
// output of the calculation. When the specified value is in `Fee`, the protocol fee will
|
|
216
|
-
// be deducted from amountGiven before adding to the pool or added to
|
|
217
|
-
// amountWanted to calculate amountOut. Otherwise we add the protocol fee
|
|
218
|
-
// to amountWanted.
|
|
219
|
-
const { amountIn, amountOut } = swapFn({
|
|
220
|
-
amountGiven: subtractFees(amountGiven, fees),
|
|
221
|
-
poolAllocation,
|
|
222
|
-
amountWanted: addFees(amountWanted, fees),
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
if (AmountMath.isEmpty(amountOut)) {
|
|
226
|
-
return noTransaction;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// The swapper pays extra or receives less to cover the fees.
|
|
230
|
-
const swapperGives = addFees(amountIn, fees);
|
|
231
|
-
const swapperGets = subtractFees(amountOut, fees);
|
|
232
|
-
|
|
233
|
-
// return noTransaction if fees would eat up all the trader's proceeds,
|
|
234
|
-
// the trader specified an amountGiven, and the trade would require more, or
|
|
235
|
-
// the trade would require them to give more than they specified.
|
|
236
|
-
if (
|
|
237
|
-
AmountMath.isEmpty(swapperGets) ||
|
|
238
|
-
(!AmountMath.isEmpty(amountGiven) && amountGT(swapperGives, amountGiven)) ||
|
|
239
|
-
amountGT(amountWanted, swapperGets)
|
|
240
|
-
) {
|
|
241
|
-
return noTransaction;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const xIncrement = addRelevantFees(amountIn, fees.poolFee);
|
|
245
|
-
const yDecrement = subtractRelevantFees(amountOut, fees.poolFee);
|
|
246
|
-
|
|
247
|
-
// poolFee is the amount the pool will grow over the no-fee calculation.
|
|
248
|
-
// protocolFee is to be separated and sent to an external purse.
|
|
249
|
-
// The swapper amounts are what will be paid and received.
|
|
250
|
-
// xIncrement and yDecrement are what will be added and removed from the pools.
|
|
251
|
-
// Either xIncrement will be increased by the pool fee or yDecrement will be
|
|
252
|
-
// reduced by it in order to compensate the pool.
|
|
253
|
-
// newX and newY are the new pool balances, for comparison with start values.
|
|
254
|
-
const result = harden({
|
|
255
|
-
protocolFee: fees.protocolFee,
|
|
256
|
-
poolFee: fees.poolFee,
|
|
257
|
-
swapperGives,
|
|
258
|
-
swapperGets,
|
|
259
|
-
xIncrement,
|
|
260
|
-
yDecrement,
|
|
261
|
-
newX: addOrSubtractFromPool(AmountMath.add, poolAllocation, xIncrement),
|
|
262
|
-
newY: addOrSubtractFromPool(
|
|
263
|
-
AmountMath.subtract,
|
|
264
|
-
poolAllocation,
|
|
265
|
-
yDecrement,
|
|
266
|
-
),
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
return result;
|
|
270
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @callback Maximum
|
|
3
|
-
* @param {Amount} left
|
|
4
|
-
* @param {Amount} right
|
|
5
|
-
* @returns {Amount}
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A bigint representing a number that will be divided by 10,0000. Financial
|
|
10
|
-
* ratios are often represented in basis points.
|
|
11
|
-
*
|
|
12
|
-
* @typedef {bigint} BASIS_POINTS
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Make a Ratio representing a fee expressed in Basis Points. (hundredths of a
|
|
17
|
-
* percent)
|
|
18
|
-
*
|
|
19
|
-
* @callback MakeFeeRatio
|
|
20
|
-
* @param {BASIS_POINTS} feeBP
|
|
21
|
-
* @param {Brand} brandOfFee
|
|
22
|
-
* @returns {Ratio}
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @callback AmountGT
|
|
27
|
-
* @param {Amount} left
|
|
28
|
-
* @param {Amount} right
|
|
29
|
-
* @returns {boolean}
|
|
30
|
-
*/
|