hopli/
methods.rs

1//! This module contains all the methods used for onchain interaction, especially with Safe instance, Mutlicall, and Multisend contracts.
2//!
3//! [SafeTxOperation] corresponds to the `Operation` Enum used in Safe smart contract.
4//!
5//! [MultisendTransaction] struct is used for building transactions interacting with Multisend contract
6
7use ethers::{
8    abi::AbiEncode,
9    contract::{
10        abigen,
11        multicall_contract::{Aggregate3ValueCall, Call3Value},
12        ContractError, Multicall, MulticallError, MULTICALL_ADDRESS,
13    },
14    providers::Middleware,
15    types::{Address, Bytes, Eip1559TransactionRequest, H160, H256, U256},
16    utils::{format_units, get_create2_address, keccak256, parse_units},
17};
18use hex_literal::hex;
19use std::sync::Arc;
20use std::{ops::Add, str::FromStr};
21use tracing::{debug, info};
22
23use hopr_bindings::{
24    hopr_network_registry::HoprNetworkRegistry,
25    hopr_node_management_module::{
26        AddChannelsAndTokenTargetCall, HoprNodeManagementModule, IncludeNodeCall, RemoveNodeCall, ScopeTargetTokenCall,
27    },
28    hopr_node_safe_registry::{DeregisterNodeBySafeCall, HoprNodeSafeRegistry},
29    hopr_node_stake_factory::HoprNodeStakeFactory,
30    hopr_token::{ApproveCall, HoprToken},
31};
32use hopr_chain_rpc::TypedTransaction;
33use hopr_crypto_types::keypairs::{ChainKeypair, Keypair};
34
35use crate::utils::{
36    HelperErrors, DEFAULT_ANNOUNCEMENT_PERMISSIONS, DEFAULT_CAPABILITY_PERMISSIONS, DEFAULT_NODE_PERMISSIONS,
37    DOMAIN_SEPARATOR_TYPEHASH, SAFE_COMPATIBILITYFALLBACKHANDLER_ADDRESS, SAFE_EXECUTION_SUCCESS,
38    SAFE_MULTISEND_ADDRESS, SAFE_SAFEPROXYFACTORY_ADDRESS, SAFE_SAFE_ADDRESS, SAFE_TX_TYPEHASH, SENTINEL_OWNERS,
39};
40
41abigen!(
42    SafeSingleton,
43    r"[
44    function setup(address[],uint256,address,bytes,address,address,uint256,address)
45    function execTransaction(address to, uint256 value, bytes calldata data, uint8 operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address payable refundReceiver, bytes memory signatures) public payable returns (bool)
46    function removeOwner(address prevOwner, address owner, uint256 _threshold) public
47    function getThreshold() public view returns (uint256)
48    function getOwners() public view returns (address[] memory)
49    function nonce() public view returns (uint256)
50    function domainSeparator() public view returns (bytes32)
51    function encodeTransactionData(address to, uint256 value, bytes calldata data, uint8 operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, uint256 _nonce) public view returns (bytes memory)
52    function getTransactionHash(address to, uint256 value, bytes calldata data, uint8 operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, uint256 _nonce) public view returns (bytes32)
53    function isModuleEnabled(address module) public view returns (bool)
54]"
55);
56abigen!(
57    ModuleSingleton,
58    r"[
59    function isNode(address) external view returns (bool)
60    function getTargets() external view returns (uint256[] memory)
61    function owner() public view returns (address)
62]"
63);
64
65abigen!(
66    MultiSend,
67    r"[
68        function multiSend(bytes memory transactions) public payable
69    ]"
70);
71
72/// Enums of Safe transaction operation
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub enum SafeTxOperation {
75    Call,
76    DelegateCall,
77}
78impl SafeTxOperation {
79    /// convert the SafeTxOperation to exact one byte
80    pub fn to_byte(&self) -> [u8; 1] {
81        match self {
82            SafeTxOperation::Call => hex!("00"),
83            SafeTxOperation::DelegateCall => hex!("01"),
84        }
85    }
86}
87
88impl From<SafeTxOperation> for u8 {
89    fn from(s: SafeTxOperation) -> u8 {
90        s as u8
91    }
92}
93
94/// Struct to make a multisend transaction, mainly used by safe instances
95#[derive(Debug, Clone)]
96pub struct MultisendTransaction {
97    // data paylaod encoded with selector
98    pub encoded_data: Bytes,
99    // transaction type
100    pub tx_operation: SafeTxOperation,
101    // target address
102    pub to: Address,
103    // payable eth sending along the tx
104    pub value: U256,
105}
106
107/// Methods for Multisend transaction
108impl MultisendTransaction {
109    /// encode a multisend transaction
110    fn encode_packed(&self) -> Vec<u8> {
111        let tx_operation_bytes = self.tx_operation.to_byte();
112
113        let fixed_length_values = ethers::abi::Token::FixedArray(vec![
114            ethers::abi::Token::Uint(self.value),                          // 32 bytes
115            ethers::abi::Token::Uint(U256::from(self.encoded_data.len())), // 32 bytes
116        ]);
117
118        ethers::abi::encode_packed(&[
119            ethers::abi::Token::Bytes(tx_operation_bytes.to_vec()), // 1 bytes
120            ethers::abi::Token::Address(self.to),                   // 20 bytes
121            fixed_length_values,                                    // 2 * 32 bytes
122            ethers::abi::Token::Bytes(self.encoded_data.to_vec()),  // bytes
123        ])
124        .unwrap_or_else(|_| panic!("failed to encode_packed a multisig transaction"))
125    }
126
127    /// build a multisend transaction data payload
128    fn build_multisend_tx(transactions: Vec<MultisendTransaction>) -> Vec<u8> {
129        let mut payload: Vec<u8> = Vec::new();
130        for transaction in transactions {
131            payload = [payload, transaction.encode_packed()].concat();
132        }
133        debug!("payload {:?}", hex::encode(&payload));
134        payload
135    }
136}
137
138/// get the domain separator of a safe instance
139/// contract_address should be safe address
140fn get_domain_separator(chain_id: U256, contract_address: Address) -> [u8; 32] {
141    keccak256(ethers::abi::encode(&[
142        ethers::abi::Token::FixedBytes(
143            hex::decode(DOMAIN_SEPARATOR_TYPEHASH).unwrap_or_else(|_| panic!("decode the DOMAIN_SEPARATOR_TYPEHASH")),
144        ), // DOMAIN_SEPARATOR_TYPEHASH
145        ethers::abi::Token::Uint(chain_id),            // getChainId
146        ethers::abi::Token::Address(contract_address), // this
147    ]))
148}
149
150/// Implement getTransactionHash() function as in vendor/solidity/safe-contracts-1.4.1/contracts/Safe.sol
151/// Note that `safeTxGas`, `baseGas`, and `gasPrice` are zero; `gasToken` is also address zero
152fn get_safe_transaction_hash(
153    to: Address,
154    value: U256,
155    data: Vec<u8>,
156    operation: SafeTxOperation,
157    refund_address: Address,
158    nonce: U256,
159    domain_separator: [u8; 32],
160) -> [u8; 32] {
161    // first encodeTransactionData()
162    let data_hash = keccak256(data);
163
164    let encoded = ethers::abi::encode(&[
165        ethers::abi::Token::FixedBytes(
166            hex::decode(SAFE_TX_TYPEHASH).unwrap_or_else(|_| panic!("failed to decode the SAFE_TX_TYPEHASH")),
167        ), // SAFE_TX_TYPEHASH
168        ethers::abi::Token::Address(to),                       // to
169        ethers::abi::Token::Uint(value),                       // value
170        ethers::abi::Token::FixedBytes(data_hash.into()),      // keccak256
171        ethers::abi::Token::Uint(U256::from(operation as u8)), // operation
172        ethers::abi::Token::Uint(U256::zero()),                // safeTxGas
173        ethers::abi::Token::Uint(U256::zero()),                // baseGas
174        ethers::abi::Token::Uint(U256::zero()),                // gasPrice
175        ethers::abi::Token::Address(Address::zero()),          // gasToken
176        ethers::abi::Token::Address(refund_address),           // refundReceiver
177        ethers::abi::Token::Uint(nonce),                       // _nonce
178    ]);
179
180    let safe_hash = keccak256(encoded);
181
182    let encoded_transaction_data = ethers::abi::encode_packed(&[
183        ethers::abi::Token::Bytes(hex!("1901").to_vec()),
184        ethers::abi::Token::FixedBytes(domain_separator.into()),
185        ethers::abi::Token::FixedBytes(safe_hash.into()),
186    ])
187    .unwrap_or_else(|_| panic!("failed to encode_packed a transaction with ethereum prefix"));
188
189    let transaction_hash = keccak256(encoded_transaction_data);
190    debug!("transaction_hash {:?}", hex::encode(transaction_hash));
191    transaction_hash
192}
193
194/// Use safe to delegatecall to multisend contract
195/// Note that when no additional signature is provided, the safe must have a threshold of one,
196/// so that the transaction can be executed.
197/// Note that the refund address is the caller (safe owner) wallet
198pub async fn send_multisend_safe_transaction_with_threshold_one<M: Middleware>(
199    safe: SafeSingleton<M>,
200    signer_key: ChainKeypair,
201    multisend_contract: Address,
202    multisend_txns: Vec<MultisendTransaction>,
203    chain_id: U256,
204    nonce: U256,
205) -> Result<(), HelperErrors> {
206    // get signer
207    let signer = safe.client().default_sender().expect("client must have a sender");
208    let wallet =
209        ethers::signers::LocalWallet::from_bytes(signer_key.secret().as_ref()).expect("failed to construct wallet");
210
211    // prepare a safe transaction:
212    // 1. calculate total value
213    let total_value = multisend_txns
214        .clone()
215        .into_iter()
216        .fold(U256::zero(), |acc, cur| acc.add(cur.value));
217    // 2. prepare tx payload
218    let tx_payload = MultisendTransaction::build_multisend_tx(multisend_txns);
219    let multisend_payload = MultiSendCall {
220        transactions: tx_payload.into(),
221    }
222    .encode();
223    // 3. get domain separator
224    let domain_separator = get_domain_separator(chain_id, safe.address());
225
226    debug!("multisend_payload {:?}", hex::encode(&multisend_payload));
227
228    // get transaction hash
229    let transaction_hash = get_safe_transaction_hash(
230        multisend_contract,
231        total_value,
232        multisend_payload.clone(),
233        SafeTxOperation::DelegateCall,
234        signer,
235        nonce,
236        domain_separator,
237    );
238
239    // sign the transaction
240    let signature = wallet
241        .sign_hash(transaction_hash.into())
242        .unwrap_or_else(|_| panic!("failed to sign a transaction hash"));
243    debug!("signature {:?}", hex::encode(signature.to_vec()));
244
245    // execute the transaction
246    let tx = safe
247        .exec_transaction(
248            multisend_contract,
249            total_value,
250            multisend_payload.into(),
251            SafeTxOperation::DelegateCall.into(),
252            U256::zero(),
253            U256::zero(),
254            U256::zero(),
255            Address::zero(),
256            signer,
257            signature.to_vec().into(),
258        )
259        .send()
260        .await
261        .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
262        .await
263        .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"))
264        .ok_or(HelperErrors::MultiSendError)?;
265
266    tx.logs
267        .iter()
268        .find(|log| log.topics[0].eq(&SAFE_EXECUTION_SUCCESS.parse::<H256>().unwrap()))
269        .ok_or(HelperErrors::MultiSendError)?;
270
271    Ok(())
272}
273
274/// Send one transaction via safe
275#[allow(clippy::too_many_arguments)]
276pub async fn send_safe_transaction_with_threshold_one<M: Middleware>(
277    safe: SafeSingleton<M>,
278    signer_key: ChainKeypair,
279    target: Address,
280    tx_payload: Vec<u8>,
281    operation: SafeTxOperation,
282    total_value: U256,
283    chain_id: U256,
284    nonce: U256,
285) -> Result<(), HelperErrors> {
286    // get signer
287    let signer = safe.client().default_sender().expect("client must have a sender");
288    let wallet =
289        ethers::signers::LocalWallet::from_bytes(signer_key.secret().as_ref()).expect("failed to construct wallet");
290
291    // prepare a safe transaction: get domain separator
292    let domain_separator = get_domain_separator(chain_id, safe.address());
293
294    // get transaction hash
295    let transaction_hash = get_safe_transaction_hash(
296        target,
297        total_value,
298        tx_payload.clone(),
299        operation.clone(),
300        signer,
301        nonce,
302        domain_separator,
303    );
304
305    // sign the transaction
306    let signature = wallet.sign_hash(transaction_hash.into())?;
307    debug!("signature {:?}", hex::encode(signature.to_vec()));
308
309    // execute the transaction
310    let tx = safe
311        .exec_transaction(
312            target,
313            total_value,
314            tx_payload.into(),
315            operation.into(),
316            U256::zero(),
317            U256::zero(),
318            U256::zero(),
319            Address::zero(),
320            signer,
321            signature.to_vec().into(),
322        )
323        .send()
324        .await
325        .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
326        .await
327        .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"))
328        .ok_or(HelperErrors::MultiSendError)?;
329
330    tx.logs
331        .iter()
332        .find(|log| log.topics[0].eq(&SAFE_EXECUTION_SUCCESS.parse::<H256>().unwrap()))
333        .ok_or(HelperErrors::MultiSendError)?;
334
335    Ok(())
336}
337
338/// Deploy a MULTICALL contract into Anvil local chain for testing
339pub async fn deploy_multicall3_for_testing<M: Middleware>(provider: Arc<M>) -> Result<(), ContractError<M>> {
340    // Fund Multicall3 deployer and deploy ERC1820Registry
341    let mut tx = Eip1559TransactionRequest::new();
342    tx = tx.to(H160::from_str(crate::utils::MULTICALL3_DEPLOYER).unwrap());
343    tx = tx.value(crate::utils::ETH_VALUE_FOR_MULTICALL3_DEPLOYER);
344
345    provider
346        .send_transaction(tx, None)
347        .await
348        .map_err(|e| ContractError::MiddlewareError { e })?
349        .await?;
350
351    provider.send_raw_transaction(
352        hex!("f90f538085174876e800830f42408080b90f00608060405234801561001057600080fd5b50610ee0806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c00331ca0edce47092c0f398cebf3ffc267f05c8e7076e3b89445e0fe50f6332273d4569ba01b0b9d000e19b24c5869b0fc3b22b0d6fa47cd63316875cbbd577d76e6fde086")
353            .into()).await.map_err(|e| ContractError::MiddlewareError {e})?.await?;
354    Ok(())
355}
356
357/// Get chain id and safe nonce
358pub async fn get_chain_id_and_safe_nonce<M: Middleware>(safe: SafeSingleton<M>) -> Result<(U256, U256), HelperErrors> {
359    let provider = safe.client();
360    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
361        .await
362        .expect("cannot create multicall");
363
364    multicall.add_get_chain_id().add_call(
365        safe.method::<_, U256>("nonce", ())
366            .map_err(|e| HelperErrors::MulticallError(e.to_string()))?,
367        false,
368    );
369
370    let result: (U256, U256) = multicall
371        .call()
372        .await
373        .map_err(|_| HelperErrors::MulticallError("failed in getting chain id and safe nonce".to_string()))?;
374
375    Ok(result)
376}
377
378/// Get native balance and hopr token balance for given addresses
379pub async fn get_native_and_token_balances<M: Middleware>(
380    hopr_token: HoprToken<M>,
381    addresses: Vec<Address>,
382) -> Result<(Vec<U256>, Vec<U256>), MulticallError<M>> {
383    let provider = hopr_token.client();
384    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS)).await?;
385
386    for address in addresses {
387        multicall.add_get_eth_balance(address, false).add_call(
388            hopr_token
389                .method::<_, U256>("balanceOf", address)
390                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
391            false,
392        );
393    }
394
395    let response: Vec<U256> = multicall.call_array().await?;
396    let mut native_balance: Vec<U256> = vec![];
397    let mut token_balance: Vec<U256> = vec![];
398
399    for (i, &balance) in response.iter().enumerate() {
400        if i % 2 == 0 {
401            native_balance.push(balance);
402        } else {
403            token_balance.push(balance);
404        }
405    }
406
407    Ok((native_balance, token_balance))
408}
409
410/// Transfer some HOPR tokens from the caller to the list of addresses
411/// Address_i receives amounts_i HOPR tokens.
412/// When there's not enough token in caller's balance, if the caller is
413/// a minter, mint the missing tokens. If not, returns error
414///
415/// Attention! Do not use this function to distribute large amount of tokens
416///
417/// Note that to save gas in batch funding, we use multicall to facilitate token distribution via `transferFrom`
418/// To use this functionality, caller must grant Multicall3 contract the exact allowance equal to the sum of tokens
419/// to be transferred. As it's a separate function, there is a window between granting the allowance and executing
420/// the transactin. Attacker may take advantage of this window and steal tokens from the caller's account.
421///
422/// TODO: To mitigate this risk, create a MulticallErc777Recipient contract to enable receiption of tokens
423/// on the multicall contract and purposely re-entrance with forwarded payload
424pub async fn transfer_or_mint_tokens<M: Middleware>(
425    hopr_token: HoprToken<M>,
426    addresses: Vec<Address>,
427    amounts: Vec<U256>,
428) -> Result<U256, HelperErrors> {
429    let caller = hopr_token.client().default_sender().expect("client must have a sender");
430    let provider = hopr_token.client();
431    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
432        .await
433        .expect("cannot create multicall");
434
435    // check if two vectors have the same length
436    assert_eq!(
437        addresses.len(),
438        amounts.len(),
439        "addresses and amounts are of different lengths in transfer_or_mint_tokens"
440    );
441
442    // early return if no recipient is provided
443    if addresses.is_empty() {
444        return Ok(U256::zero());
445    }
446
447    // calculate the sum of tokens to be sent
448    let total = amounts.iter().fold(U256::zero(), |acc, cur| acc.add(cur));
449    info!("total amount of HOPR tokens to be transferred {:?}", total.to_string());
450
451    // get caller balance and its role
452    let encoded_minter_role: [u8; 32] = keccak256(b"MINTER_ROLE");
453    multicall
454        .add_call(
455            hopr_token
456                .method::<_, U256>("balanceOf", caller)
457                .map_err(|e| HelperErrors::MulticallError(e.to_string()))?,
458            false,
459        )
460        .add_call(
461            hopr_token
462                .method::<_, bool>("hasRole", (encoded_minter_role, caller))
463                .map_err(|e| HelperErrors::MulticallError(e.to_string()))?,
464            false,
465        );
466    let result: (U256, bool) = multicall.call().await.map_err(|_| {
467        HelperErrors::MulticallError(
468            "failed in getting caller balance and its role in transfer_or_mint_tokens".to_string(),
469        )
470    })?;
471
472    // compare the total with caller's current balance. If caller doens't have enough balance, try to mint some. Otherwise, revert
473    if total.gt(&result.0) {
474        info!("caller does not have enough balance to transfer tokens to recipients.");
475        if result.1 {
476            info!("caller tries to mint tokens");
477            hopr_token
478                .mint(caller, total, Bytes::default(), Bytes::default())
479                .send()
480                .await
481                .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
482                .await
483                .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
484        } else {
485            return Err(HelperErrors::NotAMinter);
486        }
487    }
488
489    // when there are multiple recipients, use multicall; when single recipient, direct transfer
490    if addresses.len() == 1 {
491        // direct transfer
492        hopr_token
493            .transfer(addresses[0], amounts[0])
494            .send()
495            .await
496            .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
497            .await
498            .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
499    } else {
500        // use multicall
501        // TODO: introduce a new ERC777Recipient contract and batch the following separated steps into one, to mitigate the attack vector
502        // approve the multicall to be able to transfer from caller's wallet
503        hopr_token
504            .approve(MULTICALL_ADDRESS, total)
505            .send()
506            .await
507            .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
508            .await
509            .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
510
511        // transfer token to multicall contract and transfer to multiple recipients
512        for (i, address) in addresses.iter().enumerate() {
513            // skip transferring zero amount of tokens
514            if amounts[i].gt(&U256::zero()) {
515                multicall.add_call(
516                    hopr_token
517                        .method::<_, bool>("transferFrom", (caller, *address, amounts[i]))
518                        .map_err(|e| HelperErrors::MulticallError(e.to_string()))?,
519                    false,
520                );
521            }
522        }
523
524        multicall
525            .send()
526            .await
527            .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
528            .await
529            .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
530    }
531
532    Ok(total)
533}
534
535/// Transfer some native tokens from the caller to the list of addresses
536/// Address_i receives amounts_i native tokens.
537pub async fn transfer_native_tokens<M: Middleware>(
538    provider: Arc<M>,
539    addresses: Vec<Address>,
540    amounts: Vec<U256>,
541) -> Result<U256, HelperErrors> {
542    // check if two vectors have the same length
543    assert_eq!(
544        addresses.len(),
545        amounts.len(),
546        "addresses and amounts are of different lengths in transfer_native_tokens"
547    );
548    // calculate the sum of tokens to be sent
549    let total = amounts.iter().fold(U256::zero(), |acc, cur| acc.add(cur));
550    info!(
551        "total amount of native tokens to be transferred {:?}",
552        total.to_string()
553    );
554
555    let call3values: Vec<Call3Value> = addresses
556        .iter()
557        .enumerate()
558        .map(|(i, addr)| Call3Value {
559            target: *addr,
560            allow_failure: false,
561            value: amounts[i],
562            call_data: Bytes::default(),
563        })
564        .collect();
565    // send native tokens to multicall contract along with the multicall transaction that transfers funds to multiple recipients
566    let mut tx = TypedTransaction::Eip1559(Eip1559TransactionRequest::new());
567    tx.set_to(MULTICALL_ADDRESS);
568    tx.set_data(Aggregate3ValueCall { calls: call3values }.encode().into());
569    tx.set_value(total);
570
571    provider
572        .send_transaction(tx, None)
573        .await
574        .map_err(|e| HelperErrors::MiddlewareError(e.to_string()))?
575        .await
576        .map_err(|e| HelperErrors::MiddlewareError(e.to_string()))?;
577
578    Ok(total)
579}
580
581/// Get registered safes for given nodes on the network registry
582pub async fn get_registered_safes_for_nodes_on_network_registry<M: Middleware>(
583    network_registry: HoprNetworkRegistry<M>,
584    node_addresses: Vec<H160>,
585) -> Result<Vec<H160>, MulticallError<M>> {
586    let provider = network_registry.client();
587    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
588        .await
589        .expect("cannot create multicall");
590
591    for node in node_addresses {
592        multicall.add_call(
593            network_registry
594                .method::<_, Address>("nodeRegisterdToAccount", node)
595                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
596            false,
597        );
598    }
599
600    let response: Vec<Address> = multicall.call_array().await?;
601
602    Ok(response)
603}
604
605/// Register safes and nodes to the network registry, and force-sync the eligibility to true.
606/// It returns the number of removed nodes and nodes being added.
607/// - If nodes have been registered to a different safe, overwrite it (remove the old safe and regsiter with the new safe)
608/// - If ndoes have been registered to the same safe, no op
609/// - If nodes have not been registered to any safe, register it
610///
611/// After all the nodes have been added to the network registry, force-sync the eligibility of all the added safes to true
612pub async fn register_safes_and_nodes_on_network_registry<M: Middleware>(
613    network_registry: HoprNetworkRegistry<M>,
614    safe_addresses: Vec<H160>,
615    node_addresses: Vec<H160>,
616) -> Result<(usize, usize), HelperErrors> {
617    assert_eq!(
618        safe_addresses.len(),
619        node_addresses.len(),
620        "unmatched lengths of safes and nodes"
621    );
622
623    // check registered safes of given node addresses
624    let registered_safes =
625        get_registered_safes_for_nodes_on_network_registry(network_registry.clone(), node_addresses.clone())
626            .await
627            .map_err(|e| HelperErrors::MulticallError(e.to_string()))?;
628
629    let mut nodes_to_remove: Vec<H160> = Vec::new();
630    let mut safes_to_add: Vec<H160> = Vec::new();
631    let mut nodes_to_add: Vec<H160> = Vec::new();
632
633    for (i, registered_safe) in registered_safes.iter().enumerate() {
634        if registered_safe.eq(&H160::zero()) {
635            // no entry, add to network registry
636            safes_to_add.push(safe_addresses[i]);
637            nodes_to_add.push(node_addresses[i]);
638        } else if registered_safe.ne(&safe_addresses[i]) {
639            // remove first then add
640            nodes_to_remove.push(node_addresses[i]);
641            safes_to_add.push(safe_addresses[i]);
642            nodes_to_add.push(node_addresses[i]);
643        } else {
644            // no-op
645        }
646    }
647
648    if !nodes_to_remove.is_empty() {
649        // need to remove some nodes
650        network_registry
651            .manager_deregister(nodes_to_remove.clone())
652            .send()
653            .await
654            .unwrap()
655            .await
656            .unwrap();
657    }
658
659    network_registry
660        .manager_register(safes_to_add.clone(), nodes_to_add.clone())
661        .send()
662        .await
663        .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
664        .await
665        .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
666
667    // force sync their eligibility
668    network_registry
669        .manager_force_sync(safes_to_add.clone(), vec![true; safes_to_add.len()])
670        .send()
671        .await
672        .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
673        .await
674        .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
675
676    Ok((nodes_to_remove.len(), nodes_to_add.len()))
677}
678
679/// Deregister safes and nodes from the network registry. Does not do any action on the eligibility.
680/// It returns the number of removed nodes
681/// - If nodes have been registered to a safe, remove the node
682/// - If nodes have not been registered to any safe, no op
683pub async fn deregister_nodes_from_network_registry<M: Middleware>(
684    network_registry: HoprNetworkRegistry<M>,
685    node_addresses: Vec<H160>,
686) -> Result<usize, HelperErrors> {
687    // check registered safes of given node addresses
688    let registered_safes =
689        get_registered_safes_for_nodes_on_network_registry(network_registry.clone(), node_addresses.clone())
690            .await
691            .map_err(|e| HelperErrors::MulticallError(e.to_string()))?;
692
693    let mut nodes_to_remove: Vec<H160> = Vec::new();
694
695    for (i, registered_safe) in registered_safes.iter().enumerate() {
696        if registered_safe.ne(&H160::zero()) {
697            // remove the node
698            nodes_to_remove.push(node_addresses[i]);
699        }
700    }
701
702    if !nodes_to_remove.is_empty() {
703        // need to remove some nodes
704        network_registry
705            .manager_deregister(nodes_to_remove.clone())
706            .send()
707            .await
708            .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
709            .await
710            .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
711    }
712    Ok(nodes_to_remove.len())
713}
714
715/// Force-sync the eligibility to given values. This can only be called with a manager account
716pub async fn force_sync_safes_on_network_registry<M: Middleware>(
717    network_registry: HoprNetworkRegistry<M>,
718    safe_addresses: Vec<H160>,
719    eligibilities: Vec<bool>,
720) -> Result<(), HelperErrors> {
721    assert_eq!(
722        safe_addresses.len(),
723        eligibilities.len(),
724        "unmatched lengths of safes and eligibilities"
725    );
726
727    // force sync their eligibility
728    network_registry
729        .manager_force_sync(safe_addresses, eligibilities)
730        .send()
731        .await
732        .unwrap_or_else(|_| panic!("failed to exeute a pending transaction"))
733        .await
734        .unwrap_or_else(|_| panic!("failed to resolve a transaction receipt"));
735
736    Ok(())
737}
738
739/// Helper function to predict module address. Note that here the caller is the contract deployer
740pub fn predict_module_address(
741    caller: Address,
742    nonce: [u8; 32],
743    factory_address: Address,
744    implementation_address: Address,
745) -> Result<Address, HelperErrors> {
746    let module_salt = keccak256(ethers::abi::encode_packed(&[
747        ethers::abi::Token::Address(caller),
748        ethers::abi::Token::Bytes(nonce.into()),
749    ])?);
750    debug!("module_salt {:?}", module_salt);
751
752    let module_creation_code = ethers::abi::encode_packed(&[
753        ethers::abi::Token::Bytes(hex!("3d602d80600a3d3981f3363d3d373d3d3d363d73").to_vec()),
754        ethers::abi::Token::Address(implementation_address),
755        ethers::abi::Token::Bytes(hex!("5af43d82803e903d91602b57fd5bf3").to_vec()),
756    ])?;
757    debug!("module_creation_code {:?}", module_creation_code);
758
759    let predict_module_addr = get_create2_address(factory_address, module_salt, module_creation_code);
760    debug!("predict_module_addr {:?}", predict_module_addr);
761
762    Ok(predict_module_addr)
763}
764
765/// Helper function to predict safe address
766pub fn predict_safe_address(
767    stake_factory: Address,
768    admins: Vec<Address>,
769    nonce: [u8; 32],
770    safe_fallback: Address,
771    safe_singleton: Address,
772    safe_factory: Address,
773) -> Result<Address, HelperErrors> {
774    let mut temp_admins = admins.clone();
775    temp_admins[0] = stake_factory;
776
777    let initializer = SetupCall(
778        temp_admins,
779        U256::one(),
780        Address::zero(),
781        Bytes::from(hex!("00")),
782        safe_fallback,
783        Address::zero(),
784        U256::zero(),
785        Address::zero(),
786    )
787    .encode();
788
789    let safe_salt = get_salt_from_salt_nonce(initializer, nonce)?;
790    debug!("safe_salt {:?}", hex::encode(safe_salt));
791
792    let predict_safe_addr = deploy_proxy(safe_singleton, safe_salt, safe_factory)?;
793    debug!("predict_safe_addr {:?}", hex::encode(predict_safe_addr));
794
795    Ok(predict_safe_addr)
796}
797
798/// helper function to get salt nonce
799fn get_salt_from_salt_nonce(initializer: Vec<u8>, salt_nonce: [u8; 32]) -> Result<[u8; 32], HelperErrors> {
800    let hashed_initializer = keccak256(initializer);
801
802    Ok(keccak256(ethers::abi::encode_packed(&[
803        ethers::abi::Token::Bytes(hashed_initializer.into()),
804        ethers::abi::Token::Bytes(salt_nonce.into()),
805    ])?))
806}
807
808/// helper function to compute create2 safe proxy address
809fn deploy_proxy(safe_singleton: Address, safe_salt: [u8; 32], safe_factory: Address) -> Result<Address, HelperErrors> {
810    let safe_creation_code = ethers::abi::encode_packed(&[
811        ethers::abi::Token::Bytes(hex!("608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564").to_vec()),
812        ethers::abi::Token::Bytes(hex!("000000000000000000000000").to_vec()),    // pad address to bytes32
813        ethers::abi::Token::Address(safe_singleton),
814    ])?;
815    debug!("safe_creation_code {:?}", hex::encode(safe_creation_code.clone()));
816
817    let predict_safe_addr = get_create2_address(safe_factory, safe_salt, safe_creation_code);
818    debug!("predict_safe_addr {:?}", hex::encode(predict_safe_addr));
819
820    Ok(predict_safe_addr)
821}
822
823/// Wrap a transaction into a safe transaction payload
824/// Add the safe transaction to multicall
825pub fn prepare_safe_tx_from_owner_contract<M: Middleware>(
826    mut multicall: Multicall<M>,
827    deployed_safe: SafeSingleton<M>,
828    target: Address,
829    refund_address: Address,
830    tx_payload: Vec<u8>,
831) -> Result<Multicall<M>, HelperErrors> {
832    let approval_hash_sig = ethers::abi::encode_packed(&[
833        ethers::abi::Token::Bytes(hex!("000000000000000000000000").to_vec()),
834        ethers::abi::Token::Address(MULTICALL_ADDRESS),
835        ethers::abi::Token::Bytes(hex!("0000000000000000000000000000000000000000000000000000000000000000").to_vec()),
836        ethers::abi::Token::Bytes(hex!("01").to_vec()),
837    ])?;
838
839    multicall.add_call(
840        deployed_safe
841            .method::<_, bool>(
842                "execTransaction",
843                (
844                    target,
845                    U256::zero(),
846                    Bytes::from(tx_payload),
847                    0u8,
848                    U256::zero(),
849                    U256::zero(),
850                    U256::zero(),
851                    Address::zero(),
852                    refund_address,
853                    Bytes::from(approval_hash_sig),
854                ),
855            )
856            .map_err(|e| HelperErrors::MulticallError(e.to_string()))?,
857        false,
858    );
859    Ok(multicall)
860}
861
862/// Deploy a safe and a module proxies via HoprStakeFactory contract with default permissions and announcement targets
863/// Within one multicall, as an owner of the safe:
864/// - deploy a safe proxy instance and a module proxy instance with multicall as an owner
865/// - add announcement as a permitted target in the deployed module proxy
866/// - approve token transfer to be done for the safe by channel contracts
867/// - if node addresses are known, include nodes to the module by safe
868/// - transfer safe ownership to actual admins
869/// - set desired threshold
870/// - if node addresses are known, include nodes and safes to the network registry.
871///
872/// Returns safe proxy address and module proxy address
873#[allow(clippy::too_many_arguments)]
874pub async fn deploy_safe_module_with_targets_and_nodes<M: Middleware>(
875    hopr_node_stake_factory: HoprNodeStakeFactory<M>,
876    hopr_token_address: Address,
877    hopr_channels_address: Address,
878    hopr_module_implementation_address: Address,
879    hopr_announcement_address: Address,
880    allowance: U256,
881    node_addresses: Option<Vec<Address>>,
882    admins: Vec<Address>,
883    threshold: U256,
884) -> Result<(SafeSingleton<M>, HoprNodeManagementModule<M>), HelperErrors> {
885    let caller = hopr_node_stake_factory
886        .client()
887        .default_sender()
888        .expect("client must have a sender");
889    let provider = hopr_node_stake_factory.client();
890    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
891        .await
892        .expect("cannot create multicall");
893
894    // check safes owners are provided and threshold is valid
895    assert!(!admins.is_empty(), "safe must have valid admin(s)");
896    assert!(
897        threshold.ge(&U256::one()) && threshold.le(&admins.len().into()),
898        "safe threshold must be at least one and not greater than the total number of admins"
899    );
900    assert!(
901        !admins.contains(&MULTICALL_ADDRESS),
902        "multicall contract cannot be an admin"
903    );
904
905    // build a new temporary admin
906    let mut temporary_admins: Vec<Address> = admins.clone();
907    temporary_admins.insert(0, MULTICALL_ADDRESS);
908    info!(
909        "temporary_admins expends from admin from {:?} addresses to {:?}",
910        admins.len(),
911        temporary_admins.len()
912    );
913
914    // build the default permissions of capabilities
915    let default_target: [u8; 32] =
916        U256::from_str(format!("{:?}{}", hopr_channels_address, DEFAULT_CAPABILITY_PERMISSIONS).as_str())
917            .unwrap()
918            .into();
919    debug!("default target {:?}", default_target);
920    // salt nonce
921    let curr_nonce = provider
922        .get_transaction_count(caller, Some(ethers::types::BlockNumber::Pending.into()))
923        .await
924        .map_err(|e| HelperErrors::MiddlewareError(e.to_string()))?;
925    let nonce = keccak256(ethers::abi::encode_packed(&[
926        ethers::abi::Token::Address(caller),
927        ethers::abi::Token::Uint(curr_nonce),
928    ])?);
929
930    debug!("curr_nonce {} and nonce {:?}", curr_nonce, nonce);
931
932    // predict module and safe address
933    let module_address = predict_module_address(
934        MULTICALL_ADDRESS,
935        nonce,
936        hopr_node_stake_factory.address(),
937        hopr_module_implementation_address,
938    )?;
939    info!("predicted module address {:?}", module_address);
940
941    let safe_address = predict_safe_address(
942        hopr_node_stake_factory.address(),
943        temporary_admins.clone(),
944        nonce,
945        Address::from_str(SAFE_COMPATIBILITYFALLBACKHANDLER_ADDRESS).unwrap(),
946        Address::from_str(SAFE_SAFE_ADDRESS).unwrap(),
947        Address::from_str(SAFE_SAFEPROXYFACTORY_ADDRESS).unwrap(),
948    )?;
949    info!("predicted safe address {:?}", safe_address);
950
951    let deployed_module = HoprNodeManagementModule::new(module_address, provider.clone());
952    let deployed_safe = SafeSingleton::new(safe_address, provider.clone());
953
954    // Use multicall to deploy a safe proxy instance and a module proxy instance with multicall as an owner
955    multicall.add_call(
956        hopr_node_stake_factory
957            .method::<_, (Address, Address)>(
958                "clone",
959                (
960                    hopr_module_implementation_address,
961                    temporary_admins,
962                    U256::from(nonce),
963                    default_target,
964                ),
965            )
966            .map_err(|e| HelperErrors::MulticallError(e.to_string()))?,
967        false,
968    );
969    info!("Safe and module have been deployed");
970
971    // add announcement as a permitted target in the deployed module proxy
972    let announcement_target =
973        U256::from_str(format!("{:?}{}", hopr_announcement_address, DEFAULT_ANNOUNCEMENT_PERMISSIONS).as_str())
974            .unwrap();
975    let scope_announcement_tx_payload = ScopeTargetTokenCall {
976        default_target: announcement_target,
977    }
978    .encode();
979
980    multicall = prepare_safe_tx_from_owner_contract(
981        multicall.clone(),
982        deployed_safe.clone(),
983        module_address,
984        caller,
985        scope_announcement_tx_payload,
986    )?;
987    info!("Announcement smart contract has been scoped as target");
988
989    // approve token transfer to be done for the safe by channel contracts
990    let approve_tx_payload = ApproveCall {
991        spender: hopr_channels_address,
992        value: allowance,
993    }
994    .encode();
995
996    multicall = prepare_safe_tx_from_owner_contract(
997        multicall.clone(),
998        deployed_safe.clone(),
999        hopr_token_address,
1000        caller,
1001        approve_tx_payload,
1002    )?;
1003    info!("Token transfer allowance has been set for channel contract");
1004
1005    // if node addresses are known, include nodes to the module by safe
1006    if let Some(nodes) = node_addresses {
1007        for node in nodes {
1008            let node_target = U256::from_str(format!("{:?}{}", node, DEFAULT_NODE_PERMISSIONS).as_str()).unwrap();
1009            let include_node_tx_payload = IncludeNodeCall {
1010                node_default_target: node_target,
1011            }
1012            .encode();
1013            multicall = prepare_safe_tx_from_owner_contract(
1014                multicall.clone(),
1015                deployed_safe.clone(),
1016                module_address,
1017                caller,
1018                include_node_tx_payload,
1019            )?;
1020        }
1021        info!("Nodes have been included in the module");
1022    } else {
1023        info!("No node has been provided. Skip node inclusion action");
1024    }
1025
1026    // renounce ownership granted to multicall so that only actual admins are included. Set the threshold.
1027    let remove_owner_tx_payload = RemoveOwnerCall {
1028        prev_owner: Address::from_str(SENTINEL_OWNERS).unwrap(),
1029        owner: MULTICALL_ADDRESS,
1030        threshold,
1031    }
1032    .encode();
1033
1034    multicall = prepare_safe_tx_from_owner_contract(
1035        multicall.clone(),
1036        deployed_safe.clone(),
1037        safe_address,
1038        caller,
1039        remove_owner_tx_payload,
1040    )?;
1041    info!("Admins and threshold have been set to provided values");
1042
1043    let receipt = multicall
1044        .send()
1045        .await
1046        .map_err(|e| HelperErrors::MulticallError(e.to_string()))?
1047        .await
1048        .unwrap()
1049        .unwrap();
1050    info!("multicall receipt {:?}", receipt.transaction_hash);
1051
1052    Ok((deployed_safe, deployed_module))
1053}
1054
1055/// Get registered safes for given nodes on the node-safe registry
1056pub async fn get_registered_safes_for_nodes_on_node_safe_registry<M: Middleware>(
1057    node_safe_registry: HoprNodeSafeRegistry<M>,
1058    node_addresses: Vec<H160>,
1059) -> Result<Vec<H160>, MulticallError<M>> {
1060    let provider = node_safe_registry.client();
1061    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
1062        .await
1063        .expect("cannot create multicall");
1064
1065    for node in node_addresses {
1066        multicall.add_call(
1067            node_safe_registry
1068                .method::<_, Address>("nodeToSafe", node)
1069                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1070            false,
1071        );
1072    }
1073
1074    let response: Vec<Address> = multicall.call_array().await?;
1075
1076    Ok(response)
1077}
1078
1079/// Deregister safes and nodes from the node-safe registry.
1080/// It returns the number of removed nodes
1081/// - If nodes have been registered to a safe, remove the node
1082/// - If nodes have not been registered to any safe, no op
1083///
1084/// When deregsitering one node, also remove the node from the module
1085pub async fn deregister_nodes_from_node_safe_registry_and_remove_from_module<M: Middleware>(
1086    node_safe_registry: HoprNodeSafeRegistry<M>,
1087    node_addresses: Vec<H160>,
1088    module_addresses: Vec<H160>,
1089    owner_chain_key: ChainKeypair,
1090) -> Result<u32, HelperErrors> {
1091    let provider = node_safe_registry.client();
1092    // check registered safes of given node addresses
1093    let registered_safes =
1094        get_registered_safes_for_nodes_on_node_safe_registry(node_safe_registry.clone(), node_addresses.clone())
1095            .await
1096            .unwrap();
1097
1098    let mut nodes_to_remove_counter = 0u32;
1099
1100    for (i, registered_safe) in registered_safes.iter().enumerate() {
1101        if registered_safe.ne(&H160::zero()) {
1102            // connect to safe
1103            let safe = SafeSingleton::new(registered_safe.to_owned(), provider.clone());
1104            // update counter
1105            nodes_to_remove_counter += 1;
1106            // get chain id and nonce
1107            let (chain_id, safe_nonce) = get_chain_id_and_safe_nonce(safe.clone()).await?;
1108
1109            // for each safe, prepare a multisend transaction to dergister node from safe and remove node from module
1110            let multisend_txns: Vec<MultisendTransaction> = vec![
1111                MultisendTransaction {
1112                    // build multisend tx payload
1113                    encoded_data: DeregisterNodeBySafeCall {
1114                        node_addr: node_addresses[i],
1115                    }
1116                    .encode()
1117                    .into(),
1118                    tx_operation: SafeTxOperation::Call,
1119                    to: node_safe_registry.address(),
1120                    value: U256::zero(),
1121                },
1122                MultisendTransaction {
1123                    // build multisend tx payload
1124                    encoded_data: RemoveNodeCall {
1125                        node_address: node_addresses[i],
1126                    }
1127                    .encode()
1128                    .into(),
1129                    tx_operation: SafeTxOperation::Call,
1130                    to: module_addresses[i],
1131                    value: U256::zero(),
1132                },
1133            ];
1134
1135            // send safe transaction
1136            send_multisend_safe_transaction_with_threshold_one(
1137                safe,
1138                owner_chain_key.clone(),
1139                H160::from_str(SAFE_MULTISEND_ADDRESS).unwrap(),
1140                multisend_txns,
1141                chain_id,
1142                safe_nonce,
1143            )
1144            .await?;
1145        }
1146    }
1147
1148    Ok(nodes_to_remove_counter)
1149}
1150
1151/// Include nodes to the module
1152pub async fn include_nodes_to_module<M: Middleware>(
1153    safe: SafeSingleton<M>,
1154    node_addresses: Vec<H160>,
1155    module_address: H160,
1156    owner_chain_key: ChainKeypair,
1157) -> Result<(), HelperErrors> {
1158    // get chain id and nonce
1159    let (chain_id, safe_nonce) = get_chain_id_and_safe_nonce(safe.clone()).await?;
1160
1161    // prepare a multisend transaction to include each node to the  module
1162    let mut multisend_txns: Vec<MultisendTransaction> = Vec::new();
1163    for node_address in node_addresses {
1164        let node_target = U256::from_str(format!("{:?}{}", node_address, DEFAULT_NODE_PERMISSIONS).as_str()).unwrap();
1165        multisend_txns.push(MultisendTransaction {
1166            encoded_data: IncludeNodeCall {
1167                node_default_target: node_target,
1168            }
1169            .encode()
1170            .into(),
1171            tx_operation: SafeTxOperation::Call,
1172            to: module_address,
1173            value: U256::zero(),
1174        });
1175    }
1176
1177    // send safe transaction
1178    send_multisend_safe_transaction_with_threshold_one(
1179        safe,
1180        owner_chain_key.clone(),
1181        H160::from_str(SAFE_MULTISEND_ADDRESS).unwrap(),
1182        multisend_txns,
1183        chain_id,
1184        safe_nonce,
1185    )
1186    .await?;
1187
1188    Ok(())
1189}
1190
1191/// Migrate nodes to be able to run in a new network.
1192// - scope the Channel contract of the new network to the module as target and set default permissions.
1193// - scope the Announcement contract as target to the module
1194// - approve HOPR tokens of the Safe proxy to be transferred by the new Channels contract
1195pub async fn migrate_nodes<M: Middleware>(
1196    safe: SafeSingleton<M>,
1197    module_addresses: Address,
1198    channels_address: Address,
1199    token_address: Address,
1200    announcement_address: Address,
1201    allowance: U256,
1202    owner_chain_key: ChainKeypair,
1203) -> Result<(), HelperErrors> {
1204    let (chain_id, safe_nonce) = get_chain_id_and_safe_nonce(safe.clone()).await?;
1205
1206    let mut multisend_txns: Vec<MultisendTransaction> = Vec::new();
1207
1208    // scope channels and tokens contract of the network
1209    let default_target =
1210        U256::from_str(format!("{:?}{}", channels_address, DEFAULT_CAPABILITY_PERMISSIONS).as_str()).unwrap();
1211    debug!("default target {:?}", default_target);
1212
1213    multisend_txns.push(MultisendTransaction {
1214        // build multisend tx payload
1215        encoded_data: AddChannelsAndTokenTargetCall { default_target }.encode().into(),
1216        tx_operation: SafeTxOperation::Call,
1217        to: module_addresses,
1218        value: U256::zero(),
1219    });
1220
1221    // scope announcement contract of the new network
1222    let announcement_target =
1223        U256::from_str(format!("{:?}{}", announcement_address, DEFAULT_ANNOUNCEMENT_PERMISSIONS).as_str()).unwrap();
1224
1225    multisend_txns.push(MultisendTransaction {
1226        // build multisend tx payload
1227        encoded_data: ScopeTargetTokenCall {
1228            default_target: announcement_target,
1229        }
1230        .encode()
1231        .into(),
1232        tx_operation: SafeTxOperation::Call,
1233        to: module_addresses,
1234        value: U256::zero(),
1235    });
1236
1237    // approve token transfer by the new Channels contract
1238    multisend_txns.push(MultisendTransaction {
1239        // build multisend tx payload
1240        encoded_data: ApproveCall {
1241            spender: channels_address,
1242            value: allowance,
1243        }
1244        .encode()
1245        .into(),
1246        tx_operation: SafeTxOperation::Call,
1247        to: token_address,
1248        value: U256::zero(),
1249    });
1250
1251    // send safe transaction
1252    send_multisend_safe_transaction_with_threshold_one(
1253        safe,
1254        owner_chain_key.clone(),
1255        H160::from_str(SAFE_MULTISEND_ADDRESS).unwrap(),
1256        multisend_txns,
1257        chain_id,
1258        safe_nonce,
1259    )
1260    .await?;
1261
1262    Ok(())
1263}
1264
1265/// Quick check if the following values are correct, for one single node:
1266/// 1. node xDAI balance
1267/// 2. If node has been included on Network Registry
1268/// 3. If node and safe are associated on Node Safe Registry
1269pub async fn debug_node_safe_module_setup_on_balance_and_registries<M: Middleware>(
1270    network_registry: HoprNetworkRegistry<M>,
1271    node_safe_registry: HoprNodeSafeRegistry<M>,
1272    node_address: &H160,
1273) -> Result<Address, MulticallError<M>> {
1274    let provider = network_registry.client();
1275    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
1276        .await
1277        .expect("cannot create multicall");
1278
1279    info!("checking for node {:?}", node_address);
1280    multicall
1281        // 1. node xDAI balance
1282        .add_get_eth_balance(*node_address, false)
1283        // 2. get safe address from the Network Registry
1284        .add_call(
1285            network_registry
1286                .method::<_, Address>("nodeRegisterdToAccount", *node_address)
1287                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1288            false,
1289        )
1290        // 3. get the safe address from the Node Safe Registry
1291        .add_call(
1292            node_safe_registry
1293                .method::<_, Address>("nodeToSafe", *node_address)
1294                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1295            false,
1296        );
1297
1298    let (node_native_balance, safe_in_network_registry, safe_in_nodesafe_registry): (U256, Address, Address) =
1299        multicall.call().await?;
1300
1301    info!(
1302        "node does{:?} have xDAI balance {:?}",
1303        if node_native_balance.ge(&U256::from(
1304            parse_units(0.1, "ether").unwrap_or_else(|_| panic!("cannot parse node_native_balance"))
1305        )) {
1306            ""
1307        } else {
1308            " NOT"
1309        },
1310        format_units(node_native_balance, "ether").unwrap_or("Unknown balance".into())
1311    );
1312
1313    if safe_in_network_registry.eq(&H160::zero()) {
1314        info!("Please register the node to the network registry");
1315    } else {
1316        info!("safe in network registry {:?}", safe_in_network_registry);
1317    }
1318
1319    if safe_in_nodesafe_registry.eq(&H160::zero()) {
1320        info!("Please start the node. It will auto-register to node-safe registry");
1321    } else {
1322        info!("safe in node-safe registry {:?}", safe_in_nodesafe_registry);
1323    }
1324    info!(
1325        "Safes in both registies should match: {:?}",
1326        safe_in_network_registry.eq(&safe_in_nodesafe_registry)
1327    );
1328
1329    Ok(safe_in_network_registry)
1330}
1331
1332/// Quick check if the following values are correct, for one single node:
1333/// 4. If Safe is owned by the correct owner(s)
1334/// 5. Safe’s wxHOPR balance and allowance
1335/// 6. if the module is enabled
1336/// 7. if node is included in the module
1337/// 8. Get all the targets of the safe (then check if channel and announcement are there)
1338/// 9. Get the owner of the module
1339pub async fn debug_node_safe_module_setup_main<M: Middleware>(
1340    hopr_token: HoprToken<M>,
1341    module_address: &H160,
1342    node_address: &H160,
1343    safe_address: &H160,
1344    channel_address: &H160,
1345    announce_address: &H160,
1346) -> Result<(), MulticallError<M>> {
1347    let provider = hopr_token.client();
1348    let mut multicall = Multicall::new(provider.clone(), Some(MULTICALL_ADDRESS))
1349        .await
1350        .expect("cannot create multicall");
1351
1352    let safe = SafeSingleton::new(safe_address.to_owned(), provider.clone());
1353    let module = ModuleSingleton::new(module_address.to_owned(), provider.clone());
1354
1355    info!("checking for safe {:?} module {:?}", safe_address, module_address);
1356    multicall
1357        // 4. get owners of the safe
1358        .add_call(
1359            safe.method::<_, Vec<Address>>("getOwners", ())
1360                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1361            false,
1362        )
1363        // 5.a. get the wxHOPR balance for the safe address
1364        .add_call(
1365            hopr_token
1366                .method::<_, U256>("balanceOf", *safe_address)
1367                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1368            false,
1369        )
1370        // 5.b. get the wxHOPR balance for the safe address
1371        .add_call(
1372            hopr_token
1373                .method::<_, U256>("allowance", (*safe_address, *channel_address))
1374                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1375            false,
1376        )
1377        // 6. if the module is enabled
1378        .add_call(
1379            safe.method::<_, bool>("isModuleEnabled", *module_address)
1380                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1381            false,
1382        )
1383        // 7. if node is included in the module
1384        .add_call(
1385            module
1386                .method::<_, bool>("isNode", *node_address)
1387                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1388            false,
1389        )
1390        // 7. get targets of the safe
1391        .add_call(
1392            module
1393                .method::<_, Vec<U256>>("getTargets", ())
1394                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1395            false,
1396        )
1397        // 8. get owner of the module
1398        .add_call(
1399            module
1400                .method::<_, Address>("owner", ())
1401                .map_err(|e| MulticallError::ContractError(ContractError::AbiError(e)))?,
1402            false,
1403        );
1404
1405    let (
1406        safe_owners,
1407        safe_wxhopr_balance,
1408        safe_wxhopr_allownace,
1409        is_module_enabled,
1410        is_node_included,
1411        module_targets,
1412        module_owner,
1413    ): (Vec<Address>, U256, U256, bool, bool, Vec<U256>, Address) = multicall.call().await?;
1414
1415    info!("safe has owners: {:?}", safe_owners);
1416    info!(
1417        "safe has wxHOPR balance: {:?}",
1418        format_units(safe_wxhopr_balance, "ether").unwrap_or("Unknown balance".into())
1419    );
1420    info!(
1421        "safe has wxHOPR allowance: {:?}",
1422        format_units(safe_wxhopr_allownace, "ether").unwrap_or("Unknown balance".into())
1423    );
1424    info!("module is enabled: {:?}", is_module_enabled);
1425    info!("node is included in the module: {:?}", is_node_included);
1426    info!("module has targets:");
1427    for target in module_targets {
1428        let target_address = format!("{:#x}", target);
1429        let has_channels = target_address.contains(&format!("{:#x}", channel_address));
1430        let has_announcement = target_address.contains(&format!("{:#x}", announce_address));
1431        // check if it contains channel and announcement
1432        info!(
1433            "Target {:?} has channels {:?} has announcement {:?}",
1434            target_address, has_channels, has_announcement
1435        );
1436    }
1437
1438    info!(
1439        "module owner: {:?} same as safe address: {:?}",
1440        module_owner,
1441        module_owner.eq(safe_address)
1442    );
1443    Ok(())
1444}
1445
1446#[cfg(test)]
1447mod tests {
1448    use super::*;
1449
1450    use ethers::abi::AbiDecode;
1451    use ethers::types::TransactionRequest;
1452    use std::vec;
1453
1454    use hopr_bindings::{hopr_announcements::HoprAnnouncements, hopr_channels::HoprChannels};
1455    use hopr_chain_rpc::client::{create_rpc_client_to_anvil, surf_client::SurfRequestor};
1456    use hopr_chain_types::ContractInstances;
1457    use hopr_crypto_types::keypairs::{ChainKeypair, Keypair};
1458    use hopr_primitive_types::prelude::BytesRepresentable;
1459    use hopr_primitive_types::primitives::Address;
1460
1461    use crate::utils::{NEW_HOPR_NODE_STAKE_MODULE_TOPIC, NEW_HOPR_NODE_STAKE_SAFE_TOPIC};
1462
1463    fn get_random_address_for_testing() -> Address {
1464        // Creates a random Ethereum address, only used for testing
1465        Address::new(&hopr_crypto_random::random_bytes::<{ Address::SIZE }>())
1466    }
1467
1468    async fn deploy_safe_suites<M: Middleware>(provider: Arc<M>) -> Result<(), ContractError<M>> {
1469        // Check if safe suite has been deployed. If so, skip this step
1470        let code = provider
1471            .get_code(
1472                "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7"
1473                    .parse::<ethers::types::Address>()
1474                    .unwrap(),
1475                None,
1476            )
1477            .await
1478            .map_err(|e| ContractError::MiddlewareError { e })?;
1479
1480        // only deploy contracts when needed
1481        if code.len() == 0 {
1482            debug!("deploying safe code");
1483            // Deploy Safe diamond deployment proxy singleton
1484            let safe_diamond_proxy_address = {
1485                // Fund Safe singleton deployer 0.01 anvil-eth and deploy Safe singleton
1486                let mut tx = Eip1559TransactionRequest::new();
1487                tx = tx.to(H160::from_str("E1CB04A0fA36DdD16a06ea828007E35e1a3cBC37").unwrap());
1488                tx = tx.value(10000000000000000u128);
1489
1490                provider
1491                    .send_transaction(tx, None)
1492                    .await
1493                    .map_err(|e| ContractError::MiddlewareError { e })?
1494                    .await?;
1495
1496                let tx = provider.send_raw_transaction(
1497            hex!("f8a78085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf382f4f5a00dc4d1d21b308094a30f5f93da35e4d72e99115378f135f2295bea47301a3165a0636b822daad40aa8c52dd5132f378c0c0e6d83b4898228c7e21c84e631a0b891")
1498                .into()).await.map_err(|e| ContractError::MiddlewareError {e})?.await?.unwrap();
1499                tx.contract_address.unwrap()
1500            };
1501            debug!("Safe diamond proxy singleton {:?}", safe_diamond_proxy_address);
1502
1503            // Deploy minimum Safe suite
1504            // 1. Safe proxy factory deploySafeProxyFactory();
1505            let _tx_safe_proxy_factory = TransactionRequest::new().to(safe_diamond_proxy_address).data::<Bytes>(
1506            hex!("0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b50610bee806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80631688f0b91461005c5780633408e4701461016b57806353e5d93514610189578063d18af54d1461020c578063ec9e80bb1461033b575b600080fd5b61013f6004803603606081101561007257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156100af57600080fd5b8201836020820111156100c157600080fd5b803590602001918460018302840111640100000000831117156100e357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919050505061044a565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101736104fe565b6040518082815260200191505060405180910390f35b61019161050b565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101d15780820151818401526020810190506101b6565b50505050905090810190601f1680156101fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61030f6004803603608081101561022257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561025f57600080fd5b82018360208201111561027157600080fd5b8035906020019184600183028401116401000000008311171561029357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610536565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61041e6004803603606081101561035157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561038e57600080fd5b8201836020820111156103a057600080fd5b803590602001918460018302840111640100000000831117156103c257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001909291905050506106e5565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008083805190602001208360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012090506104908585836107a8565b91508173ffffffffffffffffffffffffffffffffffffffff167f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e23586604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a2509392505050565b6000804690508091505090565b60606040518060200161051d906109c5565b6020820181038252601f19601f82011660405250905090565b6000808383604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1660601b8152601401925050506040516020818303038152906040528051906020012060001c905061059186868361044a565b9150600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106dc578273ffffffffffffffffffffffffffffffffffffffff16631e52b518838888886040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015610674578082015181840152602081019050610659565b50505050905090810190601f1680156106a15780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156106c357600080fd5b505af11580156106d7573d6000803e3d6000fd5b505050505b50949350505050565b6000808380519060200120836106f96104fe565b60405160200180848152602001838152602001828152602001935050505060405160208183030381529060405280519060200120905061073a8585836107a8565b91508173ffffffffffffffffffffffffffffffffffffffff167f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e23586604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a2509392505050565b60006107b3846109b2565b610825576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f53696e676c65746f6e20636f6e7472616374206e6f74206465706c6f7965640081525060200191505060405180910390fd5b600060405180602001610837906109c5565b6020820181038252601f19601f820116604052508573ffffffffffffffffffffffffffffffffffffffff166040516020018083805190602001908083835b602083106108985780518252602082019150602081019050602083039250610875565b6001836020036101000a038019825116818451168082178552505050505050905001828152602001925050506040516020818303038152906040529050828151826020016000f59150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610984576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f437265617465322063616c6c206661696c65640000000000000000000000000081525060200191505060405180910390fd5b6000845111156109aa5760008060008651602088016000875af114156109a957600080fd5b5b509392505050565b600080823b905060008111915050919050565b6101e6806109d38339019056fe608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564a26469706673582212200fd975ca8e62d9bf08aa3d09c74b9bdc9d7acba7621835be4187989ddd0e54b164736f6c63430007060033").into()
1507        );
1508            // 2. Handler: only CompatibilityFallbackHandler and omit TokenCallbackHandler as it's not used now
1509            let _tx_safe_compatibility_fallback_handler = TransactionRequest::new().to(safe_diamond_proxy_address).data::<Bytes>(
1510            hex!("0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b5061073f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100565760003560e01c806223de291461005b57806301ffc9a714610193578063150b7a02146101f6578063bc197c81146102ec578063f23a6e6114610482575b600080fd5b610191600480360360c081101561007157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156100f857600080fd5b82018360208201111561010a57600080fd5b8035906020019184600183028401116401000000008311171561012c57600080fd5b90919293919293908035906020019064010000000081111561014d57600080fd5b82018360208201111561015f57600080fd5b8035906020019184600183028401116401000000008311171561018157600080fd5b9091929391929390505050610582565b005b6101de600480360360208110156101a957600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919050505061058c565b60405180821515815260200191505060405180910390f35b6102b76004803603608081101561020c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561027357600080fd5b82018360208201111561028557600080fd5b803590602001918460018302840111640100000000831117156102a757600080fd5b90919293919293905050506106c6565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b61044d600480360360a081101561030257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561035f57600080fd5b82018360208201111561037157600080fd5b8035906020019184602083028401116401000000008311171561039357600080fd5b9091929391929390803590602001906401000000008111156103b457600080fd5b8201836020820111156103c657600080fd5b803590602001918460208302840111640100000000831117156103e857600080fd5b90919293919293908035906020019064010000000081111561040957600080fd5b82018360208201111561041b57600080fd5b8035906020019184600183028401116401000000008311171561043d57600080fd5b90919293919293905050506106db565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b61054d600480360360a081101561049857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019064010000000081111561050957600080fd5b82018360208201111561051b57600080fd5b8035906020019184600183028401116401000000008311171561053d57600080fd5b90919293919293905050506106f3565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b5050505050505050565b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061065757507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806106bf57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600063150b7a0260e01b905095945050505050565b600063bc197c8160e01b905098975050505050505050565b600063f23a6e6160e01b9050969550505050505056fea2646970667358221220f62cd059f3672bb04062df149e7ae71534a8512cca0172e695d98a43cff0c53564736f6c63430007060033").into()
1511        );
1512            // 3. Library: only MultiSendCallOnly and omit MultiSendCall
1513            let _tx_safe_multisend_call_only = TransactionRequest::new().to(safe_diamond_proxy_address).data::<Bytes>(
1514            hex!("0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b5061019a806100206000396000f3fe60806040526004361061001e5760003560e01c80638d80ff0a14610023575b600080fd5b6100dc6004803603602081101561003957600080fd5b810190808035906020019064010000000081111561005657600080fd5b82018360208201111561006857600080fd5b8035906020019184600183028401116401000000008311171561008a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506100de565b005b805160205b8181101561015f578083015160f81c6001820184015160601c60158301850151603584018601516055850187016000856000811461012857600181146101385761013d565b6000808585888a5af1915061013d565b600080fd5b50600081141561014c57600080fd5b82605501870196505050505050506100e3565b50505056fea26469706673582212208d297bb003abee230b5dfb38774688f37a6fbb97a82a21728e8049b2acb9b73564736f6c63430007060033").into()
1515        );
1516            // 4. Safe singleton deploySafe();
1517            let _tx_safe_singleton = TransactionRequest::new().to(safe_diamond_proxy_address).data::<Bytes>(
1518            hex!("0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b506001600481905550615c1b80620000296000396000f3fe6080604052600436106101d15760003560e01c8063affed0e0116100f7578063e19a9dd911610095578063f08a032311610064578063f08a03231461156b578063f698da25146115bc578063f8dc5dd9146115e7578063ffa1ad741461166257610226565b8063e19a9dd9146112bf578063e318b52b14611310578063e75235b8146113a1578063e86637db146113cc57610226565b8063cc2f8452116100d1578063cc2f84521461100c578063d4d9bdcd146110d9578063d8d11f7814611114578063e009cfde1461124e57610226565b8063affed0e014610d89578063b4faba0914610db4578063b63e800d14610e9c57610226565b80635624b25b1161016f5780636a7612021161013e5780636a761202146109895780637d83297414610b45578063934f3a1114610bb4578063a0e67e2b14610d1d57610226565b80635624b25b146107f05780635ae6bd37146108ae578063610b5925146108fd578063694e80c31461094e57610226565b80632f54bf6e116101ab5780632f54bf6e146104c85780633408e4701461052f578063468721a71461055a5780635229073f1461066f57610226565b80630d582f131461029357806312fb68e0146102ee5780632d9ad53d1461046157610226565b36610226573373ffffffffffffffffffffffffffffffffffffffff167f3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d346040518082815260200191505060405180910390a2005b34801561023257600080fd5b5060007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b905080548061026757600080f35b36600080373360601b365260008060143601600080855af13d6000803e8061028e573d6000fd5b3d6000f35b34801561029f57600080fd5b506102ec600480360360408110156102b657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506116f2565b005b3480156102fa57600080fd5b5061045f6004803603608081101561031157600080fd5b81019080803590602001909291908035906020019064010000000081111561033857600080fd5b82018360208201111561034a57600080fd5b8035906020019184600183028401116401000000008311171561036c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156103cf57600080fd5b8201836020820111156103e157600080fd5b8035906020019184600183028401116401000000008311171561040357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190505050611ad8565b005b34801561046d57600080fd5b506104b06004803603602081101561048457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506123d6565b60405180821515815260200191505060405180910390f35b3480156104d457600080fd5b50610517600480360360208110156104eb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506124a8565b60405180821515815260200191505060405180910390f35b34801561053b57600080fd5b5061054461257a565b6040518082815260200191505060405180910390f35b34801561056657600080fd5b506106576004803603608081101561057d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156105c457600080fd5b8201836020820111156105d657600080fd5b803590602001918460018302840111640100000000831117156105f857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff169060200190929190505050612587565b60405180821515815260200191505060405180910390f35b34801561067b57600080fd5b5061076c6004803603608081101561069257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156106d957600080fd5b8201836020820111156106eb57600080fd5b8035906020019184600183028401116401000000008311171561070d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff16906020019092919050505061278d565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107b4578082015181840152602081019050610799565b50505050905090810190601f1680156107e15780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156107fc57600080fd5b506108336004803603604081101561081357600080fd5b8101908080359060200190929190803590602001909291905050506127c3565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610873578082015181840152602081019050610858565b50505050905090810190601f1680156108a05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156108ba57600080fd5b506108e7600480360360208110156108d157600080fd5b810190808035906020019092919050505061284a565b6040518082815260200191505060405180910390f35b34801561090957600080fd5b5061094c6004803603602081101561092057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612862565b005b34801561095a57600080fd5b506109876004803603602081101561097157600080fd5b8101908080359060200190929190505050612bea565b005b610b2d60048036036101408110156109a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156109e757600080fd5b8201836020820111156109f957600080fd5b80359060200191846001830284011164010000000083111715610a1b57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610aa757600080fd5b820183602082011115610ab957600080fd5b80359060200191846001830284011164010000000083111715610adb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612d24565b60405180821515815260200191505060405180910390f35b348015610b5157600080fd5b50610b9e60048036036040811015610b6857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613253565b6040518082815260200191505060405180910390f35b348015610bc057600080fd5b50610d1b60048036036060811015610bd757600080fd5b810190808035906020019092919080359060200190640100000000811115610bfe57600080fd5b820183602082011115610c1057600080fd5b80359060200191846001830284011164010000000083111715610c3257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610c9557600080fd5b820183602082011115610ca757600080fd5b80359060200191846001830284011164010000000083111715610cc957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050613278565b005b348015610d2957600080fd5b50610d32613307565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d75578082015181840152602081019050610d5a565b505050509050019250505060405180910390f35b348015610d9557600080fd5b50610d9e6134b0565b6040518082815260200191505060405180910390f35b348015610dc057600080fd5b50610e9a60048036036040811015610dd757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610e1457600080fd5b820183602082011115610e2657600080fd5b80359060200191846001830284011164010000000083111715610e4857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506134b6565b005b348015610ea857600080fd5b5061100a6004803603610100811015610ec057600080fd5b8101908080359060200190640100000000811115610edd57600080fd5b820183602082011115610eef57600080fd5b80359060200191846020830284011164010000000083111715610f1157600080fd5b909192939192939080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610f5c57600080fd5b820183602082011115610f6e57600080fd5b80359060200191846001830284011164010000000083111715610f9057600080fd5b9091929391929390803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506134d8565b005b34801561101857600080fd5b506110656004803603604081101561102f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613696565b60405180806020018373ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b838110156110c45780820151818401526020810190506110a9565b50505050905001935050505060405180910390f35b3480156110e557600080fd5b50611112600480360360208110156110fc57600080fd5b81019080803590602001909291905050506139f9565b005b34801561112057600080fd5b50611238600480360361014081101561113857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561117f57600080fd5b82018360208201111561119157600080fd5b803590602001918460018302840111640100000000831117156111b357600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613b98565b6040518082815260200191505060405180910390f35b34801561125a57600080fd5b506112bd6004803603604081101561127157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613bc5565b005b3480156112cb57600080fd5b5061130e600480360360208110156112e257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613f4c565b005b34801561131c57600080fd5b5061139f6004803603606081101561133357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614138565b005b3480156113ad57600080fd5b506113b6614796565b6040518082815260200191505060405180910390f35b3480156113d857600080fd5b506114f060048036036101408110156113f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561143757600080fd5b82018360208201111561144957600080fd5b8035906020019184600183028401116401000000008311171561146b57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506147a0565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611530578082015181840152602081019050611515565b50505050905090810190601f16801561155d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561157757600080fd5b506115ba6004803603602081101561158e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614948565b005b3480156115c857600080fd5b506115d161499f565b6040518082815260200191505060405180910390f35b3480156115f357600080fd5b506116606004803603606081101561160a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050614a1d565b005b34801561166e57600080fd5b50611677614e46565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156116b757808201518184015260208101905061169c565b50505050905090810190601f1680156116e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6116fa614e7f565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156117645750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561179c57503073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b61180e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461190f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003600081548092919060010191905055508173ffffffffffffffffffffffffffffffffffffffff167f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2660405160405180910390a28060045414611ad457611ad381612bea565b5b5050565b611aec604182614f2290919063ffffffff16565b82511015611b62576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000808060008060005b868110156123ca57611b7e8882614f5c565b80945081955082965050505060008460ff1614156120035789898051906020012014611c12576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323700000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8260001c9450611c2c604188614f2290919063ffffffff16565b8260001c1015611ca4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8751611cbd60208460001c614f8b90919063ffffffff16565b1115611d31576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006020838a01015190508851611d6782611d5960208760001c614f8b90919063ffffffff16565b614f8b90919063ffffffff16565b1115611ddb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60606020848b010190506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff166320c13b0b8d846040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015611e7d578082015181840152602081019050611e62565b50505050905090810190601f168015611eaa5780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b83811015611ee3578082015181840152602081019050611ec8565b50505050905090810190601f168015611f105780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b158015611f2f57600080fd5b505afa158015611f43573d6000803e3d6000fd5b505050506040513d6020811015611f5957600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614611ffc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5050612248565b60018460ff161415612117578260001c94508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806120a057506000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000205414155b612112576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b612247565b601e8460ff1611156121df5760018a60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048603858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156121ce573d6000803e3d6000fd5b505050602060405103519450612246565b60018a85858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015612239573d6000803e3d6000fd5b5050506020604051035194505b5b5b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1611801561230f5750600073ffffffffffffffffffffffffffffffffffffffff16600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b80156123485750600173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b6123ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323600000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8495508080600101915050611b6c565b50505050505050505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff16141580156124a15750600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156125735750600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000804690508091505090565b6000600173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156126525750600073ffffffffffffffffffffffffffffffffffffffff16600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b6126c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6126f1858585857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614faa565b90508015612741573373ffffffffffffffffffffffffffffffffffffffff167f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb860405160405180910390a2612785565b3373ffffffffffffffffffffffffffffffffffffffff167facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd37560405160405180910390a25b949350505050565b6000606061279d86868686612587565b915060405160203d0181016040523d81523d6000602083013e8091505094509492505050565b606060006020830267ffffffffffffffff811180156127e157600080fd5b506040519080825280601f01601f1916602001820160405280156128145781602001600182028036833780820191505090505b50905060005b8381101561283f5780850154806020830260208501015250808060010191505061281a565b508091505092915050565b60076020528060005260406000206000915090505481565b61286a614e7f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156128d45750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b612946576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612a47576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844060405160405180910390a250565b612bf2614e7f565b600354811115612c6a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001811015612ce1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b806004819055507f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c936004546040518082815260200191505060405180910390a150565b6000806000612d3e8e8e8e8e8e8e8e8e8e8e6005546147a0565b905060056000815480929190600101919050555080805190602001209150612d67828286613278565b506000612d72614ff6565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612f58578073ffffffffffffffffffffffffffffffffffffffff166375f0bb528f8f8f8f8f8f8f8f8f8f8f336040518d63ffffffff1660e01b8152600401808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c8152602001806020018a6001811115612e1557fe5b81526020018981526020018881526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff168152602001806020018473ffffffffffffffffffffffffffffffffffffffff16815260200183810383528d8d82818152602001925080828437600081840152601f19601f820116905080830192505050838103825285818151815260200191508051906020019080838360005b83811015612ee7578082015181840152602081019050612ecc565b50505050905090810190601f168015612f145780820380516001836020036101000a031916815260200191505b509e505050505050505050505050505050600060405180830381600087803b158015612f3f57600080fd5b505af1158015612f53573d6000803e3d6000fd5b505050505b6101f4612f7f6109c48b01603f60408d0281612f7057fe5b0461502790919063ffffffff16565b015a1015612ff5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60005a905061305e8f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e60008d14613053578e613059565b6109c45a035b614faa565b93506130735a8261504190919063ffffffff16565b90508380613082575060008a14155b8061308e575060008814155b613100576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008089111561311a57613117828b8b8b8b615061565b90505b841561315d57837f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e826040518082815260200191505060405180910390a2613196565b837f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d23826040518082815260200191505060405180910390a25b5050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613242578073ffffffffffffffffffffffffffffffffffffffff16639327136883856040518363ffffffff1660e01b815260040180838152602001821515815260200192505050600060405180830381600087803b15801561322957600080fd5b505af115801561323d573d6000803e3d6000fd5b505050505b50509b9a5050505050505050505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b60006004549050600081116132f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61330184848484611ad8565b50505050565b6060600060035467ffffffffffffffff8111801561332457600080fd5b506040519080825280602002602001820160405280156133535781602001602082028036833780820191505090505b50905060008060026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146134a757808383815181106133fe57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081806001019250506133bd565b82935050505090565b60055481565b600080825160208401855af4806000523d6020523d600060403e60403d016000fd5b6135238a8a80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505089615267565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146135615761356084615767565b5b6135af8787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050615838565b60008211156135c9576135c782600060018685615061565b505b3373ffffffffffffffffffffffffffffffffffffffff167f141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a88b8b8b8b8960405180806020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252878782818152602001925060200280828437600081840152601f19601f820116905080830192505050965050505050505060405180910390a250505050505050505050565b60606000600173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806136da57506136d9846123d6565b5b61374c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600083116137c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303600000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8267ffffffffffffffff811180156137d957600080fd5b506040519080825280602002602001820160405280156138085781602001602082028036833780820191505090505b5091506000600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156138da5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b80156138e557508381105b156139a057818382815181106138f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508080600101915050613870565b600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146139ee578260018203815181106139e357fe5b602002602001015191505b808352509250929050565b600073ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415613afb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16817ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c60405160405180910390a350565b6000613bad8c8c8c8c8c8c8c8c8c8c8c6147a0565b8051906020012090509b9a5050505050505050505050565b613bcd614e7f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015613c375750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b613ca9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613da9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427660405160405180910390a25050565b613f54614e7f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146140c6578073ffffffffffffffffffffffffffffffffffffffff166301ffc9a77fe6d7a83a000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060206040518083038186803b15801561401857600080fd5b505afa15801561402c573d6000803e3d6000fd5b505050506040513d602081101561404257600080fd5b81019080805190602001909291905050506140c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475333303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b60007f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b90508181558173ffffffffffffffffffffffffffffffffffffffff167f1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa260405160405180910390a25050565b614140614e7f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156141aa5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156141e257503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b614254576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614355576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156143bf5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b614431576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614531576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff167ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf60405160405180910390a28073ffffffffffffffffffffffffffffffffffffffff167f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2660405160405180910390a2505050565b6000600454905090565b606060007fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d860001b8d8d8d8d60405180838380828437808301925050509250505060405180910390208c8c8c8c8c8c8c604051602001808c81526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a815260200189815260200188600181111561483157fe5b81526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019b505050505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b6148bd61499f565b8360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529150509b9a5050505050505050505050565b614950614e7f565b61495981615767565b8073ffffffffffffffffffffffffffffffffffffffff167f5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b060405160405180910390a250565b60007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b6149cd61257a565b30604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405160208183030381529060405280519060200120905090565b614a25614e7f565b806001600354031015614aa0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015614b0a5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b614b7c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614c7c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360008154809291906001900391905055508173ffffffffffffffffffffffffffffffffffffffff167ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf60405160405180910390a28060045414614e4157614e4081612bea565b5b505050565b6040518060400160405280600581526020017f312e342e3100000000000000000000000000000000000000000000000000000081525081565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614614f20576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b600080831415614f355760009050614f56565b6000828402905082848281614f4657fe5b0414614f5157600080fd5b809150505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b600080828401905083811015614fa057600080fd5b8091505092915050565b6000600180811115614fb857fe5b836001811115614fc457fe5b1415614fdd576000808551602087018986f49050614fed565b600080855160208701888a87f190505b95945050505050565b6000807f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b9050805491505090565b6000818310156150375781615039565b825b905092915050565b60008282111561505057600080fd5b600082840390508091505092915050565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461509e57826150a0565b325b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156151b85761510a3a86106150e7573a6150e9565b855b6150fc888a614f8b90919063ffffffff16565b614f2290919063ffffffff16565b91508073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050506151b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61525d565b6151dd856151cf888a614f8b90919063ffffffff16565b614f2290919063ffffffff16565b91506151ea848284615b0e565b61525c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5095945050505050565b6000600454146152df576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8151811115615356576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60018110156153cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006001905060005b83518110156156d35760008482815181106153ed57fe5b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156154615750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561549957503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156154d157508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b615543576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614615644576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508092505080806001019150506153d6565b506001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825160038190555081600481905550505050565b3073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415615809576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475334303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b90508181555050565b600073ffffffffffffffffffffffffffffffffffffffff1660016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461593a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001806000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614615b0a576159f682615bd2565b615a68576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b615a978260008360017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614faa565b615b09576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5050565b60008063a9059cbb8484604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050602060008251602084016000896127105a03f13d60008114615bb55760208114615bbd5760009350615bc8565b819350615bc8565b600051158215171593505b5050509392505050565b600080823b90506000811191505091905056fea264697066735822122057398fa72884cf9a6cb78aab2fb58a6b927f0e9d97d75b015daaee0959a153bf64736f6c63430007060033").into()
1519        );
1520            // 5. Safe multisend:
1521            let _tx_safe_multisend = TransactionRequest::new().to(safe_diamond_proxy_address).data::<Bytes>(
1522                hex!("000000000000000000000000000000000000000000000000000000000000000060a060405234801561001057600080fd5b503073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1660601b8152505060805160601c6102756100646000398060e052506102756000f3fe60806040526004361061001e5760003560e01c80638d80ff0a14610023575b600080fd5b6100dc6004803603602081101561003957600080fd5b810190808035906020019064010000000081111561005657600080fd5b82018360208201111561006857600080fd5b8035906020019184600183028401116401000000008311171561008a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506100de565b005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161415610183576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806102106030913960400191505060405180910390fd5b805160205b8181101561020a578083015160f81c6001820184015160601c6015830185015160358401860151605585018701600085600081146101cd57600181146101dd576101e8565b6000808585888a5af191506101e8565b6000808585895af491505b5060008114156101f757600080fd5b8260550187019650505050505050610188565b50505056fe4d756c746953656e642073686f756c64206f6e6c792062652063616c6c6564207669612064656c656761746563616c6ca264697066735822122021102e6d5bc1da75411b41fe2792a1748bf5c49c794e51e81405ccd2399da13564736f6c63430007060033").into()
1523            );
1524            // other omitted libs: SimulateTxAccessor, CreateCall, and SignMessageLib
1525            // broadcast those transactions
1526            provider
1527                .send_transaction(_tx_safe_proxy_factory, None)
1528                .await
1529                .unwrap()
1530                .await
1531                .unwrap();
1532            provider
1533                .send_transaction(_tx_safe_compatibility_fallback_handler, None)
1534                .await
1535                .unwrap()
1536                .await
1537                .unwrap();
1538            provider
1539                .send_transaction(_tx_safe_multisend_call_only, None)
1540                .await
1541                .unwrap()
1542                .await
1543                .unwrap();
1544            provider
1545                .send_transaction(_tx_safe_singleton, None)
1546                .await
1547                .unwrap()
1548                .await
1549                .unwrap();
1550            provider
1551                .send_transaction(_tx_safe_multisend, None)
1552                .await
1553                .unwrap()
1554                .await
1555                .unwrap();
1556        }
1557        Ok(())
1558    }
1559
1560    #[async_std::test]
1561    async fn test_native_and_token_balances_in_anvil_with_multicall() -> anyhow::Result<()> {
1562        // create a keypair
1563        let kp = ChainKeypair::random();
1564        let kp_address = Address::from(&kp);
1565
1566        // launch local anvil instance
1567        let anvil = hopr_chain_types::utils::create_anvil(None);
1568        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1569        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1570        // deploy hopr contracts
1571        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1572            .await
1573            .expect("failed to deploy");
1574        // deploy multicall contract
1575        deploy_multicall3_for_testing(client.clone()).await?;
1576
1577        // get native and token balances
1578        let (native_balance, token_balance) =
1579            get_native_and_token_balances(instances.token, vec![kp_address.into()]).await?;
1580        assert_eq!(native_balance.len(), 1, "invalid native balance lens");
1581        assert_eq!(token_balance.len(), 1, "invalid token balance lens");
1582        assert_eq!(native_balance[0].as_u64(), 0u64, "wrong native balance");
1583        assert_eq!(token_balance[0].as_u64(), 0u64, "wrong token balance");
1584        drop(anvil);
1585        Ok(())
1586    }
1587
1588    #[async_std::test]
1589    async fn test_transfer_or_mint_tokens_in_anvil_with_multicall() -> anyhow::Result<()> {
1590        let mut addresses: Vec<ethers::types::Address> = Vec::new();
1591        for _ in 0..4 {
1592            addresses.push(get_random_address_for_testing().into());
1593        }
1594        let desired_amount = vec![U256::from(1), U256::from(2), U256::from(3), U256::from(4)];
1595
1596        // launch local anvil instance
1597        let anvil = hopr_chain_types::utils::create_anvil(None);
1598        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1599        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1600        // deploy hopr contracts
1601        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1602            .await
1603            .expect("failed to deploy");
1604
1605        // deploy multicall contract
1606        deploy_multicall3_for_testing(client.clone()).await?;
1607        // grant deployer token minter role
1608        let encoded_minter_role: [u8; 32] = keccak256(b"MINTER_ROLE");
1609        instances
1610            .token
1611            .grant_role(
1612                encoded_minter_role.clone(),
1613                contract_deployer.public().to_address().into(),
1614            )
1615            .send()
1616            .await?
1617            .await?;
1618
1619        // test the deployer has minter role now
1620        let check_minter_role = instances
1621            .token
1622            .has_role(
1623                encoded_minter_role.clone(),
1624                contract_deployer.public().to_address().into(),
1625            )
1626            .call()
1627            .await?;
1628        assert!(check_minter_role, "deployer does not have minter role yet");
1629
1630        // transfer or mint tokens to addresses
1631        let total_transferred_amount =
1632            transfer_or_mint_tokens(instances.token.clone(), addresses.clone(), desired_amount.clone()).await?;
1633
1634        // get native and token balances
1635        let (native_balance, token_balance) =
1636            get_native_and_token_balances(instances.token, addresses.clone().into()).await?;
1637        assert_eq!(native_balance.len(), 4, "invalid native balance lens");
1638        assert_eq!(token_balance.len(), 4, "invalid token balance lens");
1639        for (i, amount) in desired_amount.iter().enumerate() {
1640            assert_eq!(token_balance[i].as_u64(), amount.as_u64(), "token balance unmatch");
1641        }
1642
1643        assert_eq!(
1644            total_transferred_amount,
1645            U256::from(10),
1646            "amount transferred does not equal to the desired amount"
1647        );
1648        Ok(())
1649    }
1650
1651    #[async_std::test]
1652    async fn test_transfer_or_mint_tokens_in_anvil_with_one_recipient() -> anyhow::Result<()> {
1653        let addresses: Vec<ethers::types::Address> = vec![get_random_address_for_testing().into()];
1654        let desired_amount = vec![U256::from(42)];
1655
1656        // launch local anvil instance
1657        let anvil = hopr_chain_types::utils::create_anvil(None);
1658        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1659        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1660        // deploy hopr contracts
1661        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1662            .await
1663            .expect("failed to deploy");
1664
1665        // deploy multicall contract
1666        deploy_multicall3_for_testing(client.clone()).await?;
1667        // grant deployer token minter role
1668        let encoded_minter_role: [u8; 32] = keccak256(b"MINTER_ROLE");
1669        instances
1670            .token
1671            .grant_role(
1672                encoded_minter_role.clone(),
1673                contract_deployer.public().to_address().into(),
1674            )
1675            .send()
1676            .await?
1677            .await?;
1678
1679        // test the deployer has minter role now
1680        let check_minter_role = instances
1681            .token
1682            .has_role(
1683                encoded_minter_role.clone(),
1684                contract_deployer.public().to_address().into(),
1685            )
1686            .call()
1687            .await?;
1688        assert!(check_minter_role, "deployer does not have minter role yet");
1689
1690        // transfer or mint tokens to addresses
1691        let total_transferred_amount =
1692            transfer_or_mint_tokens(instances.token.clone(), addresses.clone(), desired_amount.clone()).await?;
1693
1694        // get native and token balances
1695        let (native_balance, token_balance) =
1696            get_native_and_token_balances(instances.token, addresses.clone().into()).await?;
1697        assert_eq!(native_balance.len(), 1, "invalid native balance lens");
1698        assert_eq!(token_balance.len(), 1, "invalid token balance lens");
1699        for (i, amount) in desired_amount.iter().enumerate() {
1700            assert_eq!(token_balance[i].as_u64(), amount.as_u64(), "token balance unmatch");
1701        }
1702
1703        assert_eq!(
1704            total_transferred_amount, desired_amount[0],
1705            "amount transferred does not equal to the desired amount"
1706        );
1707        Ok(())
1708    }
1709
1710    #[async_std::test]
1711    async fn test_transfer_or_mint_tokens_in_anvil_without_recipient() -> anyhow::Result<()> {
1712        let addresses: Vec<ethers::types::Address> = Vec::new();
1713        let desired_amount: Vec<U256> = Vec::new();
1714
1715        // launch local anvil instance
1716        let anvil = hopr_chain_types::utils::create_anvil(None);
1717        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1718        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1719        // deploy hopr contracts
1720        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1721            .await
1722            .expect("failed to deploy");
1723
1724        // deploy multicall contract
1725        deploy_multicall3_for_testing(client.clone()).await?;
1726
1727        // transfer or mint tokens to addresses
1728        let total_transferred_amount =
1729            transfer_or_mint_tokens(instances.token.clone(), addresses.clone(), desired_amount.clone()).await?;
1730
1731        // get native and token balances
1732        let (native_balance, token_balance) =
1733            get_native_and_token_balances(instances.token, addresses.clone().into()).await?;
1734        assert_eq!(native_balance.len(), 0, "invalid native balance lens");
1735        assert_eq!(token_balance.len(), 0, "invalid token balance lens");
1736        // for (i, amount) in desired_amount.iter().enumerate() {
1737        //     assert_eq!(token_balance[i].as_u64(), amount.as_u64(), "token balance unmatch");
1738        // }
1739
1740        assert_eq!(
1741            total_transferred_amount,
1742            U256::from(0),
1743            "amount transferred does not equal to the desired amount"
1744        );
1745        Ok(())
1746    }
1747
1748    #[async_std::test]
1749    async fn test_transfer_native_tokens_in_anvil_with_multicall() -> anyhow::Result<()> {
1750        let mut addresses: Vec<ethers::types::Address> = Vec::new();
1751        for _ in 0..4 {
1752            addresses.push(get_random_address_for_testing().into());
1753        }
1754        let desired_amount = vec![U256::from(1), U256::from(2), U256::from(3), U256::from(4)];
1755
1756        // launch local anvil instance
1757        let anvil = hopr_chain_types::utils::create_anvil(None);
1758        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1759        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1760        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1761            .await
1762            .expect("failed to deploy");
1763
1764        // deploy multicall contract
1765        deploy_multicall3_for_testing(client.clone()).await?;
1766
1767        // transfer native tokens to addresses
1768        let total_transferred_amount =
1769            transfer_native_tokens(client.clone(), addresses.clone(), desired_amount.clone()).await?;
1770
1771        // get native and token balances
1772        let (native_balance, token_balance) =
1773            get_native_and_token_balances(instances.token, addresses.clone().into()).await?;
1774        assert_eq!(native_balance.len(), 4, "invalid native balance lens");
1775        assert_eq!(token_balance.len(), 4, "invalid token balance lens");
1776        for (i, amount) in desired_amount.iter().enumerate() {
1777            assert_eq!(native_balance[i].as_u64(), amount.as_u64(), "native balance unmatch");
1778        }
1779
1780        assert_eq!(
1781            total_transferred_amount,
1782            U256::from(10),
1783            "amount transferred does not equal to the desired amount"
1784        );
1785        Ok(())
1786    }
1787
1788    #[async_std::test]
1789    async fn test_register_safes_and_nodes_then_deregister_nodes_in_anvil_with_multicall() -> anyhow::Result<()> {
1790        let mut safe_addresses: Vec<ethers::types::Address> = Vec::new();
1791        let mut node_addresses: Vec<ethers::types::Address> = Vec::new();
1792        for _ in 0..4 {
1793            safe_addresses.push(get_random_address_for_testing().into());
1794            node_addresses.push(get_random_address_for_testing().into());
1795        }
1796
1797        // launch local anvil instance
1798        let anvil = hopr_chain_types::utils::create_anvil(None);
1799        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1800        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1801        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1802            .await
1803            .expect("failed to deploy");
1804        // deploy multicall contract
1805        deploy_multicall3_for_testing(client.clone()).await?;
1806
1807        // register some nodes
1808        let (removed_amt, added_amt) = register_safes_and_nodes_on_network_registry(
1809            instances.network_registry.clone(),
1810            safe_addresses.clone(),
1811            node_addresses.clone(),
1812        )
1813        .await?;
1814
1815        assert_eq!(removed_amt, 0, "should not remove any safe");
1816        assert_eq!(added_amt, 4, "there should be 4 additions");
1817
1818        // get registered safes from nodes
1819        let registered_safes = get_registered_safes_for_nodes_on_network_registry(
1820            instances.network_registry.clone(),
1821            node_addresses.clone(),
1822        )
1823        .await?;
1824
1825        assert_eq!(safe_addresses.len(), registered_safes.len(), "returned length unmatch");
1826        for (i, safe_addr) in safe_addresses.iter().enumerate() {
1827            assert_eq!(safe_addr, &registered_safes[i], "registered safe addresses unmatch");
1828        }
1829
1830        // deregister 3 of them
1831        let deregisterd_nodes = deregister_nodes_from_network_registry(
1832            instances.network_registry.clone(),
1833            node_addresses.split_at(3).0.to_vec(),
1834        )
1835        .await?;
1836        assert_eq!(deregisterd_nodes, 3, "cannot deregister all the nodes");
1837
1838        // re-register 4 of them
1839        let (removed_amt_2, added_amt_2) = register_safes_and_nodes_on_network_registry(
1840            instances.network_registry.clone(),
1841            safe_addresses.clone(),
1842            node_addresses.clone(),
1843        )
1844        .await?;
1845
1846        assert_eq!(removed_amt_2, 0, "should not remove any safe");
1847        assert_eq!(added_amt_2, 3, "there should be 3 additions");
1848        Ok(())
1849    }
1850
1851    #[async_std::test]
1852    async fn test_deploy_proxy() -> anyhow::Result<()> {
1853        let prediction = deploy_proxy(
1854            H160::from_str("41675c099f32341bf84bfc5382af534df5c7461a")?,
1855            hex!("09e458584ce79e57b65cb303dc136c5d53e17b676599b9b7bc03815e0eef5172").into(),
1856            H160::from_str(SAFE_SAFEPROXYFACTORY_ADDRESS)?,
1857        )?;
1858
1859        assert_eq!(
1860            prediction,
1861            H160::from_str("ec5c8d045dfa1f93785125c26e187e9439f67105")?,
1862            "cannot reproduce proxy"
1863        );
1864        Ok(())
1865    }
1866    #[async_std::test]
1867    async fn test_get_salt_from_salt_nonce() -> anyhow::Result<()> {
1868        let salt = get_salt_from_salt_nonce(
1869            hex!("b63e800d00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000002a15de4410d4c8af0a7b6c12803120f43c42b8200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000098b275485c406573d042848d66eb9d63fca311c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000").into(),
1870            U256::from_dec_str("103994836888229670573364883831672511342967953907147914065931589108526220754063")?.into(),
1871        )?;
1872
1873        assert_eq!(
1874            salt.to_vec(),
1875            Bytes::from_str("09e458584ce79e57b65cb303dc136c5d53e17b676599b9b7bc03815e0eef5172")?,
1876            "cannot reproduce salt"
1877        );
1878        Ok(())
1879    }
1880
1881    #[async_std::test]
1882    async fn test_safe_and_module_address_prediction() -> anyhow::Result<()> {
1883        // testing value extracted from https://dashboard.tenderly.co/tx/xdai/0x510e3ac3dc7939cae2525a0b0f096ad709b23d94169e0fbf2e1154fdd6911c49?trace=0
1884        let _ = env_logger::builder().is_test(true).try_init();
1885
1886        // prepare some input data
1887        let mut admin_addresses: Vec<ethers::types::Address> = Vec::new();
1888        for _ in 0..2 {
1889            admin_addresses.push(get_random_address_for_testing().into());
1890        }
1891
1892        // launch local anvil instance
1893        let anvil = hopr_chain_types::utils::create_anvil(None);
1894        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1895        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1896        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1897            .await
1898            .expect("failed to deploy");
1899        // deploy multicall contract
1900        deploy_multicall3_for_testing(client.clone()).await?;
1901        // deploy safe suits
1902        deploy_safe_suites(client.clone()).await?;
1903
1904        let caller = client.default_sender().expect("client must have a sender");
1905
1906        // build the default permissions of capabilities
1907        let default_target = format!("{:?}{}", instances.channels.address(), DEFAULT_CAPABILITY_PERMISSIONS);
1908        debug!("default target {:?}", default_target);
1909        // salt nonce
1910        let curr_nonce = client
1911            .get_transaction_count(caller, Some(ethers::types::BlockNumber::Pending.into()))
1912            .await?;
1913        let nonce = keccak256(ethers::abi::encode_packed(&[
1914            ethers::abi::Token::Address(caller),
1915            ethers::abi::Token::Uint(curr_nonce),
1916        ])?);
1917
1918        let module_address = predict_module_address(
1919            caller,
1920            nonce,
1921            instances.stake_factory.address(),
1922            instances.module_implementation.address(),
1923        )?;
1924        debug!("predict_module_addr {:?}", module_address);
1925
1926        let safe_address = predict_safe_address(
1927            instances.stake_factory.address(),
1928            vec![H160::from_str("9062a96b9e947b2b57283e705c97b871f5eb6561")?],
1929            nonce,
1930            H160::from_str(SAFE_COMPATIBILITYFALLBACKHANDLER_ADDRESS)?,
1931            H160::from_str(SAFE_SAFE_ADDRESS)?,
1932            H160::from_str(SAFE_SAFEPROXYFACTORY_ADDRESS)?,
1933        )?;
1934
1935        debug!("predict_safe_address {:?}", safe_address);
1936
1937        // deploy a safe proxy instance and a module proxy instance with multicall as an owner
1938        let deployment_receipt = instances
1939            .stake_factory
1940            .clone(
1941                instances.module_implementation.address(),
1942                vec![caller],
1943                nonce.into(),
1944                U256::from_str(&default_target)?.into(),
1945            )
1946            .send()
1947            .await?
1948            .await?
1949            .unwrap();
1950        debug!("deployment_receipt {:?}", deployment_receipt);
1951        // parse the safe and module addresses
1952        let module_log = deployment_receipt
1953            .logs
1954            .iter()
1955            .find(|log| log.topics[0].eq(&NEW_HOPR_NODE_STAKE_MODULE_TOPIC.parse::<H256>().unwrap()))
1956            .ok_or(HelperErrors::ContractNotDeployed("module".into()))?; // "NewHoprNodeStakeModule(address,address)
1957
1958        debug!("module_log {:?}", module_log);
1959        let safe_log = deployment_receipt
1960            .logs
1961            .iter()
1962            .find(|log| log.topics[0].eq(&NEW_HOPR_NODE_STAKE_SAFE_TOPIC.parse::<H256>().unwrap()))
1963            .ok_or(HelperErrors::ContractNotDeployed("safe".into()))?; // "NewHoprNodeStakeSafe(address)"
1964        debug!("safe_log {:?}", safe_log);
1965        let module_addr = H160::decode(module_log.data.clone())?;
1966        debug!("module_addr {:?}", module_addr);
1967
1968        let safe_addr = H160::decode(safe_log.data.clone())?;
1969        debug!("safe_addr {:?}", safe_addr);
1970
1971        assert_eq!(module_addr, module_address, "module prediction does not match");
1972        assert_eq!(safe_addr, safe_address, "safe prediction does not match");
1973        Ok(())
1974    }
1975
1976    #[async_std::test]
1977    async fn test_deploy_safe_and_module() -> anyhow::Result<()> {
1978        let _ = env_logger::builder().is_test(true).try_init();
1979
1980        // prepare some input data
1981        let mut admin_addresses: Vec<ethers::types::Address> = Vec::new();
1982        for _ in 0..2 {
1983            admin_addresses.push(get_random_address_for_testing().into());
1984        }
1985        let mut node_addresses: Vec<ethers::types::Address> = Vec::new();
1986        for _ in 0..2 {
1987            node_addresses.push(get_random_address_for_testing().into());
1988        }
1989
1990        // launch local anvil instance
1991        let anvil = hopr_chain_types::utils::create_anvil(None);
1992        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
1993        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
1994        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
1995            .await
1996            .expect("failed to deploy");
1997        // deploy multicall contract
1998        deploy_multicall3_for_testing(client.clone()).await?;
1999        // deploy safe suits
2000        deploy_safe_suites(client.clone()).await?;
2001
2002        // register some nodes
2003        let (safe, node_module) = deploy_safe_module_with_targets_and_nodes(
2004            instances.stake_factory,
2005            instances.token.address(),
2006            instances.channels.address(),
2007            instances.module_implementation.address(),
2008            instances.announcements.address(),
2009            U256::max_value(),
2010            Some(node_addresses.clone()),
2011            admin_addresses.clone(),
2012            U256::from(2),
2013        )
2014        .await?;
2015
2016        // check announcement is a target
2017        let try_get_announcement_target = node_module
2018            .try_get_target(instances.announcements.address())
2019            .call()
2020            .await?;
2021
2022        assert!(try_get_announcement_target.0, "announcement is not a target");
2023
2024        // check allowance for channel contract has increased
2025        let allowance = instances
2026            .token
2027            .allowance(safe.address(), instances.channels.address())
2028            .await?;
2029
2030        assert_eq!(allowance, U256::max_value(), "allowance is not set");
2031
2032        // check nodes have been included in the module
2033        for node_address in node_addresses {
2034            let is_node_included = node_module.is_node(node_address).call().await?;
2035            assert!(is_node_included, "failed to include a node");
2036        }
2037
2038        // check owners are provided admins
2039        let owners = safe.get_owners().call().await?;
2040        let thresold = safe.get_threshold().call().await?;
2041
2042        assert_eq!(owners.len(), 2, "should have 2 owners");
2043        for (i, owner) in owners.iter().enumerate() {
2044            assert_eq!(owner, &admin_addresses[i], "admin is wrong");
2045        }
2046        assert_eq!(thresold, U256::from(2), "threshold should be two");
2047        Ok(())
2048    }
2049
2050    #[async_std::test]
2051    async fn test_safe_tx_via_multisend() -> anyhow::Result<()> {
2052        // set allowance for token transfer for the safe multiple times
2053        let _ = env_logger::builder().is_test(true).try_init();
2054
2055        // prepare some input data
2056        let desired_amount = vec![U256::from(1), U256::from(2), U256::from(3), U256::from(4)];
2057
2058        // launch local anvil instance
2059        let anvil = hopr_chain_types::utils::create_anvil(None);
2060        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
2061        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
2062        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
2063            .await
2064            .expect("failed to deploy");
2065        // deploy multicall contract
2066        deploy_multicall3_for_testing(client.clone()).await?;
2067        // deploy safe suits
2068        deploy_safe_suites(client.clone()).await?;
2069
2070        // create a safe
2071        let (safe, _node_module) = deploy_safe_module_with_targets_and_nodes(
2072            instances.stake_factory,
2073            instances.token.address(),
2074            instances.channels.address(),
2075            instances.module_implementation.address(),
2076            instances.announcements.address(),
2077            U256::max_value(),
2078            None,
2079            vec![contract_deployer.public().to_address().into()],
2080            U256::from(1),
2081        )
2082        .await?;
2083
2084        // check owner of safe
2085        let is_owner = safe.get_owners().call().await?;
2086        assert_eq!(is_owner.len(), 1, "safe has too many owners");
2087        assert_eq!(
2088            is_owner[0],
2089            contract_deployer.public().to_address().into(),
2090            "safe wrong owner"
2091        );
2092
2093        // check allowance for channel contract is zero
2094        let allowance = instances
2095            .token
2096            .allowance(safe.address(), instances.channels.address())
2097            .await?;
2098
2099        assert_eq!(allowance, U256::max_value(), "allowance initiation is wrong");
2100
2101        let mut multisend_txns: Vec<MultisendTransaction> = Vec::new();
2102        for val in desired_amount {
2103            multisend_txns.push(MultisendTransaction {
2104                // build multisend tx payload
2105                encoded_data: ApproveCall {
2106                    spender: instances.channels.address(),
2107                    value: val,
2108                }
2109                .encode()
2110                .into(),
2111                tx_operation: SafeTxOperation::Call,
2112                to: instances.token.address(),
2113                value: U256::zero(),
2114            });
2115        }
2116
2117        // get chain_id and safe_nonce
2118        let chain_id = client.get_chainid().await?;
2119        let safe_nonce = safe.nonce().await?;
2120        debug!("safe address {:?}", safe.address());
2121        debug!("chain_id {:?}", chain_id);
2122        debug!("safe_nonce {:?}", safe_nonce);
2123
2124        // send safe transaction
2125        send_multisend_safe_transaction_with_threshold_one(
2126            safe.clone(),
2127            contract_deployer,
2128            H160::from_str(SAFE_MULTISEND_ADDRESS)?,
2129            multisend_txns,
2130            chain_id,
2131            safe_nonce,
2132        )
2133        .await?;
2134
2135        // check allowance for channel contract is 4
2136        let new_allowance = instances
2137            .token
2138            .allowance(safe.address(), instances.channels.address())
2139            .await?;
2140
2141        assert_eq!(new_allowance, U256::from(4), "final allowance is not desired");
2142        Ok(())
2143    }
2144
2145    #[async_std::test]
2146    async fn test_register_nodes_to_node_safe_registry() -> anyhow::Result<()> {
2147        // set allowance for token transfer for the safe multiple times
2148        let _ = env_logger::builder().is_test(true).try_init();
2149
2150        // launch local anvil instance
2151        let anvil = hopr_chain_types::utils::create_anvil(None);
2152        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
2153        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
2154        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
2155            .await
2156            .expect("failed to deploy");
2157        // deploy multicall contract
2158        deploy_multicall3_for_testing(client.clone()).await?;
2159        // deploy safe suits
2160        deploy_safe_suites(client.clone()).await?;
2161
2162        let deployer_vec: Vec<H160> = vec![contract_deployer.public().to_address().into()];
2163
2164        // create a safe
2165        let (safe, node_module) = deploy_safe_module_with_targets_and_nodes(
2166            instances.stake_factory,
2167            instances.token.address(),
2168            instances.channels.address(),
2169            instances.module_implementation.address(),
2170            instances.announcements.address(),
2171            U256::max_value(),
2172            Some(deployer_vec.clone()),
2173            deployer_vec.clone(),
2174            U256::from(1),
2175        )
2176        .await?;
2177
2178        // register one node to safe
2179        instances
2180            .safe_registry
2181            .register_safe_by_node(safe.address())
2182            .send()
2183            .await?
2184            .await?;
2185
2186        // get registration info
2187        let get_registered_safe =
2188            get_registered_safes_for_nodes_on_node_safe_registry(instances.safe_registry.clone(), deployer_vec.clone())
2189                .await?;
2190
2191        assert_eq!(get_registered_safe.len(), 1, "cannot read registered safe");
2192        assert_eq!(get_registered_safe[0], safe.address(), "registered safe is wrong");
2193
2194        // deregister the node from safe
2195        deregister_nodes_from_node_safe_registry_and_remove_from_module(
2196            instances.safe_registry.clone(),
2197            deployer_vec.clone(),
2198            vec![node_module.address()],
2199            contract_deployer.clone(),
2200        )
2201        .await?;
2202
2203        // get registration info (updated)
2204        let get_registered_safe =
2205            get_registered_safes_for_nodes_on_node_safe_registry(instances.safe_registry.clone(), deployer_vec.clone())
2206                .await?;
2207
2208        assert_eq!(get_registered_safe.len(), 1, "cannot read registered safe");
2209        assert_eq!(get_registered_safe[0], H160::zero(), "node is still registered");
2210
2211        // node is removed
2212        let is_removed = node_module
2213            .is_node(contract_deployer.public().to_address().into())
2214            .call()
2215            .await?;
2216        assert!(!is_removed, "node is not removed");
2217        Ok(())
2218    }
2219
2220    #[async_std::test]
2221    async fn test_include_nodes_to_module() -> anyhow::Result<()> {
2222        // set allowance for token transfer for the safe multiple times
2223        let _ = env_logger::builder().is_test(true).try_init();
2224
2225        let mut node_addresses: Vec<ethers::types::Address> = Vec::new();
2226        for _ in 0..2 {
2227            node_addresses.push(get_random_address_for_testing().into());
2228        }
2229
2230        // launch local anvil instance
2231        let anvil = hopr_chain_types::utils::create_anvil(None);
2232        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
2233        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
2234        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
2235            .await
2236            .expect("failed to deploy");
2237        // deploy multicall contract
2238        deploy_multicall3_for_testing(client.clone()).await?;
2239        // deploy safe suits
2240        deploy_safe_suites(client.clone()).await?;
2241
2242        let deployer_vec: Vec<H160> = vec![contract_deployer.public().to_address().into()];
2243
2244        // create a safe
2245        let (safe, node_module) = deploy_safe_module_with_targets_and_nodes(
2246            instances.stake_factory,
2247            instances.token.address(),
2248            instances.channels.address(),
2249            instances.module_implementation.address(),
2250            instances.announcements.address(),
2251            U256::max_value(),
2252            None,
2253            deployer_vec.clone(),
2254            U256::from(1),
2255        )
2256        .await?;
2257
2258        // check ndoes are not included
2259        for node_addr in node_addresses.clone() {
2260            // node is removed
2261            let node_is_not_included = node_module.is_node(node_addr).call().await?;
2262            assert!(!node_is_not_included, "node should not be included");
2263        }
2264
2265        // include nodes to safe
2266        include_nodes_to_module(safe, node_addresses.clone(), node_module.address(), contract_deployer).await?;
2267
2268        // check ndoes are included
2269        // check ndoes are not included
2270        for node_addr in node_addresses {
2271            // node is removed
2272            let node_is_included = node_module.is_node(node_addr).call().await?;
2273            assert!(node_is_included, "node should be included");
2274        }
2275        Ok(())
2276    }
2277
2278    #[async_std::test]
2279    async fn test_migrate_nodes_to_new_network() -> anyhow::Result<()> {
2280        // set allowance for token transfer for the safe multiple times
2281        let _ = env_logger::builder().is_test(true).try_init();
2282
2283        let mut node_addresses: Vec<ethers::types::Address> = Vec::new();
2284        for _ in 0..2 {
2285            node_addresses.push(get_random_address_for_testing().into());
2286        }
2287
2288        // launch local anvil instance
2289        let anvil = hopr_chain_types::utils::create_anvil(None);
2290        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
2291        let self_address: H160 = contract_deployer.public().to_address().into();
2292        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
2293        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
2294            .await
2295            .expect("failed to deploy");
2296        // deploy multicall contract
2297        deploy_multicall3_for_testing(client.clone()).await?;
2298        // deploy safe suits
2299        deploy_safe_suites(client.clone()).await?;
2300
2301        // deploy some new contracts for the new network
2302        let new_safe_registry = HoprNodeSafeRegistry::deploy(client.clone(), ())?.send().await?;
2303        let new_token = HoprToken::deploy(client.clone(), ())?.send().await?;
2304        let new_channels = HoprChannels::deploy(
2305            client.clone(),
2306            ethers::abi::Token::Tuple(vec![
2307                ethers::abi::Token::Address(new_token.address()),
2308                ethers::abi::Token::Uint(1_u32.into()),
2309                ethers::abi::Token::Address(new_safe_registry.address()),
2310            ]),
2311        )?
2312        .send()
2313        .await?;
2314        let new_announcements =
2315            HoprAnnouncements::deploy(client.clone(), ethers::abi::Token::Address(new_safe_registry.address()))?
2316                .send()
2317                .await?;
2318        let _new_network_registry = HoprNetworkRegistry::deploy(
2319            client.clone(),
2320            (
2321                ethers::types::Address::from(instances.network_registry_proxy.address()),
2322                self_address,
2323                self_address,
2324            ),
2325        )?
2326        .send()
2327        .await?;
2328
2329        let deployer_vec: Vec<H160> = vec![self_address];
2330
2331        // create a safe
2332        let (safe, node_module) = deploy_safe_module_with_targets_and_nodes(
2333            instances.stake_factory,
2334            instances.token.address(),
2335            instances.channels.address(),
2336            instances.module_implementation.address(),
2337            instances.announcements.address(),
2338            U256::max_value(),
2339            None,
2340            deployer_vec.clone(),
2341            U256::from(1),
2342        )
2343        .await?;
2344
2345        // check new network is not included
2346        let old_channels_inclusion = node_module.try_get_target(instances.channels.address()).call().await?;
2347        assert!(old_channels_inclusion.0, "old channel should be included");
2348        let new_channels_inclusion = node_module.try_get_target(new_channels.address()).call().await?;
2349        assert!(!new_channels_inclusion.0, "new channel should not be included");
2350
2351        // migrate nodes
2352        migrate_nodes(
2353            safe,
2354            node_module.address(),
2355            new_channels.address(),
2356            new_token.address(),
2357            new_announcements.address(),
2358            U256::max_value(),
2359            contract_deployer,
2360        )
2361        .await?;
2362
2363        // check new network is included
2364        let old_channels_inclusion = node_module.try_get_target(instances.channels.address()).call().await?;
2365        assert!(old_channels_inclusion.0, "old channel should still be included");
2366        let new_channels_inclusion = node_module.try_get_target(new_channels.address()).call().await?;
2367        assert!(new_channels_inclusion.0, "new channel should now be included");
2368        Ok(())
2369    }
2370
2371    #[async_std::test]
2372    async fn test_debug_node_safe_module_setup_on_balance_and_registries() -> anyhow::Result<()> {
2373        // set allowance for token transfer for the safe multiple times
2374        let _ = env_logger::builder().is_test(true).try_init();
2375
2376        let mut node_addresses: Vec<ethers::types::Address> = Vec::new();
2377        for _ in 0..2 {
2378            node_addresses.push(get_random_address_for_testing().into());
2379        }
2380
2381        // launch local anvil instance
2382        let anvil = hopr_chain_types::utils::create_anvil(None);
2383        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
2384        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
2385        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
2386            .await
2387            .expect("failed to deploy");
2388        // deploy multicall contract
2389        deploy_multicall3_for_testing(client.clone()).await?;
2390        // deploy safe suits
2391        deploy_safe_suites(client.clone()).await?;
2392
2393        let deployer_vec: Vec<H160> = vec![contract_deployer.public().to_address().into()];
2394
2395        // create a safe
2396        let (safe, _) = deploy_safe_module_with_targets_and_nodes(
2397            instances.stake_factory,
2398            instances.token.address(),
2399            instances.channels.address(),
2400            instances.module_implementation.address(),
2401            instances.announcements.address(),
2402            U256::max_value(),
2403            None,
2404            deployer_vec.clone(),
2405            U256::from(1),
2406        )
2407        .await?;
2408        let registered_safe_before_registration = debug_node_safe_module_setup_on_balance_and_registries(
2409            instances.network_registry.clone(),
2410            instances.safe_registry.clone(),
2411            &node_addresses[0],
2412        )
2413        .await?;
2414
2415        assert_eq!(
2416            registered_safe_before_registration,
2417            H160::zero(),
2418            "safe is already registered"
2419        );
2420
2421        // register some nodes
2422        let (_, _) = register_safes_and_nodes_on_network_registry(
2423            instances.network_registry.clone(),
2424            vec![safe.address()],
2425            vec![node_addresses[0]],
2426        )
2427        .await?;
2428
2429        let registered_safe_after_registration = debug_node_safe_module_setup_on_balance_and_registries(
2430            instances.network_registry.clone(),
2431            instances.safe_registry.clone(),
2432            &node_addresses[0],
2433        )
2434        .await?;
2435
2436        assert_eq!(
2437            registered_safe_after_registration,
2438            safe.address(),
2439            "safe is not registered"
2440        );
2441        Ok(())
2442    }
2443
2444    #[async_std::test]
2445    async fn test_debug_node_safe_module_setup_main() -> anyhow::Result<()> {
2446        // set allowance for token transfer for the safe multiple times
2447        let _ = env_logger::builder().is_test(true).try_init();
2448
2449        let mut node_addresses: Vec<ethers::types::Address> = Vec::new();
2450        for _ in 0..2 {
2451            node_addresses.push(get_random_address_for_testing().into());
2452        }
2453
2454        // launch local anvil instance
2455        let anvil = hopr_chain_types::utils::create_anvil(None);
2456        let contract_deployer = ChainKeypair::from_secret(anvil.keys()[0].to_bytes().as_ref())?;
2457        let client = create_rpc_client_to_anvil(SurfRequestor::default(), &anvil, &contract_deployer);
2458        let instances = ContractInstances::deploy_for_testing(client.clone(), &contract_deployer)
2459            .await
2460            .expect("failed to deploy");
2461        // deploy multicall contract
2462        deploy_multicall3_for_testing(client.clone()).await?;
2463        // deploy safe suits
2464        deploy_safe_suites(client.clone()).await?;
2465
2466        let deployer_vec: Vec<H160> = vec![contract_deployer.public().to_address().into()];
2467
2468        // create a safe
2469        let (safe, node_module) = deploy_safe_module_with_targets_and_nodes(
2470            instances.stake_factory,
2471            instances.token.address(),
2472            instances.channels.address(),
2473            instances.module_implementation.address(),
2474            instances.announcements.address(),
2475            U256::max_value(),
2476            None,
2477            deployer_vec.clone(),
2478            U256::from(1),
2479        )
2480        .await?;
2481
2482        // register some nodes
2483        let (_, _) = register_safes_and_nodes_on_network_registry(
2484            instances.network_registry.clone(),
2485            vec![safe.address()],
2486            vec![node_addresses[0]],
2487        )
2488        .await?;
2489
2490        debug_node_safe_module_setup_main(
2491            instances.token.clone(),
2492            &node_module.address(),
2493            &node_addresses[0],
2494            &safe.address(),
2495            &instances.channels.address(),
2496            &instances.announcements.address(),
2497        )
2498        .await?;
2499        Ok(())
2500    }
2501}