diff --git a/CHANGES.md b/CHANGES.md index 75898d1c..e0a3d97a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,24 @@ Note to self: Breaking changes must increment either --> +## 0.30.0 (2024-07-04) + +_**Breaking**_ + +> No breaking changes were introduced in this version. + +_**Features**_ + +- feat: add validator for trx addresses by @msamsami in [#384](https://github.com/python-validators/validators/pull/384) + +_**Maintenance**_ + +- maint: bump version by @msamsami in [#384](https://github.com/python-validators/validators/pull/384) + +**Full Changelog**: [`0.29.0...0.30.0`](https://github.com/python-validators/validators/compare/0.29.0...0.30.0) + +--- + ## 0.29.0 (2024-07-01) _**Breaking**_ ⚠️ @@ -25,6 +43,8 @@ _**Maintenance**_ **Full Changelog**: [`0.28.3...0.29.0`](https://github.com/python-validators/validators/compare/0.28.3...0.29.0) +--- + ## 0.28.3 (2024-05-25) _**Breaking**_ diff --git a/SECURITY.md b/SECURITY.md index 2a65546a..2231e167 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ | Version | Supported | | ---------- | ------------------ | -| `>=0.29.0` | :white_check_mark: | +| `>=0.30.0` | :white_check_mark: | ## Reporting a Vulnerability diff --git a/docs/api/crypto_addresses.md b/docs/api/crypto_addresses.md index 628e061b..226ef0c5 100644 --- a/docs/api/crypto_addresses.md +++ b/docs/api/crypto_addresses.md @@ -2,3 +2,4 @@ ::: validators.crypto_addresses.btc_address ::: validators.crypto_addresses.eth_address +::: validators.crypto_addresses.trx_address diff --git a/docs/api/crypto_addresses.rst b/docs/api/crypto_addresses.rst index 60e733b8..09ebfe41 100644 --- a/docs/api/crypto_addresses.rst +++ b/docs/api/crypto_addresses.rst @@ -4,3 +4,4 @@ crypto_addresses .. module:: validators.crypto_addresses .. autofunction:: btc_address .. autofunction:: eth_address +.. autofunction:: trx_address diff --git a/src/validators/__init__.py b/src/validators/__init__.py index a554051e..a58a574c 100644 --- a/src/validators/__init__.py +++ b/src/validators/__init__.py @@ -5,7 +5,7 @@ from .card import amex, card_number, diners, discover, jcb, mastercard, unionpay, visa from .country import calling_code, country_code, currency from .cron import cron -from .crypto_addresses import btc_address, eth_address +from .crypto_addresses import btc_address, eth_address, trx_address from .domain import domain from .email import email from .encoding import base58, base64 @@ -39,6 +39,7 @@ # crypto_addresses "btc_address", "eth_address", + "trx_address", # cards "amex", "card_number", @@ -104,4 +105,4 @@ "validator", ) -__version__ = "0.29.0" +__version__ = "0.30.0" diff --git a/src/validators/crypto_addresses/__init__.py b/src/validators/crypto_addresses/__init__.py index 87c5e5c8..d6bd2d61 100644 --- a/src/validators/crypto_addresses/__init__.py +++ b/src/validators/crypto_addresses/__init__.py @@ -3,5 +3,6 @@ # local from .btc_address import btc_address from .eth_address import eth_address +from .trx_address import trx_address -__all__ = ("btc_address", "eth_address") +__all__ = ("btc_address", "eth_address", "trx_address") diff --git a/src/validators/crypto_addresses/trx_address.py b/src/validators/crypto_addresses/trx_address.py new file mode 100644 index 00000000..3b021fbc --- /dev/null +++ b/src/validators/crypto_addresses/trx_address.py @@ -0,0 +1,62 @@ +"""TRX Address.""" + +# standard +import hashlib +import re + +# local +from validators.utils import validator + + +def _base58_decode(addr: str) -> bytes: + """Decode a base58 encoded address.""" + alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + num = 0 + for char in addr: + num = num * 58 + alphabet.index(char) + return num.to_bytes(25, byteorder="big") + + +def _validate_trx_checksum_address(addr: str) -> bool: + """Validate TRX type checksum address.""" + if len(addr) != 34: + return False + + try: + address = _base58_decode(addr) + except ValueError: + return False + + if len(address) != 25 or address[0] != 0x41: + return False + + check_sum = hashlib.sha256(hashlib.sha256(address[:-4]).digest()).digest()[:4] + return address[-4:] == check_sum + + +@validator +def trx_address(value: str, /): + """Return whether or not given value is a valid tron address. + + Full validation is implemented for TRC20 tron addresses. + + Examples: + >>> trx_address('TLjfbTbpZYDQ4EoA4N5CLNgGjfbF8ZWz38') + # Output: True + >>> trx_address('TR2G7Rm4vFqF8EpY4U5xdLdQ7XgJ2U8Vd') + # Output: ValidationError(func=trx_address, args=...) + + Args: + value: + Tron address string to validate. + + Returns: + (Literal[True]): If `value` is a valid tron address. + (ValidationError): If `value` is an invalid tron address. + """ + if not value: + return False + + return re.compile(r"^[T][a-km-zA-HJ-NP-Z1-9]{33}$").match( + value + ) and _validate_trx_checksum_address(value) diff --git a/tests/crypto_addresses/test_trx_address.py b/tests/crypto_addresses/test_trx_address.py new file mode 100644 index 00000000..68bb0d94 --- /dev/null +++ b/tests/crypto_addresses/test_trx_address.py @@ -0,0 +1,54 @@ +"""Test TRX address.""" + +# external +import pytest + +# local +from validators import ValidationError, trx_address + + +@pytest.mark.parametrize( + "value", + [ + "TLjfbTbpZYDQ4EoA4N5CLNgGjfbF8ZWz38", + "TDQ6C92wuNqvMWE967sMptCFaXq77uj1PF", + "TFuGbxCQGSL4oLnJzVsen844LDwFbrUY4e", + "TFAPKADDRhkSe3v27CsR8TZSjN8eJ8ycDK", + "TSJHywLNva2MNjCD5iYfn5QAKD9Rk5Ncit", + "TEi1qhi5LuTicg1u9oAstyXCSf5uibSyqo", + "TAGvx5An6VBeHTu91cQwdABNcAYMRPcP4n", + "TXbE5tXTejqT3Q47sYKCDb9NJDm3xrFpab", + "TMTxQWNuWHXvHcYXc5D1wQhFmZFJijAxcG", + "TPHgw9E8QYM3esNWih5KVnUVpUHwLTPfpA", + "TFFLtBTi9jdaGwV3hznjCmPYaJme5AeqwU", + "TC74QG8tbtixG5Raa4fEifywgjrFs45fNz", + ], +) +def test_returns_true_on_valid_trx_address(value: str): + """Test returns true on valid trx address.""" + assert trx_address(value) + + +@pytest.mark.parametrize( + "value", + [ + "T12345678901234567890123456789012345", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678", + "TR2G7Rm4vFqF8EpY4U5xdLdQ7XgJ2U8Vd", + "TP6ah2v5mdsj8Z3hGz1yDMvDq7BzEbK8o", + "TQmmhp6uz2Xre8yL3FsPYZyo4mhtw4vg4XX", + "TQNy2C6VHJPk4P32bsEX3QSGx2Qqm4J2k9", + "TP6ah2v5mdsj8Z3hGz1yDMvDq7BzEbK8oN", + "TSTVdfU1x4L7K3Bc3v5C28Gp2J1rPyeL3f", + "THPByuCzvU5QER9j2NC2mUQ2JPyRCam4e7", + "TW5eZqUZgdW4rxFKAKsc2ryJbfFA94WXvD", + "TR2G7Rm4vFqF8EpY4U5xdLdQ7XgJ2U8Vdd", + "tQmmhp6uz2Xre8yL3FsPYZyo4mhtw4vg4X", + "TR2G7Rm4vFqF8EpY4U5xdLdQ7Xg", + "TQmmhp6uz2Xre8yL3FsPYZyo4mhtw4vg4x", + "my-trox-address.trx", + ], +) +def test_returns_failed_validation_on_invalid_trx_address(value: str): + """Test returns failed validation on invalid trx address.""" + assert isinstance(trx_address(value), ValidationError) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy