@@ -8,7 +8,11 @@ import { M } from '@endo/patterns';
88import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js' ;
99import { PendingTxStatus } from '../constants.js' ;
1010import { makeFeeTools } from '../utils/fees.js' ;
11- import { EvmHashShape } from '../type-guards.js' ;
11+ import {
12+ CctpTxEvidenceShape ,
13+ EvmHashShape ,
14+ makeNatAmountShape ,
15+ } from '../type-guards.js' ;
1216
1317/**
1418 * @import {FungibleTokenPacketData} from '@agoric/cosmic-proto/ibc/applications/transfer/v2/packet.js';
@@ -18,7 +22,7 @@ import { EvmHashShape } from '../type-guards.js';
1822 * @import {Zone} from '@agoric/zone';
1923 * @import {HostOf, HostInterface} from '@agoric/async-flow';
2024 * @import {TargetRegistration} from '@agoric/vats/src/bridge-target.js';
21- * @import {NobleAddress, LiquidityPoolKit, FeeConfig, EvmHash, LogFn} from '../types.js';
25+ * @import {NobleAddress, LiquidityPoolKit, FeeConfig, EvmHash, LogFn, CctpTxEvidence } from '../types.js';
2226 * @import {StatusManager} from './status-manager.js';
2327 */
2428
@@ -31,6 +35,15 @@ import { EvmHashShape } from '../type-guards.js';
3135const makeMintedEarlyKey = ( addr , amount ) =>
3236 `pendingTx:${ JSON . stringify ( [ addr , String ( amount ) ] ) } ` ;
3337
38+ /** @param {Brand<'nat'> } USDC */
39+ export const makeAdvanceDetailsShape = USDC =>
40+ harden ( {
41+ destination : ChainAddressShape ,
42+ forwardingAddress : M . string ( ) ,
43+ fullAmount : makeNatAmountShape ( USDC ) ,
44+ txHash : EvmHashShape ,
45+ } ) ;
46+
3447/**
3548 * @param {Zone } zone
3649 * @param {object } caps
@@ -69,24 +82,21 @@ export const prepareSettler = (
6982 } ) ,
7083 notify : M . interface ( 'SettlerNotifyI' , {
7184 notifyAdvancingResult : M . call (
72- M . record ( ) , // XXX fill in details TODO
85+ makeAdvanceDetailsShape ( USDC ) ,
7386 M . boolean ( ) ,
7487 ) . returns ( ) ,
88+ checkMintedEarly : M . call (
89+ CctpTxEvidenceShape ,
90+ ChainAddressShape ,
91+ ) . returns ( M . boolean ( ) ) ,
7592 } ) ,
7693 self : M . interface ( 'SettlerSelfI' , {
77- disburse : M . call ( EvmHashShape , M . string ( ) , M . nat ( ) ) . returns (
78- M . promise ( ) ,
79- ) ,
80- forward : M . call (
81- M . opt ( EvmHashShape ) ,
82- M . string ( ) ,
83- M . nat ( ) ,
84- M . string ( ) ,
85- ) . returns ( ) ,
94+ disburse : M . call ( EvmHashShape , M . nat ( ) ) . returns ( M . promise ( ) ) ,
95+ forward : M . call ( EvmHashShape , M . nat ( ) , M . string ( ) ) . returns ( ) ,
8696 } ) ,
8797 transferHandler : M . interface ( 'SettlerTransferI' , {
88- onFulfilled : M . call ( M . any ( ) , M . record ( ) ) . returns ( ) ,
89- onRejected : M . call ( M . any ( ) , M . record ( ) ) . returns ( ) ,
98+ onFulfilled : M . call ( M . undefined ( ) , M . string ( ) ) . returns ( ) ,
99+ onRejected : M . call ( M . error ( ) , M . string ( ) ) . returns ( ) ,
90100 } ) ,
91101 } ,
92102 /**
@@ -174,20 +184,24 @@ export const prepareSettler = (
174184 log ( 'dequeued' , found , 'for' , nfa , amount ) ;
175185 switch ( found ?. status ) {
176186 case PendingTxStatus . Advanced :
177- return self . disburse ( found . txHash , nfa , amount ) ;
187+ return self . disburse ( found . txHash , amount ) ;
178188
179189 case PendingTxStatus . Advancing :
190+ log ( '⚠️ tap: minted while advancing' , nfa , amount ) ;
180191 this . state . mintedEarly . add ( makeMintedEarlyKey ( nfa , amount ) ) ;
181192 return ;
182193
183194 case PendingTxStatus . Observed :
184195 case PendingTxStatus . AdvanceSkipped :
185196 case PendingTxStatus . AdvanceFailed :
186- return self . forward ( found . txHash , nfa , amount , EUD ) ;
197+ return self . forward ( found . txHash , amount , EUD ) ;
187198
188199 case undefined :
189200 default :
190- log ( '⚠️ tap: no status for ' , nfa , amount ) ;
201+ log ( '⚠️ tap: minted before observed' , nfa , amount ) ;
202+ // XXX consider capturing in vstorage
203+ // we would need a new key, as this does not have a txHash
204+ this . state . mintedEarly . add ( makeMintedEarlyKey ( nfa , amount ) ) ;
191205 }
192206 } ,
193207 } ,
@@ -210,16 +224,12 @@ export const prepareSettler = (
210224 const key = makeMintedEarlyKey ( forwardingAddress , fullValue ) ;
211225 if ( mintedEarly . has ( key ) ) {
212226 mintedEarly . delete ( key ) ;
227+ statusManager . advanceOutcomeForMintedEarly ( txHash , success ) ;
213228 if ( success ) {
214- void this . facets . self . disburse (
215- txHash ,
216- forwardingAddress ,
217- fullValue ,
218- ) ;
229+ void this . facets . self . disburse ( txHash , fullValue ) ;
219230 } else {
220231 void this . facets . self . forward (
221232 txHash ,
222- forwardingAddress ,
223233 fullValue ,
224234 destination . value ,
225235 ) ;
@@ -228,14 +238,39 @@ export const prepareSettler = (
228238 statusManager . advanceOutcome ( forwardingAddress , fullValue , success ) ;
229239 }
230240 } ,
241+ /**
242+ * @param {CctpTxEvidence } evidence
243+ * @param {ChainAddress } destination
244+ * @returns {boolean }
245+ * @throws {Error } if minted early, so advancer doesn't advance
246+ */
247+ checkMintedEarly ( evidence , destination ) {
248+ const {
249+ tx : { forwardingAddress, amount } ,
250+ txHash,
251+ } = evidence ;
252+ const key = makeMintedEarlyKey ( forwardingAddress , amount ) ;
253+ const { mintedEarly } = this . state ;
254+ if ( mintedEarly . has ( key ) ) {
255+ log (
256+ 'matched minted early key, initiating forward' ,
257+ forwardingAddress ,
258+ amount ,
259+ ) ;
260+ mintedEarly . delete ( key ) ;
261+ statusManager . advanceOutcomeForUnknownMint ( evidence ) ;
262+ void this . facets . self . forward ( txHash , amount , destination . value ) ;
263+ return true ;
264+ }
265+ return false ;
266+ } ,
231267 } ,
232268 self : {
233269 /**
234270 * @param {EvmHash } txHash
235- * @param {NobleAddress } nfa
236271 * @param {NatValue } fullValue
237272 */
238- async disburse ( txHash , nfa , fullValue ) {
273+ async disburse ( txHash , fullValue ) {
239274 const { repayer, settlementAccount } = this . state ;
240275 const received = AmountMath . make ( USDC , fullValue ) ;
241276 const { zcfSeat : settlingSeat } = zcf . makeEmptySeatKit ( ) ;
@@ -260,56 +295,43 @@ export const prepareSettler = (
260295 ) ;
261296 repayer . repay ( settlingSeat , split ) ;
262297
263- // update status manager, marking tx `SETTLED `
298+ // update status manager, marking tx `DISBURSED `
264299 statusManager . disbursed ( txHash , split ) ;
265300 } ,
266301 /**
267302 * @param {EvmHash } txHash
268- * @param {NobleAddress } nfa
269303 * @param {NatValue } fullValue
270304 * @param {string } EUD
271305 */
272- forward ( txHash , nfa , fullValue , EUD ) {
306+ forward ( txHash , fullValue , EUD ) {
273307 const { settlementAccount, intermediateRecipient } = this . state ;
274-
275308 const dest = chainHub . makeChainAddress ( EUD ) ;
276-
277- // TODO? statusManager.forwarding(txHash, sender, amount);
278309 const txfrV = E ( settlementAccount ) . transfer (
279310 dest ,
280311 AmountMath . make ( USDC , fullValue ) ,
281312 { forwardOpts : { intermediateRecipient } } ,
282313 ) ;
283- void vowTools . watch ( txfrV , this . facets . transferHandler , {
284- txHash,
285- nfa,
286- fullValue,
287- } ) ;
314+ void vowTools . watch ( txfrV , this . facets . transferHandler , txHash ) ;
288315 } ,
289316 } ,
290317 transferHandler : {
291318 /**
292319 * @param {unknown } _result
293- * @param {SettlerTransferCtx } ctx
294- *
295- * @typedef {{
296- * txHash: EvmHash;
297- * nfa: NobleAddress;
298- * fullValue: NatValue;
299- * }} SettlerTransferCtx
320+ * @param {EvmHash } txHash
300321 */
301- onFulfilled ( _result , ctx ) {
302- const { txHash , nfa , fullValue } = ctx ;
303- statusManager . forwarded ( txHash , nfa , fullValue ) ;
322+ onFulfilled ( _result , txHash ) {
323+ // update status manager, marking tx `FORWARDED` without fee split
324+ statusManager . forwarded ( txHash , true ) ;
304325 } ,
305326 /**
306327 * @param {unknown } reason
307- * @param {SettlerTransferCtx } ctx
328+ * @param {EvmHash } txHash
308329 */
309- onRejected ( reason , ctx ) {
310- log ( '⚠️ transfer rejected!' , reason , ctx ) ;
311- // const { txHash, nfa, amount } = ctx;
312- // TODO(#10510): statusManager.forwardFailed(txHash, nfa, amount);
330+ onRejected ( reason , txHash ) {
331+ log ( '⚠️ forward transfer rejected!' , reason , txHash ) ;
332+ // update status manager, flagging a terminal state that needs to be
333+ // manual intervention or a code update to remediate
334+ statusManager . forwarded ( txHash , false ) ;
313335 } ,
314336 } ,
315337 } ,
0 commit comments