tomi Domains
tomi Domains
tomi Domains
  • Introduction
    • Domains
      • Terminology
      • Frequently Asked Questions
      • Domains Deployments
      • Registrar Frequently Asked Questions
      • DNS Registrar guide
      • Domains Improvement Proposals
      • DomainsIP-2: Initial Hash Registrar
      • DomainsIP-3: Reverse Resolution
      • DomainsIP-4: Support for contract ABIs
      • DomainsIP-5: Text Records
      • DomainsIP-6: DNS-in-Domains
      • DomainsIP-7: Interface Discovery
      • DomainsIP-8: Multichain Address Resolution
      • DomainsIP-9: Wildcard Resolution
      • DomainsIP-10: EVM compatible Chain Address Resolution
      • DomainsIP-11: Avatar Text Records
      • DomainsIP-12: SAFE Authentication for Domains
      • DomainsIP-13: On-chain Source Parameter
      • Dapp Developer Guide
      • Managing Names
      • Registering & Renewing Names
      • Domains Front-End Design Guidelines
      • Domains AS NFT
      • Domains Layer2 and offchain data support
      • Domains Data guide
      • Name Processing
      • Registry
      • ReverseRegistrar
      • TestRegistrar
      • PublicResolver
      • .tomi Permanent Registrar
        • Registrar
        • Controller
      • DNS Registrar
      • Subgraph
        • Query Examples
      • Resolving Names On-chain
      • Writing a Resolver
      • Writing a Registrar
      • Guide for DApp Developers
      • Technical Description
Powered by GitBook
On this page
  1. Introduction
  2. Domains

DomainsIP-8: Multichain Address Resolution

Introduces new overloads for the `addr` field for Domains resolvers, which permit resolution of addresses for other blockchains via Domains (formerly EIP-2304).

Specification

A new accessor function for resolvers is specified:

function addr(bytes32 node, uint coinType) external view returns(bytes memory);

When called on a resolver, this function must return the cryptocurrency address for the specified namehash and coin type. A zero-length string must be returned if the specified coin ID does not exist on the specified node.

coinType is the cryptocurrency coin type index from SLIP44.

The return value is the cryptocurrency address in its native binary format. Detailed descriptions of the binary encodings for several popular chains are provided in the Address Encoding section below.

A new event for resolvers is defined:

event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);

Resolvers MUST emit this event on each change to the address for a name and coin type.

Recommended accessor functions

The following function provides the recommended interface for changing the addresses stored for a node. Resolvers SHOULD implement this interface for setting addresses unless their needs dictate a different interface.

function setAddr(bytes32 node, uint coinType, bytes calldata addr);

setAddr adds or replaces the address for the given node and coin type. The parameters for this function are as per those described in addr() above.

This function emits an AddressChanged event with the new address; see also the backwards compatibility section below for resolvers that also support addr(bytes32).

Address Encoding

In general, the native binary representation of the address should be used, without any checksum commonly used in the text representation.

A table of encodings for common blockchains is provided, followed by a more detailed description of each format. In the table, 'encodings' lists the address encodings supported by that chain, along with any relevant parameters. Details of those address encodings are described in the following sections.

Cryptocurrency
Coin Type
Encoding

Bitcoin

0

P2PKH(0x00), P2SH(0x05), SegWit('bc')

Litecoin

2

P2PKH(0x30), P2SH(0x32), P2SH(0x05), SegWit('ltc')

Dogecoin

3

P2PKH(0x1e), P2SH(0x16)

Monacoin

22

P2PKH(0x32), P2SH(0x05)

Ethereum

60

ChecksummedHex

Ethereum Classic

61

ChecksummedHex

Rootstock

137

ChecksummedHex(30)

Ripple

144

Ripple

Bitcoin Cash

145

P2PKH(0x00), P2SH(0x05), CashAddr

Binance

714

Bech32('bnb')

SegWit(hrp)

The scriptPubkey encoding for a bech32 address, as defined in BIP141, is OP_n, where n is the witness version, followed by a push of the witness program. Note this warning from BIP173:

