Skip to content

Bridge Operations

This section covers core asset bridging between Bittensor and EVM chains (e.g. Ethereum) using sdk.bridge.


Before initiating a bridge, fetch supported chains and assets to populate your UI.

// Get all supported chains
const chains = await sdk.api.getSupportedChains();
console.log('Supported Chains:', chains);
// Get all supported assets (paginated)
const assetsResponse = await sdk.api.getAssetList();
const assets = Array.isArray(assetsResponse?.data?.assets)
? assetsResponse.data.assets
: Array.isArray(assetsResponse?.data)
? assetsResponse.data
: Array.isArray(assetsResponse)
? assetsResponse
: [];
console.log('Supported Assets:', assets);

Calculate the bridge fee and the estimated amount the recipient will receive before initiating a transaction.

const estimate = await sdk.bridge.getBridgeFeeEstimate({
fromToken: 'wtao',
toToken: 'tao',
amount: 1.5,
});
if (estimate.success) {
console.log(`Fee: ${estimate.data.fee}`);
console.log(`Recipient gets: ${estimate.data.recipientAmount}`);
}

See the Fee Schedule for a full breakdown of base and percentage fees per direction.


Bridging is a two-step process:

  1. Request bridge data — Call sdk.bridge.bridge() to receive the transaction payload.
  2. Sign & send — Use your connected wallet to broadcast the transaction on-chain.
PropertyTypeRequiredDescription
fromWalletstringSender wallet address.
toWalletstringRecipient wallet address on the destination chain.
fromTokenstringSource token symbol, lowercase (e.g. wtao).
toTokenstringDestination token symbol, lowercase (e.g. tao).
fromChainstringSource chain ID (e.g. ethereum).
toChainstringDestination chain ID (e.g. bittensor).
amountnumberAmount to bridge.
subnetIdnumber⚠️ ConditionalRequired for Bittensor bridging. Use 0 for TAO, or the subnet ID for Alpha.

The SDK returns a constructed evmTransaction object ready to sign and send.

// Step 1 — Request bridge payload
const response = await sdk.bridge.bridge({
fromChain: 'ethereum',
toChain: 'bittensor',
fromToken: 'wtao',
toToken: 'tao',
fromWallet: '0xEvmSender...',
toWallet: '5BitRecip...',
amount: 10,
});
// Step 2 — Send via wallet provider
if (response.evmTransaction) {
const { to, data, value } = response.evmTransaction;
const txHash = await window.ethereum.request({
method: 'eth_sendTransaction',
params: [{ from: '0xEvmSender...', to, data, value }],
});
console.log('Bridge transaction sent:', txHash);
}

The SDK response includes:

FieldDescription
identifierUnique transaction ID — must be included in the on-chain remark.
toAddressBridge admin coldkey (destination of the stake transfer).
subnetDestinationHotkeyTarget hotkey for the stake transfer.
// Step 1 — Request bridge payload
const response = await sdk.bridge.bridge({
fromChain: 'bittensor',
toChain: 'ethereum',
fromToken: 'tao',
toToken: 'wtao',
fromWallet: '5BitSender...',
toWallet: '0xEvmRecip...',
amount: 5,
subnetId: 0, // TAO always uses subnetId 0
});
const { identifier, toAddress, subnetDestinationHotkey } = response;
// Step 2 — Construct and send the batched Bittensor transaction
async function sendTaoStakeBridgeTx(
sender,
amount,
adminColdkey,
hotkey,
subnetId,
bridgeIdentifier,
) {
const provider = new WsProvider('wss://finney.opentensor.ai:443');
const api = await ApiPromise.create({ provider });
const injector = await web3FromSource(sender.source);
// Convert amount to RAO (1 TAO = 1e9 RAO)
const amountRao = api.createType('Balance', amount * 1e9).toString();
const transferStakeTx = api.tx.subtensorModule.transferStake(
adminColdkey, // Bridge coldkey (from toAddress)
hotkey, // Destination hotkey (from subnetDestinationHotkey)
subnetId, // Origin subnet (0 for TAO)
subnetId, // Destination subnet (0 for TAO)
amountRao,
);
const remarkTx = api.tx.system.remarkWithEvent(bridgeIdentifier);
const batchTx = api.tx.utility.batchAll([transferStakeTx, remarkTx]);
await batchTx.signAndSend(sender.address, { signer: injector.signer }, (result) => {
console.log('Tx status:', result.status.type);
});
}

Bridging subnet Alpha tokens uses the same transferStake + remark batch pattern. The subnetId corresponding to the subnet must be provided.

// Step 1 — Request bridge payload
const response = await sdk.bridge.bridge({
fromChain: 'bittensor',
toChain: 'ethereum',
fromToken: 'alpha',
toToken: 'walpha',
fromWallet: '5BitSender...',
toWallet: '0xEvmRecip...',
amount: 100,
subnetId: 1, // Required — use the correct subnet ID for this Alpha token
});
const { identifier, toAddress, subnetDestinationHotkey } = response;
// Step 2 — Construct and send the batched Bittensor transaction
async function sendAlphaBridgeTx(sender, amount, adminColdkey, hotkey, subnetId, bridgeIdentifier) {
const provider = new WsProvider('wss://finney.opentensor.ai:443');
const api = await ApiPromise.create({ provider });
const injector = await web3FromSource(sender.source);
const amountRao = api.createType('Balance', amount * 1e9).toString();
const transferStakeTx = api.tx.subtensorModule.transferStake(
adminColdkey, // Bridge coldkey (from toAddress)
hotkey, // Subnet hotkey (from subnetDestinationHotkey)
subnetId, // Origin subnet ID
subnetId, // Destination subnet ID
amountRao,
);
const remarkTx = api.tx.system.remarkWithEvent(bridgeIdentifier);
const batchTx = api.tx.utility.batchAll([transferStakeTx, remarkTx]);
await batchTx.signAndSend(sender.address, { signer: injector.signer }, (result) => {
console.log('Tx status:', result.status.type);
});
}

This follows the same pattern as the standard EVM burn (wTAO → TAO).

// Step 1 — Request bridge payload
const response = await sdk.bridge.bridge({
fromChain: 'ethereum',
toChain: 'bittensor',
fromToken: 'walpha',
toToken: 'alpha',
fromWallet: '0xEvmSender...',
toWallet: '5BitRecip...',
amount: 100,
subnetId: 1, // Required for Alpha — must match the target subnet
});
// Step 2 — Execute EVM burn via wallet
if (response.evmTransaction) {
await window.ethereum.request({
method: 'eth_sendTransaction',
params: [response.evmTransaction],
});
}

DirectionMethodOn-chain ActionsubnetId Required
EVM → Bittensor (wTAO → TAO)bridge()EVM burn via evmTransactionNo
Bittensor → EVM (TAO → wTAO)bridge()transferStake + remark batchYes (0)
Bittensor → EVM (Alpha → wAlpha)bridge()transferStake + remark batchYes (subnet ID)
EVM → Bittensor (wAlpha → Alpha)bridge()EVM burn via evmTransactionYes (subnet ID)