@agoric/fast-usdc 0.1.1-dev-059601c.0 → 0.1.1-dev-4feddb0.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-059601c.0+059601c",
3
+ "version": "0.1.1-dev-4feddb0.0+4feddb0",
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-059601c.0+059601c",
26
- "@agoric/vats": "0.15.2-dev-059601c.0+059601c",
27
- "@agoric/zone": "0.2.3-dev-059601c.0+059601c",
25
+ "@agoric/swingset-liveslots": "0.10.3-dev-4feddb0.0+4feddb0",
26
+ "@agoric/vats": "0.15.2-dev-4feddb0.0+4feddb0",
27
+ "@agoric/zone": "0.2.3-dev-4feddb0.0+4feddb0",
28
28
  "@fast-check/ava": "^2.0.1",
29
29
  "ava": "^5.3.0",
30
30
  "c8": "^10.1.2",
@@ -32,15 +32,15 @@
32
32
  "ts-blank-space": "^0.4.4"
33
33
  },
34
34
  "dependencies": {
35
- "@agoric/client-utils": "0.1.1-dev-059601c.0+059601c",
36
- "@agoric/ertp": "0.16.3-dev-059601c.0+059601c",
37
- "@agoric/internal": "0.3.3-dev-059601c.0+059601c",
38
- "@agoric/notifier": "0.6.3-dev-059601c.0+059601c",
39
- "@agoric/orchestration": "0.1.1-dev-059601c.0+059601c",
40
- "@agoric/store": "0.9.3-dev-059601c.0+059601c",
41
- "@agoric/vat-data": "0.5.3-dev-059601c.0+059601c",
42
- "@agoric/vow": "0.1.1-dev-059601c.0+059601c",
43
- "@agoric/zoe": "0.26.3-dev-059601c.0+059601c",
35
+ "@agoric/client-utils": "0.1.1-dev-4feddb0.0+4feddb0",
36
+ "@agoric/ertp": "0.16.3-dev-4feddb0.0+4feddb0",
37
+ "@agoric/internal": "0.3.3-dev-4feddb0.0+4feddb0",
38
+ "@agoric/notifier": "0.6.3-dev-4feddb0.0+4feddb0",
39
+ "@agoric/orchestration": "0.1.1-dev-4feddb0.0+4feddb0",
40
+ "@agoric/store": "0.9.3-dev-4feddb0.0+4feddb0",
41
+ "@agoric/vat-data": "0.5.3-dev-4feddb0.0+4feddb0",
42
+ "@agoric/vow": "0.1.1-dev-4feddb0.0+4feddb0",
43
+ "@agoric/zoe": "0.26.3-dev-4feddb0.0+4feddb0",
44
44
  "@cosmjs/proto-signing": "^0.32.4",
45
45
  "@cosmjs/stargate": "^0.32.4",
46
46
  "@endo/base64": "^1.0.9",
@@ -80,5 +80,5 @@
80
80
  "publishConfig": {
81
81
  "access": "public"
82
82
  },
83
- "gitHead": "059601c7e5961085634c8553c4998dc9043e1792"
83
+ "gitHead": "4feddb0e0fbdf2343622c7424c6e6d3de013c85d"
84
84
  }
@@ -3,7 +3,6 @@ import { assertAllDefined, makeTracer } from '@agoric/internal';
3
3
  import { AnyNatAmountShape, ChainAddressShape } from '@agoric/orchestration';
4
4
  import { pickFacet } from '@agoric/vat-data';
5
5
  import { VowShape } from '@agoric/vow';
6
- import { q } from '@endo/errors';
7
6
  import { E } from '@endo/far';
8
7
  import { M } from '@endo/patterns';
