For the complete documentation index, see llms.txt. This page is also available as Markdown.

How to test

Check that your address validation automation works

Test seed

Every vector on this page is derived from a single seed phrase, so you can check your implementation on all three chain families with one wallet.

seed: bamboo feed assist glove soda merry medal vanish almost solid bean loop
code: 1234
message: MtPelerin-1234
Chain
Derivation path
Address

Ethereum

m/44'/60'/0'/0/0

0xEa22e16EA50A43092853329F3cEEa0825Cb9B03e

Bitcoin, native SegWit

m/84'/0'/0'/0/0

bc1qjq907v02ra3pde52zza345c7cj52guwuucz527

Bitcoin, Taproot

m/86'/0'/0'/0/0

bc1p2uj2zul3vl87grth4ju9fqmam5gxsncr4w9sdzvdv44sr90v657s4ey7a0

Bitcoin, nested SegWit

m/49'/0'/0'/0/0

39MJF9h9YUcHtmgB9yfpqhPcuVFA848unL

Bitcoin, legacy

m/44'/0'/0'/0/0

17RudQJ5mepFTCoqErbuwRkey6hPWULcnb

Tezos

m/44'/1729'/0'/0'

tz1dnCbNYHDoxmHss9kEQVjWQj6GvYX4gYp5

The same code is reused across all the vectors below to keep them comparable. In production you must generate a different code for each address.

EVM

What goes in hash

The raw bytes returned by personal_sign, encoded in base64. The widget accepts any EVM network, and smart contract wallets are supported through the chain parameter, see below.

Test vector

A second vector, from a standalone private key with no seed phrase:

Browser, Metamask

NodeJS, ethers

Smart contract wallets

To validate the address of a smart contract wallet (EIP-1271), add the chain parameter so the on-chain isValidSignature call targets the right network. Counterfactual wallets that are not deployed yet are also accepted, through EIP-6492.

Accepted values: arbitrum_mainnet, avalanche_mainnet, base_mainnet, bsc_mainnet (BNB Chain), celo_mainnet, mainnet (Ethereum), matic_mainnet (Polygon), optimism_mainnet, rsk_mainnet (Rootstock), sonic_mainnet, tempo_mainnet, xdai_mainnet (Gnosis Chain), zksync_mainnet.

Ready to use URL

Bitcoin

What goes in hash

The base64 signature of the message, sent as is. Two schemes are accepted:

  • BIP-322 simple, for native SegWit (bc1q...), nested SegWit (3...) and single-key-spend Taproot (bc1p...). This is what modern wallets return.

  • BIP-137, the legacy signmessage scheme, for legacy addresses (1...).

Unlike the EVM flow, there is no hex to base64 conversion to do: Bitcoin wallets already return base64.

Test vector, native SegWit

Test vector, Taproot

Note Taproot is the one exception on this page: BIP-340 signatures embed auxiliary random data, so signing the same message twice with the same key gives two different signatures. Yours will not match the value above, and both are valid. Every other vector on this page is deterministic and must match byte for byte.

Test vector, nested SegWit

Test vector, legacy

Browser, wallet extensions

Wallets that implement message signing return the base64 signature directly, so the value goes straight into hash once URL encoded. Ask for the BIP-322 scheme when the wallet lets you choose:

NodeJS, bip322-js

For a legacy address, bitcoinjs-message produces the accepted BIP-137 form:

Ready to use URLs

Native SegWit:

Taproot:

Nested SegWit:

Legacy:

Info Base64 signatures contain +, / and =, which all have a meaning in a query string. If your signature is refused, check that they were encoded as %2B, %2F and %3D.

Tezos

What the wallet signs

Tezos does not sign the message directly. It signs the Michelson PACK form of the message prefixed with Tezos Signed Message: , that is the two bytes 05 01, the byte length on 4 bytes big-endian, then the UTF-8 bytes.

For the code 1234, the bytes handed to the wallet are:

The armored block

The hash parameter is not a bare signature: it is the standard Tezos armored block, exactly 6 lines joined by \n. A missing line, an extra line, a trailing newline or \r\n line endings are all rejected.

  • Line 2: Tezos Signed Message: followed by MtPelerin-{code}, byte for byte.

  • Line 4: the signer's public key.

  • Line 5: the signature.

The public key on line 4 must correspond to the address passed in addr. A block signed by a different key is rejected, even when the signature itself is valid.

Test vector

Browser, Beacon SDK

NodeJS, Taquito

Ready to use URL

Supported Tezos addresses

  • tz1 (Ed25519), tz2 (secp256k1) and tz3 (P-256) are supported.

  • KT1 originated accounts (smart contracts) and tz4 (BLS) cannot be validated by signature.

  • The address is case sensitive. Pass it exactly as the wallet returns it, never lowercased.

Lightning

Lightning accounts cannot be validated through this URL mechanism, because the proof is produced by the node key while the account holds a Lightning address. They are validated inside the widget, or by paying a 1 sat invoice.

Last updated