@agoric/fast-usdc 0.2.0-u19.1 → 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.
- package/README.md +17 -91
- package/package.json +22 -29
- package/src/cli/config.js +1 -1
- package/src/cli/lp-commands.js +2 -2
- package/src/cli/operator-commands.js +1 -4
- package/src/cli/transfer.js +2 -2
- package/src/constants.js +2 -2
- package/src/operator-kit-interface.js +29 -0
- package/src/pool-share-math.js +18 -26
- package/src/type-guards.js +49 -13
- package/src/types.ts +58 -12
- package/src/utils/fees.js +104 -18
- package/tools/mock-evidence.ts +208 -0
- package/src/add-operators.core.js +0 -63
- package/src/distribute-fees.core.js +0 -93
- package/src/exos/advancer.js +0 -369
- package/src/exos/liquidity-pool.js +0 -414
- package/src/exos/operator-kit.js +0 -124
- package/src/exos/settler.js +0 -393
- package/src/exos/status-manager.js +0 -427
- package/src/exos/transaction-feed.js +0 -259
- package/src/fast-usdc-policy.core.js +0 -65
- package/src/fast-usdc.contract.js +0 -316
- package/src/fast-usdc.flows.js +0 -23
- package/src/start-fast-usdc.core.js +0 -246
- package/src/utils/chain-policies.js +0 -140
- package/src/utils/config-marshal.js +0 -130
- package/src/utils/core-eval.js +0 -73
- package/src/utils/deploy-config.js +0 -127
- package/src/utils/zoe.js +0 -28
package/src/exos/advancer.js
DELETED
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
|
|
2
|
-
import { AmountMath } from '@agoric/ertp';
|
|
3
|
-
import { assertAllDefined, makeTracer } from '@agoric/internal';
|
|
4
|
-
import { AnyNatAmountShape, ChainAddressShape } from '@agoric/orchestration';
|
|
5
|
-
import { pickFacet } from '@agoric/vat-data';
|
|
6
|
-
import { VowShape } from '@agoric/vow';
|
|
7
|
-
import { E } from '@endo/far';
|
|
8
|
-
import { M, mustMatch } from '@endo/patterns';
|
|
9
|
-
import { Fail, q } from '@endo/errors';
|
|
10
|
-
import {
|
|
11
|
-
AddressHookShape,
|
|
12
|
-
EvmHashShape,
|
|
13
|
-
EvidenceWithRiskShape,
|
|
14
|
-
} from '../type-guards.js';
|
|
15
|
-
import { makeFeeTools } from '../utils/fees.js';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @import {HostInterface} from '@agoric/async-flow';
|
|
19
|
-
* @import {Amount, Brand} from '@agoric/ertp';
|
|
20
|
-
* @import {TypedPattern} from '@agoric/internal'
|
|
21
|
-
* @import {NatAmount} from '@agoric/ertp';
|
|
22
|
-
* @import {ChainAddress, ChainHub, Denom, OrchestrationAccount} from '@agoric/orchestration';
|
|
23
|
-
* @import {ZoeTools} from '@agoric/orchestration/src/utils/zoe-tools.js';
|
|
24
|
-
* @import {VowTools} from '@agoric/vow';
|
|
25
|
-
* @import {Zone} from '@agoric/zone';
|
|
26
|
-
* @import {AddressHook, EvmHash, FeeConfig, LogFn, NobleAddress, EvidenceWithRisk} from '../types.js';
|
|
27
|
-
* @import {StatusManager} from './status-manager.js';
|
|
28
|
-
* @import {LiquidityPoolKit} from './liquidity-pool.js';
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @typedef {{
|
|
33
|
-
* chainHub: ChainHub;
|
|
34
|
-
* feeConfig: FeeConfig;
|
|
35
|
-
* log?: LogFn;
|
|
36
|
-
* statusManager: StatusManager;
|
|
37
|
-
* usdc: { brand: Brand<'nat'>; denom: Denom; };
|
|
38
|
-
* vowTools: VowTools;
|
|
39
|
-
* zcf: ZCF;
|
|
40
|
-
* zoeTools: ZoeTools;
|
|
41
|
-
* }} AdvancerKitPowers
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
/** @type {TypedPattern<AdvancerVowCtx>} */
|
|
45
|
-
const AdvancerVowCtxShape = M.splitRecord(
|
|
46
|
-
{
|
|
47
|
-
fullAmount: AnyNatAmountShape,
|
|
48
|
-
advanceAmount: AnyNatAmountShape,
|
|
49
|
-
destination: ChainAddressShape,
|
|
50
|
-
forwardingAddress: M.string(),
|
|
51
|
-
txHash: EvmHashShape,
|
|
52
|
-
},
|
|
53
|
-
{ tmpSeat: M.remotable() },
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
/** type guards internal to the AdvancerKit */
|
|
57
|
-
const AdvancerKitI = harden({
|
|
58
|
-
advancer: M.interface('AdvancerI', {
|
|
59
|
-
handleTransactionEvent: M.callWhen(EvidenceWithRiskShape).returns(),
|
|
60
|
-
setIntermediateRecipient: M.call(ChainAddressShape).returns(),
|
|
61
|
-
}),
|
|
62
|
-
depositHandler: M.interface('DepositHandlerI', {
|
|
63
|
-
onFulfilled: M.call(M.undefined(), AdvancerVowCtxShape).returns(VowShape),
|
|
64
|
-
onRejected: M.call(M.error(), AdvancerVowCtxShape).returns(),
|
|
65
|
-
}),
|
|
66
|
-
transferHandler: M.interface('TransferHandlerI', {
|
|
67
|
-
onFulfilled: M.call(M.undefined(), AdvancerVowCtxShape).returns(
|
|
68
|
-
M.undefined(),
|
|
69
|
-
),
|
|
70
|
-
onRejected: M.call(M.error(), AdvancerVowCtxShape).returns(M.undefined()),
|
|
71
|
-
}),
|
|
72
|
-
withdrawHandler: M.interface('WithdrawHandlerI', {
|
|
73
|
-
onFulfilled: M.call(M.undefined(), {
|
|
74
|
-
advanceAmount: AnyNatAmountShape,
|
|
75
|
-
tmpReturnSeat: M.remotable(),
|
|
76
|
-
}).returns(M.undefined()),
|
|
77
|
-
onRejected: M.call(M.error(), {
|
|
78
|
-
advanceAmount: AnyNatAmountShape,
|
|
79
|
-
tmpReturnSeat: M.remotable(),
|
|
80
|
-
}).returns(M.undefined()),
|
|
81
|
-
}),
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* @typedef {{
|
|
86
|
-
* fullAmount: NatAmount;
|
|
87
|
-
* advanceAmount: NatAmount;
|
|
88
|
-
* destination: ChainAddress;
|
|
89
|
-
* forwardingAddress: NobleAddress;
|
|
90
|
-
* txHash: EvmHash;
|
|
91
|
-
* }} AdvancerVowCtx
|
|
92
|
-
*/
|
|
93
|
-
|
|
94
|
-
export const stateShape = harden({
|
|
95
|
-
notifier: M.remotable(),
|
|
96
|
-
borrower: M.remotable(),
|
|
97
|
-
poolAccount: M.remotable(),
|
|
98
|
-
intermediateRecipient: M.opt(ChainAddressShape),
|
|
99
|
-
settlementAddress: M.opt(ChainAddressShape),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* @param {Zone} zone
|
|
104
|
-
* @param {AdvancerKitPowers} caps
|
|
105
|
-
*/
|
|
106
|
-
export const prepareAdvancerKit = (
|
|
107
|
-
zone,
|
|
108
|
-
{
|
|
109
|
-
chainHub,
|
|
110
|
-
feeConfig,
|
|
111
|
-
log = makeTracer('Advancer', true),
|
|
112
|
-
statusManager,
|
|
113
|
-
usdc,
|
|
114
|
-
vowTools: { watch, when },
|
|
115
|
-
zcf,
|
|
116
|
-
zoeTools: { localTransfer, withdrawToSeat },
|
|
117
|
-
},
|
|
118
|
-
) => {
|
|
119
|
-
assertAllDefined({
|
|
120
|
-
chainHub,
|
|
121
|
-
feeConfig,
|
|
122
|
-
statusManager,
|
|
123
|
-
watch,
|
|
124
|
-
when,
|
|
125
|
-
});
|
|
126
|
-
const feeTools = makeFeeTools(feeConfig);
|
|
127
|
-
/** @param {bigint} value */
|
|
128
|
-
const toAmount = value => AmountMath.make(usdc.brand, value);
|
|
129
|
-
|
|
130
|
-
return zone.exoClassKit(
|
|
131
|
-
'Fast USDC Advancer',
|
|
132
|
-
AdvancerKitI,
|
|
133
|
-
/**
|
|
134
|
-
* @param {{
|
|
135
|
-
* notifier: import('./settler.js').SettlerKit['notifier'];
|
|
136
|
-
* borrower: LiquidityPoolKit['borrower'];
|
|
137
|
-
* poolAccount: HostInterface<OrchestrationAccount<{chainId: 'agoric'}>>;
|
|
138
|
-
* settlementAddress: ChainAddress;
|
|
139
|
-
* intermediateRecipient?: ChainAddress;
|
|
140
|
-
* }} config
|
|
141
|
-
*/
|
|
142
|
-
config =>
|
|
143
|
-
harden({
|
|
144
|
-
...config,
|
|
145
|
-
// make sure the state record has this property, perhaps with an undefined value
|
|
146
|
-
intermediateRecipient: config.intermediateRecipient,
|
|
147
|
-
}),
|
|
148
|
-
{
|
|
149
|
-
advancer: {
|
|
150
|
-
/**
|
|
151
|
-
* Must perform a status update for every observed transaction.
|
|
152
|
-
*
|
|
153
|
-
* We do not expect any callers to depend on the settlement of
|
|
154
|
-
* `handleTransactionEvent` - errors caught are communicated to the
|
|
155
|
-
* `StatusManager` - so we don't need to concern ourselves with
|
|
156
|
-
* preserving the vow chain for callers.
|
|
157
|
-
*
|
|
158
|
-
* @param {EvidenceWithRisk} evidenceWithRisk
|
|
159
|
-
*/
|
|
160
|
-
async handleTransactionEvent({ evidence, risk }) {
|
|
161
|
-
await null;
|
|
162
|
-
try {
|
|
163
|
-
if (statusManager.hasBeenObserved(evidence)) {
|
|
164
|
-
log('txHash already seen:', evidence.txHash);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (risk.risksIdentified?.length) {
|
|
169
|
-
log('risks identified, skipping advance');
|
|
170
|
-
statusManager.skipAdvance(evidence, risk.risksIdentified);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
const { settlementAddress } = this.state;
|
|
174
|
-
const { recipientAddress } = evidence.aux;
|
|
175
|
-
const decoded = decodeAddressHook(recipientAddress);
|
|
176
|
-
mustMatch(decoded, AddressHookShape);
|
|
177
|
-
if (decoded.baseAddress !== settlementAddress.value) {
|
|
178
|
-
throw Fail`⚠️ baseAddress of address hook ${q(decoded.baseAddress)} does not match the expected address ${q(settlementAddress.value)}`;
|
|
179
|
-
}
|
|
180
|
-
const { EUD } = /** @type {AddressHook['query']} */ (decoded.query);
|
|
181
|
-
log(`decoded EUD: ${EUD}`);
|
|
182
|
-
// throws if the bech32 prefix is not found
|
|
183
|
-
const destination = chainHub.makeChainAddress(EUD);
|
|
184
|
-
|
|
185
|
-
const fullAmount = toAmount(evidence.tx.amount);
|
|
186
|
-
const { borrower, notifier, poolAccount } = this.state;
|
|
187
|
-
// do not advance if we've already received a mint/settlement
|
|
188
|
-
const mintedEarly = notifier.checkMintedEarly(
|
|
189
|
-
evidence,
|
|
190
|
-
destination,
|
|
191
|
-
);
|
|
192
|
-
if (mintedEarly) return;
|
|
193
|
-
|
|
194
|
-
// throws if requested does not exceed fees
|
|
195
|
-
const advanceAmount = feeTools.calculateAdvance(fullAmount);
|
|
196
|
-
|
|
197
|
-
const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit();
|
|
198
|
-
// throws if the pool has insufficient funds
|
|
199
|
-
borrower.borrow(tmpSeat, advanceAmount);
|
|
200
|
-
|
|
201
|
-
// this cannot throw since `.isSeen()` is called in the same turn
|
|
202
|
-
statusManager.advance(evidence);
|
|
203
|
-
|
|
204
|
-
const depositV = localTransfer(
|
|
205
|
-
tmpSeat,
|
|
206
|
-
// @ts-expect-error LocalAccountMethods vs OrchestrationAccount
|
|
207
|
-
poolAccount,
|
|
208
|
-
harden({ USDC: advanceAmount }),
|
|
209
|
-
);
|
|
210
|
-
void watch(depositV, this.facets.depositHandler, {
|
|
211
|
-
advanceAmount,
|
|
212
|
-
destination,
|
|
213
|
-
forwardingAddress: evidence.tx.forwardingAddress,
|
|
214
|
-
fullAmount,
|
|
215
|
-
tmpSeat,
|
|
216
|
-
txHash: evidence.txHash,
|
|
217
|
-
});
|
|
218
|
-
} catch (error) {
|
|
219
|
-
log('Advancer error:', error);
|
|
220
|
-
statusManager.skipAdvance(evidence, [error.message]);
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
/** @param {ChainAddress} intermediateRecipient */
|
|
224
|
-
setIntermediateRecipient(intermediateRecipient) {
|
|
225
|
-
this.state.intermediateRecipient = intermediateRecipient;
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
depositHandler: {
|
|
229
|
-
/**
|
|
230
|
-
* @param {undefined} result
|
|
231
|
-
* @param {AdvancerVowCtx & { tmpSeat: ZCFSeat }} ctx
|
|
232
|
-
*/
|
|
233
|
-
onFulfilled(result, ctx) {
|
|
234
|
-
const { poolAccount, intermediateRecipient, settlementAddress } =
|
|
235
|
-
this.state;
|
|
236
|
-
const { destination, advanceAmount, tmpSeat, ...detail } = ctx;
|
|
237
|
-
tmpSeat.exit();
|
|
238
|
-
const amount = harden({
|
|
239
|
-
denom: usdc.denom,
|
|
240
|
-
value: advanceAmount.value,
|
|
241
|
-
});
|
|
242
|
-
const transferOrSendV =
|
|
243
|
-
destination.chainId === settlementAddress.chainId
|
|
244
|
-
? E(poolAccount).send(destination, amount)
|
|
245
|
-
: E(poolAccount).transfer(destination, amount, {
|
|
246
|
-
forwardOpts: { intermediateRecipient },
|
|
247
|
-
});
|
|
248
|
-
return watch(transferOrSendV, this.facets.transferHandler, {
|
|
249
|
-
destination,
|
|
250
|
-
advanceAmount,
|
|
251
|
-
...detail,
|
|
252
|
-
});
|
|
253
|
-
},
|
|
254
|
-
/**
|
|
255
|
-
* We do not expect this to be a common failure. it should only occur
|
|
256
|
-
* if USDC is not registered in vbank or the tmpSeat has less than
|
|
257
|
-
* `advanceAmount`.
|
|
258
|
-
*
|
|
259
|
-
* If we do hit this path, we return funds to the Liquidity Pool and
|
|
260
|
-
* notify of Advancing failure.
|
|
261
|
-
*
|
|
262
|
-
* @param {Error} error
|
|
263
|
-
* @param {AdvancerVowCtx & { tmpSeat: ZCFSeat }} ctx
|
|
264
|
-
*/
|
|
265
|
-
onRejected(error, { tmpSeat, advanceAmount, ...restCtx }) {
|
|
266
|
-
log(
|
|
267
|
-
'⚠️ deposit to localOrchAccount failed, attempting to return payment to LP',
|
|
268
|
-
error,
|
|
269
|
-
);
|
|
270
|
-
try {
|
|
271
|
-
const { borrower, notifier } = this.state;
|
|
272
|
-
notifier.notifyAdvancingResult(restCtx, false);
|
|
273
|
-
borrower.returnToPool(tmpSeat, advanceAmount);
|
|
274
|
-
tmpSeat.exit();
|
|
275
|
-
} catch (e) {
|
|
276
|
-
log('🚨 deposit to localOrchAccount failure recovery failed', e);
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
|
-
transferHandler: {
|
|
281
|
-
/**
|
|
282
|
-
* @param {undefined} result
|
|
283
|
-
* @param {AdvancerVowCtx} ctx
|
|
284
|
-
*/
|
|
285
|
-
onFulfilled(result, ctx) {
|
|
286
|
-
const { notifier } = this.state;
|
|
287
|
-
const { advanceAmount, destination, ...detail } = ctx;
|
|
288
|
-
log('Advance succeeded', { advanceAmount, destination });
|
|
289
|
-
// During development, due to a bug, this call threw.
|
|
290
|
-
// The failure was silent (no diagnostics) due to:
|
|
291
|
-
// - #10576 Vows do not report unhandled rejections
|
|
292
|
-
// For now, the advancer kit relies on consistency between
|
|
293
|
-
// notify, statusManager, and callers of handleTransactionEvent().
|
|
294
|
-
// TODO: revisit #10576 during #10510
|
|
295
|
-
notifier.notifyAdvancingResult({ destination, ...detail }, true);
|
|
296
|
-
},
|
|
297
|
-
/**
|
|
298
|
-
* @param {Error} error
|
|
299
|
-
* @param {AdvancerVowCtx} ctx
|
|
300
|
-
*/
|
|
301
|
-
onRejected(error, ctx) {
|
|
302
|
-
const { notifier, poolAccount } = this.state;
|
|
303
|
-
log('Advance failed', error);
|
|
304
|
-
const { advanceAmount, ...restCtx } = ctx;
|
|
305
|
-
notifier.notifyAdvancingResult(restCtx, false);
|
|
306
|
-
const { zcfSeat: tmpReturnSeat } = zcf.makeEmptySeatKit();
|
|
307
|
-
const withdrawV = withdrawToSeat(
|
|
308
|
-
// @ts-expect-error LocalAccountMethods vs OrchestrationAccount
|
|
309
|
-
poolAccount,
|
|
310
|
-
tmpReturnSeat,
|
|
311
|
-
harden({ USDC: advanceAmount }),
|
|
312
|
-
);
|
|
313
|
-
void watch(withdrawV, this.facets.withdrawHandler, {
|
|
314
|
-
advanceAmount,
|
|
315
|
-
tmpReturnSeat,
|
|
316
|
-
});
|
|
317
|
-
},
|
|
318
|
-
},
|
|
319
|
-
withdrawHandler: {
|
|
320
|
-
/**
|
|
321
|
-
*
|
|
322
|
-
* @param {undefined} result
|
|
323
|
-
* @param {{ advanceAmount: Amount<'nat'>; tmpReturnSeat: ZCFSeat; }} ctx
|
|
324
|
-
*/
|
|
325
|
-
onFulfilled(result, { advanceAmount, tmpReturnSeat }) {
|
|
326
|
-
const { borrower } = this.state;
|
|
327
|
-
try {
|
|
328
|
-
borrower.returnToPool(tmpReturnSeat, advanceAmount);
|
|
329
|
-
} catch (e) {
|
|
330
|
-
// If we reach here, the unused advance funds will remain in `tmpReturnSeat`
|
|
331
|
-
// and must be retrieved from recovery sets.
|
|
332
|
-
log(
|
|
333
|
-
`🚨 return ${q(advanceAmount)} to pool failed. funds remain on "tmpReturnSeat"`,
|
|
334
|
-
e,
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
tmpReturnSeat.exit();
|
|
338
|
-
},
|
|
339
|
-
/**
|
|
340
|
-
* @param {Error} error
|
|
341
|
-
* @param {{ advanceAmount: Amount<'nat'>; tmpReturnSeat: ZCFSeat; }} ctx
|
|
342
|
-
*/
|
|
343
|
-
onRejected(error, { advanceAmount, tmpReturnSeat }) {
|
|
344
|
-
log(
|
|
345
|
-
`🚨 withdraw ${q(advanceAmount)} from "poolAccount" to return to pool failed`,
|
|
346
|
-
error,
|
|
347
|
-
);
|
|
348
|
-
// If we reach here, the unused advance funds will remain in the `poolAccount`.
|
|
349
|
-
// A contract update will be required to return them to the LiquidityPool.
|
|
350
|
-
tmpReturnSeat.exit();
|
|
351
|
-
},
|
|
352
|
-
},
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
stateShape,
|
|
356
|
-
},
|
|
357
|
-
);
|
|
358
|
-
};
|
|
359
|
-
harden(prepareAdvancerKit);
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* @param {Zone} zone
|
|
363
|
-
* @param {AdvancerKitPowers} caps
|
|
364
|
-
*/
|
|
365
|
-
export const prepareAdvancer = (zone, caps) => {
|
|
366
|
-
const makeAdvancerKit = prepareAdvancerKit(zone, caps);
|
|
367
|
-
return pickFacet(makeAdvancerKit, 'advancer');
|
|
368
|
-
};
|
|
369
|
-
harden(prepareAdvancer);
|