| 
 | 1 | +// Copyright 2019-2022 Parity Technologies (UK) Ltd.  | 
 | 2 | +// This file is part of subxt.  | 
 | 3 | +//  | 
 | 4 | +// subxt is free software: you can redistribute it and/or modify  | 
 | 5 | +// it under the terms of the GNU General Public License as published by  | 
 | 6 | +// the Free Software Foundation, either version 3 of the License, or  | 
 | 7 | +// (at your option) any later version.  | 
 | 8 | +//  | 
 | 9 | +// subxt is distributed in the hope that it will be useful,  | 
 | 10 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
 | 11 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  | 
 | 12 | +// GNU General Public License for more details.  | 
 | 13 | +//  | 
 | 14 | +// You should have received a copy of the GNU General Public License  | 
 | 15 | +// along with subxt.  If not, see <http://www.gnu.org/licenses/>.  | 
 | 16 | + | 
 | 17 | +//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.  | 
 | 18 | +//!  | 
 | 19 | +//! E.g.  | 
 | 20 | +//! ```bash  | 
 | 21 | +//! curl "https://github.com/paritytech/polkadot/releases/download/v0.9.13/polkadot" --output /usr/local/bin/polkadot --location  | 
 | 22 | +//! polkadot --dev --tmp  | 
 | 23 | +//! ```  | 
 | 24 | +
  | 
 | 25 | +use futures::StreamExt;  | 
 | 26 | +use sp_keyring::AccountKeyring;  | 
 | 27 | +use std::time::Duration;  | 
 | 28 | +use subxt::{  | 
 | 29 | +    ClientBuilder,  | 
 | 30 | +    DefaultConfig,  | 
 | 31 | +    DefaultExtra,  | 
 | 32 | +    PairSigner,  | 
 | 33 | +};  | 
 | 34 | + | 
 | 35 | +#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]  | 
 | 36 | +pub mod polkadot {}  | 
 | 37 | + | 
 | 38 | +/// Subscribe to all events, and then manually look through them and  | 
 | 39 | +/// pluck out the events that we care about.  | 
 | 40 | +#[async_std::main]  | 
 | 41 | +async fn main() -> Result<(), Box<dyn std::error::Error>> {  | 
 | 42 | +    env_logger::init();  | 
 | 43 | + | 
 | 44 | +    let api = ClientBuilder::new()  | 
 | 45 | +        .build()  | 
 | 46 | +        .await?  | 
 | 47 | +        .to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();  | 
 | 48 | + | 
 | 49 | +    // Subscribe to any events that occur:  | 
 | 50 | +    let mut event_sub = api.events().subscribe().await?;  | 
 | 51 | + | 
 | 52 | +    // While this subscription is active, balance transfers are made somewhere:  | 
 | 53 | +    async_std::task::spawn(async {  | 
 | 54 | +        let signer = PairSigner::new(AccountKeyring::Alice.pair());  | 
 | 55 | +        let api = ClientBuilder::new()  | 
 | 56 | +            .build()  | 
 | 57 | +            .await  | 
 | 58 | +            .unwrap()  | 
 | 59 | +            .to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();  | 
 | 60 | + | 
 | 61 | +        let mut transfer_amount = 1_000_000_000;  | 
 | 62 | + | 
 | 63 | +        // Make small balance transfers from Alice to Bob in a loop:  | 
 | 64 | +        loop {  | 
 | 65 | +            api.tx()  | 
 | 66 | +                .balances()  | 
 | 67 | +                .transfer(AccountKeyring::Bob.to_account_id().into(), transfer_amount)  | 
 | 68 | +                .sign_and_submit(&signer)  | 
 | 69 | +                .await  | 
 | 70 | +                .unwrap();  | 
 | 71 | + | 
 | 72 | +            async_std::task::sleep(Duration::from_secs(10)).await;  | 
 | 73 | +            transfer_amount += 100_000_000;  | 
 | 74 | +        }  | 
 | 75 | +    });  | 
 | 76 | + | 
 | 77 | +    // Our subscription will see the events emitted as a result of this:  | 
 | 78 | +    while let Some(events) = event_sub.next().await {  | 
 | 79 | +        let events = events?;  | 
 | 80 | +        let block_hash = events.block_hash();  | 
 | 81 | + | 
 | 82 | +        // We can iterate, statically decoding all events if we want:  | 
 | 83 | +        println!("All events in block {block_hash:?}:");  | 
 | 84 | +        println!("  Static event details:");  | 
 | 85 | +        for event in events.iter() {  | 
 | 86 | +            let event = event?;  | 
 | 87 | +            println!("    {event:?}");  | 
 | 88 | +        }  | 
 | 89 | + | 
 | 90 | +        // Or we can dynamically decode events:  | 
 | 91 | +        println!("  Dynamic event details: {block_hash:?}:");  | 
 | 92 | +        for event in events.iter_raw() {  | 
 | 93 | +            let event = event?;  | 
 | 94 | +            let is_balance_transfer = event  | 
 | 95 | +                .as_event::<polkadot::balances::events::Transfer>()?  | 
 | 96 | +                .is_some();  | 
 | 97 | +            let pallet = event.pallet;  | 
 | 98 | +            let variant = event.variant;  | 
 | 99 | +            println!(  | 
 | 100 | +                "    {pallet}::{variant} (is balance transfer? {is_balance_transfer})"  | 
 | 101 | +            );  | 
 | 102 | +        }  | 
 | 103 | + | 
 | 104 | +        // Or we can dynamically find the first transfer event, ignoring any others:  | 
 | 105 | +        let transfer_event =  | 
 | 106 | +            events.find_first_event::<polkadot::balances::events::Transfer>()?;  | 
 | 107 | + | 
 | 108 | +        if let Some(ev) = transfer_event {  | 
 | 109 | +            println!("  - Balance transfer success: value: {:?}", ev.amount);  | 
 | 110 | +        } else {  | 
 | 111 | +            println!("  - No balance transfer event found in this block");  | 
 | 112 | +        }  | 
 | 113 | +    }  | 
 | 114 | + | 
 | 115 | +    Ok(())  | 
 | 116 | +}  | 
0 commit comments