@agoric/fast-usdc 0.1.1-dev-b78165c.0 → 0.1.1-dev-2af926f.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/package.json +15 -15
- package/src/exos/liquidity-pool.js +19 -31
- package/src/pool-share-math.js +50 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/fast-usdc",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
3
|
+
"version": "0.1.1-dev-2af926f.0+2af926f",
|
|
4
4
|
"description": "CLI and library for Fast USDC product",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"lint:eslint": "eslint ."
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@agoric/swingset-liveslots": "0.10.3-dev-
|
|
26
|
-
"@agoric/vats": "0.15.2-dev-
|
|
27
|
-
"@agoric/zone": "0.2.3-dev-
|
|
25
|
+
"@agoric/swingset-liveslots": "0.10.3-dev-2af926f.0+2af926f",
|
|
26
|
+
"@agoric/vats": "0.15.2-dev-2af926f.0+2af926f",
|
|
27
|
+
"@agoric/zone": "0.2.3-dev-2af926f.0+2af926f",
|
|
28
28
|
"@fast-check/ava": "^2.0.1",
|
|
29
29
|
"ava": "^5.3.0",
|
|
30
30
|
"c8": "^10.1.2",
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"ts-blank-space": "^0.4.4"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@agoric/client-utils": "0.1.1-dev-
|
|
36
|
-
"@agoric/cosmic-proto": "0.4.1-dev-
|
|
37
|
-
"@agoric/ertp": "0.16.3-dev-
|
|
38
|
-
"@agoric/internal": "0.3.3-dev-
|
|
39
|
-
"@agoric/notifier": "0.6.3-dev-
|
|
40
|
-
"@agoric/orchestration": "0.1.1-dev-
|
|
41
|
-
"@agoric/store": "0.9.3-dev-
|
|
42
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
43
|
-
"@agoric/vow": "0.1.1-dev-
|
|
44
|
-
"@agoric/zoe": "0.26.3-dev-
|
|
35
|
+
"@agoric/client-utils": "0.1.1-dev-2af926f.0+2af926f",
|
|
36
|
+
"@agoric/cosmic-proto": "0.4.1-dev-2af926f.0+2af926f",
|
|
37
|
+
"@agoric/ertp": "0.16.3-dev-2af926f.0+2af926f",
|
|
38
|
+
"@agoric/internal": "0.3.3-dev-2af926f.0+2af926f",
|
|
39
|
+
"@agoric/notifier": "0.6.3-dev-2af926f.0+2af926f",
|
|
40
|
+
"@agoric/orchestration": "0.1.1-dev-2af926f.0+2af926f",
|
|
41
|
+
"@agoric/store": "0.9.3-dev-2af926f.0+2af926f",
|
|
42
|
+
"@agoric/vat-data": "0.5.3-dev-2af926f.0+2af926f",
|
|
43
|
+
"@agoric/vow": "0.1.1-dev-2af926f.0+2af926f",
|
|
44
|
+
"@agoric/zoe": "0.26.3-dev-2af926f.0+2af926f",
|
|
45
45
|
"@cosmjs/proto-signing": "^0.32.4",
|
|
46
46
|
"@cosmjs/stargate": "^0.32.4",
|
|
47
47
|
"@endo/base64": "^1.0.9",
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"publishConfig": {
|
|
82
82
|
"access": "public"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "2af926fa985109a5612811edab6708b4fb1fcfe3"
|
|
85
85
|
}
|
|
@@ -8,6 +8,7 @@ import { M } from '@endo/patterns';
|
|
|
8
8
|
import { Fail, q } from '@endo/errors';
|
|
9
9
|
import {
|
|
10
10
|
borrowCalc,
|
|
11
|
+
checkPoolBalance,
|
|
11
12
|
depositCalc,
|
|
12
13
|
makeParity,
|
|
13
14
|
repayCalc,
|
|
@@ -29,32 +30,7 @@ import {
|
|
|
29
30
|
* @import {PoolStats} from '../types.js';
|
|
30
31
|
*/
|
|
31
32
|
|
|
32
|
-
const { add,
|
|
33
|
-
|
|
34
|
-
/** @param {Brand} brand */
|
|
35
|
-
const makeDust = brand => AmountMath.make(brand, 1n);
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Verifies that the total pool balance (unencumbered + encumbered) matches the
|
|
39
|
-
* shareWorth numerator. The total pool balance consists of:
|
|
40
|
-
* 1. unencumbered balance - USDC available in the pool for borrowing
|
|
41
|
-
* 2. encumbered balance - USDC currently lent out
|
|
42
|
-
*
|
|
43
|
-
* A negligible `dust` amount is used to initialize shareWorth with a non-zero
|
|
44
|
-
* denominator. It must remain in the pool at all times.
|
|
45
|
-
*
|
|
46
|
-
* @param {ZCFSeat} poolSeat
|
|
47
|
-
* @param {ShareWorth} shareWorth
|
|
48
|
-
* @param {Brand} USDC
|
|
49
|
-
* @param {Amount<'nat'>} encumberedBalance
|
|
50
|
-
*/
|
|
51
|
-
const checkPoolBalance = (poolSeat, shareWorth, USDC, encumberedBalance) => {
|
|
52
|
-
const unencumberedBalance = poolSeat.getAmountAllocated('USDC', USDC);
|
|
53
|
-
const dust = makeDust(USDC);
|
|
54
|
-
const grossBalance = add(add(unencumberedBalance, dust), encumberedBalance);
|
|
55
|
-
isEqual(grossBalance, shareWorth.numerator) ||
|
|
56
|
-
Fail`🚨 pool balance ${q(unencumberedBalance)} and encumbered balance ${q(encumberedBalance)} inconsistent with shareWorth ${q(shareWorth)}`;
|
|
57
|
-
};
|
|
33
|
+
const { add, isGTE, makeEmpty } = AmountMath;
|
|
58
34
|
|
|
59
35
|
/**
|
|
60
36
|
* @typedef {{
|
|
@@ -127,7 +103,7 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
|
|
|
127
103
|
(shareMint, node) => {
|
|
128
104
|
const { brand: PoolShares } = shareMint.getIssuerRecord();
|
|
129
105
|
const proposalShapes = makeProposalShapes({ USDC, PoolShares });
|
|
130
|
-
const shareWorth = makeParity(
|
|
106
|
+
const shareWorth = makeParity(USDC, PoolShares);
|
|
131
107
|
const { zcfSeat: poolSeat } = zcf.makeEmptySeatKit();
|
|
132
108
|
const { zcfSeat: feeSeat } = zcf.makeEmptySeatKit();
|
|
133
109
|
const poolMetricsRecorderKit = tools.makeRecorderKit(
|
|
@@ -215,7 +191,11 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
|
|
|
215
191
|
poolStats,
|
|
216
192
|
shareWorth,
|
|
217
193
|
} = this.state;
|
|
218
|
-
checkPoolBalance(
|
|
194
|
+
checkPoolBalance(
|
|
195
|
+
poolSeat.getCurrentAllocation(),
|
|
196
|
+
shareWorth,
|
|
197
|
+
encumberedBalance,
|
|
198
|
+
);
|
|
219
199
|
|
|
220
200
|
const fromSeatAllocation = fromSeat.getCurrentAllocation();
|
|
221
201
|
// Validate allocation equals amounts and Principal <= encumberedBalance
|
|
@@ -272,7 +252,11 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
|
|
|
272
252
|
/** @type {USDCProposalShapes['deposit']} */
|
|
273
253
|
// @ts-expect-error ensured by proposalShape
|
|
274
254
|
const proposal = lp.getProposal();
|
|
275
|
-
checkPoolBalance(
|
|
255
|
+
checkPoolBalance(
|
|
256
|
+
poolSeat.getCurrentAllocation(),
|
|
257
|
+
shareWorth,
|
|
258
|
+
encumberedBalance,
|
|
259
|
+
);
|
|
276
260
|
const post = depositCalc(shareWorth, proposal);
|
|
277
261
|
|
|
278
262
|
// COMMIT POINT
|
|
@@ -308,8 +292,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
|
|
|
308
292
|
// @ts-expect-error ensured by proposalShape
|
|
309
293
|
const proposal = lp.getProposal();
|
|
310
294
|
const { zcfSeat: burn } = zcf.makeEmptySeatKit();
|
|
311
|
-
|
|
312
|
-
|
|
295
|
+
const post = withdrawCalc(
|
|
296
|
+
shareWorth,
|
|
297
|
+
proposal,
|
|
298
|
+
poolSeat.getCurrentAllocation(),
|
|
299
|
+
encumberedBalance,
|
|
300
|
+
);
|
|
313
301
|
|
|
314
302
|
// COMMIT POINT
|
|
315
303
|
try {
|
package/src/pool-share-math.js
CHANGED
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
} from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
8
8
|
import { Fail, q } from '@endo/errors';
|
|
9
9
|
|
|
10
|
-
const {
|
|
10
|
+
const { keys } = Object;
|
|
11
|
+
const { add, isEmpty, isEqual, isGTE, make, makeEmpty, subtract } = AmountMath;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @import {Amount, Brand, DepositFacet, NatValue, Payment} from '@agoric/ertp';
|
|
@@ -18,8 +19,7 @@ const { getValue, add, isEmpty, isEqual, isGTE, subtract } = AmountMath;
|
|
|
18
19
|
/**
|
|
19
20
|
* Invariant: shareWorth is the pool balance divided by shares outstanding.
|
|
20
21
|
*
|
|
21
|
-
* Use `makeParity(
|
|
22
|
-
* value, for some negligible `epsilon` such as 1n.
|
|
22
|
+
* Use `makeParity(USDC, PoolShares)` for an initial value.
|
|
23
23
|
*
|
|
24
24
|
* @typedef {Ratio} ShareWorth
|
|
25
25
|
*/
|
|
@@ -27,12 +27,12 @@ const { getValue, add, isEmpty, isEqual, isGTE, subtract } = AmountMath;
|
|
|
27
27
|
/**
|
|
28
28
|
* Make a 1-to-1 ratio between amounts of 2 brands.
|
|
29
29
|
*
|
|
30
|
-
* @param {
|
|
30
|
+
* @param {Brand<'nat'>} numeratorBrand
|
|
31
31
|
* @param {Brand<'nat'>} denominatorBrand
|
|
32
32
|
*/
|
|
33
|
-
export const makeParity = (
|
|
34
|
-
const
|
|
35
|
-
return makeRatio(
|
|
33
|
+
export const makeParity = (numeratorBrand, denominatorBrand) => {
|
|
34
|
+
const dust = 1n;
|
|
35
|
+
return makeRatio(dust, numeratorBrand, dust, denominatorBrand);
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -95,14 +95,54 @@ export const depositCalc = (shareWorth, { give, want }) => {
|
|
|
95
95
|
});
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Verifies that the total pool balance (unencumbered + encumbered) matches the
|
|
100
|
+
* shareWorth numerator. The total pool balance consists of:
|
|
101
|
+
* 1. unencumbered balance - USDC available in the pool for borrowing
|
|
102
|
+
* 2. encumbered balance - USDC currently lent out
|
|
103
|
+
*
|
|
104
|
+
* A negligible `dust` amount is used to initialize shareWorth with a non-zero
|
|
105
|
+
* denominator. It must remain in the pool at all times.
|
|
106
|
+
*
|
|
107
|
+
* @param {Allocation} poolAlloc
|
|
108
|
+
* @param {ShareWorth} shareWorth
|
|
109
|
+
* @param {Amount<'nat'>} encumberedBalance
|
|
110
|
+
*/
|
|
111
|
+
export const checkPoolBalance = (poolAlloc, shareWorth, encumberedBalance) => {
|
|
112
|
+
const { brand: usdcBrand } = encumberedBalance;
|
|
113
|
+
const unencumberedBalance = poolAlloc.USDC || makeEmpty(usdcBrand);
|
|
114
|
+
const kwds = keys(poolAlloc);
|
|
115
|
+
kwds.length === 0 ||
|
|
116
|
+
(kwds.length === 1 && kwds[0] === 'USDC') ||
|
|
117
|
+
Fail`unexpected pool allocations: ${poolAlloc}`;
|
|
118
|
+
const dust = make(usdcBrand, 1n);
|
|
119
|
+
const grossBalance = add(add(unencumberedBalance, dust), encumberedBalance);
|
|
120
|
+
isEqual(grossBalance, shareWorth.numerator) ||
|
|
121
|
+
Fail`🚨 pool balance ${q(unencumberedBalance)} and encumbered balance ${q(encumberedBalance)} inconsistent with shareWorth ${q(shareWorth)}`;
|
|
122
|
+
return harden({ unencumberedBalance, grossBalance });
|
|
123
|
+
};
|
|
124
|
+
|
|
98
125
|
/**
|
|
99
126
|
* Compute payout from a withdraw proposal, along with updated shareWorth
|
|
100
127
|
*
|
|
101
128
|
* @param {ShareWorth} shareWorth
|
|
102
129
|
* @param {USDCProposalShapes['withdraw']} proposal
|
|
130
|
+
* @param {Allocation} poolAlloc
|
|
131
|
+
* @param {Amount<'nat'>} [encumberedBalance]
|
|
103
132
|
* @returns {{ shareWorth: ShareWorth, payouts: { USDC: Amount<'nat'> }}}
|
|
104
133
|
*/
|
|
105
|
-
export const withdrawCalc = (
|
|
134
|
+
export const withdrawCalc = (
|
|
135
|
+
shareWorth,
|
|
136
|
+
{ give, want },
|
|
137
|
+
poolAlloc,
|
|
138
|
+
encumberedBalance = makeEmpty(shareWorth.numerator.brand),
|
|
139
|
+
) => {
|
|
140
|
+
const { unencumberedBalance } = checkPoolBalance(
|
|
141
|
+
poolAlloc,
|
|
142
|
+
shareWorth,
|
|
143
|
+
encumberedBalance,
|
|
144
|
+
);
|
|
145
|
+
|
|
106
146
|
assert(!isEmpty(give.PoolShare));
|
|
107
147
|
assert(!isEmpty(want.USDC));
|
|
108
148
|
|
|
@@ -112,6 +152,8 @@ export const withdrawCalc = (shareWorth, { give, want }) => {
|
|
|
112
152
|
const { denominator: sharesOutstanding, numerator: poolBalance } = shareWorth;
|
|
113
153
|
!isGTE(want.USDC, poolBalance) ||
|
|
114
154
|
Fail`cannot withdraw ${q(want.USDC)}; only ${q(poolBalance)} in pool`;
|
|
155
|
+
isGTE(unencumberedBalance, want.USDC) ||
|
|
156
|
+
Fail`cannot withdraw ${q(want.USDC)}; ${q(encumberedBalance)} is in use; stand by for pool to return to ${q(poolBalance)}`;
|
|
115
157
|
const balancePost = subtract(poolBalance, payout);
|
|
116
158
|
// giving more shares than are outstanding is impossible,
|
|
117
159
|
// so it's not worth a custom diagnostic. subtract will fail
|