bevy_web3/
lib.rs

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}