Implementations should take special care when converting the address to a scriptPubkey, where witness version n is stored as OP_n. OP_0 is encoded as 0x00, but OP_1 through OP_16 are encoded as 0x51 though 0x60 (81 to 96 in decimal). If a bech32 address is converted to an incorrect scriptPubKey the result will likely be either unspendable or insecure.

ChecksummedHex(chainId?)

To translate a text format checksummed hex address into binary format, simply remove the '0x' prefix and hex decode it. 0x314159265dD8dbb310642f98f50C066173C1259b is hex-decoded and stored as the 20 bytes 314159265dd8dbb310642f98f50c066173c1259b.

When encoding an address from binary to text, an EIP55/RSKIP60 checksum MUST be used - so the correct encoding of the above address for Ethereum is 0x314159265dD8dbb310642f98f50C066173C1259b.

Ripple

Both address types should be stored in Domains by performing ripple's version of base58check decoding and storing them directly (including version byte). For example, the ripple address rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn decodes to and is stored as 004b4e9c06f24296074f7bc48f92a97916c6dc5ea9, while the address X7qvLs7gSnNoKvZzNWUT2e8st17QPY64PPe7zriLNuJszeg decodes to and is stored as 05444b4e9c06f24296074f7bc48f92a97916c6dc5ea9000000000000000000.

CashAddr

Bech32

For example, the BNB address bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2 decodes to the binary representation 40c2979694bbc961023d1d27be6fc4d21a9febe6, which is stored directly in Domains.

Example

An example implementation of a resolver that supports this DomainsIP is provided here:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

import "../ResolverBase.sol";
import "./IAddrResolver.sol";
import "./IAddressResolver.sol";

abstract contract AddrResolver is IAddrResolver, IAddressResolver, ResolverBase {
   uint constant private COIN_TYPE_ETH = 60;

   mapping(bytes32=>mapping(uint=>bytes)) _addresses;

   /**
    * Sets the address associated with an TDNS node.
    * May only be called by the owner of that node in the TDNS registry.
    * @param node The node to update.
    * @param a The address to set.
    */
   function setAddr(bytes32 node, address a) virtual external authorised(node) {
       setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
   }

   /**
    * Returns the address associated with an TDNS node.
    * @param node The TDNS node to query.
    * @return The associated address.
    */
   function addr(bytes32 node) virtual override public view returns (address payable) {
       bytes memory a = addr(node, COIN_TYPE_ETH);
       if(a.length == 0) {
           return payable(0);
       }
       return bytesToAddress(a);
   }

   function setAddr(bytes32 node, uint coinType, bytes memory a) virtual public authorised(node) {
       emit AddressChanged(node, coinType, a);
       if(coinType == COIN_TYPE_ETH) {
           emit AddrChanged(node, bytesToAddress(a));
       }
       _addresses[node][coinType] = a;
   }

   function addr(bytes32 node, uint coinType) virtual override public view returns(bytes memory) {
       return _addresses[node][coinType];
   }

   function supportsInterface(bytes4 interfaceID) virtual override public view returns(bool) {
       return interfaceID == type(IAddrResolver).interfaceId || interfaceID == type(IAddressResolver).interfaceId || super.supportsInterface(interfaceID);
   }

   function bytesToAddress(bytes memory b) internal pure returns(address payable a) {
       require(b.length == 20);
       assembly {
           a := div(mload(add(b, 32)), exp(256, 12))
       }
   }

   function addressToBytes(address a) internal pure returns(bytes memory b) {
       b = new bytes(20);
       assembly {
           mstore(add(b, 32), mul(a, exp(256, 12)))
       }
   }
}

An implementation of this interface is provided in the ensdomains/resolvers repository.

Backwards Compatibility

If the resolver supports the addr(bytes32) interface defined in DomainsIP-1, the resolver MUST treat this as a special case of this new specification in the following ways:

  • The value returned by addr(node) from DomainsIP-1 should always match the value returned by addr(node, 60) (60 is the coin type ID for Ethereum).

  • Anything that causes the AddrChanged event from DomainsIP-1 to be emitted must also emit an AddressChanged event from this DomainsIP, with the coinType specified as 60, and vice-versa.

