hopr_chain_types/
lib.rs

1//! This crate contains various on-chain related modules and types.
2
3use ethers::prelude::*;
4use hex_literal::hex;
5use serde::{Deserialize, Serialize};
6use std::sync::Arc;
7
8use hopr_bindings::hopr_announcements::HoprAnnouncements;
9use hopr_bindings::hopr_channels::HoprChannels;
10use hopr_bindings::hopr_dummy_proxy_for_network_registry::HoprDummyProxyForNetworkRegistry;
11use hopr_bindings::hopr_network_registry::HoprNetworkRegistry;
12use hopr_bindings::hopr_node_management_module::HoprNodeManagementModule;
13use hopr_bindings::hopr_node_safe_registry::HoprNodeSafeRegistry;
14use hopr_bindings::hopr_node_stake_factory::HoprNodeStakeFactory;
15use hopr_bindings::hopr_safe_proxy_for_network_registry::HoprSafeProxyForNetworkRegistry;
16use hopr_bindings::hopr_ticket_price_oracle::HoprTicketPriceOracle;
17use hopr_bindings::hopr_token::HoprToken;
18use hopr_bindings::hopr_winning_probability_oracle::HoprWinningProbabilityOracle;
19
20use ethers::abi::Token;
21use hopr_crypto_types::keypairs::{ChainKeypair, Keypair};
22use hopr_primitive_types::primitives::Address;
23use std::str::FromStr;
24
25pub mod actions;
26pub mod chain_events;
27
28// Various (mostly testing related) utility functions
29pub mod utils;
30
31pub use ethers::core::types::transaction::eip2718::TypedTransaction;
32
33lazy_static::lazy_static! {
34    pub static ref ERC_1820_REGISTRY_DEPLOY_CODE: [u8; 2619] = hex!("f90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820");
35}
36
37/// Short-hand for creating new EIP1559 transaction object.
38pub fn create_eip1559_transaction() -> TypedTransaction {
39    TypedTransaction::Eip1559(Eip1559TransactionRequest::new())
40}
41
42/// Holds addresses of all smart contracts.
43#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
44pub struct ContractAddresses {
45    /// Token contract
46    pub token: Address,
47    /// Channels contract
48    pub channels: Address,
49    /// Announcements contract
50    pub announcements: Address,
51    /// Network registry contract
52    pub network_registry: Address,
53    /// Network registry proxy contract
54    pub network_registry_proxy: Address,
55    /// Safe registry contract
56    pub safe_registry: Address,
57    /// Price oracle contract
58    pub price_oracle: Address,
59    /// Minimum ticket winning probability contract
60    pub win_prob_oracle: Address,
61    /// Stake factory contract
62    pub stake_factory: Address,
63    /// Node management module contract (can be zero if safe is not used)
64    pub module_implementation: Address,
65}
66
67#[derive(Debug, Clone)]
68pub enum NetworkRegistryProxy<M: Middleware> {
69    Dummy(HoprDummyProxyForNetworkRegistry<M>),
70    Safe(HoprSafeProxyForNetworkRegistry<M>),
71}
72
73impl<M: Middleware> NetworkRegistryProxy<M> {
74    pub fn address(&self) -> Address {
75        match self {
76            NetworkRegistryProxy::Dummy(c) => c.address().into(),
77            NetworkRegistryProxy::Safe(c) => c.address().into(),
78        }
79    }
80}
81
82/// Holds instances to contracts.
83#[derive(Debug)]
84pub struct ContractInstances<M: Middleware> {
85    pub token: HoprToken<M>,
86    pub channels: HoprChannels<M>,
87    pub announcements: HoprAnnouncements<M>,
88    pub network_registry: HoprNetworkRegistry<M>,
89    pub network_registry_proxy: NetworkRegistryProxy<M>,
90    pub safe_registry: HoprNodeSafeRegistry<M>,
91    pub price_oracle: HoprTicketPriceOracle<M>,
92    pub win_prob_oracle: HoprWinningProbabilityOracle<M>,
93    pub stake_factory: HoprNodeStakeFactory<M>,
94    pub module_implementation: HoprNodeManagementModule<M>,
95}
96
97impl<M: Middleware> Clone for ContractInstances<M> {
98    fn clone(&self) -> Self {
99        // Requires manual clone implementation, because `M` is usually never `Clone`
100        let client = self.token.client();
101        Self {
102            token: HoprToken::new(self.token.address(), client.clone()),
103            channels: HoprChannels::new(self.channels.address(), client.clone()),
104            announcements: HoprAnnouncements::new(self.announcements.address(), client.clone()),
105            network_registry: HoprNetworkRegistry::new(self.network_registry.address(), client.clone()),
106            network_registry_proxy: match &self.network_registry_proxy {
107                NetworkRegistryProxy::Dummy(nr) => {
108                    NetworkRegistryProxy::Dummy(HoprDummyProxyForNetworkRegistry::new(nr.address(), client.clone()))
109                }
110                NetworkRegistryProxy::Safe(nr) => {
111                    NetworkRegistryProxy::Safe(HoprSafeProxyForNetworkRegistry::new(nr.address(), client.clone()))
112                }
113            },
114            safe_registry: HoprNodeSafeRegistry::new(self.safe_registry.address(), client.clone()),
115            price_oracle: HoprTicketPriceOracle::new(self.price_oracle.address(), client.clone()),
116            win_prob_oracle: HoprWinningProbabilityOracle::new(self.win_prob_oracle.address(), client.clone()),
117            stake_factory: HoprNodeStakeFactory::new(self.stake_factory.address(), client.clone()),
118            module_implementation: HoprNodeManagementModule::new(self.module_implementation.address(), client.clone()),
119        }
120    }
121}
122
123impl<M: Middleware> ContractInstances<M> {
124    pub fn new(contract_addresses: &ContractAddresses, provider: Arc<M>, use_dummy_nr: bool) -> Self {
125        Self {
126            token: HoprToken::new(contract_addresses.token, provider.clone()),
127            channels: HoprChannels::new(contract_addresses.channels, provider.clone()),
128            announcements: HoprAnnouncements::new(contract_addresses.announcements, provider.clone()),
129            network_registry: HoprNetworkRegistry::new(contract_addresses.network_registry, provider.clone()),
130            network_registry_proxy: if use_dummy_nr {
131                NetworkRegistryProxy::Dummy(HoprDummyProxyForNetworkRegistry::new(
132                    contract_addresses.network_registry_proxy,
133                    provider.clone(),
134                ))
135            } else {
136                NetworkRegistryProxy::Safe(HoprSafeProxyForNetworkRegistry::new(
137                    contract_addresses.network_registry_proxy,
138                    provider.clone(),
139                ))
140            },
141            safe_registry: HoprNodeSafeRegistry::new(contract_addresses.safe_registry, provider.clone()),
142            price_oracle: HoprTicketPriceOracle::new(contract_addresses.price_oracle, provider.clone()),
143            win_prob_oracle: HoprWinningProbabilityOracle::new(contract_addresses.win_prob_oracle, provider.clone()),
144            stake_factory: HoprNodeStakeFactory::new(contract_addresses.stake_factory, provider.clone()),
145            module_implementation: HoprNodeManagementModule::new(
146                contract_addresses.module_implementation,
147                provider.clone(),
148            ),
149        }
150    }
151
152    /// Deploys testing environment (with dummy network registry proxy) via the given provider.
153    pub async fn deploy_for_testing(provider: Arc<M>, deployer: &ChainKeypair) -> Result<Self, ContractError<M>> {
154        {
155            // Fund 1820 deployer and deploy ERC1820Registry
156            let mut tx = Eip1559TransactionRequest::new();
157            tx = tx.to(H160::from_str(crate::utils::ERC_1820_DEPLOYER).expect("deployer address should be valid"));
158            tx = tx.value(crate::utils::ETH_VALUE_FOR_ERC1820_DEPLOYER);
159
160            provider
161                .send_transaction(tx, None)
162                .await
163                .map_err(|e| ContractError::MiddlewareError { e })?
164                .await?;
165
166            provider
167                .send_raw_transaction(Bytes::from_static(&*ERC_1820_REGISTRY_DEPLOY_CODE))
168                .await
169                .map_err(|e| ContractError::MiddlewareError { e })?
170                .await?;
171        }
172
173        // Get deployer address
174        let self_address: types::Address = deployer.public().to_address().into();
175
176        let stake_factory = HoprNodeStakeFactory::deploy(provider.clone(), ())?.send().await?;
177        let module_implementation = HoprNodeManagementModule::deploy(provider.clone(), ())?.send().await?;
178        let safe_registry = HoprNodeSafeRegistry::deploy(provider.clone(), ())?.send().await?;
179        let price_oracle = HoprTicketPriceOracle::deploy(
180            provider.clone(),
181            (self_address, ethers::types::U256::from(100000000000000000_u128)),
182        )?
183        .send()
184        .await?;
185        let win_prob_oracle = HoprWinningProbabilityOracle::deploy(
186            provider.clone(),
187            (self_address, ethers::types::U256::from(72057594037927935_u128)), // 0xFFFFFFFFFFFFFF
188        )?
189        .send()
190        .await?;
191        let token = HoprToken::deploy(provider.clone(), ())?.send().await?;
192        let network_registry_proxy = HoprDummyProxyForNetworkRegistry::deploy(provider.clone(), self_address)?
193            .send()
194            .await?;
195        let channels = HoprChannels::deploy(
196            provider.clone(),
197            Token::Tuple(vec![
198                Token::Address(token.address()),
199                Token::Uint(1_u32.into()),
200                Token::Address(safe_registry.address()),
201            ]),
202        )?
203        .send()
204        .await?;
205        let announcements = HoprAnnouncements::deploy(provider.clone(), Token::Address(safe_registry.address()))?
206            .send()
207            .await?;
208        let network_registry = HoprNetworkRegistry::deploy(
209            provider.clone(),
210            (
211                ethers::types::Address::from(network_registry_proxy.address()),
212                self_address,
213                self_address,
214            ),
215        )?
216        .send()
217        .await?;
218
219        // Disable network registry in local environment
220        network_registry.disable_registry().send().await?.await?;
221
222        Ok(Self {
223            token,
224            channels,
225            announcements,
226            network_registry,
227            network_registry_proxy: NetworkRegistryProxy::Dummy(network_registry_proxy),
228            safe_registry,
229            price_oracle,
230            win_prob_oracle,
231            stake_factory,
232            module_implementation,
233        })
234    }
235}
236
237impl<M: Middleware> From<&ContractInstances<M>> for ContractAddresses {
238    fn from(value: &ContractInstances<M>) -> Self {
239        Self {
240            token: value.token.address().into(),
241            channels: value.channels.address().into(),
242            announcements: value.announcements.address().into(),
243            network_registry: value.network_registry.address().into(),
244            network_registry_proxy: value.network_registry_proxy.address(),
245            safe_registry: value.safe_registry.address().into(),
246            price_oracle: value.price_oracle.address().into(),
247            win_prob_oracle: value.win_prob_oracle.address().into(),
248            stake_factory: value.stake_factory.address().into(),
249            module_implementation: value.module_implementation.address().into(),
250        }
251    }
252}
253
254/// Creates local Anvil instance.
255///
256/// Used for testing. When block time is given, new blocks are mined periodically.
257/// Otherwise, a new block is mined per transaction.
258pub fn create_anvil(block_time: Option<std::time::Duration>) -> ethers::utils::AnvilInstance {
259    // The anvil binary must be in the PATH.
260    let mut anvil = ethers::utils::Anvil::new();
261
262    if let Some(bt) = block_time {
263        anvil = anvil.block_time(bt.as_secs());
264    }
265
266    anvil.spawn()
267}