def get_top_holders(address: str) -> List: address = to_address(address) if address not in _token_holders: holders = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{address}", params={ "apiKey": _ethplorer_api_key, "limit": "50" }, ).json() if "error" in holders: api_key_message = "" if _ethplorer_api_key == "freekey": api_key_message = ( " Adding $ETHPLORER_API_KEY (from https://ethplorer.io) as environment variable" " may solve the problem.") raise BrownieTokensError( f"Ethplorer returned error: {holders['error']}." + api_key_message) _token_holders[address] = [ to_address(i["address"]) for i in holders["holders"] ] if address in _token_holders[address]: # don't steal from the treasury - that could cause wierdness _token_holders[address].remove(address) update_skipped_addresses(address) return _token_holders[address]
def simulate(): # fetch the top holders so we can pass the vote data = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{TARGET['token']}", params={ "apiKey": "freekey", "limit": 50 }, ).json()["holders"][::-1] # create a list of top holders that will be sufficient to make quorum holders = [] weight = 0 while weight < TARGET["quorum"] + 5: row = data.pop() holders.append(to_address(row["address"])) weight += row["share"] # make the new vote top_holder = holders[0] vote_id = make_vote(top_holder) # vote aragon = Contract(TARGET["voting"]) for acct in holders: aragon.vote(vote_id, True, False, {"from": acct}) # sleep for a week so it has time to pass chain.sleep(86400 * 7) # moment of truth - execute the vote! aragon.executeVote(vote_id, {"from": top_holder})
def simulate(): voting_escrow = Contract("0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2") aragon = Contract("0xe478de485ad2fe566d49342cbd03e49ed7db3356") # make the new vote vote_id = make_vote() # fetch the top veCRV holders so we can pass the vote data = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{voting_escrow}", params={ 'apiKey': "freekey", 'limit': 50 }, ).json()['holders'][::-1] # vote needs 30% to reach qurom, we'll vote with 35% in case # there's been some decay since ethplorer pulled their data holders = [] weight = 0 while weight < 35: row = data.pop() holders.append(to_address(row['address'])) weight += row['share'] # vote for acct in holders: aragon.vote(vote_id, True, False, {'from': acct}) # sleep for a week so it has time to pass chain.sleep(86400 * 7) # moment of truth - execute the vote! aragon.executeVote(vote_id, {'from': holders[0]})
def __eq__(self, other): if type(other) is str: try: address = to_address(other) return address == self.address except ValueError: return False return super().__eq__(other)
def __eq__(self, other): if isinstance(other, str): try: address = to_address(other) return address == self.address except ValueError: return False return super().__eq__(other)
def get_balances_for_position_in_accounts_dot_balances(accounts, pos): # sl = sublist return { to_address(balance['account']['address']): balance['shares'] for sl in [x['balances'] for x in accounts if 0 < len(x['balances'])] for balance in sl if balance['position'] == str(pos) }
def remove(self, address): '''Removes an account instance from the container. Args: address: Account instance or address string of account to remove.''' address = to_address(address) try: self._accounts.remove(address) except ValueError: raise UnknownAccount(f"No account exists for {address}")
def __eq__(self, other): if isinstance(other, str): try: address = to_address(other) return address == self.address except ValueError: return False if isinstance(other, PublicKeyAccount): return other.address == self.address return super().__eq__(other)
def __eq__(self, other): if type(other) is Contract: return self.address == other.address and self.bytecode == other.bytecode if type(other) is str: try: address = to_address(other) return address == self.address except ValueError: return False return super().__eq__(other)
def __eq__(self, other): if isinstance(other, _DeployedContractBase): return self.address == other.address and self.bytecode == other.bytecode if isinstance(other, str): try: address = to_address(other) return address == self.address except ValueError: return False return super().__eq__(other)
def transfer( self, to: "Accounts" = None, amount: int = 0, gas_limit: Optional[int] = None, gas_price: Optional[int] = None, data: str = None, silent: bool = False, ) -> "TransactionReceipt": """ Broadcast a transaction from this account. Kwargs: to: Account instance or address string to transfer to. amount: Amount of ether to send, in wei. gas_limit: Gas limit of the transaction. gas_price: Gas price of the transaction. data: Hexstring of data to include in transaction. silent: Toggles console verbosity. Returns: TransactionReceipt object """ tx = { "from": self.address, "value": Wei(amount), "nonce": self.nonce, "gasPrice": Wei(gas_price) if gas_price is not None else self._gas_price(), "gas": Wei(gas_limit) or self._gas_limit(to, amount, data), "data": HexBytes(data or ""), } if to: tx["to"] = to_address(str(to)) try: txid = self._transact(tx) # type: ignore revert_data = None except ValueError as e: txid, revert_data = _raise_or_return_tx(e) if rpc.is_active(): rpc._add_to_undo_buffer(self.transfer, (to, amount, gas_limit, gas_price, data), {}) return TransactionReceipt(txid, self, silent=silent, revert_data=revert_data)
def test_wrong_length(): with pytest.raises(ValueError): to_address("0x00") with pytest.raises(ValueError): to_address(addr[:20]) with pytest.raises(ValueError): to_address(addr + "00")
def estimate_gas(self, to: "Account" = None, amount: int = 0, gas_price: int = None, data: str = None) -> int: """ Estimate the gas cost for a transaction. Raises VirtualMachineError if the transaction would revert. Arguments --------- to : Account, optional Account instance or address string of transaction recipient. amount : int, optional Amount of ether to send in wei. gas_price : int, optional Gas price of the transaction. data : str, optional Transaction data hexstring. Returns ------- Estimated gas value in wei. """ tx: Dict = { "from": self.address, "to": to_address(str(to)) if to else None, "value": Wei(amount), "data": HexBytes(data or ""), } if gas_price is not None: tx["gasPrice"] = gas_price try: return web3.eth.estimate_gas(tx) except ValueError as exc: revert_gas_limit = CONFIG.active_network["settings"][ "reverting_tx_gas_limit"] if revert_gas_limit == "max": revert_gas_limit = web3.eth.get_block("latest")["gasLimit"] CONFIG.active_network["settings"][ "reverting_tx_gas_limit"] = revert_gas_limit if revert_gas_limit: return revert_gas_limit msg = exc.args[0]["message"] if isinstance(exc.args[0], dict) else str(exc) raise ValueError( f"Gas estimation failed: '{msg}'. This transaction will likely revert. " "If you wish to broadcast, you must set the gas limit manually." )
def _resolve_address(address: str) -> str: if not isinstance(address, str) or "." not in address: return to_address(address) address = address.lower() if address not in _ens_cache: try: ns = ENS.fromWeb3(web3._mainnet) except MainnetUndefined as e: raise MainnetUndefined( f"Cannot resolve ENS address - {e}") from None resolved_address = ns.address(address) _ens_cache[address] = resolved_address if _ens_cache[address] is None: raise UnsetENSName(f"ENS address '{address}' is not set") return _ens_cache[address]
def test_alice_and_bob_exist(): gql = """ query { accounts { id } } """ result = query(gql) accounts = [to_address(x['id']) for x in result['accounts']] assert ENV("ALICE") in accounts, "Alice is not in returned accounts" assert ENV("BOB") in accounts, "Bob is not in returned accounts"
def at(self, address): '''Retrieves an Account instance from the address string. Raises ValueError if the account cannot be found. Args: address: string of the account address. Returns: Account instance. ''' address = to_address(address) try: return next(i for i in self._accounts if i == address) except StopIteration: raise UnknownAccount(f"No account exists for {address}")
def swap( alice, base_pool, factory, plain_implementations, meta_implementation_idx, coins, project, plain_pool_size, pool_type, is_meta_pool, web3, ): if not is_meta_pool: # modifies the factory so should be module scoped tx = factory.deploy_plain_pool( "Test Plain Pool", "TPP", coins + [ZERO_ADDRESS] * (4 - plain_pool_size), 200, 4000000, 0, pool_type, {"from": alice}, ) return getattr(project, plain_implementations[pool_type]._name).at( tx.return_value) else: if factory.pool_count() != 0: return state._find_contract(factory.pool_list(0)) tx = factory.deploy_metapool( base_pool, "Test Meta Pool", "TMP", coins[0], 200, 4000000, meta_implementation_idx, {"from": alice}, ) key = convert.to_address( HexBytes(web3.eth.get_code(tx.return_value))[10:30].hex()) instance = Contract.from_abi("Meta Instance", tx.return_value, meta_contracts[key]) instance._build["language"] = "Vyper" state._add_contract(instance) return instance
def __init__(self, address): super().__init__(address) # get top token holder addresses address = self.address if address not in _holders: holders = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{address}", params={ 'apiKey': "freekey", 'limit': 50 }, ).json() _holders[address] = [ to_address(i['address']) for i in holders['holders'] ]
def _resolve_address(domain: str) -> str: # convert ENS domain to address if not isinstance(domain, str) or "." not in domain: return to_address(domain) domain = domain.lower() if domain not in _ens_cache or time.time() - _ens_cache[domain][1] > 86400: try: ns = ENS.fromWeb3(web3._mainnet) except MainnetUndefined as e: raise MainnetUndefined(f"Cannot resolve ENS address - {e}") from None address = ns.address(domain) _ens_cache[domain] = [address, int(time.time())] with _get_path().open("w") as fp: json.dump(_ens_cache, fp) if _ens_cache[domain][0] is None: raise UnsetENSName(f"ENS domain '{domain}' is not set") return _ens_cache[domain][0]
def __init__(self, address, pool_data): super().__init__(address) # standardize mint / rate methods if 'wrapped_contract' in pool_data: fn_names = WRAPPED_COIN_METHODS[pool_data['wrapped_contract']] for target, attr in fn_names.items(): if hasattr(self, attr): setattr(self, target, getattr(self, attr)) # get top token holder addresses address = self.address if address not in _holders: holders = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{address}", params={'apiKey': "freekey", 'limit': 50}, ).json() _holders[address] = [to_address(i['address']) for i in holders['holders']]
def __init__(self, address, pool_data=None): super().__init__(address) # standardize mint / rate methods if pool_data is not None and "wrapped_contract" in pool_data: fn_names = WRAPPED_COIN_METHODS[pool_data["wrapped_contract"]] for target, attr in fn_names.items(): if hasattr(self, attr) and target != attr: setattr(self, target, getattr(self, attr)) # get top token holder addresses address = self.address if address not in _holders: holders = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{address}", params={"apiKey": "freekey", "limit": 50}, ).json() _holders[address] = [to_address(i["address"]) for i in holders["holders"]]
def main(): voting_escrow = Contract("0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2") aragon = Contract("0xe478de485ad2fe566d49342cbd03e49ed7db3356") agent = Contract("0x40907540d8a6c65c637785e8f8b742ae6b0b9968") # fetch the top veCRV holders so we can pass the vote data = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{voting_escrow}", params={ 'apiKey': "freekey", 'limit': 50 }, ).json()['holders'][::-1] # vote needs 30% to reach qurom, we'll vote with 35% in case # there's been some decay since ethplorer pulled their data holders = [] weight = 0 while weight < 35: row = data.pop() holders.append(to_address(row['address'])) weight += row['share'] # prepare the evm calldata for the vote agent_calldata = agent.execute.encode_input(TARGET, 0, CALLDATA)[2:] length = hex(len(agent_calldata) // 2)[2:].zfill(8) evm_script = f"0x0000000140907540d8a6c65c637785e8f8b742ae6b0b9968{length}{agent_calldata}" # create the new vote tx = aragon.newVote(evm_script, DESCRIPTION, False, False, {'from': holders[0]}) vote_id = tx.events['StartVote']['voteId'] # vote for acct in holders: aragon.vote(vote_id, True, False, {'from': acct}) # sleep for a week so it has time to pass chain.sleep(86400 * 7) # moment of truth - execute the vote! aragon.executeVote(vote_id, {'from': holders[0]}) print(f"Success!\n\nEVM script for vote: {evm_script}")
def connect_to_clef(self, uri: str = None, timeout: int = 120) -> None: """ Connect to Clef and import open accounts. Clef is an account signing utility packaged with Geth, which can be used to interact with HW wallets in Brownie. Before calling this function, Clef must be running in another command prompt. Arguments --------- uri : str IPC path or http url to use to connect to clef. If None is given, uses the default IPC path on Unix systems or localhost on Windows. timeout : int The number of seconds to wait on a clef request before raising a timeout exception. """ provider = None if uri is None: if sys.platform == "win32": uri = "http://localhost:8550/" else: uri = Path.home().joinpath(".clef/clef.ipc").as_posix() try: if Path(uri).exists(): provider = IPCProvider(uri, timeout=timeout) except OSError: if uri is not None and uri.startswith("http"): provider = HTTPProvider(uri, {"timeout": timeout}) if provider is None: raise ValueError( "Unknown URI, must be IPC socket path or URL starting with 'http'" ) response = provider.make_request("account_list", []) if "error" in response: raise ValueError(response["error"]["message"]) for address in response["result"]: if to_address(address) not in self._accounts: self._accounts.append(ClefAccount(address, provider))
def at(self, address, owner=None, tx=None): '''Returns a contract address. Raises ValueError if no bytecode exists at the address. Args: address: Address string of the contract. owner: Default Account instance to send contract transactions from. tx: Transaction ID of the contract creation.''' address = to_address(address) contract = _contracts.find(address) if contract: if contract._name == self._name: return contract raise ValueError( f"Contract '{contract._name}' already declared at {address}") if web3.eth.getCode(address).hex() == "0x": raise ValueError(f"No contract deployed at {address}") contract = Contract(address, self._build, owner, tx) _contracts.add(contract) return contract
def __init__(self, address, owner=None, tx=None): address = to_address(address) self.bytecode = web3.eth.getCode(address).hex()[2:] if not self.bytecode: raise ContractNotFound(f"No contract deployed at {address}") self._owner = owner self.tx = tx self.address = address fn_names = [i['name'] for i in self.abi if i['type'] == "function"] for abi in [i for i in self.abi if i['type'] == "function"]: name = f"{self._name}.{abi['name']}" if fn_names.count(abi['name']) == 1: self._check_and_set( abi['name'], _get_method_object(address, abi, name, owner)) continue if not hasattr(self, abi['name']): self._check_and_set(abi['name'], OverloadedMethod(address, name, owner)) key = ",".join(i['type'] for i in abi['inputs']).replace('256', '') getattr(self, abi['name']).methods[key] = _get_method_object( address, abi, name, owner)
def crypto_pool( alice, crypto_project, crypto_math, crypto_lp_token, crypto_views, crypto_coins, crypto_initial_prices, ): # taken from curvefi/curve-crypto-contract keys = [0, 1, 2, 16, 17, 18, "1,#0", "1,#1", "1,#2"] values = ( [crypto_math.address, crypto_lp_token.address, crypto_views.address] + [coin.address for coin in crypto_coins] + [f"{10 ** (18 - coin.decimals())}," for coin in crypto_coins] ) source = crypto_project.CurveCryptoSwap._build["source"] for k, v in zip(keys, values): if isinstance(k, int): k = convert.to_address(convert.to_bytes(k, "bytes20")) source.replace(k, v) CryptoPool = compile_source(source, vyper_version="0.2.12").Vyper swap = CryptoPool.deploy( alice, 135 * 3 ** 3, # A int(7e-5 * 1e18), # gamma int(4e-4 * 1e10), # mid_fee int(4e-3 * 1e10), # out_fee int(0.0028 * 1e18), # price_threshold int(0.01 * 1e18), # fee_gamma int(0.0015 * 1e18), # adjustment_step 0, # admin_fee 600, # ma_half_time crypto_initial_prices, {"from": alice}, ) crypto_lp_token.set_minter(swap, {"from": alice}) return swap
def transfer( self, to: "Accounts", amount: int, gas_limit: int = None, gas_price: int = None, data: str = "", ) -> "TransactionReceipt": """Transfers ether from this account. Args: to: Account instance or address string to transfer to. amount: Amount of ether to send, in wei. Kwargs: gas_limit: Gas limit of the transaction. gas_price: Gas price of the transaction. data: Hexstring of data to include in transaction. Returns: TransactionReceipt object""" try: txid = self._transact( # type: ignore { "from": self.address, "to": to_address(str(to)), "value": Wei(amount), "nonce": self.nonce, "gasPrice": Wei(gas_price) if gas_price is not None else self._gas_price(), "gas": Wei(gas_limit) or self._gas_limit(to, amount, data), "data": HexBytes(data), } ) revert_data = None except ValueError as e: txid, revert_data = _raise_or_return_tx(e) return TransactionReceipt(txid, self, revert_data=revert_data)
def __init__(self, coin_data, is_wrapped): self._coin_data = coin_data wrapped_address = coin_data.get("wrapped_address") underlying_address = coin_data.get("underlying_address") if is_wrapped: address = wrapped_address or underlying_address else: address = underlying_address or wrapped_address super().__init__(address) if is_wrapped and wrapped_address: self._rate_fn = next( getattr(self, i) for i in self._rate_methods if hasattr(self, i)) else: if "base_pool_token" in coin_data: base_pool = next(i for i in _pooldata.values() if i.get("lp_token_address") == self.address) self._rate_fn = Contract( base_pool["swap_address"]).get_virtual_price else: self._rate_fn = None # get top token holder addresses address = self.address if address not in _holders: holders = requests.get( f"https://api.ethplorer.io/getTopTokenHolders/{address}", params={ 'apiKey': "freekey", 'limit': 50 }, ).json() _holders[address] = [ to_address(i['address']) for i in holders['holders'] ]
def __contains__(self, address: str) -> bool: try: address = to_address(address) return address in self._accounts except ValueError: return False
def transfer( self, to: "Account" = None, amount: int = 0, gas_limit: Optional[int] = None, gas_buffer: Optional[float] = None, gas_price: Optional[int] = None, data: str = None, nonce: Optional[int] = None, required_confs: int = 1, allow_revert: bool = None, silent: bool = None, ) -> TransactionReceipt: """ Broadcast a transaction from this account. Kwargs: to: Account instance or address string to transfer to. amount: Amount of ether to send, in wei. gas_limit: Gas limit of the transaction. gas_buffer: Multiplier to apply to gas limit. gas_price: Gas price of the transaction. nonce: Nonce to use for the transaction. data: Hexstring of data to include in transaction. silent: Toggles console verbosity. Returns: TransactionReceipt object """ if gas_limit and gas_buffer: raise ValueError("Cannot set gas_limit and gas_buffer together") if silent is None: silent = bool(CONFIG.mode == "test" or CONFIG.argv["silent"]) with self._lock: gas_price, gas_strategy, gas_iter = self._gas_price(gas_price) gas_limit = Wei(gas_limit) or self._gas_limit( to, amount, gas_price, gas_buffer, data) tx = { "from": self.address, "value": Wei(amount), "nonce": nonce if nonce is not None else self._pending_nonce(), "gasPrice": gas_price, "gas": gas_limit, "data": HexBytes(data or ""), } if to: tx["to"] = to_address(str(to)) try: txid = self._transact(tx, allow_revert) # type: ignore exc, revert_data = None, None except ValueError as e: exc = VirtualMachineError(e) if not hasattr(exc, "txid"): raise exc from None txid = exc.txid revert_data = (exc.revert_msg, exc.pc, exc.revert_type) receipt = TransactionReceipt( txid, self, required_confs=required_confs, is_blocking=False, silent=silent, revert_data=revert_data, ) receipt = self._await_confirmation(receipt, required_confs, gas_strategy, gas_iter) if rpc.is_active(): undo_thread = threading.Thread( target=Chain()._add_to_undo_buffer, args=( receipt, self.transfer, (to, amount, gas_limit, gas_buffer, gas_price, data, None), {}, ), daemon=True, ) undo_thread.start() receipt._raise_if_reverted(exc) return receipt