9
8
  import {
@@ -153,6 +152,7 @@ export const prepareAdvancerKit = (
153
152
  recipientAddress,
154
153
  EudParamShape,
155
154
  );
155
+ log(`decoded EUD: ${EUD}`);
156
156
  // throws if the bech32 prefix is not found
157
157
  const destination = chainHub.makeChainAddress(EUD);
158
158
 
@@ -161,9 +161,8 @@ export const prepareAdvancerKit = (
161
161
  const advanceAmount = feeTools.calculateAdvance(fullAmount);
162
162
 
163
163
  const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit();
164
- const amountKWR = harden({ USDC: advanceAmount });
165
164
  // throws if the pool has insufficient funds
166
- borrowerFacet.borrow(tmpSeat, amountKWR);
165
+ borrowerFacet.borrow(tmpSeat, advanceAmount);
167
166
 
168
167
  // this cannot throw since `.isSeen()` is called in the same turn
169
168
  statusManager.advance(evidence);
@@ -172,7 +171,7 @@ export const prepareAdvancerKit = (
172
171
  tmpSeat,
173
172
  // @ts-expect-error LocalAccountMethods vs OrchestrationAccount
174
173
  poolAccount,
175
- amountKWR,
174
+ harden({ USDC: advanceAmount }),
176
175
  );
177
176
  void watch(depositV, this.facets.depositHandler, {
178
177
  fullAmount,
@@ -182,8 +181,8 @@ export const prepareAdvancerKit = (
182
181
  tmpSeat,
183
182
  txHash: evidence.txHash,
184
183
  });
185
- } catch (e) {
186
- log('Advancer error:', q(e).toString());
184
+ } catch (error) {
185
+ log('Advancer error:', error);
187
186
  statusManager.observe(evidence);
188
187
  }
189
188
  },
@@ -212,18 +211,28 @@ export const prepareAdvancerKit = (
212
211
  });
213
212
  },
214
213
  /**
214
+ * We do not expect this to be a common failure. it should only occur
215
+ * if USDC is not registered in vbank or the tmpSeat has less than
216
+ * `advanceAmount`.
217
+ *
218
+ * If we do hit this path, we return funds to the Liquidity Pool and
219
+ * notify of Advancing failure.
220
+ *
215
221
  * @param {Error} error
216
222
  * @param {AdvancerVowCtx & { tmpSeat: ZCFSeat }} ctx
217
223
  */
218
- onRejected(error, { tmpSeat }) {
219
- // TODO return seat allocation from ctx to LP?
220
- log('🚨 advance deposit failed', q(error).toString());
221
- // TODO #10510 (comprehensive error testing) determine
222
- // course of action here
224
+ onRejected(error, { tmpSeat, advanceAmount, ...restCtx }) {
223
225
  log(
224
- 'TODO live payment on seat to return to LP',
225
- q(tmpSeat).toString(),
226
+ '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP',
227
+ error,
226
228
  );
229
+ try {
230
+ const { borrowerFacet, notifyFacet } = this.state;
231
+ notifyFacet.notifyAdvancingResult(restCtx, false);
232
+ borrowerFacet.returnToPool(tmpSeat, advanceAmount);
233
+ } catch (e) {
234
+ log('🚨 deposit to localOrchAccount failure recovery failed', e);
235
+ }
227
236
  },
228
237
  },
