@agoric/fast-usdc 0.1.1-dev-35cb8ca.0 → 0.1.1-dev-83c2ebd.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-35cb8ca.0+35cb8ca",
3
+ "version": "0.1.1-dev-83c2ebd.0+83c2ebd",
4
4
  "description": "CLI and library for Fast USDC product",
5
5
  "type": "module",
6
6
  "files": [
@@ -23,9 +23,9 @@
23
23
  "lint:eslint": "eslint ."
24
24
  },
25
25
  "devDependencies": {
26
- "@agoric/swingset-liveslots": "0.10.3-dev-35cb8ca.0+35cb8ca",
27
- "@agoric/vats": "0.15.2-dev-35cb8ca.0+35cb8ca",
28
- "@agoric/zone": "0.2.3-dev-35cb8ca.0+35cb8ca",
26
+ "@agoric/swingset-liveslots": "0.10.3-dev-83c2ebd.0+83c2ebd",
27
+ "@agoric/vats": "0.15.2-dev-83c2ebd.0+83c2ebd",
28
+ "@agoric/zone": "0.2.3-dev-83c2ebd.0+83c2ebd",
29
29
  "@fast-check/ava": "^2.0.1",
30
30
  "ava": "^5.3.0",
31
31
  "c8": "^10.1.2",
@@ -33,16 +33,16 @@
33
33
  "ts-blank-space": "^0.4.4"
34
34
  },
35
35
  "dependencies": {
36
- "@agoric/client-utils": "0.1.1-dev-35cb8ca.0+35cb8ca",
37
- "@agoric/cosmic-proto": "0.4.1-dev-35cb8ca.0+35cb8ca",
38
- "@agoric/ertp": "0.16.3-dev-35cb8ca.0+35cb8ca",
39
- "@agoric/internal": "0.3.3-dev-35cb8ca.0+35cb8ca",
40
- "@agoric/notifier": "0.6.3-dev-35cb8ca.0+35cb8ca",
41
- "@agoric/orchestration": "0.1.1-dev-35cb8ca.0+35cb8ca",
42
- "@agoric/store": "0.9.3-dev-35cb8ca.0+35cb8ca",
43
- "@agoric/vat-data": "0.5.3-dev-35cb8ca.0+35cb8ca",
44
- "@agoric/vow": "0.1.1-dev-35cb8ca.0+35cb8ca",
45
- "@agoric/zoe": "0.26.3-dev-35cb8ca.0+35cb8ca",
36
+ "@agoric/client-utils": "0.1.1-dev-83c2ebd.0+83c2ebd",
37
+ "@agoric/cosmic-proto": "0.4.1-dev-83c2ebd.0+83c2ebd",
38
+ "@agoric/ertp": "0.16.3-dev-83c2ebd.0+83c2ebd",
39
+ "@agoric/internal": "0.3.3-dev-83c2ebd.0+83c2ebd",
40
+ "@agoric/notifier": "0.6.3-dev-83c2ebd.0+83c2ebd",
41
+ "@agoric/orchestration": "0.1.1-dev-83c2ebd.0+83c2ebd",
42
+ "@agoric/store": "0.9.3-dev-83c2ebd.0+83c2ebd",
43
+ "@agoric/vat-data": "0.5.3-dev-83c2ebd.0+83c2ebd",
44
+ "@agoric/vow": "0.1.1-dev-83c2ebd.0+83c2ebd",
45
+ "@agoric/zoe": "0.26.3-dev-83c2ebd.0+83c2ebd",
46
46
  "@cosmjs/proto-signing": "^0.32.4",
47
47
  "@cosmjs/stargate": "^0.32.4",
48
48
  "@endo/base64": "^1.0.9",
@@ -82,5 +82,5 @@
82
82
  "publishConfig": {
83
83
  "access": "public"
84
84
  },
85
- "gitHead": "35cb8caa621416371d94b570762804e703a23461"
85
+ "gitHead": "83c2ebdab859d3ac8365e2b7237e055360bd0536"
86
86
  }
package/src/cli/cli.js CHANGED
@@ -13,7 +13,7 @@ import { addConfigCommands } from './config-commands.js';
13
13
  import { addOperatorCommands } from './operator-commands.js';
14
14
  import * as configLib from './config.js';
15
15
  import transferLib from './transfer.js';
16
- import { makeFile } from '../util/file.js';
16
+ import { makeFile } from './util/file.js';
17
17
  import { addLPCommands } from './lp-commands.js';
18
18
 