Tests

The table below specifies test vectors for valid address encodings for each cryptocurrency described above.

Cryptocurrency
Coin Type
Text
Onchain (hex)

Bitcoin

0

1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa

3Ai1JZ8pdJb2ksieUV8FsxSNVJCpoPi8W6

BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4

76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac

a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1887

0014751e76e8199196d454941c45d1b3a323f1433bd6

Litecoin

2

LaMT348PWRnrqeeWArpwQPbuanpXDZGEUz

MQMcJhpWHYVeQArcZR3sBgyPZxxRtnH441

ltc1qdp7p2rpx4a2f80h7a4crvppczgg4egmv5c78w8

76a914a5f4d12ce3685781b227c1f39548ddef429e978388ac

a914b48297bff5dadecc5f36145cec6a5f20d57c8f9b87

0014687c150c26af5493befeed7036043812115ca36c

Dogecoin

3

DBXu2kgc3xtvCUWFcxFE3r9hEYgmuaaCyD

AF8ekvSf6eiSBRspJjnfzK6d1EM6pnPq3G

76a9144620b70031f0e9437e374a2100934fba4911046088a

a914f8f5d99a9fc21aa676e74d15e7b8134557615bda87

Monacoin

22

MHxgS2XMXjeJ4if2PRRbWYcdwZPWfdwaDT

76a9146e5bb7226a337fe8307b4192ae5c3fab9fa9edf588ac

Ethereum

60

0x314159265dD8dbb310642f98f50C066173C1259b

314159265dd8dbb310642f98f50c066173c1259b

Rootstock

137

0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD

5aaeb6053f3e94c9b9a09f33669435e7ef1beaed

Ripple

144

rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn

X7qvLs7gSnNoKvZzNWUT2e8st17QPY64PPe7zriLNuJszeg

004b4e9c06f24296074f7bc48f92a97916c6dc5ea9

05444b4e9c06f24296074f7bc48f92a97916c6dc5ea9000000000000000000

Bitcoin Cash

145

1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu

bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a

3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC

bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq

76a91476a04053bda0a88bda5177b86a15c3b29f55987388ac

76a91476a04053bda0a88bda5177b86a15c3b29f55987388ac

a91476a04053bda0a88bda5177b86a15c3b29f55987387

a91476a04053bda0a88bda5177b86a15c3b29f55987387

Binance

714

bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2

40c2979694bbc961023d1d27be6fc4d21a9febe6

PreviousDomainsIP-7: Interface DiscoveryNextDomainsIP-9: Wildcard Resolution

Last updated 9 months ago

SegWit addresses are encoded with. Bech32 addresses consist of a human-readable part - 'bc' for Bitcoin mainnet - and a machine readable part. For SegWit addresses, this decodes to a 'witness version', between 0 and 15, and a 'witness program', as defined in.

A checksum format is specified by EIP-55, and extended by, which specifies a means of including the chain ID in the checksum. The checksum on a text format address must be checked. Addresses with invalid checksums that are not all uppercase or all lowercase MUST be rejected with an error. Implementations may choose whether to accept non-checksummed addresses, but the authors recommend at least providing a warning to users in this situation.

Ripple addresses are encoded using a version of base58check with an alternative alphabet, described. Two types of ripple addresses are supported, 'r-addresses', and 'X-addresss'. r-addresses consist of a version byte followed by a 20 byte hash, while X-addresses consist of a version byte, a 20 byte hash, and a tag, specified.

Bitcoin Cash defines a new address format called 'CashAddr', specified. This uses a variant of bech32 encoding to encode and decode (non-segwit) Bitcoin Cash addresses, using a prefix of 'bitcoincash:'. A CashAddr should be decoded using this bech32 variant, then converted and stored based on its type (P2PKH or P2SH) as described in the relevant sections above.

addresses consist of a human-readable part - for example, 'bnb' for Binance - and a machine readable part. The encoded data is simply the address, which can be converted to binary and stored directly.

bech32
BIP141
RSKIP60
here
here
here
Bech32