@@ -14,11 +14,11 @@ use ethers::{
14
14
middleware:: { signer:: SignerMiddlewareError , SignerMiddleware } ,
15
15
providers:: { Http , Middleware , Provider } ,
16
16
signers:: LocalWallet ,
17
- types:: { Address , TransactionRequest , H256 } ,
17
+ types:: { Address , TransactionRequest , H160 , H256 } ,
18
18
utils:: { parse_checksummed, parse_ether, to_checksum, ConversionError , WEI_IN_ETHER } ,
19
19
} ;
20
20
use serde:: Deserialize ;
21
- use tokio:: sync:: Mutex ;
21
+ use tokio:: sync:: { Mutex , OnceCell } ;
22
22
23
23
#[ derive( Template ) ]
24
24
#[ template( path = "home.html" ) ]
@@ -36,11 +36,20 @@ enum RequestStatus {
36
36
AddrErr ( anyhow:: Error ) ,
37
37
SendErr ( SignerMiddlewareError < Provider < Http > , LocalWallet > ) ,
38
38
RateLimitErr ( Duration ) ,
39
+ ConfigErr ( anyhow:: Error ) ,
39
40
}
40
41
41
- async fn home_inner ( State ( state) : State < Arc < AppState > > , status : Option < RequestStatus > ) -> Home {
42
+ async fn home_inner ( State ( state) : State < Arc < AppState > > , mut status : Option < RequestStatus > ) -> Home {
43
+ let addr = match state. provider ( ) . await {
44
+ Ok ( p) => p. address ( ) ,
45
+ Err ( e) => {
46
+ eprintln ! ( "{e:?}" ) ;
47
+ status = Some ( RequestStatus :: ConfigErr ( e) ) ;
48
+ H160 :: zero ( )
49
+ }
50
+ } ;
42
51
Home {
43
- from_addr : to_checksum ( & state . provider . address ( ) , None ) ,
52
+ from_addr : to_checksum ( & addr , None ) ,
44
53
native_token_symbol : state. config . native_token_symbol . clone ( ) ,
45
54
amount : state. config . eth_amount . clone ( ) ,
46
55
explorer_url : state. config . explorer_url . clone ( ) ,
@@ -55,6 +64,7 @@ async fn home_inner(State(state): State<Arc<AppState>>, status: Option<RequestSt
55
64
"Request made too recently, please wait {} seconds before trying again" ,
56
65
d. as_secs( )
57
66
) ) ,
67
+ Some ( RequestStatus :: ConfigErr ( e) ) => Some ( format ! ( "Spout is misconfigured: {e:?}" ) ) ,
58
68
_ => None ,
59
69
} ,
60
70
}
@@ -150,16 +160,17 @@ async fn request(State(state): State<Arc<AppState>>, Form(request): Form<Request
150
160
}
151
161
}
152
162
153
- let value = parse_ether ( & state. config . eth_amount ) . unwrap_or ( WEI_IN_ETHER ) ;
154
- let chain_id = match state. provider . get_chainid ( ) . await {
155
- Ok ( c) => c,
163
+ let provider = match state. provider ( ) . await {
164
+ Ok ( p) => p,
156
165
Err ( e) => {
157
166
eprintln ! ( "{e:?}" ) ;
158
- return home_inner ( State ( state. clone ( ) ) , Some ( RequestStatus :: SendErr ( e) ) ) . await ;
167
+ return home_inner ( State ( state. clone ( ) ) , Some ( RequestStatus :: ConfigErr ( e) ) ) . await ;
159
168
}
160
169
} ;
161
- let tx = TransactionRequest :: pay ( address, value) . chain_id ( chain_id. low_u64 ( ) ) ;
162
- let status = match state. provider . send_transaction ( tx, None ) . await {
170
+
171
+ let value = parse_ether ( & state. config . eth_amount ) . unwrap_or ( WEI_IN_ETHER ) ;
172
+ let tx = TransactionRequest :: pay ( address, value) ;
173
+ let status = match provider. send_transaction ( tx, None ) . await {
163
174
Ok ( t) => RequestStatus :: Sent ( t. tx_hash ( ) ) ,
164
175
Err ( e) => {
165
176
eprintln ! ( "{e:?}" ) ;
@@ -217,22 +228,29 @@ impl Config {
217
228
}
218
229
219
230
struct AppState {
220
- provider : SignerMiddleware < Provider < Http > , LocalWallet > ,
231
+ provider : OnceCell < SignerMiddleware < Provider < Http > , LocalWallet > > ,
221
232
config : Config ,
222
233
last_request : Mutex < HashMap < Address , Instant > > ,
223
234
}
224
235
236
+ impl AppState {
237
+ async fn provider ( & self ) -> Result < & SignerMiddleware < Provider < Http > , LocalWallet > > {
238
+ let provider = Provider :: try_from ( & self . config . rpc_url ) ?;
239
+ let wallet: LocalWallet = self . config . private_key . parse ( ) ?;
240
+ Ok ( self
241
+ . provider
242
+ . get_or_try_init ( || SignerMiddleware :: new_with_provider_chain ( provider, wallet) )
243
+ . await ?)
244
+ }
245
+ }
246
+
225
247
#[ tokio:: main]
226
248
async fn main ( ) -> Result < ( ) > {
227
249
let config = Config :: from_env ( ) ?;
228
250
229
- let provider = Provider :: try_from ( & config. rpc_url ) ?;
230
- let wallet: LocalWallet = config. private_key . parse ( ) ?;
231
- let provider = SignerMiddleware :: new ( provider, wallet) ;
232
-
233
251
let addr = ( "0.0.0.0" . parse :: < IpAddr > ( ) ?, config. http_port ) ;
234
252
let state = Arc :: new ( AppState {
235
- provider,
253
+ provider : OnceCell :: new ( ) ,
236
254
config,
237
255
last_request : Default :: default ( ) ,
238
256
} ) ;
0 commit comments