Simple wallet address validator and normalizer for cryptocurrencies addresses in Ruby.
Inspired by ognus/wallet-address-validator.
Add this line to your application's Gemfile:
gem 'adequate_crypto_address'Or install it yourself as:
gem install adequate_crypto_address0.3.0 is additive and has no breaking changes — upgrade freely. It adds
validators for TRON (trx/tron), Tezos (xtz/tezos), Cosmos
(atom/cosmos), and BNB Smart Chain (bsc/binancesmartchain); see the
supported crypto currencies list for their
types. If you are coming from 0.1.x, also read the notes below.
0.2.0 hardens the validators against malformed input and makes the
address_type API consistent. Most callers of .valid? need no changes, but a
few behaviors changed. See the CHANGELOG for the full list.
Some malformed addresses that earlier versions incorrectly accepted are now rejected. If your app stored or allow-listed such values, re-validate them:
- BCH legacy addresses with a bad checksum/length, CashAddr addresses with a
non-
bitcoincash/bchtest/bchregprefix (e.g.evil:...), or a payload shorter than the version byte declares. - TON any 48-character string (e.g.
"A" * 48) — a valid tag, workchain, and CRC16 checksum are now required. - Monero anything that is not a checksum-valid Base58 address (e.g.
"4" + "!" * 94).
If you rely on a currency name, note that unknown names still raise
AdequateCryptoAddress::UnknownCurrency, but a nil or malformed address
now consistently returns false from .valid? instead of raising.
AdequateCryptoAddress.address_type(address, currency) is a supported public
method for every currency. It returns the detected type as a Symbol when the
address is valid, or nil when it is not.
Some returned type symbols changed. Update any code that compared against the old values:
| Currency | 0.1.x | 0.2.0 |
|---|---|---|
| TON | :TON |
:ton_mainnet / :ton_testnet |
| Monero | :monero |
:standard / :integrated / :subaddress |
| ETH | nil |
:eth |
| SOL | nil |
:solana |
| XLM | nil |
:account / :muxed |
# 0.1.x
AdequateCryptoAddress::Ton.new(addr).send(:address_type) # private, => :TON
# 0.2.0
AdequateCryptoAddress.address_type(addr, :TON) # public, => :ton_mainnetType symbols passed to .valid? for these currencies changed accordingly, e.g.
valid?(addr, :TON, :ton_mainnet).
SegWit Bitcoin types are network-agnostic; call .network to enforce a network:
AdequateCryptoAddress.address('bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', :btc).network #=> :mainnet
AdequateCryptoAddress.address('tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx', :btc).network #=> :testnetXmr#network reports :mainnet / :testnet / :stagenet.
The BCH internal helper address_type(address_code, address_type) was renamed
to type_mapping(address_code, address_type). The public address_type (no
arguments) now returns the detected type.
- address - Wallet address to validate.
- currency - Currency name string or symbol in any case,
:bitcoinor'BTC'or:btcor'BitCoin' - type - Optional. You can enforce validation with specific type. Not all currencies support types.
Returns true if the address (string) is a valid wallet address for the crypto currency specified, see below for supported currencies. An unknown currency raises
AdequateCryptoAddress::UnknownCurrency; anilor malformed address returnsfalse.
Returns the detected address type as a
Symbolwhen the address is valid for the currency, ornilwhen it is not. The type vocabulary per currency is listed below.
AdequateCryptoAddress.address_type('bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', :btc) #=> :segwit_v0_keyhash
AdequateCryptoAddress.address_type('not a real address', :btc) #=> nil- Bitcoin/BTC,
'bitcoin'or'BTC'types::segwit_v0_keyhash :segwit_v0_scripthash :taproot :hash160 :p2sh :hash160test :p2shtest. SegWit types are network-agnostic; callAdequateCryptoAddress.address(addr, :btc).networkto get:mainnet/:testnet. - BitcoinCash/BCH,
'bitcoincash'or'BCH'types::p2sh :p2pkh :p2pkhtest :p2shtest - Cardano/ADA,
'cardano'or'ADA'types::prod :test - Dash,
'dash'or'DASH'types::prod :test - Dogecoin/DOGE,
'dogecoin'or'DOGE'types::prod :test - Zcash/ZEC,
'zcash'or'ZEC'types::prod :test - Ethereum/ETH,
'ethereum'or'ETH'type::eth - Litecoin/LTC,
'litecoin'or'LTC'types::prod :test - Ripple/XRP,
'ripple'or'XRP'type::common - Solana/SOL,
'solana'or'SOL'type::solana - Stellar/XLM,
'stellar'or'XLM'types::account :muxed - Toncoin/TON,
'TON'or'Toncoin'types::ton_mainnet :ton_testnet - Monero/XMR,
'monero'or'XMR'types::standard :integrated :subaddress(.networkreports:mainnet/:testnet/:stagenet) - TRON/TRX,
'tron'or'TRX'type::prod - Tezos/XTZ,
'tezos'or'XTZ'types::implicit :originated - Cosmos/ATOM,
'cosmos'or'ATOM'type::prod - BNB Smart Chain/BSC,
'bsc'or'binancesmartchain'type::bsc(Ethereum-format address)
This gem validates the mainstream, checksum-bearing payment address for each
supported chain. The following related formats are currently out of scope and
are rejected (they return false) rather than silently accepted. They may be
added in future releases:
- Bitcoin witness versions 2–16 and newer output forms (e.g. P2MR / BIP-360); only v0 (Bech32) and v1 Taproot (Bech32m) are recognized.
- Litecoin MWEB (
ltcmweb1...) addresses and future witness versions. - Zcash Sapling, Unified, Orchard, and TEX addresses; only transparent
t-addresses are validated. - XRP X-addresses (with embedded destination tags); only classic
r...addresses are validated. - Dash Platform Bech32m addresses; only Core Base58Check addresses are validated.
- Cardano Byron and stake/reward addresses; only Shelley payment address types 0–7 are validated. Stake addresses are intentionally excluded from a payment-address validator.
- Stellar contract (
C...) and other SEP-23 StrKey types; onlyG(account) andM(muxed) addresses are validated. - TON raw
workchain:account_idaddresses; only the Base64URL user-friendly form is validated.
require 'adequate_crypto_address'
# BTC
AdequateCryptoAddress.valid?('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y', 'BTC') #=> true
AdequateCryptoAddress.valid?('3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt', :bitcoin, :p2sh) #=> true
# BCH
AdequateCryptoAddress.valid?('bitcoincash:qrtj3rd8524cndt2eew3s6wljqggmne00sgh4kfypk', :bch) #=> true
AdequateCryptoAddress.valid?('mmRH4e9WW4ekZUP5HvBScfUyaSUjfQRyvD', :BCH, :p2pkhtest) #=> true
# ETH
AdequateCryptoAddress.valid?('0xde709f2102306220921060314715629080e2fb77', :ETH) #=> true
AdequateCryptoAddress.valid?('de709f2102306220921060314715629080e2fb77', :ethereum) #=> truerequire 'adequate_crypto_address'
# BCH
AdequateCryptoAddress.address('mmRH4e9WW4ekZUP5HvBScfUyaSUjfQRyvD', 'bch').cash_address #=> "bchtest:qpqtmmfpw79thzq5z7s0spcd87uhn6d34uqqem83hf"
AdequateCryptoAddress.address('bitcoincash:qrtj3rd8524cndt2eew3s6wljqggmne00sgh4kfypk', 'bch').legacy_address #=> "1LcerwTc1oPsMtByDCNUXFxReZpN1EXHoe"
address_string = 'qrtj3rd8524cndt2eew3s6wljqggmne00sgh4kfypk'
addr = AdequateCryptoAddress.address(address_string, 'bch')
addr.prefix #=> "bitcoincash"
addr.type #=> :p2pkh
addr.address #=> "bitcoincash:qrtj3rd8524cndt2eew3s6wljqggmne00sgh4kfypk"
# ETH
AdequateCryptoAddress.address('D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb', 'eth').address #=> "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"class Model < ActiveRecord::Base
attribute :address, :string
attribute :dest_tag, :string
attribute :currency, :string
validate :validate_address_type
validate :validate_destination_tag
def validate_address_type
errors.add(:address, 'invalid address') unless AdequateCryptoAddress.valid?(address, currency)
end
# for Ripple
def validate_destination_tag
errors.add(:dest_tag, 'invalid destination tag') if dest_tag.present? && !(dest_tag =~ /\A\d{1,10}\z/)
end
end# frozen_string_literal: true
# for Rails /config/initializers/adequate_crypto_address.rb
module AdequateCryptoAddress
class Coin
attr_reader :address
def initialize(address_sring)
@address = address_sring
end
def valid?(_type)
address.present?
end
end
end
AdequateCryptoAddress.valid?('addr', :coin) #=> trueThe repository pins Ruby with mise. Install the toolchain and dependencies, then run the complete local quality gate:
mise trust
mise install
mise run setup
mise run checkIndividual tasks are available as mise run test, mise run lint, and mise run build. Use
mise run console for an interactive prompt.
- Fork the repo
- Trust and install the toolchain:
mise trust && mise install - Grab dependencies:
mise run setup - Make your changes
- Make sure everything is working:
mise run check - Create a pull request
Bug reports and pull requests are welcome on GitHub at https://github.com/vtm9/adequate_crypto_address/issues