def wait_for_transaction_receipt(self, txid): LOG.info("Waiting for transaction receipt from the DID sidechain...") try: w3 = Web3(Web3.HTTPProvider(self.sidechain_rpc)) tx_receipt = w3.eth.wait_for_transaction_receipt(txid, timeout=30, poll_latency=0.1) return { "tx_receipt": json.loads(Web3.toJSON(tx_receipt)), "err_type": None, "err_message": None } except TimeExhausted as e: LOG.info( f"Timed out while sending transactions to the DID sidechain: {str(e)}" ) return { "tx_receipt": {}, "err_type": "TimeExhausted", "err_message": str(e) } except Exception as e: LOG.info( f"Error while sending transactions to the DID sidechain: {str(e)}" ) return { "tx_receipt": {}, "err_type": "Exception", "err_message": str(e) }
def collect_policy_rate_and_value(alice: Alice, rate: int, value: int, shares: int, force: bool) -> Tuple[int, int]: policy_value_provided = bool(value) or bool(rate) if not policy_value_provided: # TODO #1709 - Fine tuning and selection of default rates rate = alice.default_rate # wei if not force: default_gwei = Web3.fromWei(rate, 'gwei') # wei -> gwei prompt = "Confirm rate of {node_rate} gwei * {shares} nodes ({period_rate} gwei per period)?" if not click.confirm(prompt.format( node_rate=default_gwei, period_rate=default_gwei * shares, shares=shares), default=True): interactive_rate = click.prompt( 'Enter rate per period in gwei', type=GWEI) # TODO: Interactive rate sampling & validation (#1709) interactive_prompt = prompt.format( node_rate=interactive_rate, period_rate=interactive_rate * shares, shares=shares) click.confirm(interactive_prompt, default=True, abort=True) rate = Web3.toWei(interactive_rate, 'gwei') # gwei -> wei return rate, value
def send_ether(from_wallet: Wallet, to_address: str, amount: int) -> AttributeDict: if not Web3.isChecksumAddress(to_address): to_address = Web3.toChecksumAddress(to_address) web3 = from_wallet.web3 chain_id = web3.eth.chain_id tx = { "from": from_wallet.address, "to": to_address, "value": amount, "chainId": chain_id, "gasPrice": get_gas_price(web3), } tx["gas"] = web3.eth.estimate_gas(tx) raw_tx = from_wallet.sign_tx(tx) tx_hash = web3.eth.send_raw_transaction(raw_tx) block_confirmations = from_wallet.block_confirmations.value block_number_poll_interval = BLOCK_NUMBER_POLL_INTERVAL[chain_id] transaction_timeout = from_wallet.transaction_timeout.value wait_for_transaction_receipt_and_block_confirmations( web3, tx_hash, block_confirmations, block_number_poll_interval, transaction_timeout, ) return web3.eth.get_transaction_receipt(tx_hash)
def get_block_count(self) -> int: LOG.info("Get block count...") try: w3 = Web3(Web3.HTTPProvider(self.sidechain_rpc)) currentBlock = w3.eth.get_block_number() LOG.info("Actual block number: " + str(currentBlock)) return currentBlock except Exception as e: LOG.info(f"Error while getting block count: {str(e)}") return None
def get_raw_transaction(self, txid): LOG.info(f"Retrieving transaction {txid} from the DID sidechain...") try: w3 = Web3(Web3.HTTPProvider(self.sidechain_rpc)) tx = w3.eth.get_transaction_receipt(txid) return json.loads(Web3.toJSON(tx)) except Exception as e: LOG.info( f"Error while getting raw transaction for a txid: {str(e)}") return None
def send_raw_transaction(self, signed_transaction): LOG.info("Sending transaction to the DID sidechain...") try: w3 = Web3(Web3.HTTPProvider(self.sidechain_rpc)) tx = w3.eth.send_raw_transaction(signed_transaction.rawTransaction) return {"tx_id": tx.hex(), "error": None} except Exception as e: LOG.info( f"Error while sending transactions to the DID sidechain: {str(e)}" ) return {"tx_id": None, "error": str(e)}
def get_balance(self, address): LOG.info( f"Retrieving current balance on DID sidechain for address {address}" ) balance = 0 try: w3 = Web3(Web3.HTTPProvider(self.sidechain_rpc)) balance = float(w3.eth.get_balance( Web3.toChecksumAddress(address))) balance = balance / 1000000000000000000.0 except Exception as e: LOG.info(f"Error while retrieving balance for an address: {e}") return balance
def convert_to_text(data: bytes) -> str: """ :param data: :return: """ return Web3.toText(data)
def convert_to_string(data: bytes) -> HexStr: """ :param data: :return: """ return Web3.toHex(data)
def convert_to_bytes(data: str) -> bytes: """ :param data: :return: """ return Web3.toBytes(text=data)
def confirm_staged_grant(emitter, grant_request: Dict, federated: bool, seconds_per_period=None) -> None: pretty_request = grant_request.copy() # WARNING: Do not mutate if federated: # Boring table = [[field.capitalize(), value] for field, value in pretty_request.items()] emitter.echo(tabulate(table, tablefmt="simple")) return period_rate = Web3.fromWei(pretty_request['n'] * pretty_request['rate'], 'gwei') pretty_request['rate'] = f"{pretty_request['rate']} wei/period * {pretty_request['n']} nodes" expiration = pretty_request['expiration'] periods = calculate_period_duration(future_time=MayaDT.from_datetime(expiration), seconds_per_period=seconds_per_period) periods += 1 # current period is always included pretty_request['expiration'] = f"{pretty_request['expiration']} ({periods} periods)" # M of N pretty_request['Threshold Shares'] = f"{pretty_request['m']} of {pretty_request['n']}" del pretty_request['m'] del pretty_request['n'] def prettify_field(field): field_words = [word.capitalize() for word in field.split('_')] field = ' '.join(field_words) return field table = [[prettify_field(field), value] for field, value in pretty_request.items()] table.append(['Period Rate', f'{period_rate} gwei']) table.append(['Policy Value', f'{period_rate * periods} gwei']) emitter.echo("\nSuccessfully staged grant, Please review the details:\n", color='green') emitter.echo(tabulate(table, tablefmt="simple")) click.confirm('\nGrant access and sign transaction?', abort=True)
def to_32byte_hex(val: int) -> str: """ :param val: :return: """ return Web3.toBytes(val).rjust(32, b"\0")
def from_wei(amount_in_wei: int, decimals: int = DECIMALS_18) -> Decimal: """Convert token amount from wei to ether, quantized to the specified number of decimal places.""" # Coerce to Decimal because Web3.fromWei can return int 0 amount_in_ether = Decimal(Web3.fromWei(amount_in_wei, "ether")) decimal_places = Decimal(10)**-abs(decimals) return amount_in_ether.quantize(decimal_places, context=ETHEREUM_DECIMAL_CONTEXT)
def sign_message(self, account: str, message: bytes, content_type: str = None, validator_address: str = None, **kwargs) -> HexBytes: """ See https://github.com/ethereum/go-ethereum/blob/a32a2b933ad6793a2fe4172cd46c5c5906da259a/signer/core/signed_data.go#L185 """ if isinstance(message, bytes): message = Web3.toHex(message) if not content_type: content_type = self.DEFAULT_CONTENT_TYPE elif content_type not in self.SIGN_DATA_CONTENT_TYPES: raise ValueError(f'{content_type} is not a valid content type. ' f'Valid types are {self.SIGN_DATA_CONTENT_TYPES}') if content_type == self.SIGN_DATA_FOR_VALIDATOR: if not validator_address or validator_address == NULL_ADDRESS: raise ValueError( 'When using the intended validator type, a validator address is required.' ) data = {'address': validator_address, 'message': message} elif content_type == self.SIGN_DATA_FOR_ECRECOVER: data = message else: raise NotImplementedError signed_data = self.__ipc_request("account_signData", content_type, account, data) return HexBytes(signed_data)
def retrieve(self, request, *args, **kwargs): game = self.get_object() prize_data = [] if game.status in (Game.STATUS_PUBLISHED, Game.STATUS_FINISHING): i = 1 for prize in game.calculate_prizes(): prize_data.append({ 'address': '0x0000000000000000000000000000000000000000', 'position': i, 'prize_amount': Web3.fromWei(prize, 'ether') }) i += 1 elif game.status == Game.STATUS_FINISHED: i = 1 for address, prize in game.get_winners().items(): prize_data.append({ 'address': address, 'position': i, 'prize_amount': prize }) i += 1 serializer = GameWinner(prize_data, many=True) return Response(serializer.data)
def get_liquidity_logs( self, event_name: str, from_block: int, to_block: Optional[int] = None, user_address: Optional[str] = None, this_pool_only: bool = True, ) -> Tuple: """ :param event_name: str, one of LOG_JOIN, LOG_EXIT, LOG_SWAP """ topic0 = self.get_event_signature(event_name) to_block = to_block or "latest" topics = [topic0] if user_address: assert Web3.isChecksumAddress(user_address) topics.append( f"0x000000000000000000000000{remove_0x_prefix(user_address).lower()}" ) event = getattr(self.events, event_name) argument_filters = {"topics": topics} logs = self.getLogs( event(), argument_filters=argument_filters, fromBlock=from_block, toBlock=to_block, from_all_addresses=not this_pool_only, ) return logs
def paint_preallocation_status(emitter, preallocation_agent, token_agent) -> None: blockchain = token_agent.blockchain staking_address = preallocation_agent.principal_contract.address token_balance = NU.from_nunits(token_agent.get_balance(staking_address)) eth_balance = Web3.fromWei(blockchain.client.get_balance(staking_address), 'ether') initial_locked_amount = NU.from_nunits( preallocation_agent.initial_locked_amount) current_locked_amount = NU.from_nunits(preallocation_agent.unvested_tokens) available_amount = NU.from_nunits(preallocation_agent.available_balance) end_timestamp = preallocation_agent.end_timestamp width = 64 output = f""" {" Addresses ".center(width, "-")} Staking contract: ... {staking_address} Beneficiary: ........ {preallocation_agent.beneficiary} {" Locked Tokens ".center(width, "-")} Initial locked amount: {initial_locked_amount} Current locked amount: {current_locked_amount} Locked until: ........ {maya.MayaDT(epoch=end_timestamp)} {" NU and ETH Balance ".center(width, "-")} NU balance: .......... {token_balance} Available: ....... {available_amount} ETH balance: ......... {eth_balance} ETH """ emitter.echo(output)
async def get_token_owner(self, network: str, tokenId: int) -> str: contract = self.get_contract(network=network) ownerIdResponse = await self._call_function( contract=contract, methodName=contract.ownerOfMethodName, arguments={'tokenId': int(tokenId)}) ownerId = Web3.toChecksumAddress(ownerIdResponse[0].strip()) return ownerId
def get_winners(self): """ :rtype: dict """ if not Web3.isAddress(self.smart_contract_id): return [] contract = self.get_smart_contract() winners, prizes = contract.call().getWinners() result = {} #Setting address for i, winner in enumerate([w_player for w_player in winners]): result[winner] = Web3.fromWei(prizes[i], 'ether') return OrderedDict(reversed(sorted(result.items(), key=lambda t: t[1])))
def get_signature_vrs(raw): try: hashed_raw = sha256(raw) wallet = get_aquarius_wallet() keys_pk = keys.PrivateKey(wallet.key) prefix = "\x19Ethereum Signed Message:\n32" signable_hash = Web3.solidityKeccak( ["bytes", "bytes"], [Web3.toBytes(text=prefix), Web3.toBytes(hashed_raw.digest())], ) signed = keys.ecdsa_sign(message_hash=signable_hash, private_key=keys_pk) values = { "hash": "0x" + hashed_raw.hexdigest(), "publicKey": wallet.address } values["v"] = (signed.v + 27) if signed.v <= 1 else signed.v values["r"] = (Web3.toHex(Web3.toBytes(signed.r).rjust(32, b"\0")), ) values["s"] = (Web3.toHex(Web3.toBytes(signed.s).rjust(32, b"\0")), ) except AquariusPrivateKeyException: values = {"hash": "", "publicKey": "", "r": "", "s": "", "v": ""} return values
def ec_revoverable_message(msg, private_key): signed_message = sign_message(msg, private_key) ec_recover_args = (msghash, v, r, s) = ( Web3.toHex(signed_message.messageHash), signed_message.v, to_32byte_hex(signed_message.r), to_32byte_hex(signed_message.s), ) return ec_recover_args
def __init__(self, ipc_path: str = DEFAULT_IPC_PATH, timeout: int = TIMEOUT, testnet: bool = False): super().__init__() self.w3 = Web3(provider=IPCProvider(ipc_path=ipc_path, timeout=timeout) ) # TODO: Unify with clients or build error handling self.ipc_path = ipc_path self.testnet = testnet
async def get_migration_target(self, network: str) -> str: contract = self.get_contract(network=network) if not contract.migrationTargetMethodName: raise BadRequestException( 'Contract does not have a migrationTargetMethodName') ownerIdResponse = await self._call_function( contract=contract, methodName=contract.migrationTargetMethodName) migrationTarget = Web3.toChecksumAddress(ownerIdResponse[0].strip()) return migrationTarget
def calculate_prizes(self): """ :rtype: list """ result = [] if Web3.isAddress(self.smart_contract_id): contract = self.get_smart_contract() result = contract.call().calcaultePrizes() else: calculator = UnilotPrizeCalculator() bet = Web3.toWei(((self.prize_amount / self.num_players) / 0.7), 'ether') rawData = calculator.calculate_prizes(bet, self.num_players) result = [ prize_amount for prize_amount in rawData if int(prize_amount) > 0 ] return result
def generate_multi_value_hash(types: List[str], values: List[str]) -> HexBytes: """ Return the hash of the given list of values. This is equivalent to packing and hashing values in a solidity smart contract hence the use of `soliditySha3`. :param types: list of solidity types expressed as strings :param values: list of values matching the `types` list :return: bytes """ assert len(types) == len(values) return Web3.solidityKeccak(types, values)
def finish(self): if not Web3.isAddress(self.smart_contract_id): raise AttributeError('Invalid smart contract address') if self.status != Game.STATUS_PUBLISHED: raise RuntimeError('Invalid status') num_players = self.get_stat().get('numPlayers', 0) if num_players < 5: self.ending_at += timezone.timedelta(hours=24) self.save() push_message = push.GameExtendedPushMessage(payload=self) PushHelper.inform_all_devices(push_message) return None self.status = Game.STATUS_FINISHING self.ending_at += timezone.timedelta(hours=1) keep_trying = True while keep_trying: try: AccountHelper.unlock_base_account() keep_trying = False except socket.timeout: keep_trying = True keep_trying = True while keep_trying: try: contract = self.get_smart_contract() tx = contract.transact( transaction={ 'from': AccountHelper.get_base_account(), 'gasPrice': ContractHelper.getGasPrice() }).finish() keep_trying = False except socket.timeout: keep_trying = True self.save() push_message = push.GameUnpublishedPushMessage(payload=self) PushHelper.inform_all_devices(push_message) return tx
async def get_latest_update_block_number(self, network: str, tokenId: int) -> List[int]: contract = self.get_contract(network=network) if not contract.updateMethodSignature: return [] events = await contract.ethClient.get_log_entries( address=contract.address, startBlockNumber=contract.startBlockNumber, topics=[ Web3.keccak(text=contract.updateMethodSignature).hex(), int_to_hex(tokenId) ]) return next((event['blockNumber'] for event in reversed(events)), None)
async def get_transferred_token_ids_in_blocks( self, network: str, startBlockNumber: int, endBlockNumber: int) -> List[int]: contract = self.get_contract(network=network) events = await contract.ethClient.get_log_entries( address=contract.address, startBlockNumber=startBlockNumber, endBlockNumber=endBlockNumber, topics=[Web3.keccak(text=contract.transferMethodSignature).hex()]) return [ int.from_bytes(bytes(event['topics'][3]), 'big') for event in events ]
def to_wei(amount_in_ether: Union[Decimal, str, int], decimals: int = DECIMALS_18) -> int: """ Convert token amount to wei from ether, quantized to the specified number of decimal places float input is purposfully not supported """ amount_in_ether = normalize_and_validate_ether(amount_in_ether) decimal_places = Decimal(10)**-abs(decimals) return Web3.toWei( amount_in_ether.quantize(decimal_places, context=ETHEREUM_DECIMAL_CONTEXT), "ether", )
def get_prize_amount(self, obj): result = 0 try: stat = self.__get_stat__(obj) result = Web3.fromWei(stat.get('prizeAmount'), 'ether') except: result = float(getattr(obj, 'prize_amount')) return { 'amount': float(result), 'currency': 'UNIT' if obj.type == Game.TOKEN_GAME else 'ETH' }