hopr_chain_types/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
//! This crate contains various on-chain related modules and types.

use ethers::abi::Token;
use ethers::prelude::*;
use hex_literal::hex;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use std::sync::Arc;

use hopr_bindings::hopr_announcements::HoprAnnouncements;
use hopr_bindings::hopr_channels::HoprChannels;
use hopr_bindings::hopr_dummy_proxy_for_network_registry::HoprDummyProxyForNetworkRegistry;
use hopr_bindings::hopr_network_registry::HoprNetworkRegistry;
use hopr_bindings::hopr_node_management_module::HoprNodeManagementModule;
use hopr_bindings::hopr_node_safe_registry::HoprNodeSafeRegistry;
use hopr_bindings::hopr_node_stake_factory::HoprNodeStakeFactory;
use hopr_bindings::hopr_safe_proxy_for_network_registry::HoprSafeProxyForNetworkRegistry;
use hopr_bindings::hopr_ticket_price_oracle::HoprTicketPriceOracle;
use hopr_bindings::hopr_token::HoprToken;
use hopr_bindings::hopr_winning_probability_oracle::HoprWinningProbabilityOracle;
use hopr_crypto_types::keypairs::{ChainKeypair, Keypair};
use hopr_primitive_types::primitives::Address;

pub mod actions;
pub mod chain_events;

// Various (mostly testing related) utility functions
pub mod utils;

pub use ethers::core::types::transaction::eip2718::TypedTransaction;

lazy_static::lazy_static! {
    pub static ref ERC_1820_REGISTRY_DEPLOY_CODE: [u8; 2619] = hex!("f90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820");
}

/// Short-hand for creating new EIP1559 transaction object.
pub fn create_eip1559_transaction() -> TypedTransaction {
    TypedTransaction::Eip1559(Eip1559TransactionRequest::new())
}

/// Holds addresses of all smart contracts.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct ContractAddresses {
    /// Token contract
    pub token: Address,
    /// Channels contract
    pub channels: Address,
    /// Announcements contract
    pub announcements: Address,
    /// Network registry contract
    pub network_registry: Address,
    /// Network registry proxy contract
    pub network_registry_proxy: Address,
    /// Safe registry contract
    pub safe_registry: Address,
    /// Price oracle contract
    pub price_oracle: Address,
    /// Minimum ticket winning probability contract
    pub win_prob_oracle: Address,
    /// Stake factory contract
    pub stake_factory: Address,
    /// Node management module contract (can be zero if safe is not used)
    pub module_implementation: Address,
}

#[derive(Debug, Clone)]
pub enum NetworkRegistryProxy<M: Middleware> {
    Dummy(HoprDummyProxyForNetworkRegistry<M>),
    Safe(HoprSafeProxyForNetworkRegistry<M>),
}

impl<M: Middleware> NetworkRegistryProxy<M> {
    pub fn address(&self) -> Address {
        match self {
            NetworkRegistryProxy::Dummy(c) => c.address().into(),
            NetworkRegistryProxy::Safe(c) => c.address().into(),
        }
    }
}

/// Holds instances to contracts.
#[derive(Debug)]
pub struct ContractInstances<M: Middleware> {
    pub token: HoprToken<M>,
    pub channels: HoprChannels<M>,
    pub announcements: HoprAnnouncements<M>,
    pub network_registry: HoprNetworkRegistry<M>,
    pub network_registry_proxy: NetworkRegistryProxy<M>,
    pub safe_registry: HoprNodeSafeRegistry<M>,
    pub price_oracle: HoprTicketPriceOracle<M>,
    pub win_prob_oracle: HoprWinningProbabilityOracle<M>,
    pub stake_factory: HoprNodeStakeFactory<M>,
    pub module_implementation: HoprNodeManagementModule<M>,
}

impl<M: Middleware> Clone for ContractInstances<M> {
    fn clone(&self) -> Self {
        // Requires manual clone implementation, because `M` is usually never `Clone`
        let client = self.token.client();
        Self {
            token: HoprToken::new(self.token.address(), client.clone()),
            channels: HoprChannels::new(self.channels.address(), client.clone()),
            announcements: HoprAnnouncements::new(self.announcements.address(), client.clone()),
            network_registry: HoprNetworkRegistry::new(self.network_registry.address(), client.clone()),
            network_registry_proxy: match &self.network_registry_proxy {
                NetworkRegistryProxy::Dummy(nr) => {
                    NetworkRegistryProxy::Dummy(HoprDummyProxyForNetworkRegistry::new(nr.address(), client.clone()))
                }
                NetworkRegistryProxy::Safe(nr) => {
                    NetworkRegistryProxy::Safe(HoprSafeProxyForNetworkRegistry::new(nr.address(), client.clone()))
                }
            },
            safe_registry: HoprNodeSafeRegistry::new(self.safe_registry.address(), client.clone()),
            price_oracle: HoprTicketPriceOracle::new(self.price_oracle.address(), client.clone()),
            win_prob_oracle: HoprWinningProbabilityOracle::new(self.win_prob_oracle.address(), client.clone()),
            stake_factory: HoprNodeStakeFactory::new(self.stake_factory.address(), client.clone()),
            module_implementation: HoprNodeManagementModule::new(self.module_implementation.address(), client.clone()),
        }
    }
}

