@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/fast-usdc",
3
- "version": "0.1.1-dev-b78165c.0+b78165c",
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-b78165c.0+b78165c",
26
- "@agoric/vats": "0.15.2-dev-b78165c.0+b78165c",
27
- "@agoric/zone": "0.2.3-dev-b78165c.0+b78165c",
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-b78165c.0+b78165c",
36
- "@agoric/cosmic-proto": "0.4.1-dev-b78165c.0+b78165c",
37
- "@agoric/ertp": "0.16.3-dev-b78165c.0+b78165c",
38
- "@agoric/internal": "0.3.3-dev-b78165c.0+b78165c",
39
- "@agoric/notifier": "0.6.3-dev-b78165c.0+b78165c",
40
- "@agoric/orchestration": "0.1.1-dev-b78165c.0+b78165c",
41
- "@agoric/store": "0.9.3-dev-b78165c.0+b78165c",
42
- "@agoric/vat-data": "0.5.3-dev-b78165c.0+b78165c",
43
- "@agoric/vow": "0.1.1-dev-b78165c.0+b78165c",
44
- "@agoric/zoe": "0.26.3-dev-b78165c.0+b78165c",
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": "b78165cebb22ad74ee7053e448f1e0df7f6fa4bd"
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, isEqual, isGTE, makeEmpty } = AmountMath;
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(makeDust(USDC), PoolShares);
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(poolSeat, shareWorth, USDC, encumberedBalance);
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(poolSeat, shareWorth, USDC, encumberedBalance);
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
- checkPoolBalance(poolSeat, shareWorth, USDC, encumberedBalance);
312
- const post = withdrawCalc(shareWorth, proposal);
295
+ const post = withdrawCalc(
296
+ shareWorth,
297
+ proposal,
298
+ poolSeat.getCurrentAllocation(),
299
+ encumberedBalance,
300
+ );
313
301
 
314
302
  // COMMIT POINT
315
303
  try {
@@ -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 { getValue, add, isEmpty, isEqual, isGTE, subtract } = AmountMath;
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(make(USDC, epsilon), PoolShares)` for an initial
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 {Amount<'nat'>} numerator
30
+ * @param {Brand<'nat'>} numeratorBrand
31
31
  * @param {Brand<'nat'>} denominatorBrand
32
32
  */
33
- export const makeParity = (numerator, denominatorBrand) => {
34
- const value = getValue(numerator.brand, numerator);
35
- return makeRatio(value, numerator.brand, value, denominatorBrand);
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 = (shareWorth, { give, want }) => {
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