19
19
  const packageJson = JSON.parse(
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @import {Command} from 'commander';
3
- * @import {File} from '../util/file.js';
3
+ * @import {File} from './util/file.js';
4
4
  * @import * as ConfigHelpers from './config.js';
5
5
  */
6
6
  /**
package/src/cli/config.js CHANGED
@@ -23,7 +23,7 @@ import { stdin as input, stdout as output } from 'node:process';
23
23
  }} ConfigOpts
24
24
  */
25
25
 
26
- /** @import { File } from '../util/file' */
26
+ /** @import { File } from './util/file' */
27
27
 
28
28
  export const init = async (
29
29
  /** @type {File} */ configFile,
@@ -7,16 +7,16 @@ import {
7
7
  pickEndpoint,
8
8
  } from '@agoric/client-utils';
9
9
  import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
10
- import { queryFastUSDCLocalChainAccount } from '../util/agoric.js';
11
- import { depositForBurn, makeProvider } from '../util/cctp.js';
10
+ import { queryFastUSDCLocalChainAccount } from './util/agoric.js';
11
+ import { depositForBurn, makeProvider } from './util/cctp.js';
12
12
  import {
13
13
  makeSigner,
14
14
  queryForwardingAccount,
15
15
  registerFwdAccount,
16
- } from '../util/noble.js';
17
- import { queryUSDCBalance } from '../util/bank.js';
16
+ } from './util/noble.js';
17
+ import { queryUSDCBalance } from './util/bank.js';
18
18
 
19
- /** @import { File } from '../util/file' */
19
+ /** @import { File } from './util/file' */
20
20
  /** @import { VStorage } from '@agoric/client-utils' */
21
21
  /** @import { SigningStargateClient } from '@cosmjs/stargate' */
22
22
  /** @import { JsonRpcProvider as ethProvider } from 'ethers' */
@@ -81,6 +81,14 @@ const AdvancerKitI = harden({
81
81
  * }} AdvancerVowCtx
82
82
  */
83
83
 
84
+ export const stateShape = harden({
85
+ notifier: M.remotable(),
86
+ borrower: M.remotable(),
87
+ poolAccount: M.remotable(),
88
+ intermediateRecipient: M.opt(ChainAddressShape),
89
+ settlementAddress: M.opt(ChainAddressShape),
90
+ });
91
+
84
92
  /**
85
93
  * @param {Zone} zone
86
94
  * @param {AdvancerKitPowers} caps
@@ -114,8 +122,8 @@ export const prepareAdvancerKit = (
114
122
  AdvancerKitI,
115
123
  /**
116
124
  * @param {{
117
- * notifyFacet: import('./settler.js').SettlerKit['notify'];
118
- * borrowerFacet: LiquidityPoolKit['borrower'];
125
+ * notifier: import('./settler.js').SettlerKit['notifier'];
126
+ * borrower: LiquidityPoolKit['borrower'];
119
127
  * poolAccount: HostInterface<OrchestrationAccount<{chainId: 'agoric'}>>;
120
128
  * settlementAddress: ChainAddress;
121
129
  * intermediateRecipient?: ChainAddress;
@@ -165,9 +173,9 @@ export const prepareAdvancerKit = (
165
173
  const destination = chainHub.makeChainAddress(EUD);
166
174
 
167
175
  const fullAmount = toAmount(evidence.tx.amount);
168
- const { borrowerFacet, notifyFacet, poolAccount } = this.state;
176
+ const { borrower, notifier, poolAccount } = this.state;
169
177
  // do not advance if we've already received a mint/settlement
170
- const mintedEarly = notifyFacet.checkMintedEarly(
178
+ const mintedEarly = notifier.checkMintedEarly(
171
179
  evidence,
172
180
  destination,
173
181
  );
@@ -178,7 +186,7 @@ export const prepareAdvancerKit = (
178
186
 
179
187
  const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit();
180
188
  // throws if the pool has insufficient funds
181
- borrowerFacet.borrow(tmpSeat, advanceAmount);
189
+ borrower.borrow(tmpSeat, advanceAmount);
182
190
 
183
191
  // this cannot throw since `.isSeen()` is called in the same turn
184
192
  statusManager.advance(evidence);
@@ -249,9 +257,9 @@ export const prepareAdvancerKit = (
249
257
  error,
250
258
  );
251
259
  try {
252
- const { borrowerFacet, notifyFacet } = this.state;
253
- notifyFacet.notifyAdvancingResult(restCtx, false);
254
- borrowerFacet.returnToPool(tmpSeat, advanceAmount);
260
+ const { borrower, notifier } = this.state;
261
+ notifier.notifyAdvancingResult(restCtx, false);
262
+ borrower.returnToPool(tmpSeat, advanceAmount);
255
263
  } catch (e) {
256
264
  log('🚨 deposit to localOrchAccount failure recovery failed', e);
257
265
  }
@@ -263,37 +271,31 @@ export const prepareAdvancerKit = (
263
271
  * @param {AdvancerVowCtx} ctx
264
272
  */
265
273
  onFulfilled(result, ctx) {
266
- const { notifyFacet } = this.state;
274
+ const { notifier } = this.state;
267
275
  const { advanceAmount, destination, ...detail } = ctx;
268
276
  log('Advance succeeded', { advanceAmount, destination });
269
277
  // During development, due to a bug, this call threw.
270
278
  // The failure was silent (no diagnostics) due to:
271
279
  // - #10576 Vows do not report unhandled rejections
272
280
  // For now, the advancer kit relies on consistency between
273
- // notifyFacet, statusManager, and callers of handleTransactionEvent().
281
+ // notify, statusManager, and callers of handleTransactionEvent().
274
282
  // TODO: revisit #10576 during #10510
275
- notifyFacet.notifyAdvancingResult({ destination, ...detail }, true);
283
+ notifier.notifyAdvancingResult({ destination, ...detail }, true);
276
284
  },
277
285
  /**
278
286
  * @param {Error} error
279
287
  * @param {AdvancerVowCtx} ctx
280
288
  */
281
289
  onRejected(error, ctx) {
282
- const { notifyFacet } = this.state;
290
+ const { notifier } = this.state;
283
291
  log('Advance failed', error);
284
292
  const { advanceAmount: _, ...restCtx } = ctx;
285
- notifyFacet.notifyAdvancingResult(restCtx, false);
293
+ notifier.notifyAdvancingResult(restCtx, false);
286
294
  },
287
295
  },
