1use async_channel::{unbounded, Receiver, Sender, TryRecvError};
2use bevy::{
3 prelude::*,
4 tasks::{IoTaskPool, TaskPool},
5};
6use web3::{transports::eip_1193, types::TransactionRequest};
7
8pub use web3::types::{H160, H256, H520, U256};
9
10pub enum RecvError {
11 Empty,
12 Closed,
13}
14
15impl From<TryRecvError> for RecvError {
16 fn from(e: TryRecvError) -> RecvError {
17 match e {
18 TryRecvError::Empty => RecvError::Empty,
19 TryRecvError::Closed => RecvError::Closed,
20 }
21 }
22}
23
24pub struct WalletPlugin;
25
26impl Plugin for WalletPlugin {
27 fn build(&self, app: &mut App) {
28 app.add_systems(Startup, init_wallet);
29 }
30}
31
32#[derive(Resource)]
33pub struct WalletChannel {
34 account_tx: Sender<(H160, U256)>,
35 account_rx: Receiver<(H160, U256)>,
36 signature_tx: Sender<H520>,
37 signature_rx: Receiver<H520>,
38 transaction_tx: Sender<H256>,
39 transaction_rx: Receiver<H256>,
40}
41
42fn init_wallet(mut commands: Commands) {
43 let (account_tx, account_rx) = unbounded();
44 let (signature_tx, signature_rx) = unbounded();
45 let (transaction_tx, transaction_rx) = unbounded();
46
47 commands.insert_resource(WalletChannel {
48 account_tx,
49 account_rx,
50 signature_tx,
51 signature_rx,
52 transaction_tx,
53 transaction_rx,
54 });
55}
56
57impl WalletChannel {
58 pub fn connect(&self) {
59 let tx = self.account_tx.clone();
60 IoTaskPool::get_or_init(TaskPool::new)
61 .spawn(async move {
62 let provider = eip_1193::Provider::default().unwrap().unwrap();
63 let transport = eip_1193::Eip1193::new(provider);
64 let web3 = web3::Web3::new(transport);
65
66 let addrs = web3.eth().request_accounts().await.unwrap();
67 let chain = web3.eth().chain_id().await.unwrap();
68
69 if !addrs.is_empty() {
70 info!("addrs: {:?}", addrs);
71 let _ = tx.send((addrs[0], chain)).await;
72 }
73 })
74 .detach();
75 }
76
77 pub fn sign(&self, account: H160, msg: String) {
78 let tx = self.signature_tx.clone();
79 IoTaskPool::get_or_init(TaskPool::new)
80 .spawn(async move {
81 let provider = eip_1193::Provider::default().unwrap().unwrap();
82 let transport = eip_1193::Eip1193::new(provider);
83 let web3 = web3::Web3::new(transport);
84
85 let msg = web3::types::Bytes(msg.as_bytes().to_vec());
86 let signature = web3.eth().sign(account, msg).await.unwrap();
87 let _ = tx.send(signature).await;
88 })
89 .detach();
90 }
91
92 pub fn send(&self, from: H160, to: H160, data: Vec<u8>) {
93 let tx = self.transaction_tx.clone();
94 IoTaskPool::get_or_init(TaskPool::new)
95 .spawn(async move {
96 let provider = eip_1193::Provider::default().unwrap().unwrap();
97 let transport = eip_1193::Eip1193::new(provider);
98 let web3 = web3::Web3::new(transport);
99
100 let mut txr = TransactionRequest::default();
101 txr.from = from;
102 txr.to = Some(to);
103 txr.data = Some(data.into());
104
105 let hash = web3.eth().send_transaction(txr).await.unwrap();
106 let _ = tx.send(hash).await;
107 })
108 .detach();
109 }
110
111 pub fn recv_account(&self) -> Result<(H160, U256), RecvError> {
112 Ok(self.account_rx.try_recv()?)
113 }
114
115 pub fn recv_signature(&self) -> Result<H520, RecvError> {
116 Ok(self.signature_rx.try_recv()?)
117 }
118
119 pub fn recv_transaction(&self) -> Result<H256, RecvError> {
120 Ok(self.transaction_rx.try_recv()?)
121 }
122}