@@ -119,18 +119,16 @@ type AssetMovement = {
119119 accounts : AccountsByChain ,
120120 tracer : TraceLogger ,
121121 ) => Promise < { srcPos ?: Position ; destPos ?: Position } > ;
122- recover : ( accounts : AccountsByChain , tracer : TraceLogger ) => Promise < void > ;
123122} ;
124123
125- const moveStatus = ( { apply : _a , recover : _r , ...data } : AssetMovement ) => data ;
124+ const moveStatus = ( { apply : _a , ...data } : AssetMovement ) => data ;
126125const errmsg = ( err : any ) => ( 'message' in err ? err . message : `${ err } ` ) ;
127126
128127export type TransportDetail <
129128 How extends string ,
130129 S extends SupportedChain ,
131130 D extends SupportedChain ,
132131 CTX = unknown ,
133- RecoverCTX = CTX ,
134132> = {
135133 how : How ;
136134 connections : { src : S ; dest : D } [ ] ;
@@ -140,12 +138,6 @@ export type TransportDetail<
140138 src : AccountInfoFor [ S ] ,
141139 dest : AccountInfoFor [ D ] ,
142140 ) => Promise < void > ;
143- recover : (
144- ctx : RecoverCTX ,
145- amount : NatAmount ,
146- src : AccountInfoFor [ S ] ,
147- dest : AccountInfoFor [ D ] ,
148- ) => Promise < void > ;
149141} ;
150142
151143export type ProtocolDetail <
@@ -169,9 +161,9 @@ export type ProtocolDetail<
169161} ;
170162
171163/**
172- * **Failure Handling**: Attempts to unwind failed operations, but recovery
173- * itself can fail. In that case, publishes final asset location to vstorage
174- * and gives up. Clients must manually rebalance to recover .
164+ * **Failure Handling**: Logs failures and publishes status without attempting
165+ * to unwind already-completed steps. Operators must resolve any partial
166+ * effects manually.
175167 */
176168const trackFlow = async (
177169 reporter : GuestInterface < PortfolioKit [ 'reporter' ] > ,
@@ -203,35 +195,15 @@ const trackFlow = async (
203195 reporter . publishFlowStatus ( flowId , { state : 'done' } ) ;
204196 // TODO(#NNNN): delete the flow storage node
205197 } catch ( err ) {
206- traceFlow ( '⚠️ step' , step , ' failed' , err ) ;
198+ traceFlow ( '⚠️ step' , step , 'failed' , err ) ;
207199 const failure = moves [ step - 1 ] ;
208- const errStep = step ;
209- while ( step > 1 ) {
210- step -= 1 ;
211- const traceStep = traceFlow . sub ( `step${ step } ` ) ;
212- const move = moves [ step - 1 ] ;
213- const how = `unwind: ${ move . how } ` ;
214- reporter . publishFlowStatus ( flowId , { state : 'undo' , step, how } ) ;
215- try {
216- await move . recover ( accounts , traceStep ) ;
217- } catch ( errInUnwind ) {
218- traceStep ( '⚠️ unwind failed' , errInUnwind ) ;
219- // if a recover fails, we just give up and report `where` the assets are
220- const { dest : where } = move ;
221- reporter . publishFlowStatus ( flowId , {
222- state : 'fail' ,
223- step,
224- how,
225- error : errmsg ( errInUnwind ) ,
226- where,
227- } ) ;
228- throw errInUnwind ;
229- }
200+ if ( failure ) {
201+ traceFlow ( 'failed movement details' , moveStatus ( failure ) ) ;
230202 }
231203 reporter . publishFlowStatus ( flowId , {
232204 state : 'fail' ,
233- step : errStep ,
234- how : failure . how ,
205+ step,
206+ how : failure ? .how ?? 'unknown' ,
235207 error : errmsg ( err ) ,
236208 } ) ;
237209 throw err ;
@@ -517,24 +489,6 @@ const stepFlow = async (
517489 return { srcPos : pos } ;
518490 }
519491 } ,
520- recover : async ( { [ evmChain ] : gInfo } ) => {
521- assert ( gInfo , evmChain ) ;
522- await null ;
523- if ( 'src' in way ) {
524- assert . fail ( 'last step. cannot recover' ) ;
525- } else {
526- const { lca } = agoric ;
527- const { poolKey } = way ;
528- const evmCtx = await makeEVMPoolCtx (
529- evmChain ,
530- move ,
531- lca ,
532- poolKey ,
533- ctx . transferChannels . noble . counterPartyChannelId ,
534- ) ;
535- await pImpl . supply ( evmCtx , amount , gInfo ) ;
536- }
537- } ,
538492 } ) ;
539493 } ;
540494
@@ -544,8 +498,8 @@ const stepFlow = async (
544498 traceFlow ( 'checking' , moves . length , 'moves' ) ;
545499 for ( const [ i , move ] of entries ( moves ) ) {
546500 const traceMove = traceFlow . sub ( `move${ i } ` ) ;
547- // @@@ traceMove('wayFromSrcToDesc?', move);
548501 const way = wayFromSrcToDesc ( move ) ;
502+ traceMove ( 'plan' , { move, way } ) ;
549503 const { amount } = move ;
550504 switch ( way . how ) {
551505 case 'localTransfer' : {
@@ -562,11 +516,6 @@ const stepFlow = async (
562516 await ctx . zoeTools . localTransfer ( src . seat , account , amounts ) ;
563517 return { } ;
564518 } ,
565- recover : async ( { agoric } ) => {
566- const { lca, lcaIn } = agoric ;
567- const account = move . dest === '+agoric' ? lcaIn : lca ;
568- await ctx . zoeTools . withdrawToSeat ( account , seat , amounts ) ;
569- } ,
570519 } ) ;
571520 break ;
572521 }
@@ -582,9 +531,6 @@ const stepFlow = async (
582531 await ctx . zoeTools . withdrawToSeat ( agoric . lca , seat , amounts ) ;
583532 return { } ;
584533 } ,
585- recover : async ( { agoric } ) => {
586- await ctx . zoeTools . localTransfer ( seat , agoric . lca , amounts ) ;
587- } ,
588534 } ) ;
589535 break ;
590536 }
@@ -600,9 +546,6 @@ const stepFlow = async (
600546 await lcaIn . send ( lca . getAddress ( ) , amount ) ;
601547 return { } ;
602548 } ,
603- recover : async ( ) => {
604- traceMove ( 'recover send is noop; not sending back to deposit LCA' ) ;
605- } ,
606549 } ) ;
607550 break ;
608551
@@ -629,15 +572,6 @@ const stepFlow = async (
629572 }
630573 return { } ;
631574 } ,
632- recover : async ( { agoric, noble } ) => {
633- assert ( noble ) ; // per nobleMentioned below
634- await null ;
635- if ( way . src === 'agoric' ) {
636- await agoricToNoble . recover ( ctxI , amount , agoric , noble ) ;
637- } else {
638- await nobleToAgoric . recover ( ctxI , amount , noble , agoric ) ;
639- }
640- } ,
641575 } ) ;
642576
643577 break ;
@@ -671,15 +605,6 @@ const stepFlow = async (
671605 }
672606 return { } ;
673607 } ,
674- recover : async ( { [ evmChain ] : gInfo , agoric, noble } ) => {
675- assert ( gInfo && noble , evmChain ) ;
676- await null ;
677- if ( outbound ) {
678- await CCTP . recover ( ctx , amount , noble , gInfo ) ;
679- } else {
680- await CCTPfromEVM . recover ( ctx , amount , gInfo , agoric ) ;
681- }
682- } ,
683608 } ) ;
684609
685610 break ;
@@ -709,15 +634,6 @@ const stepFlow = async (
709634 return { srcPos : pos } ;
710635 }
711636 } ,
712- recover : async ( { noble } ) => {
713- assert ( noble ) ; // per nobleMentioned below
714- await null ;
715- if ( isSupply ) {
716- Fail `no recovery from supply (final step)` ;
717- } else {
718- await protocolUSDN . supply ( ctxU , amount , noble ) ;
719- }
720- } ,
721637 } ) ;
722638
723639 break ;
@@ -759,7 +675,7 @@ const stepFlow = async (
759675 } ) ;
760676 reporter . publishFlowSteps (
761677 flowId ,
762- todo . map ( ( { apply : _a , recover : _r , ...data } ) => data ) ,
678+ todo . map ( ( { apply : _a , ...data } ) => data ) ,
763679 ) ;
764680
765681 const agoric = await provideCosmosAccount ( orch , 'agoric' , kit , traceFlow ) ;
@@ -840,11 +756,12 @@ const stepFlow = async (
840756 * More generally: move assets as instructed by client.
841757 *
842758 * **Non-Atomic Operations**: Cross-chain flows are not atomic. If operations
843- * fail partway through, assets may be left in intermediate accounts.
844- * Recovery is attempted but can also fail, leaving assets "stranded" .
759+ * fail partway through, assets may be left in intermediate accounts and must
760+ * be reconciled manually .
845761 *
846762 * **Client Recovery**: If rebalancing fails, check flow status in vstorage
847- * and call rebalance() again to move assets to desired destinations.
763+ * and call rebalance() again (or another corrective flow) to move assets to
764+ * desired destinations.
848765 *
849766 * **Input Validation**: ASSUME caller validates args
850767 *
0 commit comments