def send_telegram_message(token: str, chat_id: int, message: str) -> Result[bool]: try: bot = TeleBot(token) for text in split_string(message, 4096): bot.send_message(chat_id, text) return Result(ok=True) except Exception as e: return Result(error=str(e))
def decode_transfer_input_data(input_data: str) -> Result[Tuple[str, int]]: input_data = input_data.lower() if input_data.startswith(TRANSFER_METHOD): # noinspection PyBroadException try: input_data = input_data.replace(TRANSFER_METHOD, "") return Result(ok=decode_abi(["address", "uint256"], Web3.toBytes(hexstr=input_data))) except Exception as err: return Result(error=f"exception: {str(err)}") return Result(error="bad_request")
def eth_estimate_gas( node: str, from_: str, to: Optional[str] = None, value: Optional[int] = 0, data: Optional[str] = None, timeout=10, proxy=None, ) -> Result[int]: params: dict[str, Any] = {"from": from_} if to: params["to"] = to if data: params["data"] = data if value: params["value"] = value res = rpc_call(node=node, method="eth_estimateGas", params=[params], timeout=timeout, proxy=proxy) if res.is_error(): return res try: res.ok = int(res.ok, 16) return res except Exception as e: return Result(error=f"exception: {str(e)}")
def eth_get_transaction_by_hash(node: str, tx_hash: str, timeout=10, proxy=None) -> Result[TxData]: res = rpc_call(node=node, method="eth_getTransactionByHash", params=[tx_hash], timeout=timeout, proxy=proxy) if res.is_error(): return res if res.ok is None: return res.new_error("not found") try: res.ok = TxData( block_number=int(res.ok["blockNumber"], 16) if res.ok["blockNumber"] is not None else None, from_=res.ok["from"], to=res.ok.get("to"), gas=int(res.ok["gas"], 16), gas_price=int(res.ok["gasPrice"], 16), value=int(res.ok["value"], 16), nonce=int(res.ok["nonce"], 16), input=res.ok["input"], hash=tx_hash, v=int(res.ok["v"], 16), r=res.ok.get("r"), s=res.ok.get("s"), ) return res except Exception as e: return Result(error=f"exception: {str(e)}")
def eth_get_transaction_receipt(node: str, tx_hash: str, timeout=10, proxy=None) -> Result[TxReceipt]: res = rpc_call(node=node, method="eth_getTransactionReceipt", params=[tx_hash], timeout=timeout, proxy=proxy) if res.is_error(): return res try: status = None if "status" in res.ok: status = int(res.ok["status"], 16) res.ok = TxReceipt( tx_hash=tx_hash, tx_index=int(res.ok["transactionIndex"], 16), block_number=int(res.ok["blockNumber"], 16), from_address=res.ok["from"], to_address=res.ok.get("to"), contract_address=res.ok.get("contractAddress"), status=status, ) return res except Exception as e: return Result(error=f"exception: {str(e)}")
def _ws_call(node: str, data: dict, timeout: int) -> Result: try: ws = websocket.create_connection(node, timeout=timeout) ws.send(json.dumps(data)) response = json.loads(ws.recv()) ws.close() err = response.get("error", {}).get("message", "") if err: return Result(error=f"service_error: {err}") if "result" in response: return Result(ok=response["result"]) return Result(error=f"unknown_response: {str(response)}") except socket.timeout: return Result("timeout") except Exception as err: return Result(error=f"exception: {str(err)}")
def eth_gas_price(node: str, timeout=10, proxy=None) -> Result[int]: res = rpc_call(node=node, method="eth_gasPrice", params=[], timeout=timeout, proxy=proxy) if res.is_error(): return res try: res.ok = int(res.ok, 16) return res except Exception as e: return Result(error=f"exception: {str(e)}")
def get_type_value(type_: DConfigType, str_value: str) -> Result[Any]: try: if type_ == DConfigType.BOOLEAN: return Result(ok=bool(str_value)) elif type_ == DConfigType.INTEGER: return Result(ok=int(str_value)) elif type_ == DConfigType.FLOAT: return Result(ok=float(str_value)) elif type_ == DConfigType.DECIMAL: return Result(ok=Decimal(str_value)) elif type_ == DConfigType.STRING: return Result(ok=str_value) elif type_ == DConfigType.MULTILINE_STRING: return Result(ok=str_value.replace("\r", "")) else: return Result(ok=f"unsupported type: {type_}") except Exception as e: return Result(error=str(e))
def test_is_ok(): assert Result().is_ok() assert not Result().is_error() assert Result(ok=1).is_ok() assert not Result(ok=1).is_error() assert Result(error="bla").is_error() assert not Result(error="bla").is_ok() r = Result(ok="123", data=1) assert r.new_ok(int(r.ok)).ok == 123 assert r.new_ok(int(r.ok)).data == 1 r = Result(error="123", data=1) assert r.new_error("abc").error == "abc" assert r.new_error("abc").data == 1
def test_ok_or_error(): assert Result(ok=123, error="bla bla").ok_or_error == "bla bla" assert Result(ok=123).ok_or_error == 123
def search_block_number_by_time(node: str, search_time: datetime, timeout=10, proxy=None) -> Result[int]: res = eth_rpc.eth_block_number(node, timeout=timeout, proxy=proxy) if res.is_error(): return res current_block_number = res.ok res = eth_rpc.eth_get_block_by_number(node, current_block_number, timeout=timeout, proxy=proxy) if res.is_error(): return res current_block = res.ok current_block_time = _hex_to_datetime(current_block["timestamp"]) res = eth_rpc.eth_get_block_by_number(node, 1, timeout=timeout, proxy=proxy) if res.is_error(): return res first_block = res.ok first_block_time = _hex_to_datetime(first_block["timestamp"]) if search_time < first_block_time: return Result(error="bad_request: before the first block time") if search_time > current_block_time: return Result(error="bad_request: after the current block time") min_block = 1 max_block = current_block_number middle_block_number = 0 counter = 0 while True: counter += 1 if counter > 30: return Result(ok=middle_block_number, data=md(counter)) middle_block_number = math.floor( (max_block - min_block) / 2) + min_block res = eth_rpc.eth_get_block_by_number(node, middle_block_number, timeout=timeout, proxy=proxy) if res.is_error(): return res middle_block = res.ok middle_block_time = _hex_to_datetime(middle_block["timestamp"]) if search_time > middle_block_time: min_block = middle_block_number else: max_block = middle_block_number diff = abs(search_time - middle_block_time) if diff < timedelta(hours=1): return Result(ok=middle_block_number, data={"counter": counter})
def to_ok(self, result: Any): from mb_commons import Result return Result(ok=result, data=self)
def to_error(self, error=None): from mb_commons import Result return Result(error=error if error else self.error, data=self)