def _convert_to_classic_address(json: Dict[str, Any], field: str) -> None: """ Mutates JSON-like dictionary to convert the given field from an X-address (if applicable) to a classic address. """ if field in json and is_valid_xaddress(json[field]): json[field] = xaddress_to_classic_address(json[field])
async def get_account_info(address: str, client: Client) -> Response: """ Query the ledger for account info of given address. Args: address: the account to query. client: the network client used to make network calls. Returns: The account info for the address. Raises: XRPLRequestFailureException: if the rippled API call fails. """ if is_valid_xaddress(address): address, _, _ = xaddress_to_classic_address(address) response = await client.request_impl( AccountInfo( account=address, ledger_index="validated", )) if response.is_successful(): return response result = cast(Dict[str, Any], response.result) raise XRPLRequestFailureException(result)
def _validate_account_xaddress( json: Dict[str, Any], account_field: str, tag_field: str ) -> None: """ Mutates JSON-like dictionary so the X-Address in the account field is the classic address, and the tag is in the tag field. """ if is_valid_xaddress(json[account_field]): account, tag, _ = xaddress_to_classic_address(json[account_field]) json[account_field] = account if json[tag_field] and json[tag_field] != tag: raise XRPLException(f"{tag_field} value does not match X-Address tag") json[tag_field] = tag
async def get_latest_transaction(account: str, client: Client) -> Response: """ Fetches the most recent transaction on the ledger associated with an account. Args: account: the account to query. client: the network client used to communicate with a rippled node. Returns: The Response object containing the transaction info. Raises: XRPLRequestFailureException: if the transaction fails. """ # max == -1 means that it's the most recent validated ledger version if is_valid_xaddress(account): account, _, _ = xaddress_to_classic_address(account) response = await client.request_impl( AccountTx(account=account, ledger_index_max=-1, limit=1)) if not response.is_successful(): result = cast(Dict[str, Any], response.result) raise XRPLRequestFailureException(result) return response
async def get_account_transactions(address: str, client: Client) -> List[Dict[str, Any]]: """ Query the ledger for a list of transactions that involved a given account. Args: address: the account to query. client: the network client used to make network calls. Returns: The transaction history for the address. Raises: XRPLRequestFailureException: if the transaction fails. """ if is_valid_xaddress(address): address, _, _ = xaddress_to_classic_address(address) request = AccountTx(account=address) response = await client.request_impl(request) result = cast(Dict[str, Any], response.result) if not response.is_successful(): raise XRPLRequestFailureException(result) return cast(List[Dict[str, Any]], result["transactions"])
def from_value(cls: Type[AccountID], value: str) -> AccountID: """ Construct an AccountID from a hex string or a base58 r-Address. Args: value: The string to construct an AccountID from. Returns: The AccountID constructed from value. Raises: XRPLBinaryCodecException: If the supplied value is of the wrong type. """ if not isinstance(value, str): raise XRPLBinaryCodecException( "Invalid type to construct an AccountID: expected str," f" received {value.__class__.__name__}." ) if value == "": return cls() # hex-encoded case if _HEX_REGEX.fullmatch(value): return cls(bytes.fromhex(value)) # base58 case if is_valid_classic_address(value): return cls(decode_classic_address(value)) if is_valid_xaddress(value): classic_address, _, _ = xaddress_to_classic_address(value) return cls(decode_classic_address(classic_address)) raise XRPLBinaryCodecException( "Invalid value to construct an AccountID: expected valid classic address " f"or X-Address, received {value.__class__.__name__}." )
def test_is_valid_xaddress_empty(self): xaddress = "" result = addresscodec.is_valid_xaddress(xaddress) self.assertFalse(result)
def test_is_valid_xaddress_invalid(self): xaddress = "XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8zeUygYrCgrPh" result = addresscodec.is_valid_xaddress(xaddress) self.assertFalse(result)
def test_is_valid_xaddress_valid(self): xaddress = "X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ" result = addresscodec.is_valid_xaddress(xaddress) self.assertTrue(result)
def from_value( cls: Type[SerializedDict], value: Dict[str, Any], only_signing: bool = False ) -> SerializedDict: """ Create a SerializedDict object from a dictionary. Args: value: The dictionary to construct a SerializedDict from. only_signing: whether only the signing fields should be included. Returns: The SerializedDict object constructed from value. Raises: XRPLBinaryCodecException: If the SerializedDict can't be constructed from value. """ from xrpl.core.binarycodec.binary_wrappers.binary_serializer import ( BinarySerializer, ) serializer = BinarySerializer() xaddress_decoded = {} for (k, v) in value.items(): if isinstance(v, str) and is_valid_xaddress(v): handled = _handle_xaddress(k, v) if ( _SOURCE_TAG in handled and handled[_SOURCE_TAG] is not None and _SOURCE_TAG in value and value[_SOURCE_TAG] is not None ): raise XRPLBinaryCodecException( "Cannot have Account X-Address and SourceTag" ) if ( _DEST_TAG in handled and handled[_DEST_TAG] is not None and _DEST_TAG in value and value[_DEST_TAG] is not None ): raise XRPLBinaryCodecException( "Cannot have Destination X-Address and DestinationTag" ) xaddress_decoded.update(handled) else: xaddress_decoded[k] = _str_to_enum(k, v) sorted_keys: List[FieldInstance] = [] for field_name in xaddress_decoded: field_instance = get_field_instance(field_name) if ( field_instance is not None and xaddress_decoded[field_instance.name] is not None and field_instance.is_serialized ): sorted_keys.append(field_instance) sorted_keys.sort(key=lambda x: x.ordinal) if only_signing: sorted_keys = list(filter(lambda x: x.is_signing, sorted_keys)) for field in sorted_keys: try: associated_value = field.associated_type.from_value( xaddress_decoded[field.name] ) except XRPLBinaryCodecException as e: # mildly hacky way to get more context in the error # provides the field name and not just the type it's expecting # keeps the original stack trace e.args = (f"Error processing {field.name}: {e.args[0]}",) + e.args[1:] raise serializer.write_field_and_value(field, associated_value) if field.type == _SERIALIZED_DICT: serializer.append(_OBJECT_END_MARKER_BYTE) return SerializedDict(bytes(serializer))