Skip to content

Commit d417d93

Browse files
committed
fix(monitor): implement v2 escrow accounts
1 parent f549f3c commit d417d93

File tree

1 file changed

+119
-5
lines changed

1 file changed

+119
-5
lines changed

crates/monitor/src/escrow_accounts.rs

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,77 @@ pub async fn escrow_accounts_v2(
112112
.await
113113
}
114114

115-
// TODO implement escrow accounts v2 query
116115
async fn get_escrow_accounts_v2(
117-
_escrow_subgraph: &'static SubgraphClient,
118-
_indexer_address: Address,
119-
_reject_thawing_signers: bool,
116+
escrow_subgraph: &'static SubgraphClient,
117+
indexer_address: Address,
118+
reject_thawing_signers: bool,
120119
) -> anyhow::Result<EscrowAccounts> {
121-
Ok(EscrowAccounts::new(HashMap::new(), HashMap::new()))
120+
// V2 TAP receipts use different field names (payer/service_provider) but the underlying
121+
// escrow account model is identical to V1. Both V1 and V2 receipts reference the same
122+
// sender addresses and the same escrow relationships.
123+
//
124+
// The separation of V1/V2 escrow account watchers allows for potential future differences
125+
// in escrow models, but currently both query the same subgraph data with identical logic.
126+
//
127+
// V2 receipt flow:
128+
// 1. V2 receipt contains payer address (equivalent to V1 sender)
129+
// 2. Receipt is signed by a signer authorized by the payer
130+
// 3. Escrow accounts map: signer -> payer (sender) -> balance
131+
// 4. Service provider (indexer) receives payments from payer's escrow
132+
133+
let response = escrow_subgraph
134+
.query::<EscrowAccountQuery, _>(escrow_account::Variables {
135+
indexer: format!("{:x?}", indexer_address),
136+
thaw_end_timestamp: if reject_thawing_signers {
137+
U256::ZERO.to_string()
138+
} else {
139+
U256::MAX.to_string()
140+
},
141+
})
142+
.await?;
143+
144+
let response = response?;
145+
146+
tracing::trace!("V2 Escrow accounts response: {:?}", response);
147+
148+
let senders_balances: HashMap<Address, U256> = response
149+
.escrow_accounts
150+
.iter()
151+
.map(|account| {
152+
let balance = U256::checked_sub(
153+
U256::from_str(&account.balance)?,
154+
U256::from_str(&account.total_amount_thawing)?,
155+
)
156+
.unwrap_or_else(|| {
157+
tracing::warn!(
158+
"Balance minus total amount thawing underflowed for V2 account {}. \
159+
Setting balance to 0, no V2 queries will be served for this sender.",
160+
account.sender.id
161+
);
162+
U256::from(0)
163+
});
164+
165+
Ok((Address::from_str(&account.sender.id)?, balance))
166+
})
167+
.collect::<Result<HashMap<_, _>, anyhow::Error>>()?;
168+
169+
let senders_to_signers = response
170+
.escrow_accounts
171+
.into_iter()
172+
.map(|account| {
173+
let sender = Address::from_str(&account.sender.id)?;
174+
let signers = account
175+
.sender
176+
.signers
177+
.ok_or(anyhow!("Could not find any signers for V2 sender {sender}"))?
178+
.iter()
179+
.map(|signer| Address::from_str(&signer.id))
180+
.collect::<Result<Vec<_>, _>>()?;
181+
Ok((sender, signers))
182+
})
183+
.collect::<Result<HashMap<_, _>, anyhow::Error>>()?;
184+
185+
Ok(EscrowAccounts::new(senders_balances, senders_to_signers))
122186
}
123187

124188
async fn get_escrow_accounts_v1(
@@ -262,4 +326,54 @@ mod tests {
262326
)
263327
);
264328
}
329+
330+
#[test(tokio::test)]
331+
async fn test_current_accounts_v2() {
332+
// Set up a mock escrow subgraph - V2 uses the same subgraph as V1
333+
let mock_server = MockServer::start().await;
334+
let escrow_subgraph = Box::leak(Box::new(
335+
SubgraphClient::new(
336+
reqwest::Client::new(),
337+
None,
338+
DeploymentDetails::for_query_url(&format!(
339+
"{}/subgraphs/id/{}",
340+
&mock_server.uri(),
341+
test_assets::ESCROW_SUBGRAPH_DEPLOYMENT
342+
))
343+
.unwrap(),
344+
)
345+
.await,
346+
));
347+
348+
let mock = Mock::given(method("POST"))
349+
.and(path(format!(
350+
"/subgraphs/id/{}",
351+
test_assets::ESCROW_SUBGRAPH_DEPLOYMENT
352+
)))
353+
.respond_with(
354+
ResponseTemplate::new(200)
355+
.set_body_raw(test_assets::ESCROW_QUERY_RESPONSE, "application/json"),
356+
);
357+
mock_server.register(mock).await;
358+
359+
// Test V2 escrow accounts watcher
360+
let mut accounts = escrow_accounts_v2(
361+
escrow_subgraph,
362+
test_assets::INDEXER_ADDRESS,
363+
Duration::from_secs(60),
364+
true,
365+
)
366+
.await
367+
.unwrap();
368+
accounts.changed().await.unwrap();
369+
370+
// V2 should produce identical results to V1 since they query the same data
371+
assert_eq!(
372+
accounts.borrow().clone(),
373+
EscrowAccounts::new(
374+
ESCROW_ACCOUNTS_BALANCES.to_owned(),
375+
ESCROW_ACCOUNTS_SENDERS_TO_SIGNERS.to_owned(),
376+
)
377+
);
378+
}
265379
}

0 commit comments

Comments
 (0)