Skip to main content
SUBMIT A PRSUBMIT AN ISSUElast edit: Jun 02, 2025

Convert Ethereum (H160) Address to Substrate (SS58)

This tutorial demonstrates how to convert between Ethereum (H160) and Substrate (SS58) addresses. This is useful for moving across the boundary between EVM wallets and Subtensor Wallets on the Bittensor blockchain.

In what follows, we'll create a wallet in Metamask and convert it's public key to ss58 format in order to target it with a balance transfer using BTCLI.

Procedure

Create Wallet with MetaMask

  1. Install Metamask wallet browser extension, if you haven't already.
  2. Create a new account or import an existing one.
  3. Add the Bittensor EVM network to MetaMask:
    • Network Name: Bittensor EVM
    • RPC URL: https://test.chain.opentensor.ai
    • Chain ID: 945
    • Currency Symbol: TAO
    • Block Explorer URL: test.chain.opentensor.ai
  4. Click Save.
  5. Click Switch network.

Install the EVM Examples repo

  1. Clone the Opentensor EVM-Bittensor GitHub repo:

    git clone https://github.com/opentensor/evm-bittensor.git

  2. Navigate to evm-bittensor directory:

    cd evm-bittensor

  3. Install the dependencies:npm install

Set your config

Convert Address for Bittensor

Run the conversion script, replacing ethereumAddress with your address:

node convert-address.js

Note down the SS58 address output by the script - this is your wallet's Subtensor address on the Bittensor network.

Transfer TAO to EVM Wallet

Use btcli to transfer TAO to your SS58 address. Here we will use test network.

btcli wallet transfer --destination <your ss58 address> --network test

Verify Balance in MetaMask

  1. Open MetaMask
  2. Ensure you're connected to the Bittensor EVM network
  3. Your TAO balance should now be visible in MetaMask
  4. You can now use this wallet for EVM transactions on Bittensor

Conversion Script

Below is the code used above for the conversion.

Source code:

//convert-address.js

const { convertH160ToSS58 } = require('./address-mapping.js');

async function main() {
const ethereumAddress = "0xbdA293c21DfCaDDAeB9aa8b98455d42325599d23";

const ss58Address = convertH160ToSS58(ethereumAddress);
console.log(`ss58 mirror: ${ss58Address}`);
}

main().catch(console.error);
// address-mapping.js
function convertH160ToSS58(ethAddress) {
const prefix = 'evm:';
const prefixBytes = new TextEncoder().encode(prefix);
const addressBytes = hexToU8a(ethAddress.startsWith('0x') ? ethAddress : `0x${ethAddress}`);
const combined = new Uint8Array(prefixBytes.length + addressBytes.length);

// Concatenate prefix and Ethereum address
combined.set(prefixBytes);
combined.set(addressBytes, prefixBytes.length);

// Hash the combined data (the public key)
const hash = blake2AsU8a(combined);

// Convert the hash to SS58 format
const ss58Address = encodeAddress(hash, 42); // Network ID 42 for Bittensor
return ss58Address;
}