hopli/
methods.rs

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