Skip to content

Commit 45d0417

Browse files
authored
test: fast-usdc contract flow (#10572)
refs: #10388 closes: #10577 doesn't close until - exercise all the code in the contract (analytic; best effort) ## Description / Testing Considerations - [x] test all the sequences in the product spec - [x] enumerate all the sequences in the product spec - [x] fix advancer/settler amount agreement bug postponed: - - #10510 - [todo] C12 - Contract MUST only pay back the Pool only if they started the advance before USDC is minted - #10554 some `test.todo()`s are out of scope of contract flow tests. Some are more feasible as exo tests: - [todo] C18 - forward - MUST log and alert these incidents - [skip] LP borrow - TODO: move to exo test - [skip] LP repay - TODO: move to exo test an some are after M1: - [todo] PERF: Target: settlement completes in a few minutes (after USDC is minted) - [todo] fee levels MUST be visible to external parties - i.e., written to public storage - [todo] C21 - Contract MUST log / timestamp each step in the transaction flow ### Security / Scaling / Upgrade Considerations n/a ### Documentation Considerations Internal design docs are assumed background knowledge.
2 parents 1d5cb99 + dcc6feb commit 45d0417

11 files changed

+1399
-438
lines changed

packages/fast-usdc/src/exos/advancer.js

+42-55
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { AmountMath, AmountShape } from '@agoric/ertp';
1+
import { AmountMath } from '@agoric/ertp';
22
import { assertAllDefined, makeTracer } from '@agoric/internal';
3-
import { ChainAddressShape } from '@agoric/orchestration';
3+
import { AnyNatAmountShape, ChainAddressShape } from '@agoric/orchestration';
44
import { pickFacet } from '@agoric/vat-data';
55
import { VowShape } from '@agoric/vow';
66
import { q } from '@endo/errors';
@@ -16,6 +16,7 @@ import { makeFeeTools } from '../utils/fees.js';
1616

1717
/**
1818
* @import {HostInterface} from '@agoric/async-flow';
19+
* @import {TypedPattern} from '@agoric/internal'
1920
* @import {NatAmount} from '@agoric/ertp';
2021
* @import {ChainAddress, ChainHub, Denom, OrchestrationAccount} from '@agoric/orchestration';
2122
* @import {ZoeTools} from '@agoric/orchestration/src/utils/zoe-tools.js';
@@ -39,47 +40,40 @@ import { makeFeeTools } from '../utils/fees.js';
3940
* }} AdvancerKitPowers
4041
*/
4142

43+
/** @type {TypedPattern<AdvancerVowCtx>} */
44+
const AdvancerVowCtxShape = M.splitRecord(
45+
{
46+
fullAmount: AnyNatAmountShape,
47+
advanceAmount: AnyNatAmountShape,
48+
destination: ChainAddressShape,
49+
forwardingAddress: M.string(),
50+
txHash: EvmHashShape,
51+
},
52+
{ tmpSeat: M.remotable() },
53+
);
54+
4255
/** type guards internal to the AdvancerKit */
4356
const AdvancerKitI = harden({
4457
advancer: M.interface('AdvancerI', {
4558
handleTransactionEvent: M.callWhen(CctpTxEvidenceShape).returns(),
4659
}),
4760
depositHandler: M.interface('DepositHandlerI', {
48-
onFulfilled: M.call(M.undefined(), {
49-
amount: AmountShape,
50-
destination: ChainAddressShape,
51-
forwardingAddress: M.string(),
52-
tmpSeat: M.remotable(),
53-
txHash: EvmHashShape,
54-
}).returns(VowShape),
55-
onRejected: M.call(M.error(), {
56-
amount: AmountShape,
57-
destination: ChainAddressShape,
58-
forwardingAddress: M.string(),
59-
tmpSeat: M.remotable(),
60-
txHash: EvmHashShape,
61-
}).returns(),
61+
onFulfilled: M.call(M.undefined(), AdvancerVowCtxShape).returns(VowShape),
62+
onRejected: M.call(M.error(), AdvancerVowCtxShape).returns(),
6263
}),
6364
transferHandler: M.interface('TransferHandlerI', {
6465
// TODO confirm undefined, and not bigint (sequence)
65-
onFulfilled: M.call(M.undefined(), {
66-
amount: AmountShape,
67-
destination: ChainAddressShape,
68-
forwardingAddress: M.string(),
69-
txHash: EvmHashShape,
70-
}).returns(M.undefined()),
71-
onRejected: M.call(M.error(), {
72-
amount: AmountShape,
73-
destination: ChainAddressShape,
74-
forwardingAddress: M.string(),
75-
txHash: EvmHashShape,
76-
}).returns(M.undefined()),
66+
onFulfilled: M.call(M.undefined(), AdvancerVowCtxShape).returns(
67+
M.undefined(),
68+
),
69+
onRejected: M.call(M.error(), AdvancerVowCtxShape).returns(M.undefined()),
7770
}),
7871
});
7972

8073
/**
8174
* @typedef {{
82-
* amount: NatAmount;
75+
* fullAmount: NatAmount;
76+
* advanceAmount: NatAmount;
8377
* destination: ChainAddress;
8478
* forwardingAddress: NobleAddress;
8579
* txHash: EvmHash;
@@ -155,9 +149,9 @@ export const prepareAdvancerKit = (
155149
// throws if the bech32 prefix is not found
156150
const destination = chainHub.makeChainAddress(EUD);
157151

158-
const requestedAmount = toAmount(evidence.tx.amount);
152+
const fullAmount = toAmount(evidence.tx.amount);
159153
// throws if requested does not exceed fees
160-
const advanceAmount = feeTools.calculateAdvance(requestedAmount);
154+
const advanceAmount = feeTools.calculateAdvance(fullAmount);
161155

162156
const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit();
163157
const amountKWR = harden({ USDC: advanceAmount });
@@ -174,7 +168,8 @@ export const prepareAdvancerKit = (
174168
amountKWR,
175169
);
176170
void watch(depositV, this.facets.depositHandler, {
177-
amount: advanceAmount,
171+
fullAmount,
172+
advanceAmount,
178173
destination,
179174
forwardingAddress: evidence.tx.forwardingAddress,
180175
tmpSeat,
@@ -193,16 +188,15 @@ export const prepareAdvancerKit = (
193188
*/
194189
onFulfilled(result, ctx) {
195190
const { poolAccount } = this.state;
196-
const { amount, destination, forwardingAddress, txHash } = ctx;
191+
const { destination, advanceAmount, ...detail } = ctx;
197192
const transferV = E(poolAccount).transfer(destination, {
198193
denom: usdc.denom,
199-
value: amount.value,
194+
value: advanceAmount.value,
200195
});
201196
return watch(transferV, this.facets.transferHandler, {
202197
destination,
203-
amount,
204-
forwardingAddress,
205-
txHash,
198+
advanceAmount,
199+
...detail,
206200
});
207201
},
208202
/**
@@ -222,39 +216,32 @@ export const prepareAdvancerKit = (
222216
},
223217
transferHandler: {
224218
/**
225-
* @param {undefined} result TODO confirm this is not a bigint (sequence)
219+
* @param {unknown} result TODO confirm this is not a bigint (sequence)
226220
* @param {AdvancerVowCtx} ctx
227221
*/
228222
onFulfilled(result, ctx) {
229223
const { notifyFacet } = this.state;
230-
const { amount, destination, forwardingAddress, txHash } = ctx;
224+
const { advanceAmount, destination, ...detail } = ctx;
231225
log(
232226
'Advance transfer fulfilled',
233-
q({ amount, destination, result }).toString(),
234-
);
235-
notifyFacet.notifyAdvancingResult(
236-
txHash,
237-
forwardingAddress,
238-
amount.value,
239-
destination.value,
240-
true,
227+
q({ advanceAmount, destination, result }).toString(),
241228
);
229+
// During development, due to a bug, this call threw.
230+
// The failure was silent (no diagnostics) due to:
231+
// - #10576 Vows do not report unhandled rejections
232+
// For now, the advancer kit relies on consistency between
233+
// notifyFacet, statusManager, and callers of handleTransactionEvent().
234+
// TODO: revisit #10576 during #10510
235+
notifyFacet.notifyAdvancingResult({ destination, ...detail }, true);
242236
},
243237
/**
244238
* @param {Error} error
245239
* @param {AdvancerVowCtx} ctx
246240
*/
247241
onRejected(error, ctx) {
248242
const { notifyFacet } = this.state;
249-
const { amount, destination, forwardingAddress, txHash } = ctx;
250243
log('Advance transfer rejected', q(error).toString());
251-
notifyFacet.notifyAdvancingResult(
252-
txHash,
253-
forwardingAddress,
254-
amount.value,
255-
destination.value,
256-
false,
257-
);
244+
notifyFacet.notifyAdvancingResult(ctx, false);
258245
},
259246
},
260247
},

0 commit comments

Comments
 (0)