288
296
  },
289
297
  {
290
- stateShape: harden({
291
- notifyFacet: M.remotable(),
292
- borrowerFacet: M.remotable(),
293
- poolAccount: M.remotable(),
294
- settlementAddress: ChainAddressShape,
295
- intermediateRecipient: M.opt(ChainAddressShape),
296
- }),
298
+ stateShape,
297
299
  },
298
300
  );
299
301
  };
@@ -1,8 +1,9 @@
1
- import { AmountMath, AmountShape } from '@agoric/ertp';
1
+ import { AmountMath, AmountShape, RatioShape } from '@agoric/ertp';
2
2
  import {
3
3
  makeRecorderTopic,
4
+ RecorderKitShape,
4
5
  TopicsRecordShape,
5
- } from '@agoric/zoe/src/contractSupport/topics.js';
6
+ } from '@agoric/zoe/src/contractSupport/index.js';
6
7
  import { SeatShape } from '@agoric/zoe/src/typeGuards.js';
7
8
  import { M } from '@endo/patterns';
8
9
  import { Fail, q } from '@endo/errors';
@@ -48,6 +49,22 @@ const { add, isGTE, makeEmpty } = AmountMath;
48
49
  * }} RepayPaymentKWR
49
50
  */
50
51
 
52
+ export const stateShape = harden({
53
+ encumberedBalance: AmountShape,
54
+ feeSeat: M.remotable(),
55
+ poolStats: M.record(),
56
+ poolMetricsRecorderKit: RecorderKitShape,
57
+ poolSeat: M.remotable(),
58
+ PoolShares: M.remotable(),
59
+ proposalShapes: {
60
+ deposit: M.pattern(),
61
+ withdraw: M.pattern(),
62
+ withdrawFees: M.pattern(),
63
+ },
64
+ shareMint: M.remotable(),
65
+ shareWorth: RatioShape,
66
+ });
67
+
51
68
  /**
52
69
  * @param {Zone} zone
53
70
  * @param {ZCF} zcf
@@ -384,6 +401,7 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
384
401
  finish: ({ facets: { external } }) => {
385
402
  void external.publishPoolMetrics();
386
403
  },
404
+ stateShape,
387
405
  },
388
406
  );
389
407
  };
@@ -90,8 +90,6 @@ export const prepareOperatorKit = (zone, staticPowers) =>
90
90
  */