229
238
  transferHandler: {
@@ -234,10 +243,11 @@ export const prepareAdvancerKit = (
234
243
  onFulfilled(result, ctx) {
235
244
  const { notifyFacet } = this.state;
236
245
  const { advanceAmount, destination, ...detail } = ctx;
237
- log(
238
- 'Advance transfer fulfilled',
239
- q({ advanceAmount, destination, result }).toString(),
240
- );
246
+ log('Advance transfer fulfilled', {
247
+ advanceAmount,
248
+ destination,
249
+ result,
250
+ });
241
251
  // During development, due to a bug, this call threw.
242
252
  // The failure was silent (no diagnostics) due to:
243
253
  // - #10576 Vows do not report unhandled rejections
@@ -252,7 +262,7 @@ export const prepareAdvancerKit = (
252
262
  */
253
263
  onRejected(error, ctx) {
254
264
  const { notifyFacet } = this.state;
255
- log('Advance transfer rejected', q(error).toString());
265
+ log('Advance transfer rejected', error);
256
266
  notifyFacet.notifyAdvancingResult(ctx, false);
257
267
  },
258
268
  },
@@ -28,7 +28,7 @@ import {
28
28
  * @import {PoolStats} from '../types.js';
29
29
  */
30
30
 
31
- const { add, isEqual, makeEmpty } = AmountMath;
31
+ const { add, isEqual, isGTE, makeEmpty } = AmountMath;
32
32
 
33
33
  /** @param {Brand} brand */
34
34
  const makeDust = brand => AmountMath.make(brand, 1n);
@@ -84,10 +84,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
84
84
  'Liquidity Pool',
85
85
  {
86
86
  borrower: M.interface('borrower', {
87
- borrow: M.call(
88
- SeatShape,
89
- harden({ USDC: makeNatAmountShape(USDC, 1n) }),
90
- ).returns(),
87
+ borrow: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(),
88
+ returnToPool: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(),
91
89
  }),
92
90
  repayer: M.interface('repayer', {
93
91
  repay: M.call(
@@ -153,32 +151,48 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
153
151
  borrower: {
154
152
  /**
155
153
  * @param {ZCFSeat} toSeat
156
- * @param {{ USDC: Amount<'nat'>}} amountKWR
154
+ * @param {Amount<'nat'>} amount
157
155
  */
158
- borrow(toSeat, amountKWR) {
156
+ borrow(toSeat, amount) {
159
157
  const { encumberedBalance, poolSeat, poolStats } = this.state;
160
158
 
161
159
  // Validate amount is available in pool
162
160
  const post = borrowCalc(
163
- amountKWR.USDC,
161
+ amount,
164
162
  poolSeat.getAmountAllocated('USDC', USDC),
165
163
  encumberedBalance,
166
164
  poolStats,
167
165
  );
168
166
 
169
167
  // COMMIT POINT
170
- try {
171
- zcf.atomicRearrange(harden([[poolSeat, toSeat, amountKWR]]));
172
- } catch (cause) {
173
- const reason = Error('🚨 cannot commit borrow', { cause });
174
- console.error(reason.message, cause);
175
- zcf.shutdownWithFailure(reason);
176
- }
168
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
169
+ zcf.atomicRearrange(harden([[poolSeat, toSeat, { USDC: amount }]]));
177
170
 
178
171
  Object.assign(this.state, post);
179
172
  this.facets.external.publishPoolMetrics();
180
173
  },
181
- // TODO method to repay failed `LOA.deposit()`
174
+ /**
175
+ * If something fails during advance, return funds to the pool.
176
+ *
177
+ * @param {ZCFSeat} borrowSeat
178
+ * @param {Amount<'nat'>} amount
179
+ */
180
+ returnToPool(borrowSeat, amount) {
181
+ const { zcfSeat: repaySeat } = zcf.makeEmptySeatKit();
182
+ const returnAmounts = harden({
183
+ Principal: amount,
184
+ PoolFee: makeEmpty(USDC),
185
+ ContractFee: makeEmpty(USDC),
186
+ });
187
+ const borrowSeatAllocation = borrowSeat.getCurrentAllocation();
188
+ isGTE(borrowSeatAllocation.USDC, amount) ||
189
+ Fail`⚠️ borrowSeatAllocation ${q(borrowSeatAllocation)} less than amountKWR ${q(amount)}`;
190
+ // arrange payments in a format repay is expecting
191
+ zcf.atomicRearrange(
192
+ harden([[borrowSeat, repaySeat, { USDC: amount }, returnAmounts]]),
193
+ );
194
+ return this.facets.repayer.repay(repaySeat, returnAmounts);
195
+ },
182
196
  },
183
197
  repayer: {
184
198
  /**
@@ -208,23 +222,18 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
208
222
  const { ContractFee, ...rest } = amounts;
209
223
 
210
224
  // COMMIT POINT
211
- try {
212
- zcf.atomicRearrange(
213
- harden([
214
- [
215
- fromSeat,
216
- poolSeat,
217
- rest,
218
- { USDC: add(amounts.PoolFee, amounts.Principal) },
219
- ],
220
- [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }],
221
- ]),
222
- );
223
- } catch (cause) {
224
- const reason = Error('🚨 cannot commit repay', { cause });
225
- console.error(reason.message, cause);
226
- zcf.shutdownWithFailure(reason);
227
- }
225
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
226
+ zcf.atomicRearrange(
227
+ harden([
228
+ [
229
+ fromSeat,
230
+ poolSeat,
231
+ rest,
232
+ { USDC: add(amounts.PoolFee, amounts.Principal) },
233
+ ],
234
+ [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }],
235
+ ]),
236
+ );
228
237
 
229
238
  Object.assign(this.state, post);
230
239
  this.facets.external.publishPoolMetrics();
@@ -259,9 +268,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
259
268
  const post = depositCalc(shareWorth, proposal);
260
269
 
261
270
  // COMMIT POINT
262
-
271
+ const mint = shareMint.mintGains(post.payouts);
263
272
  try {
264
- const mint = shareMint.mintGains(post.payouts);
265
273
  this.state.shareWorth = post.shareWorth;
266
274
  zcf.atomicRearrange(
267
275
  harden([
@@ -271,12 +279,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
271
279
  [mint, lp, post.payouts],
272
280
  ]),
273
281
  );
282
+ } catch (cause) {
283
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
284
+ throw new Error('🚨 cannot commit deposit', { cause });
285
+ } finally {
274
286
  lp.exit();
275
287
  mint.exit();
276
- } catch (cause) {
277
- const reason = Error('🚨 cannot commit deposit', { cause });
278
- console.error(reason.message, cause);
279
- zcf.shutdownWithFailure(reason);
280
288
  }
281
289
  external.publishPoolMetrics();
282
290
  },
@@ -296,7 +304,6 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
296
304
  const post = withdrawCalc(shareWorth, proposal);
297
305
 
298
306
  // COMMIT POINT
299
-
300
307
  try {
301
308
  this.state.shareWorth = post.shareWorth;
302
309
  zcf.atomicRearrange(
@@ -308,12 +315,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
308
315
  ]),
309
316
  );
310
317
  shareMint.burnLosses(proposal.give, burn);
318
+ } catch (cause) {
319
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
320
+ throw new Error('🚨 cannot commit withdraw', { cause });
321
+ } finally {
311
322
  lp.exit();
312
323
  burn.exit();
313
- } catch (cause) {
314
- const reason = Error('🚨 cannot commit withdraw', { cause });
315
- console.error(reason.message, cause);
316
- zcf.shutdownWithFailure(reason);
317
324
  }
318
325
  external.publishPoolMetrics();
319
326
  },
@@ -237,13 +237,13 @@ export const prepareSettler = (
237
237
  const split = calculateSplit(received);
238
238
  log('disbursing', split);
239
239
 
240
- // TODO: what if this throws?
241
- // arguably, it cannot. Even if deposits
242
- // and notifications get out of order,
243
- // we don't ever withdraw more than has been deposited.
240
+ // If this throws, which arguably can't occur since we don't ever
241
+ // withdraw more than has been deposited (as denoted by
242
+ // `FungibleTokenPacketData`), funds will remain in the
243
+ // `settlementAccount`. A remediation can occur in a future upgrade.
244
244
  await vowTools.when(
245
245
  withdrawToSeat(
246
- // @ts-expect-error Vow vs. Promise stuff. TODO: is this OK???
246
+ // @ts-expect-error LocalAccountMethods vs OrchestrationAccount
247
247
  settlementAccount,
248
248
  settlingSeat,
249
249
  harden({ In: received }),