@@ -6,20 +6,22 @@ import { VowShape } from '@agoric/vow';
6
6
import { q } from '@endo/errors' ;
7
7
import { E } from '@endo/far' ;
8
8
import { M } from '@endo/patterns' ;
9
- import { CctpTxEvidenceShape , EudParamShape } from '../type-guards.js' ;
9
+ import {
10
+ CctpTxEvidenceShape ,
11
+ EudParamShape ,
12
+ EvmHashShape ,
13
+ } from '../type-guards.js' ;
10
14
import { addressTools } from '../utils/address.js' ;
11
15
import { makeFeeTools } from '../utils/fees.js' ;
12
16
13
- const { isGTE } = AmountMath ;
14
-
15
17
/**
16
18
* @import {HostInterface} from '@agoric/async-flow';
17
19
* @import {NatAmount} from '@agoric/ertp';
18
20
* @import {ChainAddress, ChainHub, Denom, OrchestrationAccount} from '@agoric/orchestration';
19
21
* @import {ZoeTools} from '@agoric/orchestration/src/utils/zoe-tools.js';
20
22
* @import {VowTools} from '@agoric/vow';
21
23
* @import {Zone} from '@agoric/zone';
22
- * @import {CctpTxEvidence, FeeConfig, LogFn} from '../types.js';
24
+ * @import {CctpTxEvidence, EvmHash, FeeConfig, LogFn, NobleAddress } from '../types.js';
23
25
* @import {StatusManager} from './status-manager.js';
24
26
* @import {LiquidityPoolKit} from './liquidity-pool.js';
25
27
*/
@@ -46,27 +48,44 @@ const AdvancerKitI = harden({
46
48
onFulfilled : M . call ( M . undefined ( ) , {
47
49
amount : AmountShape ,
48
50
destination : ChainAddressShape ,
51
+ forwardingAddress : M . string ( ) ,
49
52
tmpSeat : M . remotable ( ) ,
53
+ txHash : EvmHashShape ,
50
54
} ) . returns ( VowShape ) ,
51
55
onRejected : M . call ( M . error ( ) , {
52
56
amount : AmountShape ,
53
57
destination : ChainAddressShape ,
58
+ forwardingAddress : M . string ( ) ,
54
59
tmpSeat : M . remotable ( ) ,
60
+ txHash : EvmHashShape ,
55
61
} ) . returns ( ) ,
56
62
} ) ,
57
63
transferHandler : M . interface ( 'TransferHandlerI' , {
58
64
// TODO confirm undefined, and not bigint (sequence)
59
65
onFulfilled : M . call ( M . undefined ( ) , {
60
66
amount : AmountShape ,
61
67
destination : ChainAddressShape ,
68
+ forwardingAddress : M . string ( ) ,
69
+ txHash : EvmHashShape ,
62
70
} ) . returns ( M . undefined ( ) ) ,
63
71
onRejected : M . call ( M . error ( ) , {
64
72
amount : AmountShape ,
65
73
destination : ChainAddressShape ,
74
+ forwardingAddress : M . string ( ) ,
75
+ txHash : EvmHashShape ,
66
76
} ) . returns ( M . undefined ( ) ) ,
67
77
} ) ,
68
78
} ) ;
69
79
80
+ /**
81
+ * @typedef {{
82
+ * amount: NatAmount;
83
+ * destination: ChainAddress;
84
+ * forwardingAddress: NobleAddress;
85
+ * txHash: EvmHash;
86
+ * }} AdvancerVowCtx
87
+ */
88
+
70
89
/**
71
90
* @param {Zone } zone
72
91
* @param {AdvancerKitPowers } caps
@@ -100,6 +119,7 @@ export const prepareAdvancerKit = (
100
119
AdvancerKitI ,
101
120
/**
102
121
* @param {{
122
+ * notifyFacet: import('./settler.js').SettlerKit['notify'];
103
123
* borrowerFacet: LiquidityPoolKit['borrower'];
104
124
* poolAccount: HostInterface<OrchestrationAccount<{chainId: 'agoric'}>>;
105
125
* }} config
@@ -120,51 +140,32 @@ export const prepareAdvancerKit = (
120
140
async handleTransactionEvent ( evidence ) {
121
141
await null ;
122
142
try {
143
+ if ( statusManager . hasBeenObserved ( evidence ) ) {
144
+ log ( 'txHash already seen:' , evidence . txHash ) ;
145
+ return ;
146
+ }
147
+
123
148
const { borrowerFacet, poolAccount } = this . state ;
124
149
const { recipientAddress } = evidence . aux ;
150
+ // throws if EUD is not found
125
151
const { EUD } = addressTools . getQueryParams (
126
152
recipientAddress ,
127
153
EudParamShape ,
128
154
) ;
129
-
130
- // this will throw if the bech32 prefix is not found, but is handled by the catch
155
+ // throws if the bech32 prefix is not found
131
156
const destination = chainHub . makeChainAddress ( EUD ) ;
157
+
132
158
const requestedAmount = toAmount ( evidence . tx . amount ) ;
159
+ // throws if requested does not exceed fees
133
160
const advanceAmount = feeTools . calculateAdvance ( requestedAmount ) ;
134
161
135
- // TODO: consider skipping and using `borrow()`s internal balance check
136
- const poolBalance = borrowerFacet . getBalance ( ) ;
137
- if ( ! isGTE ( poolBalance , requestedAmount ) ) {
138
- log (
139
- `Insufficient pool funds` ,
140
- `Requested ${ q ( advanceAmount ) } but only have ${ q ( poolBalance ) } ` ,
141
- ) ;
142
- statusManager . observe ( evidence ) ;
143
- return ;
144
- }
145
-
146
- try {
147
- // Mark as Advanced since `transferV` initiates the advance.
148
- // Will throw if we've already .skipped or .advanced this evidence.
149
- statusManager . advance ( evidence ) ;
150
- } catch ( e ) {
151
- // Only anticipated error is `assertNotSeen`, so intercept the
152
- // catch so we don't call .skip which also performs this check
153
- log ( 'Advancer error:' , q ( e ) . toString ( ) ) ;
154
- return ;
155
- }
156
-
157
162
const { zcfSeat : tmpSeat } = zcf . makeEmptySeatKit ( ) ;
158
163
const amountKWR = harden ( { USDC : advanceAmount } ) ;
159
- try {
160
- borrowerFacet . borrow ( tmpSeat , amountKWR ) ;
161
- } catch ( e ) {
162
- // We do not expect this to fail since there are no turn boundaries
163
- // between .getBalance() and .borrow().
164
- // We catch to report outside of the normal error flow since this is
165
- // not expected.
166
- log ( '🚨 advance borrow failed' , q ( e ) . toString ( ) ) ;
167
- }
164
+ // throws if the pool has insufficient funds
165
+ borrowerFacet . borrow ( tmpSeat , amountKWR ) ;
166
+
167
+ // this cannot throw since `.isSeen()` is called in the same turn
168
+ statusManager . advance ( evidence ) ;
168
169
169
170
const depositV = localTransfer (
170
171
tmpSeat ,
@@ -175,7 +176,9 @@ export const prepareAdvancerKit = (
175
176
void watch ( depositV , this . facets . depositHandler , {
176
177
amount : advanceAmount ,
177
178
destination,
179
+ forwardingAddress : evidence . tx . forwardingAddress ,
178
180
tmpSeat,
181
+ txHash : evidence . txHash ,
179
182
} ) ;
180
183
} catch ( e ) {
181
184
log ( 'Advancer error:' , q ( e ) . toString ( ) ) ;
@@ -186,22 +189,25 @@ export const prepareAdvancerKit = (
186
189
depositHandler : {
187
190
/**
188
191
* @param {undefined } result
189
- * @param {{ amount: Amount<'nat'>; destination: ChainAddress; tmpSeat: ZCFSeat } } ctx
192
+ * @param {AdvancerVowCtx & { tmpSeat: ZCFSeat } } ctx
190
193
*/
191
- onFulfilled ( result , { amount , destination } ) {
194
+ onFulfilled ( result , ctx ) {
192
195
const { poolAccount } = this . state ;
196
+ const { amount, destination, forwardingAddress, txHash } = ctx ;
193
197
const transferV = E ( poolAccount ) . transfer ( destination , {
194
198
denom : usdc . denom ,
195
199
value : amount . value ,
196
200
} ) ;
197
201
return watch ( transferV , this . facets . transferHandler , {
198
202
destination,
199
203
amount,
204
+ forwardingAddress,
205
+ txHash,
200
206
} ) ;
201
207
} ,
202
208
/**
203
209
* @param {Error } error
204
- * @param {{ amount: Amount<'nat'>; destination: ChainAddress; tmpSeat: ZCFSeat } } ctx
210
+ * @param {AdvancerVowCtx & { tmpSeat: ZCFSeat } } ctx
205
211
*/
206
212
onRejected ( error , { tmpSeat } ) {
207
213
// TODO return seat allocation from ctx to LP?
@@ -217,25 +223,44 @@ export const prepareAdvancerKit = (
217
223
transferHandler : {
218
224
/**
219
225
* @param {undefined } result TODO confirm this is not a bigint (sequence)
220
- * @param {{ destination: ChainAddress; amount: NatAmount; } } ctx
226
+ * @param {AdvancerVowCtx } ctx
221
227
*/
222
- onFulfilled ( result , { destination , amount } ) {
223
- // TODO vstorage update? We don't currently have a status for
224
- // Advanced + transferV settled
228
+ onFulfilled ( result , ctx ) {
229
+ const { notifyFacet } = this . state ;
230
+ const { amount , destination , forwardingAddress , txHash } = ctx ;
225
231
log (
226
232
'Advance transfer fulfilled' ,
227
233
q ( { amount, destination, result } ) . toString ( ) ,
228
234
) ;
235
+ notifyFacet . notifyAdvancingResult (
236
+ txHash ,
237
+ forwardingAddress ,
238
+ amount . value ,
239
+ destination . value ,
240
+ true ,
241
+ ) ;
229
242
} ,
230
- onRejected ( error ) {
231
- // TODO #10510 (comprehensive error testing) determine
232
- // course of action here. This might fail due to timeout.
243
+ /**
244
+ * @param {Error } error
245
+ * @param {AdvancerVowCtx } ctx
246
+ */
247
+ onRejected ( error , ctx ) {
248
+ const { notifyFacet } = this . state ;
249
+ const { amount, destination, forwardingAddress, txHash } = ctx ;
233
250
log ( 'Advance transfer rejected' , q ( error ) . toString ( ) ) ;
251
+ notifyFacet . notifyAdvancingResult (
252
+ txHash ,
253
+ forwardingAddress ,
254
+ amount . value ,
255
+ destination . value ,
256
+ false ,
257
+ ) ;
234
258
} ,
235
259
} ,
236
260
} ,
237
261
{
238
262
stateShape : harden ( {
263
+ notifyFacet : M . remotable ( ) ,
239
264
borrowerFacet : M . remotable ( ) ,
240
265
poolAccount : M . remotable ( ) ,
241
266
} ) ,
0 commit comments