91
91
  async SubmitEvidence(evidence, riskAssessment) {
92
92
  const { operator } = this.facets;
93
- // TODO(bootstrap integration): cause this call to throw and confirm that it
94
- // shows up in the the smart-wallet UpdateRecord `error` property
95
93
  operator.submitEvidence(evidence, riskAssessment);
96
94
  return staticPowers.makeInertInvitation(
97
95
  'evidence was pushed in the invitation maker call',
@@ -19,7 +19,7 @@ import {
19
19
  * @import {Amount, Brand, NatValue, Payment} from '@agoric/ertp';
20
20
  * @import {Denom, OrchestrationAccount, ChainHub, ChainAddress} from '@agoric/orchestration';
21
21
  * @import {WithdrawToSeat} from '@agoric/orchestration/src/utils/zoe-tools'
22
- * @import {IBCChannelID, VTransferIBCEvent} from '@agoric/vats';
22
+ * @import {IBCChannelID, IBCPacket, VTransferIBCEvent} from '@agoric/vats';
23
23
  * @import {Zone} from '@agoric/zone';
24
24
  * @import {HostOf, HostInterface} from '@agoric/async-flow';
25
25
  * @import {TargetRegistration} from '@agoric/vats/src/bridge-target.js';
@@ -27,6 +27,53 @@ import {
27
27
  * @import {StatusManager} from './status-manager.js';
28
28
  */
29
29
 
30
+ /**
31
+ * @param {IBCPacket} data
32
+ * @param {string} remoteDenom
33
+ * @returns {{ nfa: NobleAddress, amount: bigint, EUD: string } | {error: object[]}}
34
+ */
35
+ const decodeEventPacket = ({ data }, remoteDenom) => {
36
+ // NB: may not be a FungibleTokenPacketData or even JSON
37
+ /** @type {FungibleTokenPacketData} */
38
+ let tx;
39
+ try {
40
+ tx = JSON.parse(atob(data));
41
+ } catch (e) {
42
+ return { error: ['could not parse packet data', data] };
43
+ }
44
+
45
+ // given the sourceChannel check, we can be certain of this cast
46
+ const nfa = /** @type {NobleAddress} */ (tx.sender);
47
+
48
+ if (tx.denom !== remoteDenom) {
49
+ const { denom: actual } = tx;
50
+ return { error: ['unexpected denom', { actual, expected: remoteDenom }] };
51
+ }
52
+
53
+ let EUD;
54
+ try {
55
+ ({ EUD } = decodeAddressHook(tx.receiver).query);
56
+ if (!EUD) {
57
+ return { error: ['no EUD parameter', tx.receiver] };
58
+ }
59
+ if (typeof EUD !== 'string') {
60
+ return { error: ['EUD is not a string', EUD] };
61
+ }
62
+ } catch (e) {
63
+ return { error: ['no query params', tx.receiver] };
64
+ }
65
+
66
+ let amount;
67
+ try {
68
+ amount = BigInt(tx.amount);
69
+ } catch (e) {
70
+ return { error: ['invalid amount', tx.amount] };
71
+ }
72
+
73
+ return { nfa, amount, EUD };
74
+ };
75
+ harden(decodeEventPacket);
76
+
30
77
  /**
31
78
  * NOTE: not meant to be parsable.
32
79
  *
@@ -45,6 +92,16 @@ export const makeAdvanceDetailsShape = USDC =>
45
92
  txHash: EvmHashShape,
46
93
  });
47
94
 
95
+ export const stateShape = harden({
96
+ repayer: M.remotable('Repayer'),
97
+ settlementAccount: M.remotable('Account'),
98
+ registration: M.or(M.undefined(), M.remotable('Registration')),
99
+ sourceChannel: M.string(),
100
+ remoteDenom: M.string(),
101
+ mintedEarly: M.remotable('mintedEarly'),
102
+ intermediateRecipient: M.opt(ChainAddressShape),
103
+ });
104
+
48
105
  /**
49
106
  * @param {Zone} zone
50
107
  * @param {object} caps
@@ -81,7 +138,7 @@ export const prepareSettler = (
81
138
  tap: M.interface('SettlerTapI', {
82
139
  receiveUpcall: M.call(M.record()).returns(M.promise()),
83
140
  }),
84
- notify: M.interface('SettlerNotifyI', {
141
+ notifier: M.interface('SettlerNotifyI', {
85
142
  notifyAdvancingResult: M.call(
86
143
  makeAdvanceDetailsShape(USDC),
87
144
  M.boolean(),
@@ -148,38 +205,13 @@ export const prepareSettler = (
148
205
  return;
149
206
  }
150
207
 
151
- // TODO: why is it safe to cast this without a runtime check?
152
- const tx = /** @type {FungibleTokenPacketData} */ (
153
- JSON.parse(atob(packet.data))
154
- );
155
-
156
- // given the sourceChannel check, we can be certain of this cast
157
- const nfa = /** @type {NobleAddress} */ (tx.sender);
158
-
159
- if (tx.denom !== remoteDenom) {
160
- const { denom: actual } = tx;
161
- log('unexpected denom', { actual, expected: remoteDenom });
162
- return;
163
- }
164
-
165
- let EUD;
166
- try {
167
- ({ EUD } = decodeAddressHook(tx.receiver).query);
168
- if (!EUD) {
169
- log('no EUD parameter', tx.receiver);
170
- return;
171
- }
172
- if (typeof EUD !== 'string') {
173
- log('EUD is not a string', EUD);
174
- return;
175
- }
176
- } catch (e) {
177
- log('no query params', tx.receiver);
208
+ const decoded = decodeEventPacket(event.packet, remoteDenom);
209
+ if ('error' in decoded) {
210
+ log('invalid event packet', decoded.error);
178
211
  return;
179
212
  }
180
213
 
181
- const amount = BigInt(tx.amount); // TODO: what if this throws?
182
-
214
+ const { nfa, amount, EUD } = decoded;
183
215
  const { self } = this.facets;
184
216
  const found = statusManager.dequeueStatus(nfa, amount);
185
217
  log('dequeued', found, 'for', nfa, amount);
@@ -206,7 +238,7 @@ export const prepareSettler = (
206
238
  }
207
239
  },
208
240
  },
209
- notify: {
241
+ notifier: {
210
242
  /**
211
243
  * @param {object} ctx
212
244
  * @param {EvmHash} ctx.txHash
@@ -337,21 +369,11 @@ export const prepareSettler = (
337
369
  },
338
370
  },
339
371
  {
340
- stateShape: harden({
341
- repayer: M.remotable('Repayer'),
342
- settlementAccount: M.remotable('Account'),
343
- registration: M.or(M.undefined(), M.remotable('Registration')),
344
- sourceChannel: M.string(),
345
- remoteDenom: M.string(),
346
- mintedEarly: M.remotable('mintedEarly'),
347
- intermediateRecipient: M.opt(ChainAddressShape),
348
- }),
372
+ stateShape,
349
373
  },
350
374
  );
351
375
  };
352
376
  harden(prepareSettler);
353
377
 
354
- /**
355
- * XXX consider using pickFacet (do we have pickFacets?)
356
- * @typedef {ReturnType<ReturnType<typeof prepareSettler>>} SettlerKit
357
- */
378
+ // Expose the whole kit because the contract needs `creatorFacet` and the Advancer needs `notifier`
379
+ /** @typedef {ReturnType<ReturnType<typeof prepareSettler>>} SettlerKit */
@@ -53,6 +53,12 @@ const pendingTxKeyOf = evidence => {
53
53
  * }} StatusManagerPowers
54
54
  */
55
55
 
56
+ export const stateShape = harden({
57
+ pendingSettleTxs: M.remotable(),
58
+ seenTxs: M.remotable(),
59
+ storedCompletedTxs: M.remotable(),
60
+ });
61
+
56
62
  /**
57
63
  * The `StatusManager` keeps track of Pending and Seen Transactions
58
64
  * via {@link PendingTxStatus} states, aiding in coordination between the `Advancer`
@@ -408,6 +414,7 @@ export const prepareStatusManager = (
408
414
  return pendingSettleTxs.get(key);
409
415
  },
410
416
  },
417
+ { stateShape },
411
418
  );
412
419
  };
413
420
  harden(prepareStatusManager);
@@ -59,6 +59,12 @@ const allRisksIdentified = (riskStores, txHash) => {
59
59
  return [...setOfRisks.values()].sort();
60
60
  };
61
61
 
62
+ export const stateShape = {
63
+ operators: M.remotable(),
64
+ pending: M.remotable(),
65
+ risks: M.remotable(),
66
+ };
67
+
62
68
  /**
63
69
  * @param {Zone} zone
64
70
  * @param {ZCF} zcf
@@ -245,6 +251,7 @@ export const prepareTransactionFeedKit = (zone, zcf) => {
245
251
  getEvidenceSubscriber: () => subscriber,
246
252
  },
247
253
  },
254
+ { stateShape },
248
255
  );
249
256
  };
250
257
  harden(prepareTransactionFeedKit);
@@ -284,8 +284,8 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
284
284
 
285
285
  const advancer = zone.makeOnce('Advancer', () =>
286
286
  makeAdvancer({
287
- borrowerFacet: poolKit.borrower,
288
- notifyFacet: settlerKit.notify,
287
+ borrower: poolKit.borrower,
288
+ notifier: settlerKit.notifier,
289
289
  poolAccount,
290
290
  settlementAddress,
291
291
  }),
File without changes
File without changes
File without changes
File without changes
File without changes