def get_escrow(escrow_addr: str) -> Contract: """Retrieve the Escrow contract from a given address. >>> credentials = { ... "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", ... "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5" ... } >>> rep_oracle_pub_key = b"2dbc2c2c86052702e7c219339514b2e8bd4687ba1236c478ad41b43330b08488c12c8c1797aa181f3a4596a1bd8a0c18344ea44d6655f61fa73e56e743f79e0d" >>> job = Job(credentials=credentials, escrow_manifest=manifest) Deploying a new Job to the ethereum network succeeds. >>> job.launch(rep_oracle_pub_key) True >>> type(get_escrow(job.job_contract.address)) <class 'web3._utils.datatypes.Contract'> Args: escrow_addr (str): an ethereum address of the escrow contract. Returns: Contract: returns the Escrow solidity contract. """ w3 = get_w3() contract_interface = get_contract_interface( "{}/Escrow.sol:Escrow".format(CONTRACT_FOLDER)) escrow = w3.eth.contract( address=ChecksumAddress(HexAddress(HexStr(escrow_addr))), abi=contract_interface["abi"], ) return escrow
def get_factory(factory_addr: str) -> Contract: """Retrieve the EscrowFactory contract from a given address. >>> credentials = { ... "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", ... "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5" ... } >>> job = Job(credentials=credentials, escrow_manifest=manifest) >>> type(get_factory(job.factory_contract.address)) <class 'web3._utils.datatypes.Contract'> Args: factory_addr (str): the ethereum address of the Escrow contract. Returns: Contract: returns the EscrowFactory solidity contract. """ w3 = get_w3() contract_interface = get_contract_interface( "{}/EscrowFactory.sol:EscrowFactory".format(CONTRACT_FOLDER)) escrow_factory = w3.eth.contract( address=ChecksumAddress(HexAddress(HexStr(factory_addr))), abi=contract_interface["abi"], ) return escrow_factory
def build_etherscan_manifest(uri: URI, package_name: str, version: str) -> Iterable[Tuple[str, Any]]: address, chain_id = parse.urlparse(uri).netloc.split(":") network = get_etherscan_network(chain_id) body = make_etherscan_request(address, network) contract_type = body["ContractName"] w3 = setup_w3(to_int(text=chain_id)) block_uri = create_latest_block_uri(w3) runtime_bytecode = to_hex( w3.eth.getCode(ChecksumAddress(HexAddress(HexStr(address))))) yield "package_name", package_name yield "version", version yield "manifest_version", "2" yield "sources", {f"./{contract_type}.sol": body["SourceCode"]} yield "contract_types", { contract_type: { "abi": json.loads(body["ABI"]), "runtime_bytecode": { "bytecode": runtime_bytecode }, "compiler": generate_compiler_info(body), } } yield "deployments", { block_uri: { contract_type: { "contract_type": contract_type, "address": address } } }
def _get_user_identity(address: ChecksumAddress) -> ChecksumEthAddress: """Given an address (signer) returns its protocol user identity""" return generate_address_via_create2( address=IDENTITY_FACTORY_ADDR, salt=CREATE2_SALT, init_code=IDENTITY_PROXY_INIT_CODE.format(signer_address=address.removeprefix('0x')), )
async def get_uniswap_v3_range_liquidity_points( network: str, tick_lower: int, tick_upper: int, pool_address: ChecksumAddress, block_number: BlockNumber, ) -> Balances: """Fetches users' liquidity points of the Uniswap V3 pool in the specific range.""" lowered_pool_address = pool_address.lower() last_id = "" result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_RANGE_POSITIONS_QUERY, variables=dict( block_number=block_number, tick_lower=tick_lower, tick_upper=tick_upper, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions = positions_chunk # accumulate chunks of positions while len(positions_chunk) >= 1000: last_id = positions_chunk[-1]["id"] result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_RANGE_POSITIONS_QUERY, variables=dict( block_number=block_number, tick_lower=tick_lower, tick_upper=tick_upper, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions.extend(positions_chunk) # process positions balances: Dict[ChecksumAddress, int] = {} total_supply = 0 for position in positions: account = Web3.toChecksumAddress(position["owner"]) if account == EMPTY_ADDR_HEX: continue liquidity = int(position.get("liquidity", "0")) if liquidity <= 0: continue balances[account] = balances.setdefault(account, 0) + liquidity total_supply += liquidity return Balances(total_supply=total_supply, balances=balances)
def test_solidityKeccak_ens( self, web3: "Web3", types: Sequence[TypeStr], values: Sequence[str], expected: HexBytes ) -> None: with ens_addresses(web3, { 'one.eth': ChecksumAddress( HexAddress(HexStr("0x49EdDD3769c0712032808D86597B84ac5c2F5614")) ), 'two.eth': ChecksumAddress( HexAddress(HexStr("0xA6b759bBbf4B59D24acf7E06e79f3a5D104fdCE5")) ), }): # when called as class method, any name lookup attempt will fail with pytest.raises(InvalidAddress): Web3.solidityKeccak(types, values) # when called as instance method, ens lookups can succeed actual = web3.solidityKeccak(types, values) assert actual == expected
def get_token_price(self, token_address: ChecksumAddress) -> float: """ :param token_address: :return: usd price for token address, 0. if not found """ token_address = token_address.lower() url = urljoin(self.base_url, f'api/v3/simple/token_price/ethereum?contract_addresses={token_address}&vs_currencies=usd') return self._get_price(url, token_address)
def test_eth_getBalance(self, web3: "Web3") -> None: coinbase = web3.eth.coinbase with pytest.raises(InvalidAddress): web3.eth.getBalance(ChecksumAddress(HexAddress(HexStr(coinbase.lower())))) balance = web3.eth.getBalance(coinbase) assert is_integer(balance) assert balance >= 0
def test_trace_raw_transaction( self, web3: "Web3", raw_transaction: HexStr, funded_account_for_raw_txn: ChecksumAddress, ) -> None: trace = web3.parity.traceRawTransaction(raw_transaction) assert trace['stateDiff'] is None assert trace['vmTrace'] is None assert trace['trace'][0]['action']['from'] == funded_account_for_raw_txn.lower()
def get_token_info( self, token_address: ChecksumAddress) -> Optional[Dict[str, Any]]: token_address = token_address.lower() url = urljoin( self.base_url, f"api/v3/coins/{self.asset_platform}/contract/{token_address}", ) try: return self._do_request(url) except Coingecko404: return None
def to_checksum_address(value: AnyStr) -> ChecksumAddress: """ Makes a checksum address given a supported format. """ norm_address = to_normalized_address(value) address_hash = encode_hex( keccak(text=remove_0x_prefix(HexStr(norm_address)))) checksum_address = add_0x_prefix( HexStr("".join((norm_address[i].upper( ) if int(address_hash[i], 16) > 7 else norm_address[i]) for i in range(2, 42)))) return ChecksumAddress(HexAddress(checksum_address))
def setup_owner(self, name: str, new_owner: ChecksumAddress = cast(ChecksumAddress, default), transact: Optional["TxParams"] = None) -> ChecksumAddress: """ Set the owner of the supplied name to `new_owner`. For typical scenarios, you'll never need to call this method directly, simply call :meth:`setup_name` or :meth:`setup_address`. This method does *not* set up the name to point to an address. If `new_owner` is not supplied, then this will assume you want the same owner as the parent domain. If the caller owns ``parentname.eth`` with no subdomains and calls this method with ``sub.parentname.eth``, then ``sub`` will be created as part of this call. :param str name: ENS name to set up :param new_owner: account that will own `name`. If ``None``, set owner to empty addr. If not specified, name will point to the parent domain owner's address. :param dict transact: the transaction configuration, like in :meth:`~web3.eth.Eth.send_transaction` :raises InvalidName: if `name` has invalid syntax :raises UnauthorizedError: if ``'from'`` in `transact` does not own `name` :returns: the new owner's address """ if not transact: transact = {} transact = deepcopy(transact) (super_owner, unowned, owned) = self._first_owner(name) if new_owner is default: new_owner = super_owner elif not new_owner: new_owner = ChecksumAddress(EMPTY_ADDR_HEX) else: new_owner = to_checksum_address(new_owner) current_owner = self.owner(name) if new_owner == EMPTY_ADDR_HEX and not current_owner: return None elif current_owner == new_owner: return current_owner else: self._assert_control(super_owner, name, owned) self._claim_ownership(new_owner, unowned, owned, super_owner, transact=transact) return new_owner
class ZerionTokenAdapterClient: """ Client for Zerion Token Adapter https://github.com/zeriontech/defi-sdk """ ABI = [{'inputs': [{'internalType': 'address', 'name': 'token', 'type': 'address'}], 'name': 'getComponents', 'outputs': [{'components': [{'internalType': 'address', 'name': 'token', 'type': 'address'}, {'internalType': 'string', 'name': 'tokenType', 'type': 'string'}, {'internalType': 'uint256', 'name': 'rate', 'type': 'uint256'}], 'internalType': 'struct Component[]', 'name': '', 'type': 'tuple[]'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'token', 'type': 'address'}], 'name': 'getMetadata', 'outputs': [{'components': [{'internalType': 'address', 'name': 'token', 'type': 'address'}, {'internalType': 'string', 'name': 'name', 'type': 'string'}, {'internalType': 'string', 'name': 'symbol', 'type': 'string'}, {'internalType': 'uint8', 'name': 'decimals', 'type': 'uint8'}], 'internalType': 'struct TokenMetadata', 'name': '', 'type': 'tuple'}], 'stateMutability': 'view', 'type': 'function'}] ADAPTER_ADDRESS: ChecksumAddress = ChecksumAddress(NULL_ADDRESS) def __init__(self, ethereum_client: EthereumClient, adapter_address: Optional[ChecksumAddress] = None): self.ethereum_client = ethereum_client self.adapter_address = adapter_address if adapter_address else self.ADAPTER_ADDRESS self.contract = ethereum_client.w3.eth.contract(self.adapter_address, abi=self.ABI) def get_components(self, token_address: ChecksumAddress) -> Optional[List[UniswapComponent]]: try: return [UniswapComponent(*component) for component in self.contract.functions.getComponents(token_address).call()] except ContractLogicError: return None def get_metadata(self, token_address: ChecksumAddress) -> Optional[ZerionPoolMetadata]: try: return ZerionPoolMetadata(*self.contract.functions.getMetadata(token_address).call()) except ContractLogicError: return None
def test_trace_raw_transaction( self, web3: "Web3", raw_transaction: HexStr, funded_account_for_raw_txn: ChecksumAddress, ) -> None: # address 0x39EEed73fb1D3855E90Cbd42f348b3D7b340aAA6 raw_transaction = HexStr( '0xf8648085174876e8008252089439eeed73fb1d3855e90cbd42f348b3d7b340aaa601801ba0ec1295f00936acd0c2cb90ab2cdaacb8bf5e11b3d9957833595aca9ceedb7aada05dfc8937baec0e26029057abd3a1ef8c505dca2cdc07ffacb046d090d2bea06a' ) # noqa: E501 trace = web3.parity.trace_raw_transaction(raw_transaction) assert trace['stateDiff'] is None assert trace['vmTrace'] is None assert trace['trace'][0]['action'][ 'from'] == funded_account_for_raw_txn.lower()
def test_eth_sendTransaction_addr_checksum_required( self, web3: "Web3", unlocked_account: ChecksumAddress) -> None: non_checksum_addr = unlocked_account.lower() txn_params = { 'from': unlocked_account, 'to': unlocked_account, 'value': 1, 'gas': 21000, 'gasPrice': web3.eth.gasPrice, } with pytest.raises(InvalidAddress): invalid_params = dict(txn_params, **{'from': non_checksum_addr}) web3.eth.sendTransaction(invalid_params) with pytest.raises(InvalidAddress): invalid_params = dict(txn_params, **{'to': non_checksum_addr}) web3.eth.sendTransaction(invalid_params)
def wait_for_token_network_discovery( node_endpoint: str, settings: SettingsConfig, session: Session ) -> ChecksumAddress: """Check for token network discovery with the given `node`. By default exit the wait if the token has not been discovered after `n` seconds, where `n` is the value of :attr:`.timeout`. :raises TokenNetworkDiscoveryTimeout: If we waited a set time for the token network to be discovered, but it wasn't. """ started = time.monotonic() elapsed = 0.0 while elapsed < settings.timeout: try: resp = session.get(node_endpoint) resp.raise_for_status() except HTTPError as e: # We explicitly handle 404 Not Found responses only - anything else is none # of our business. if e.response.status_code != 404: raise # Wait before continuing, no sense in spamming the node. gevent.sleep(1) # Update our elapsed time tracker. elapsed = time.monotonic() - started continue else: # The node appears to have discovered our token network. data = resp.json() if not is_checksum_address(data): # Something's amiss about this response. Notify a human. raise TypeError(f"Unexpected response type from API: {data!r}") return ChecksumAddress(data) # We could not assert that our token network was registered within an # acceptable time frame. raise TokenNetworkDiscoveryTimeout
label_to_hash, normal_name_to_hash, normalize_name, raw_name_to_hash, ) if TYPE_CHECKING: from web3 import Web3 # noqa: F401 from web3.contract import ( # noqa: F401 Contract, ) from web3.providers import ( # noqa: F401 BaseProvider, ) from web3.types import ( # noqa: F401 TxParams, ) ENS_MAINNET_ADDR = ChecksumAddress( HexAddress(HexStr('0x314159265dD8dbb310642f98f50C066173C1259b'))) class ENS: """ Quick access to common Ethereum Name Service functions, like getting the address for a name. Unless otherwise specified, all addresses are assumed to be a `str` in `checksum format <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md>`_, like: ``"0x314159265dD8dbb310642f98f50C066173C1259b"`` """ labelhash = staticmethod(label_to_hash) namehash = staticmethod(raw_name_to_hash) nameprep = staticmethod(normalize_name)
def get_address_of(self, instance_name: str) -> ChecksumAddress: instance = self.get_instance(instance_name) return ChecksumAddress(instance.address)
def test_eth_getCode_invalid_address(self, web3: "Web3", math_contract: "Contract") -> None: with pytest.raises(InvalidAddress): web3.eth.getCode( ChecksumAddress( HexAddress(HexStr(math_contract.address.lower()))))
def test_eth_getTransactionCount_invalid_address(self, web3: "Web3") -> None: coinbase = web3.eth.coinbase with pytest.raises(InvalidAddress): web3.eth.getTransactionCount( ChecksumAddress(HexAddress(HexStr(coinbase.lower()))))
LIBRARY_TOKEN_NETWORK_UTILS_LINK_KEY = "data/source/lib/TokenNetworkUtils.sol:TokenNetworkUtils" # Timeouts TEST_SETTLE_TIMEOUT_MIN = 5 TEST_SETTLE_TIMEOUT_MAX = 100000 DEPLOY_SETTLE_TIMEOUT_MIN = 500 # ~ 2 hours DEPLOY_SETTLE_TIMEOUT_MAX = 555428 # ~ 3 months # Temporary deposit limits for the Red Eyes release in WEI MAX_ETH_CHANNEL_PARTICIPANT = int(0.075 * 10 ** 18) MAX_ETH_TOKEN_NETWORK = int(250 * 10 ** 18) # Special hashes LOCKSROOT_OF_NO_LOCKS = Locksroot(keccak(b"")) EMPTY_ADDRESS = ChecksumAddress(HexAddress(HexStr("0x0000000000000000000000000000000000000000"))) # Event names # TokenNetworkRegistry EVENT_TOKEN_NETWORK_CREATED = "TokenNetworkCreated" # TokenNetwork EVENT_DEPRECATION_SWITCH = "DeprecationSwitch" # SecretRegistry EVENT_SECRET_REVEALED = "SecretRevealed" # EndpointRegistry EVENT_ADDRESS_REGISTERED = "AddressRegistered" # ServiceRegistry
async def get_uniswap_v3_single_token_balances( network: str, pool_address: ChecksumAddress, token: ChecksumAddress, block_number: BlockNumber, ) -> Balances: """Fetches users' single token balances of the Uniswap V3 pair across all the ticks.""" lowered_pool_address = pool_address.lower() result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_POOL_QUERY, variables=dict(block_number=block_number, pool_address=lowered_pool_address), ) pools = result.get("pools", []) if not pools: return Balances(total_supply=0, balances={}) pool = pools[0] try: tick_current: int = int(pool["tick"]) except TypeError: return Balances(total_supply=0, balances={}) sqrt_price: int = pool.get("sqrtPrice", "") if not sqrt_price: return Balances(total_supply=0, balances={}) sqrt_price = int(sqrt_price) token0_address: ChecksumAddress = Web3.toChecksumAddress(pool["token0"]) token1_address: ChecksumAddress = Web3.toChecksumAddress(pool["token1"]) last_id = "" result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_POSITIONS_QUERY, variables=dict( block_number=block_number, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions = positions_chunk # TODO: calculated earned fees # accumulate chunks of positions while len(positions_chunk) >= 1000: last_id = positions_chunk[-1]["id"] result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_POSITIONS_QUERY, variables=dict( block_number=block_number, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions.extend(positions_chunk) # process positions balances: Dict[ChecksumAddress, int] = {} total_supply = 0 for position in positions: account = Web3.toChecksumAddress(position["owner"]) if account == EMPTY_ADDR_HEX: continue liquidity: int = int(position["liquidity"]) if liquidity <= 0: continue try: tick_lower: int = int(position["tickLower"]) tick_upper: int = int(position["tickUpper"]) except TypeError: continue if token0_address == token: token0_amount = get_amount0( tick_current=tick_current, sqrt_ratio_x96=sqrt_price, tick_lower=tick_lower, tick_upper=tick_upper, liquidity=liquidity, ) balances[account] = balances.setdefault(account, 0) + token0_amount total_supply += token0_amount elif token1_address == token: token1_amount = get_amount1( tick_current=tick_current, sqrt_ratio_x96=sqrt_price, tick_lower=tick_lower, tick_upper=tick_upper, liquidity=liquidity, ) balances[account] = balances.setdefault(account, 0) + token1_amount total_supply += token1_amount return Balances(total_supply=total_supply, balances=balances)
class BalancerTokenAdapterClient(ZerionTokenAdapterClient): ADAPTER_ADDRESS: ChecksumAddress = ChecksumAddress( "0xb45c5AE417F70E4C52DFB784569Ce843a45FE8ca" )
is_same_address, is_string, ) from hexbytes import ( HexBytes, ) from web3.exceptions import ( BlockNotFound, InvalidAddress, TransactionNotFound, ) from web3.types import ( # noqa: F401 BlockData, FilterParams, LogReceipt, Nonce, SyncStatus, TxParams, Wei, ) UNKNOWN_ADDRESS = ChecksumAddress( HexAddress(HexStr('0xdEADBEeF00000000000000000000000000000000'))) UNKNOWN_HASH = HexStr( '0xdeadbeef00000000000000000000000000000000000000000000000000000000') if TYPE_CHECKING: from web3 import Web3 # noqa: F401 from web3.contract import Contract # noqa: F401 class EthModuleTest: def test_eth_protocolVersion(self, web3: "Web3") -> None: protocol_version = web3.eth.protocolVersion assert is_string(protocol_version) assert protocol_version.isdigit()
class ZerionUniswapV2TokenAdapterClient(ZerionTokenAdapterClient): ADAPTER_ADDRESS: ChecksumAddress = ChecksumAddress( "0x6C5D49157863f942A5E6115aaEAb7d6A67a852d3" )
async def get_token_liquidity_points( network: str, token_address: ChecksumAddress, from_block: BlockNumber, to_block: BlockNumber, ) -> Balances: """Fetches distributor token holders' balances.""" lowered_token_address = token_address.lower() last_id = "" result: Dict = await execute_sw_gql_query( network=network, query=DISTRIBUTOR_TOKEN_HOLDERS_QUERY, variables=dict( token_address=lowered_token_address, block_number=to_block, last_id=last_id, ), ) positions_chunk = result.get("distributorTokenHolders", []) positions = positions_chunk # accumulate chunks of positions while len(positions_chunk) >= 1000: last_id = positions_chunk[-1]["id"] result: Dict = await execute_sw_gql_query( network=network, query=DISTRIBUTOR_TOKEN_HOLDERS_QUERY, variables=dict( token_address=lowered_token_address, block_number=to_block, last_id=last_id, ), ) positions_chunk = result.get("distributorTokenHolders", []) positions.extend(positions_chunk) # process balances points: Dict[ChecksumAddress, int] = {} total_points = 0 for position in positions: account = Web3.toChecksumAddress(position["account"]) if account == EMPTY_ADDR_HEX: continue principal = int(position["amount"]) prev_account_points = int(position["distributorPoints"]) updated_at_block = BlockNumber(int(position["updatedAtBlock"])) if from_block > updated_at_block: updated_at_block = from_block prev_account_points = 0 account_points = prev_account_points + ( principal * (to_block - updated_at_block) ) if account_points <= 0: continue points[account] = points.get(account, 0) + account_points total_points += account_points return Balances(total_supply=total_points, balances=points)
class ZerionTokenAdapterClient: """ Client for Zerion Token Adapter https://github.com/zeriontech/defi-sdk """ ABI = [ { "inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getComponents", "outputs": [ { "components": [ {"internalType": "address", "name": "token", "type": "address"}, { "internalType": "string", "name": "tokenType", "type": "string", }, {"internalType": "uint256", "name": "rate", "type": "uint256"}, ], "internalType": "struct Component[]", "name": "", "type": "tuple[]", } ], "stateMutability": "view", "type": "function", }, { "inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getMetadata", "outputs": [ { "components": [ {"internalType": "address", "name": "token", "type": "address"}, {"internalType": "string", "name": "name", "type": "string"}, {"internalType": "string", "name": "symbol", "type": "string"}, {"internalType": "uint8", "name": "decimals", "type": "uint8"}, ], "internalType": "struct TokenMetadata", "name": "", "type": "tuple", } ], "stateMutability": "view", "type": "function", }, ] ADAPTER_ADDRESS: ChecksumAddress = ChecksumAddress(NULL_ADDRESS) def __init__( self, ethereum_client: EthereumClient, adapter_address: Optional[ChecksumAddress] = None, ): self.ethereum_client = ethereum_client self.adapter_address = ( adapter_address if adapter_address else self.ADAPTER_ADDRESS ) self.contract = ethereum_client.w3.eth.contract( self.adapter_address, abi=self.ABI ) def get_components( self, token_address: ChecksumAddress ) -> Optional[List[UniswapComponent]]: try: return [ UniswapComponent(*component) for component in self.contract.functions.getComponents( token_address ).call() ] except ContractLogicError: return None def get_metadata( self, token_address: ChecksumAddress ) -> Optional[ZerionPoolMetadata]: try: return ZerionPoolMetadata( *self.contract.functions.getMetadata(token_address).call() ) except ContractLogicError: return None
from eth_typing import ( ChecksumAddress, HexAddress, HexStr, ) from hexbytes import ( HexBytes, ) ACCEPTABLE_STALE_HOURS = 48 AUCTION_START_GAS_CONSTANT = 25000 AUCTION_START_GAS_MARGINAL = 39000 EMPTY_SHA3_BYTES = HexBytes(b'\0' * 32) EMPTY_ADDR_HEX = HexAddress(HexStr('0x' + '00' * 20)) REVERSE_REGISTRAR_DOMAIN = 'addr.reverse' ENS_MAINNET_ADDR = ChecksumAddress( HexAddress(HexStr('0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e')))