@agoric/fast-usdc 0.2.0-u19.2 → 0.2.0-u20.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.
@@ -1,414 +0,0 @@
1
- import { AmountMath, AmountShape, RatioShape } from '@agoric/ertp';
2
- import {
3
- makeRecorderTopic,
4
- RecorderKitShape,
5
- TopicsRecordShape,
6
- } from '@agoric/zoe/src/contractSupport/index.js';
7
- import { SeatShape } from '@agoric/zoe/src/typeGuards.js';
8
- import { M } from '@endo/patterns';
9
- import { Fail, q } from '@endo/errors';
10
- import {
11
- borrowCalc,
12
- checkPoolBalance,
13
- depositCalc,
14
- makeParity,
15
- repayCalc,
16
- withdrawCalc,
17
- } from '../pool-share-math.js';
18
- import {
19
- makeNatAmountShape,
20
- makeProposalShapes,
21
- PoolMetricsShape,
22
- } from '../type-guards.js';
23
-
24
- /**
25
- * @import {Amount, Brand, Payment} from '@agoric/ertp';
26
- * @import {Zone} from '@agoric/zone';
27
- * @import {Remote} from '@agoric/internal'
28
- * @import {StorageNode} from '@agoric/internal/src/lib-chainStorage.js'
29
- * @import {MakeRecorderKit} from '@agoric/zoe/src/contractSupport/recorder.js'
30
- * @import {USDCProposalShapes, ShareWorth} from '../pool-share-math.js'
31
- * @import {PoolStats} from '../types.js';
32
- */
33
-
34
- const { add, isGTE, makeEmpty } = AmountMath;
35
-
36
- /**
37
- * @typedef {{
38
- * Principal: Amount<'nat'>;
39
- * PoolFee: Amount<'nat'>;
40
- * ContractFee: Amount<'nat'>;
41
- * }} RepayAmountKWR
42
- */
43
-
44
- /**
45
- * @typedef {{
46
- * Principal: Payment<'nat'>;
47
- * PoolFee: Payment<'nat'>;
48
- * ContractFee: Payment<'nat'>;
49
- * }} RepayPaymentKWR
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
-
68
- /**
69
- * @param {Zone} zone
70
- * @param {ZCF} zcf
71
- * @param {Brand<'nat'>} USDC
72
- * @param {{
73
- * makeRecorderKit: MakeRecorderKit;
74
- * }} tools
75
- */
76
- export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
77
- return zone.exoClassKit(
78
- 'Liquidity Pool',
79
- {
80
- borrower: M.interface('borrower', {
81
- borrow: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(),
82
- returnToPool: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(),
83
- }),
84
- repayer: M.interface('repayer', {
85
- repay: M.call(
86
- SeatShape,
87
- harden({
88
- Principal: makeNatAmountShape(USDC, 1n),
89
- PoolFee: makeNatAmountShape(USDC, 0n),
90
- ContractFee: makeNatAmountShape(USDC, 0n),
91
- }),
92
- ).returns(),
93
- }),
94
- external: M.interface('external', {
95
- publishPoolMetrics: M.call().returns(),
96
- }),
97
- depositHandler: M.interface('depositHandler', {
98
- handle: M.call(SeatShape, M.any()).returns(M.promise()),
99
- }),
100
- withdrawHandler: M.interface('withdrawHandler', {
101
- handle: M.call(SeatShape, M.any()).returns(M.promise()),
102
- }),
103
- withdrawFeesHandler: M.interface('withdrawFeesHandler', {
104
- handle: M.call(SeatShape, M.any()).returns(M.promise()),
105
- }),
106
- public: M.interface('public', {
107
- makeDepositInvitation: M.call().returns(M.promise()),
108
- makeWithdrawInvitation: M.call().returns(M.promise()),
109
- getPublicTopics: M.call().returns(TopicsRecordShape),
110
- }),
111
- feeRecipient: M.interface('feeRecipient', {
112
- getContractFeeBalance: M.call().returns(AmountShape),
113
- makeWithdrawFeesInvitation: M.call().returns(M.promise()),
114
- }),
115
- },
116
- /**
117
- * @param {ZCFMint<'nat'>} shareMint
118
- * @param {Remote<StorageNode>} node
119
- */
120
- (shareMint, node) => {
121
- const { brand: PoolShares } = shareMint.getIssuerRecord();
122
- const proposalShapes = makeProposalShapes({ USDC, PoolShares });
123
- const shareWorth = makeParity(USDC, PoolShares);
124
- const { zcfSeat: poolSeat } = zcf.makeEmptySeatKit();
125
- const { zcfSeat: feeSeat } = zcf.makeEmptySeatKit();
126
- const poolMetricsRecorderKit = tools.makeRecorderKit(
127
- node,
128
- PoolMetricsShape,
129
- );
130
- const encumberedBalance = makeEmpty(USDC);
131
- /** @type {PoolStats} */
132
- const poolStats = harden({
133
- totalBorrows: makeEmpty(USDC),
134
- totalContractFees: makeEmpty(USDC),
135
- totalPoolFees: makeEmpty(USDC),
136
- totalRepays: makeEmpty(USDC),
137
- });
138
- return {
139
- /** used for `checkPoolBalance` invariant. aka 'outstanding borrows' */
140
- encumberedBalance,
141
- feeSeat,
142
- poolStats,
143
- poolMetricsRecorderKit,
144
- poolSeat,
145
- PoolShares,
146
- proposalShapes,
147
- shareMint,
148
- shareWorth,
149
- };
150
- },
151
- {
152
- borrower: {
153
- /**
154
- * @param {ZCFSeat} toSeat
155
- * @param {Amount<'nat'>} amount
156
- */
157
- borrow(toSeat, amount) {
158
- const { encumberedBalance, poolSeat, poolStats } = this.state;
159
-
160
- // Validate amount is available in pool
161
- const post = borrowCalc(
162
- amount,
163
- poolSeat.getAmountAllocated('USDC', USDC),
164
- encumberedBalance,
165
- poolStats,
166
- );
167
-
168
- // COMMIT POINT
169
- // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
170
- zcf.atomicRearrange(harden([[poolSeat, toSeat, { USDC: amount }]]));
171
-
172
- Object.assign(this.state, post);
173
- this.facets.external.publishPoolMetrics();
174
- },
175
- /**
176
- * If something fails during advance, return funds to the pool.
177
- *
178
- * @param {ZCFSeat} borrowSeat
179
- * @param {Amount<'nat'>} amount
180
- */
181
- returnToPool(borrowSeat, amount) {
182
- const { zcfSeat: repaySeat } = zcf.makeEmptySeatKit();
183
- const returnAmounts = harden({
184
- Principal: amount,
185
- PoolFee: makeEmpty(USDC),
186
- ContractFee: makeEmpty(USDC),
187
- });
188
- const borrowSeatAllocation = borrowSeat.getCurrentAllocation();
189
- isGTE(borrowSeatAllocation.USDC, amount) ||
190
- Fail`⚠️ borrowSeatAllocation ${q(borrowSeatAllocation)} less than amountKWR ${q(amount)}`;
191
- // arrange payments in a format repay is expecting
192
- zcf.atomicRearrange(
193
- harden([[borrowSeat, repaySeat, { USDC: amount }, returnAmounts]]),
194
- );
195
- this.facets.repayer.repay(repaySeat, returnAmounts);
196
- borrowSeat.exit();
197
- repaySeat.exit();
198
- },
199
- },
200
- repayer: {
201
- /**
202
- * @param {ZCFSeat} fromSeat
203
- * @param {RepayAmountKWR} amounts
204
- */
205
- repay(fromSeat, amounts) {
206
- const {
207
- encumberedBalance,
208
- feeSeat,
209
- poolSeat,
210
- poolStats,
211
- shareWorth,
212
- } = this.state;
213
- checkPoolBalance(
214
- poolSeat.getCurrentAllocation(),
215
- shareWorth,
216
- encumberedBalance,
217
- );
218
-
219
- const fromSeatAllocation = fromSeat.getCurrentAllocation();
220
- // Validate allocation equals amounts and Principal <= encumberedBalance
221
- const post = repayCalc(
222
- shareWorth,
223
- fromSeatAllocation,
224
- amounts,
225
- encumberedBalance,
226
- poolStats,
227
- );
228
-
229
- const { ContractFee, ...rest } = amounts;
230
-
231
- // COMMIT POINT
232
- // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
233
- zcf.atomicRearrange(
234
- harden([
235
- [
236
- fromSeat,
237
- poolSeat,
238
- rest,
239
- { USDC: add(amounts.PoolFee, amounts.Principal) },
240
- ],
241
- [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }],
242
- ]),
243
- );
244
-
245
- Object.assign(this.state, post);
246
- this.facets.external.publishPoolMetrics();
247
- },
248
- },
249
- external: {
250
- publishPoolMetrics() {
251
- const { poolStats, shareWorth, encumberedBalance } = this.state;
252
- const { recorder } = this.state.poolMetricsRecorderKit;
253
- // Consumers of this .write() are off-chain / outside the VM.
254
- // And there's no way to recover from a failed write.
255
- // So don't await.
256
- void recorder.write({
257
- encumberedBalance,
258
- shareWorth,
259
- ...poolStats,
260
- });
261
- },
262
- },
263
-
264
- depositHandler: {
265
- /** @param {ZCFSeat} lp */
266
- async handle(lp) {
267
- const { shareWorth, shareMint, poolSeat, encumberedBalance } =
268
- this.state;
269
- const { external } = this.facets;
270
-
271
- /** @type {USDCProposalShapes['deposit']} */
272
- // @ts-expect-error ensured by proposalShape
273
- const proposal = lp.getProposal();
274
- checkPoolBalance(
275
- poolSeat.getCurrentAllocation(),
276
- shareWorth,
277
- encumberedBalance,
278
- );
279
- const post = depositCalc(shareWorth, proposal);
280
-
281
- // COMMIT POINT
282
- const mint = shareMint.mintGains(post.payouts);
283
- try {
284
- this.state.shareWorth = post.shareWorth;
285
- zcf.atomicRearrange(
286
- harden([
287
- // zoe guarantees lp has proposal.give allocated
288
- [lp, poolSeat, proposal.give],
289
- // mintGains() above establishes that mint has post.payouts
290
- [mint, lp, post.payouts],
291
- ]),
292
- );
293
- } catch (cause) {
294
- // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
295
- throw new Error('🚨 cannot commit deposit', { cause });
296
- } finally {
297
- lp.exit();
298
- mint.exit();
299
- }
300
- external.publishPoolMetrics();
301
- },
302
- },
303
- withdrawHandler: {
304
- /** @param {ZCFSeat} lp */
305
- async handle(lp) {
306
- const { shareWorth, shareMint, poolSeat, encumberedBalance } =
307
- this.state;
308
- const { external } = this.facets;
309
-
310
- /** @type {USDCProposalShapes['withdraw']} */
311
- // @ts-expect-error ensured by proposalShape
312
- const proposal = lp.getProposal();
313
- const { zcfSeat: burn } = zcf.makeEmptySeatKit();
314
- const post = withdrawCalc(
315
- shareWorth,
316
- proposal,
317
- poolSeat.getCurrentAllocation(),
318
- encumberedBalance,
319
- );
320
-
321
- // COMMIT POINT
322
- try {
323
- this.state.shareWorth = post.shareWorth;
324
- zcf.atomicRearrange(
325
- harden([
326
- // zoe guarantees lp has proposal.give allocated
327
- [lp, burn, proposal.give],
328
- // checkPoolBalance() + withdrawCalc() guarantee poolSeat has enough
329
- [poolSeat, lp, post.payouts],
330
- ]),
331
- );
332
- shareMint.burnLosses(proposal.give, burn);
333
- } catch (cause) {
334
- // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
335
- throw new Error('🚨 cannot commit withdraw', { cause });
336
- } finally {
337
- lp.exit();
338
- burn.exit();
339
- }
340
- external.publishPoolMetrics();
341
- },
342
- },
343
- withdrawFeesHandler: {
344
- /** @param {ZCFSeat} seat */
345
- async handle(seat) {
346
- const { feeSeat } = this.state;
347
-
348
- const { want } = seat.getProposal();
349
- const available = feeSeat.getAmountAllocated('USDC', want.USDC.brand);
350
- isGTE(available, want.USDC) ||
351
- Fail`cannot withdraw ${want.USDC}; only ${available} available`;
352
-
353
- // COMMIT POINT
354
- zcf.atomicRearrange(harden([[feeSeat, seat, want]]));
355
- seat.exit();
356
- },
357
- },
358
- public: {
359
- makeDepositInvitation() {
360
- return zcf.makeInvitation(
361
- this.facets.depositHandler,
362
- 'Deposit',
363
- undefined,
364
- this.state.proposalShapes.deposit,
365
- );
366
- },
367
- makeWithdrawInvitation() {
368
- return zcf.makeInvitation(
369
- this.facets.withdrawHandler,
370
- 'Withdraw',
371
- undefined,
372
- this.state.proposalShapes.withdraw,
373
- );
374
- },
375
- getPublicTopics() {
376
- const { poolMetricsRecorderKit } = this.state;
377
- return {
378
- poolMetrics: makeRecorderTopic(
379
- 'poolMetrics',
380
- poolMetricsRecorderKit,
381
- ),
382
- };
383
- },
384
- },
385
- feeRecipient: {
386
- getContractFeeBalance() {
387
- const { feeSeat } = this.state;
388
- /** @type {Amount<'nat'>} */
389
- const balance = feeSeat.getCurrentAllocation().USDC;
390
- return balance;
391
- },
392
- makeWithdrawFeesInvitation() {
393
- return zcf.makeInvitation(
394
- this.facets.withdrawFeesHandler,
395
- 'Withdraw Fees',
396
- undefined,
397
- this.state.proposalShapes.withdrawFees,
398
- );
399
- },
400
- },
401
- },
402
- {
403
- finish: ({ facets: { external } }) => {
404
- void external.publishPoolMetrics();
405
- },
406
- stateShape,
407
- },
408
- );
409
- };
410
- harden(prepareLiquidityPoolKit);
411
-
412
- /**
413
- * @typedef {ReturnType<ReturnType<typeof prepareLiquidityPoolKit>>} LiquidityPoolKit
414
- */
@@ -1,124 +0,0 @@
1
- import { makeTracer } from '@agoric/internal';
2
- import { Fail } from '@endo/errors';
3
- import { M } from '@endo/patterns';
4
- import { CctpTxEvidenceShape, RiskAssessmentShape } from '../type-guards.js';
5
-
6
- const trace = makeTracer('TxOperator');
7
-
8
- /**
9
- * @import {Zone} from '@agoric/zone';
10
- * @import {CctpTxEvidence, RiskAssessment} from '../types.js';
11
- */
12
-
13
- /**
14
- * @typedef {object} OperatorPowers
15
- * @property {(evidence: CctpTxEvidence, riskAssessment: RiskAssessment, operatorId: string) => void} attest
16
- */
17
-
18
- /**
19
- * @typedef {object} OperatorStatus
20
- * @property {boolean} [disabled]
21
- * @property {string} operatorId
22
- */
23
-
24
- /**
25
- * @typedef {Readonly<{ operatorId: string, powers: OperatorPowers }> & {disabled: boolean}} State
26
- */
27
-
28
- const OperatorKitI = {
29
- admin: M.interface('Admin', {
30
- disable: M.call().returns(),
31
- }),
32
-
33
- invitationMakers: M.interface('InvitationMakers', {
34
- SubmitEvidence: M.call(CctpTxEvidenceShape)
35
- .optional(RiskAssessmentShape)
36
- .returns(M.promise()),
37
- }),
38
-
39
- operator: M.interface('Operator', {
40
- submitEvidence: M.call(CctpTxEvidenceShape)
41
- .optional(RiskAssessmentShape)
42
- .returns(),
43
- getStatus: M.call().returns(M.record()),
44
- }),
45
- };
46
-
47
- /**
48
- * @param {Zone} zone
49
- * @param {{ makeInertInvitation: Function }} staticPowers
50
- */
51
- export const prepareOperatorKit = (zone, staticPowers) =>
52
- zone.exoClassKit(
53
- 'Operator Kit',
54
- OperatorKitI,
55
- /**
56
- * @param {string} operatorId
57
- * @param {OperatorPowers} powers facet of the durable transaction feed
58
- * @returns {State}
59
- */
60
- (operatorId, powers) => {
61
- return {
62
- operatorId,
63
- powers,
64
- disabled: false,
65
- };
66
- },
67
- {
68
- admin: {
69
- disable() {
70
- trace(`operator ${this.state.operatorId} disabled`);
71
- this.state.disabled = true;
72
- },
73
- },
74
- /**
75
- * NB: when this kit is an offer result, the smart-wallet will detect the `invitationMakers`
76
- * key and save it for future offers.
77
- */
78
- invitationMakers: {
79
- /**
80
- * Provide an API call in the form of an invitation maker, so that the
81
- * capability is available in the smart-wallet bridge.
82
- *
83
- * NB: The `Invitation` object is evidence that the operation took
84
- * place, rather than as a means of performing it as in the
85
- * fluxAggregator contract used for price oracles.
86
- *
87
- * @param {CctpTxEvidence} evidence
88
- * @param {RiskAssessment} [riskAssessment]
89
- * @returns {Promise<Invitation>}
90
- */
91
- async SubmitEvidence(evidence, riskAssessment) {
92
- const { operator } = this.facets;
93
- operator.submitEvidence(evidence, riskAssessment);
94
- return staticPowers.makeInertInvitation(
95
- 'evidence was pushed in the invitation maker call',
96
- );
97
- },
98
- },
99
- operator: {
100
- /**
101
- * submit evidence from this operator
102
- *
103
- * @param {CctpTxEvidence} evidence
104
- * @param {RiskAssessment} [riskAssessment]
105
- * @returns {void}
106
- */
107
- submitEvidence(evidence, riskAssessment = {}) {
108
- const { state } = this;
109
- !state.disabled || Fail`submitEvidence for disabled operator`;
110
- state.powers.attest(evidence, riskAssessment, state.operatorId);
111
- },
112
- /** @returns {OperatorStatus} */
113
- getStatus() {
114
- const { state } = this;
115
- return {
116
- operatorId: state.operatorId,
117
- disabled: state.disabled,
118
- };
119
- },
120
- },
121
- },
122
- );
123
-
124
- /** @typedef {ReturnType<ReturnType<typeof prepareOperatorKit>>} OperatorKit */