-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathsender.rs
131 lines (114 loc) · 3.94 KB
/
sender.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2023-, Edge & Node, GraphOps, and Semiotic Labs.
// SPDX-License-Identifier: Apache-2.0
use axum::{
extract::{Request, State},
middleware::Next,
response::Response,
};
use indexer_monitor::EscrowAccounts;
use thegraph_core::alloy::{primitives::Address, sol_types::Eip712Domain};
use tokio::sync::watch;
use crate::{error::IndexerServiceError, tap::TapReceipt};
/// Stated used by sender middleware
#[derive(Clone)]
pub struct SenderState {
/// Used to recover the signer address
pub domain_separator: Eip712Domain,
/// Used to get the sender address given the signer address if v1 receipt
pub escrow_accounts_v1: watch::Receiver<EscrowAccounts>,
/// Used to get the sender address given the signer address if v2 receipt
pub escrow_accounts_v2: watch::Receiver<EscrowAccounts>,
}
/// The current query Sender address
#[derive(Clone)]
pub struct Sender(pub Address);
impl From<Sender> for String {
fn from(value: Sender) -> Self {
value.0.to_string()
}
}
/// Injects the sender found from the signer in the receipt
///
/// A request won't always have a receipt because they might be
/// free queries.
/// That's why we don't fail with 400.
///
/// Requires Receipt extension
pub async fn sender_middleware(
State(state): State<SenderState>,
mut request: Request,
next: Next,
) -> Result<Response, IndexerServiceError> {
if let Some(receipt) = request.extensions().get::<TapReceipt>() {
let signer = receipt.recover_signer(&state.domain_separator)?;
let sender = match receipt {
TapReceipt::V1(_) => state
.escrow_accounts_v1
.borrow()
.get_sender_for_signer(&signer)?,
TapReceipt::V2(_) => state
.escrow_accounts_v2
.borrow()
.get_sender_for_signer(&signer)?,
};
request.extensions_mut().insert(Sender(sender));
}
Ok(next.run(request).await)
}
#[cfg(test)]
mod tests {
use axum::{
body::Body,
http::{Extensions, Request},
middleware::from_fn_with_state,
routing::get,
Router,
};
use indexer_monitor::EscrowAccounts;
use reqwest::StatusCode;
use test_assets::{
create_signed_receipt, SignedReceiptRequest, ESCROW_ACCOUNTS_BALANCES,
ESCROW_ACCOUNTS_SENDERS_TO_SIGNERS,
};
use tokio::sync::watch;
use tower::ServiceExt;
use super::{sender_middleware, Sender};
use crate::{middleware::sender::SenderState, tap::TapReceipt};
#[tokio::test]
async fn test_sender_middleware() {
let escrow_accounts_v1 = watch::channel(EscrowAccounts::new(
ESCROW_ACCOUNTS_BALANCES.to_owned(),
ESCROW_ACCOUNTS_SENDERS_TO_SIGNERS.to_owned(),
))
.1;
let escrow_accounts_v2 = watch::channel(EscrowAccounts::new(
ESCROW_ACCOUNTS_BALANCES.to_owned(),
ESCROW_ACCOUNTS_SENDERS_TO_SIGNERS.to_owned(),
))
.1;
let state = SenderState {
domain_separator: test_assets::TAP_EIP712_DOMAIN.clone(),
escrow_accounts_v1,
escrow_accounts_v2,
};
let middleware = from_fn_with_state(state, sender_middleware);
async fn handle(extensions: Extensions) -> Body {
let sender = extensions.get::<Sender>().expect("Should contain sender");
assert_eq!(sender.0, test_assets::TAP_SENDER.1);
Body::empty()
}
let app = Router::new().route("/", get(handle)).layer(middleware);
let receipt = create_signed_receipt(SignedReceiptRequest::builder().build()).await;
let res = app
.oneshot(
Request::builder()
.uri("/")
.extension(TapReceipt::V1(receipt))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
}
}