impl<M: Middleware> ContractInstances<M> {
    pub fn new(contract_addresses: &ContractAddresses, provider: Arc<M>, use_dummy_nr: bool) -> Self {
        Self {
            token: HoprToken::new(contract_addresses.token, provider.clone()),
            channels: HoprChannels::new(contract_addresses.channels, provider.clone()),
            announcements: HoprAnnouncements::new(contract_addresses.announcements, provider.clone()),
            network_registry: HoprNetworkRegistry::new(contract_addresses.network_registry, provider.clone()),
            network_registry_proxy: if use_dummy_nr {
                NetworkRegistryProxy::Dummy(HoprDummyProxyForNetworkRegistry::new(
                    contract_addresses.network_registry_proxy,
                    provider.clone(),
                ))
            } else {
                NetworkRegistryProxy::Safe(HoprSafeProxyForNetworkRegistry::new(
                    contract_addresses.network_registry_proxy,
                    provider.clone(),
                ))
            },
            safe_registry: HoprNodeSafeRegistry::new(contract_addresses.safe_registry, provider.clone()),
            price_oracle: HoprTicketPriceOracle::new(contract_addresses.price_oracle, provider.clone()),
            win_prob_oracle: HoprWinningProbabilityOracle::new(contract_addresses.win_prob_oracle, provider.clone()),
            stake_factory: HoprNodeStakeFactory::new(contract_addresses.stake_factory, provider.clone()),
            module_implementation: HoprNodeManagementModule::new(
                contract_addresses.module_implementation,
                provider.clone(),
            ),
        }
    }

    /// Deploys testing environment (with dummy network registry proxy) via the given provider.
    pub async fn deploy_for_testing(provider: Arc<M>, deployer: &ChainKeypair) -> Result<Self, ContractError<M>> {
        {
            // Fund 1820 deployer and deploy ERC1820Registry
            let mut tx = Eip1559TransactionRequest::new();
            tx = tx.to(H160::from_str(crate::utils::ERC_1820_DEPLOYER).expect("deployer address should be valid"));
            tx = tx.value(crate::utils::ETH_VALUE_FOR_ERC1820_DEPLOYER);

            provider
                .send_transaction(tx, None)
                .await
                .map_err(|e| ContractError::MiddlewareError { e })?
                .await?;

            provider
                .send_raw_transaction(Bytes::from_static(&*ERC_1820_REGISTRY_DEPLOY_CODE))
                .await
                .map_err(|e| ContractError::MiddlewareError { e })?
                .await?;
        }

        // Get deployer address
        let self_address: types::Address = deployer.public().to_address().into();

        let stake_factory = HoprNodeStakeFactory::deploy(provider.clone(), ())?.send().await?;
        let module_implementation = HoprNodeManagementModule::deploy(provider.clone(), ())?.send().await?;
        let safe_registry = HoprNodeSafeRegistry::deploy(provider.clone(), ())?.send().await?;
        let price_oracle = HoprTicketPriceOracle::deploy(
            provider.clone(),
            (self_address, ethers::types::U256::from(100000000000000000_u128)),
        )?
        .send()
        .await?;
        let win_prob_oracle = HoprWinningProbabilityOracle::deploy(
            provider.clone(),
            (self_address, ethers::types::U256::from(72057594037927935_u128)), // 0xFFFFFFFFFFFFFF
        )?
        .send()
        .await?;
        let token = HoprToken::deploy(provider.clone(), ())?.send().await?;
        let network_registry_proxy = HoprDummyProxyForNetworkRegistry::deploy(provider.clone(), self_address)?
            .send()
            .await?;
        let channels = HoprChannels::deploy(
            provider.clone(),
            Token::Tuple(vec![
                Token::Address(token.address()),
                Token::Uint(1_u32.into()),
                Token::Address(safe_registry.address()),
            ]),
        )?
        .send()
        .await?;
        let announcements = HoprAnnouncements::deploy(provider.clone(), Token::Address(safe_registry.address()))?
            .send()
            .await?;
        let network_registry = HoprNetworkRegistry::deploy(
            provider.clone(),
            (
                ethers::types::Address::from(network_registry_proxy.address()),
                self_address,
                self_address,
            ),
        )?
        .send()
        .await?;

        // Disable network registry in local environment
        network_registry.disable_registry().send().await?.await?;

        Ok(Self {
            token,
            channels,
            announcements,
            network_registry,
            network_registry_proxy: NetworkRegistryProxy::Dummy(network_registry_proxy),
            safe_registry,
            price_oracle,
            win_prob_oracle,
            stake_factory,
            module_implementation,
        })
    }
}

impl<M: Middleware> From<&ContractInstances<M>> for ContractAddresses {
    fn from(value: &ContractInstances<M>) -> Self {
        Self {
            token: value.token.address().into(),
            channels: value.channels.address().into(),
            announcements: value.announcements.address().into(),
            network_registry: value.network_registry.address().into(),
            network_registry_proxy: value.network_registry_proxy.address(),
            safe_registry: value.safe_registry.address().into(),
            price_oracle: value.price_oracle.address().into(),
            win_prob_oracle: value.win_prob_oracle.address().into(),
            stake_factory: value.stake_factory.address().into(),
            module_implementation: value.module_implementation.address().into(),
        }
    }
}

/// Creates local Anvil instance.
///
/// Used for testing. When block time is given, new blocks are mined periodically.
/// Otherwise, a new block is mined per transaction.
pub fn create_anvil(block_time: Option<std::time::Duration>) -> ethers::utils::AnvilInstance {
    // The anvil binary must be in the PATH.
    let mut anvil = ethers::utils::Anvil::new();

    if let Some(bt) = block_time {
        anvil = anvil.block_time(bt.as_secs());
    }

    anvil.spawn()
}