From 317944d00683f24606d84eb5a10189980aafca84 Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Wed, 14 May 2025 14:02:04 -0700 Subject: [PATCH 01/27] wip --- docs/evm-tutorials/index.md | 30 +++ docs/evm-tutorials/metagraph-precompile.md | 201 +++++++++++++++++++++ docs/evm-tutorials/neuron-precompile.md | 192 ++++++++++++++++++++ docs/evm-tutorials/subnet-precompile.md | 153 ++++++++++++++++ sidebars.js | 7 +- 5 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 docs/evm-tutorials/metagraph-precompile.md create mode 100644 docs/evm-tutorials/neuron-precompile.md create mode 100644 docs/evm-tutorials/subnet-precompile.md diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index d11c91272..f94256d3c 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -38,6 +38,36 @@ Before you proceed to use EVM on subtensor, make a note of the following: 1. **EVM smart contract executes on subtensor**: The EVM feature allows the subtensor blockchain to execute Ethereum-compatible smart contracts. Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain. 2. **1 TAO = 1e18 on subtensor EVM**: While working with the subtensor EVM, 1 TAO should be written as 1 followed by 18 zeroes, i.e., 1e18. See this code example: [https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58). +## Available Precompiles + +The following precompiles are available on the Bittensor EVM: + +### Standard Ethereum Precompiles +- `ECRecover` (0x1) - Recover the address associated with the public key from elliptic curve signature +- `Sha256` (0x2) - SHA-256 hash function +- `Ripemd160` (0x3) - RIPEMD-160 hash function +- `Identity` (0x4) - Identity function (returns input data) +- `Modexp` (0x5) - Modular exponentiation +- `Sha3FIPS256` (0x400) - SHA3-256 hash function (FIPS variant) +- `ECRecoverPublicKey` (0x401) - Recover the public key from an elliptic curve signature + +### Bittensor-Specific Precompiles +- `Ed25519Verify` - Verify Ed25519 signatures +- `BalanceTransfer` - Transfer TAO between accounts +- `StakingPrecompileV2` (0x805) - Main staking operations including: + - `addStake` - Add stake to a hotkey + - `removeStake` - Remove stake from a hotkey + - `moveStake` - Move stake between hotkeys + - `transferStake` - Transfer stake between coldkeys + - `getTotalColdkeyStake` - Get total stake for a coldkey + - `getTotalHotkeyStake` - Get total stake for a hotkey + - `getStake` - Get stake between specific hotkey and coldkey + - `addProxy` - Add a proxy delegate + - `removeProxy` - Remove a proxy delegate +- `SubnetPrecompile` - Manage subnet operations +- `MetagraphPrecompile` - Interact with the metagraph +- `NeuronPrecompile` - Manage neuron operations + Run the below tutorials to learn how to use the EVM feature on the Bittensor blockchain. diff --git a/docs/evm-tutorials/metagraph-precompile.md b/docs/evm-tutorials/metagraph-precompile.md new file mode 100644 index 000000000..cfbc41c93 --- /dev/null +++ b/docs/evm-tutorials/metagraph-precompile.md @@ -0,0 +1,201 @@ +--- +title: "Metagraph Precompile" +--- + +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +# Metagraph Precompile + +The metagraph precompile allows you to query information about neurons, their relationships, and network state in the Bittensor network. This precompile provides read-only access to the metagraph data through smart contracts. + +## Precompile Address + +The metagraph precompile is available at address `0x802` (2050 in decimal). + +## Available Functions + +### Network Statistics + +#### `getUidCount(uint16 netuid) returns (uint16)` +Get the total number of UIDs (neurons) in a subnet. + +```solidity +function getUidCount(uint16 netuid) external view returns (uint16); +``` + +### Neuron Information + +#### `getStake(uint16 netuid, uint16 uid) returns (uint64)` +Get the total stake of a neuron in a subnet. + +```solidity +function getStake(uint16 netuid, uint16 uid) external view returns (uint64); +``` + +#### `getRank(uint16 netuid, uint16 uid) returns (uint16)` +Get the rank of a neuron in a subnet. + +```solidity +function getRank(uint16 netuid, uint16 uid) external view returns (uint16); +``` + +#### `getTrust(uint16 netuid, uint16 uid) returns (uint16)` +Get the trust score of a neuron in a subnet. + +```solidity +function getTrust(uint16 netuid, uint16 uid) external view returns (uint16); +``` + +#### `getConsensus(uint16 netuid, uint16 uid) returns (uint16)` +Get the consensus score of a neuron in a subnet. + +```solidity +function getConsensus(uint16 netuid, uint16 uid) external view returns (uint16); +``` + +#### `getIncentive(uint16 netuid, uint16 uid) returns (uint16)` +Get the incentive score of a neuron in a subnet. + +```solidity +function getIncentive(uint16 netuid, uint16 uid) external view returns (uint16); +``` + +#### `getDividends(uint16 netuid, uint16 uid) returns (uint16)` +Get the dividends of a neuron in a subnet. + +```solidity +function getDividends(uint16 netuid, uint16 uid) external view returns (uint16); +``` + +#### `getEmission(uint16 netuid, uint16 uid) returns (uint64)` +Get the emission of a neuron in a subnet. + +```solidity +function getEmission(uint16 netuid, uint16 uid) external view returns (uint64); +``` + +#### `getVtrust(uint16 netuid, uint16 uid) returns (uint16)` +Get the validator trust score of a neuron in a subnet. + +```solidity +function getVtrust(uint16 netuid, uint16 uid) external view returns (uint16); +``` + +### Neuron Status + +#### `getValidatorStatus(uint16 netuid, uint16 uid) returns (bool)` +Check if a neuron is a validator in a subnet. + +```solidity +function getValidatorStatus(uint16 netuid, uint16 uid) external view returns (bool); +``` + +#### `getLastUpdate(uint16 netuid, uint16 uid) returns (uint64)` +Get the timestamp of the last update for a neuron in a subnet. + +```solidity +function getLastUpdate(uint16 netuid, uint16 uid) external view returns (uint64); +``` + +#### `getIsActive(uint16 netuid, uint16 uid) returns (bool)` +Check if a neuron is active in a subnet. + +```solidity +function getIsActive(uint16 netuid, uint16 uid) external view returns (bool); +``` + +### Neuron Keys + +#### `getHotkey(uint16 netuid, uint16 uid) returns (bytes32)` +Get the hotkey of a neuron in a subnet. + +```solidity +function getHotkey(uint16 netuid, uint16 uid) external view returns (bytes32); +``` + +#### `getColdkey(uint16 netuid, uint16 uid) returns (bytes32)` +Get the coldkey of a neuron in a subnet. + +```solidity +function getColdkey(uint16 netuid, uint16 uid) external view returns (bytes32); +``` + +### Axon Information + +#### `getAxon(uint16 netuid, uint16 uid) returns (AxonInfo)` +Get the axon information of a neuron in a subnet. + +```solidity +struct AxonInfo { + uint64 block; + uint32 version; + uint128 ip; + uint16 port; + uint8 ip_type; + uint8 protocol; +} + +function getAxon(uint16 netuid, uint16 uid) external view returns (AxonInfo); +``` + +## Example Usage + +Here's an example of how to use the metagraph precompile in a smart contract: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IMetagraphPrecompile { + struct AxonInfo { + uint64 block; + uint32 version; + uint128 ip; + uint16 port; + uint8 ip_type; + uint8 protocol; + } + + function getUidCount(uint16 netuid) external view returns (uint16); + function getStake(uint16 netuid, uint16 uid) external view returns (uint64); + function getRank(uint16 netuid, uint16 uid) external view returns (uint16); + function getHotkey(uint16 netuid, uint16 uid) external view returns (bytes32); + function getAxon(uint16 netuid, uint16 uid) external view returns (AxonInfo); +} + +contract MetagraphQuerier { + address constant METAGRAPH_PRECOMPILE = 0x802; + IMetagraphPrecompile metagraph = IMetagraphPrecompile(METAGRAPH_PRECOMPILE); + + function getNeuronInfo(uint16 netuid, uint16 uid) external view returns ( + uint64 stake, + uint16 rank, + bytes32 hotkey, + IMetagraphPrecompile.AxonInfo memory axon + ) { + stake = metagraph.getStake(netuid, uid); + rank = metagraph.getRank(netuid, uid); + hotkey = metagraph.getHotkey(netuid, uid); + axon = metagraph.getAxon(netuid, uid); + } + + function getNetworkStats(uint16 netuid) external view returns (uint16 totalNeurons) { + totalNeurons = metagraph.getUidCount(netuid); + } +} +``` + +## Important Notes + +1. All functions in the metagraph precompile are view functions and do not modify state. +2. The precompile provides read-only access to the metagraph data. +3. All queries are specific to a subnet identified by its `netuid`. +4. The `uid` parameter must be valid for the specified subnet. +5. Some functions may return default values or revert if the neuron is not found. + +## Next Steps + +- Learn about [staking operations](/evm-tutorials/staking-precompile) +- Understand [subnet management](/evm-tutorials/subnet-precompile) +- Explore [neuron operations](/evm-tutorials/neuron-precompile) \ No newline at end of file diff --git a/docs/evm-tutorials/neuron-precompile.md b/docs/evm-tutorials/neuron-precompile.md new file mode 100644 index 000000000..2bec674d4 --- /dev/null +++ b/docs/evm-tutorials/neuron-precompile.md @@ -0,0 +1,192 @@ +--- +title: "Neuron Precompile" +--- + +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +# Neuron Precompile + +The neuron precompile allows you to interact with neuron operations on the Bittensor network through smart contracts. This precompile provides functionality for setting weights, registering neurons, and serving axons. + +## Precompile Address + +The neuron precompile is available at address `0x804` (2052 in decimal). + +## Available Functions + +### Weight Management + +#### `setWeights(uint16 netuid, uint16[] dests, uint16[] weights, uint64 version_key)` +Set weights for multiple destination neurons in a subnet. This is a payable function. + +```solidity +function setWeights( + uint16 netuid, + uint16[] dests, + uint16[] weights, + uint64 version_key +) external payable; +``` + +#### `commitWeights(uint16 netuid, bytes32 commit_hash)` +Commit weights for a subnet using a hash. This is a payable function. + +```solidity +function commitWeights(uint16 netuid, bytes32 commit_hash) external payable; +``` + +#### `revealWeights(uint16 netuid, uint16[] uids, uint16[] values, uint16[] salt, uint64 version_key)` +Reveal previously committed weights for a subnet. This is a payable function. + +```solidity +function revealWeights( + uint16 netuid, + uint16[] uids, + uint16[] values, + uint16[] salt, + uint64 version_key +) external payable; +``` + +### Neuron Registration + +#### `burnedRegister(uint16 netuid, bytes32 hotkey)` +Register a new neuron in a subnet by burning TAO. This is a payable function. + +```solidity +function burnedRegister(uint16 netuid, bytes32 hotkey) external payable; +``` + +### Axon Serving + +#### `serveAxon(uint16 netuid, uint32 version, uint128 ip, uint16 port, uint8 ip_type, uint8 protocol, uint8 placeholder1, uint8 placeholder2)` +Serve an axon for a neuron in a subnet. This is a payable function. + +```solidity +function serveAxon( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ip_type, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2 +) external payable; +``` + +#### `serveAxonTls(uint16 netuid, uint32 version, uint128 ip, uint16 port, uint8 ip_type, uint8 protocol, uint8 placeholder1, uint8 placeholder2, bytes certificate)` +Serve a TLS-enabled axon for a neuron in a subnet. This is a payable function. + +```solidity +function serveAxonTls( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ip_type, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2, + bytes certificate +) external payable; +``` + +#### `servePrometheus(uint16 netuid, uint32 version, uint128 ip, uint16 port, uint8 ip_type)` +Serve a Prometheus endpoint for a neuron in a subnet. This is a payable function. + +```solidity +function servePrometheus( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ip_type +) external payable; +``` + +## Example Usage + +Here's an example of how to use the neuron precompile in a smart contract: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface INeuronPrecompile { + function setWeights( + uint16 netuid, + uint16[] calldata dests, + uint16[] calldata weights, + uint64 version_key + ) external payable; + + function burnedRegister(uint16 netuid, bytes32 hotkey) external payable; + + function serveAxon( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ip_type, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2 + ) external payable; +} + +contract NeuronManager { + address constant NEURON_PRECOMPILE = 0x804; + INeuronPrecompile neuron = INeuronPrecompile(NEURON_PRECOMPILE); + + function setNeuronWeights( + uint16 netuid, + uint16[] calldata dests, + uint16[] calldata weights, + uint64 version_key + ) external payable { + neuron.setWeights{value: msg.value}(netuid, dests, weights, version_key); + } + + function registerNeuron(uint16 netuid, bytes32 hotkey) external payable { + neuron.burnedRegister{value: msg.value}(netuid, hotkey); + } + + function serveNeuronAxon( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ip_type, + uint8 protocol + ) external payable { + neuron.serveAxon{value: msg.value}( + netuid, + version, + ip, + port, + ip_type, + protocol, + 0, // placeholder1 + 0 // placeholder2 + ); + } +} +``` + +## Important Notes + +1. Most functions in the neuron precompile are payable and require TAO to be sent with the transaction. +2. The `setWeights` function requires the `dests` and `weights` arrays to be of equal length. +3. The `revealWeights` function requires the `uids`, `values`, and `salt` arrays to be of equal length. +4. All operations are specific to a subnet identified by its `netuid`. +5. The `version_key` parameter is used to track different versions of weights. +6. The `ip_type` parameter in axon serving functions determines the type of IP address (IPv4 or IPv6). +7. The `protocol` parameter in axon serving functions determines the communication protocol. + +## Next Steps + +- Learn about [staking operations](/evm-tutorials/staking-precompile) +- Understand [subnet management](/evm-tutorials/subnet-precompile) +- Explore [metagraph interactions](/evm-tutorials/metagraph-precompile) \ No newline at end of file diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md new file mode 100644 index 000000000..ea351a47f --- /dev/null +++ b/docs/evm-tutorials/subnet-precompile.md @@ -0,0 +1,153 @@ +--- +title: "Subnet Precompile" +--- + +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +# Subnet Precompile + +The subnet precompile allows you to interact with subnet operations on the Bittensor network through smart contracts. This precompile provides functionality for registering networks, managing network parameters, and querying network state. + +## Precompile Address + +The subnet precompile is available at address `0x803` (2051 in decimal). + +## Available Functions + +### Network Registration + +#### `registerNetwork(bytes32 hotkey)` +Register a new network with a hotkey. This is a payable function that requires TAO to be sent with the transaction. + +```solidity +function registerNetwork(bytes32 hotkey) external payable; +``` + +#### `registerNetwork(bytes32 hotkey, string subnet_name, string github_repo, string subnet_contact, string subnet_url, string discord, string description, string additional)` +Register a new network with a hotkey and identity information. This is a payable function that requires TAO to be sent with the transaction. + +```solidity +function registerNetwork( + bytes32 hotkey, + string subnet_name, + string github_repo, + string subnet_contact, + string subnet_url, + string discord, + string description, + string additional +) external payable; +``` + +### Network Parameters + +The subnet precompile provides getter and setter functions for various network parameters: + +#### Rate Limits +- `getServingRateLimit(uint16 netuid) returns (uint64)` +- `setServingRateLimit(uint16 netuid, uint64 serving_rate_limit)` + +#### Difficulty Settings +- `getMinDifficulty(uint16 netuid) returns (uint64)` +- `setMinDifficulty(uint16 netuid, uint64 min_difficulty)` +- `getMaxDifficulty(uint16 netuid) returns (uint64)` +- `setMaxDifficulty(uint16 netuid, uint64 max_difficulty)` +- `getDifficulty(uint16 netuid) returns (uint64)` +- `setDifficulty(uint16 netuid, uint64 difficulty)` + +#### Weights Management +- `getWeightsVersionKey(uint16 netuid) returns (uint64)` +- `setWeightsVersionKey(uint16 netuid, uint64 weights_version_key)` +- `getWeightsSetRateLimit(uint16 netuid) returns (uint64)` +- `setWeightsSetRateLimit(uint16 netuid, uint64 weights_set_rate_limit)` +- `getMaxWeightLimit(uint16 netuid) returns (uint16)` +- `setMaxWeightLimit(uint16 netuid, uint16 max_weight_limit)` +- `getMinAllowedWeights(uint16 netuid) returns (uint16)` +- `setMinAllowedWeights(uint16 netuid, uint16 min_allowed_weights)` + +#### Network Settings +- `getImmunityPeriod(uint16 netuid) returns (uint16)` +- `setImmunityPeriod(uint16 netuid, uint16 immunity_period)` +- `getKappa(uint16 netuid) returns (uint16)` +- `setKappa(uint16 netuid, uint16 kappa)` +- `getRho(uint16 netuid) returns (uint16)` +- `setRho(uint16 netuid, uint16 rho)` +- `getActivityCutoff(uint16 netuid) returns (uint16)` +- `setActivityCutoff(uint16 netuid, uint16 activity_cutoff)` + +#### Registration Settings +- `getNetworkRegistrationAllowed(uint16 netuid) returns (bool)` +- `setNetworkRegistrationAllowed(uint16 netuid, bool registration_allowed)` +- `getNetworkPowRegistrationAllowed(uint16 netuid) returns (bool)` +- `setNetworkPowRegistrationAllowed(uint16 netuid, bool registration_allowed)` + +#### Burn Settings +- `getMinBurn(uint16 netuid) returns (uint64)` +- `setMinBurn(uint16 netuid, uint64 min_burn)` +- `getMaxBurn(uint16 netuid) returns (uint64)` +- `setMaxBurn(uint16 netuid, uint64 max_burn)` + +#### Bonds and Alpha Settings +- `getBondsMovingAverage(uint16 netuid) returns (uint64)` +- `setBondsMovingAverage(uint16 netuid, uint64 bonds_moving_average)` +- `getAlphaValues(uint16 netuid) returns (uint16, uint16)` +- `setAlphaValues(uint16 netuid, uint16 alpha_low, uint16 alpha_high)` + +#### Commit-Reveal Settings +- `getCommitRevealWeightsEnabled(uint16 netuid) returns (bool)` +- `setCommitRevealWeightsEnabled(uint16 netuid, bool enabled)` +- `getCommitRevealWeightsInterval(uint16 netuid) returns (uint64)` +- `setCommitRevealWeightsInterval(uint16 netuid, uint64 interval)` + +#### Liquid Alpha Settings +- `getLiquidAlphaEnabled(uint16 netuid) returns (bool)` +- `setLiquidAlphaEnabled(uint16 netuid, bool enabled)` + +#### Transfer Settings +- `toggleTransfers(uint16 netuid, bool toggle)` + +## Example Usage + +Here's an example of how to use the subnet precompile in a smart contract: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ISubnetPrecompile { + function registerNetwork(bytes32 hotkey) external payable; + function getDifficulty(uint16 netuid) external view returns (uint64); + function setDifficulty(uint16 netuid, uint64 difficulty) external; +} + +contract SubnetManager { + address constant SUBNET_PRECOMPILE = 0x803; + ISubnetPrecompile subnet = ISubnetPrecompile(SUBNET_PRECOMPILE); + + function registerNewNetwork(bytes32 hotkey) external payable { + subnet.registerNetwork{value: msg.value}(hotkey); + } + + function getNetworkDifficulty(uint16 netuid) external view returns (uint64) { + return subnet.getDifficulty(netuid); + } + + function updateNetworkDifficulty(uint16 netuid, uint64 newDifficulty) external { + subnet.setDifficulty(netuid, newDifficulty); + } +} +``` + +## Important Notes + +1. Most setter functions require admin privileges to execute. +2. The `registerNetwork` functions are payable and require TAO to be sent with the transaction. +3. All network parameters are specific to a subnet identified by its `netuid`. +4. Some functions may be restricted based on network permissions and governance settings. + +## Next Steps + +- Learn about [staking operations](/evm-tutorials/staking-precompile) +- Understand [neuron management](/evm-tutorials/neuron-precompile) +- Explore [metagraph interactions](/evm-tutorials/metagraph-precompile) \ No newline at end of file diff --git a/sidebars.js b/sidebars.js index 9a0f61df4..cc7d7287d 100644 --- a/sidebars.js +++ b/sidebars.js @@ -200,11 +200,16 @@ const sidebars = { "evm-tutorials/evm-testnet-with-metamask-wallet", "evm-tutorials/evm-localnet-with-metamask-wallet", "evm-tutorials/evm-mainnet-with-metamask-wallet", + "evm-tutorials/hardhat-config-for-subtensor-evm", + "evm-tutorials/remix-config-for-subtensor-evm", "evm-tutorials/transfer-from-metamask-to-ss58", "evm-tutorials/transfer-between-two-h160-accounts", - "evm-tutorials/hardhat-config-for-subtensor-evm", "evm-tutorials/staking-precompile", "evm-tutorials/ed25519-verify-precompile", + "evm-tutorials/subnet-precompile", + "evm-tutorials/metagraph-precompile", + "evm-tutorials/neuron-precompile", + "evm-tutorials/troubleshooting" ], }, { From fdcec75767ad5a876a97469cef1af99e64cabeec Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Wed, 14 May 2025 14:49:07 -0700 Subject: [PATCH 02/27] wip --- docs/evm-tutorials/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index f94256d3c..96aa37142 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -54,6 +54,7 @@ The following precompiles are available on the Bittensor EVM: ### Bittensor-Specific Precompiles - `Ed25519Verify` - Verify Ed25519 signatures - `BalanceTransfer` - Transfer TAO between accounts +- `StakingPrecompile` - `StakingPrecompileV2` (0x805) - Main staking operations including: - `addStake` - Add stake to a hotkey - `removeStake` - Remove stake from a hotkey @@ -67,6 +68,7 @@ The following precompiles are available on the Bittensor EVM: - `SubnetPrecompile` - Manage subnet operations - `MetagraphPrecompile` - Interact with the metagraph - `NeuronPrecompile` - Manage neuron operations +- UidLookupPrecompile Run the below tutorials to learn how to use the EVM feature on the Bittensor blockchain. From b6f45777cfe051e108b11d3cd7ea6b66d0fc0b99 Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Wed, 14 May 2025 15:43:13 -0700 Subject: [PATCH 03/27] add precompile --- docs/evm-tutorials/staking-precompile.md | 210 ++++++++++++++--------- 1 file changed, 132 insertions(+), 78 deletions(-) diff --git a/docs/evm-tutorials/staking-precompile.md b/docs/evm-tutorials/staking-precompile.md index 1ea10c204..0385e2bd7 100644 --- a/docs/evm-tutorials/staking-precompile.md +++ b/docs/evm-tutorials/staking-precompile.md @@ -7,109 +7,163 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Staking Precompile -Staking precompile allows Ethereum code to interact with the staking feature of subtensor. For example, by using the staking precompile, the subtensor methods [`add_stake`](https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/staking/add_stake.rs) or [`remove_stake`](https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/staking/remove_stake.rs) can be called in order to delegate stake to a hotkey or undelegate stake from a hotkey. +The staking precompile allows you to interact with staking operations on the Bittensor network through smart contracts. This precompile provides functionality for adding and removing stakes, moving stakes between hotkeys, and querying stake information. -In this tutorial you will learn how to interact with staking precompile in two ways: +## Precompile Address -1. Call the staking precompile from another smart contract. -2. Use the staking precompile's ABI and your Metamask wallet to call the staking precompile on EVM localnet. You will use [Remix IDE](https://remix.ethereum.org/) for this. +The staking precompile is available at address `0x805` (2053 in decimal). -## Prerequisites +## Available Functions -1. You should also be comfortable using [Remix IDE](https://remix.ethereum.org/). -2. Read [EVM on Subtensor](./evm-on-subtensor.md) for a basic understanding of what an ABI is and how to use it. +### Stake Management -## Setup EVM localnet, subnet and delegate +#### `addStake(bytes32 hotkey, uint256 amount, uint256 netuid)` +Add stake to a hotkey in a specific subnet. This is a payable function that requires TAO to be sent with the transaction. -1. [Launch EVM localnet](./evm-localnet-with-metamask-wallet.md). Also, follow the instructions of running local chain all the way so that you have a Metamask address with some TAO balance. +```solidity +function addStake(bytes32 hotkey, uint256 amount, uint256 netuid) external payable; +``` -2. On this EVM localnet create one subnet and a delegate hotkey. The commands below will create a subnet, register a neuron and nominate your hotkey as a delegate, in that order: +#### `removeStake(bytes32 hotkey, uint256 amount, uint256 netuid)` +Remove stake from a hotkey in a specific subnet. - ```bash - btcli subnet create --subtensor.chain_endpoint ws://127.0.0.1:9944 - btcli subnet register --subtensor.chain_endpoint ws://127.0.0.1:9944 - btcli root nominate --subtensor.chain_endpoint ws://127.0.0.1:9944 - ``` +```solidity +function removeStake(bytes32 hotkey, uint256 amount, uint256 netuid) external; +``` -3. Save the delegate hotkey address. You will use this in the staking pool use case below. +#### `moveStake(bytes32 origin_hotkey, bytes32 destination_hotkey, uint256 origin_netuid, uint256 destination_netuid, uint256 amount)` +Move stake from one hotkey to another, potentially across different subnets. -4. Disable staking rate limits by setting `targetStakesPerInterval` to 1000. Follow these below steps: - - Open the Polkadot JS app using [this link with encoded transaction](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics/decode/0x0c00132fe803000000000000). - - Click on **Submission** tab. - - From the **using the selected account** field, select **ALICE**. - - Click on **Submit Transaction** at the bottom right. This will open the **authorize transaction** window. - - On this **authorize transaction** window, make sure the **sign and submit** toggle is ON and click on the **Sign and Submit** on the bottom right. +```solidity +function moveStake( + bytes32 origin_hotkey, + bytes32 destination_hotkey, + uint256 origin_netuid, + uint256 destination_netuid, + uint256 amount +) external; +``` -## Call the staking precompile from another smart contract (staking pool use case) +#### `transferStake(bytes32 destination_coldkey, bytes32 hotkey, uint256 origin_netuid, uint256 destination_netuid, uint256 amount)` +Transfer stake from one coldkey to another, potentially across different subnets. -In this interaction you will compile [`stake.sol`](https://github.com/opentensor/evm-bittensor/blob/main/solidity/stake.sol), a smart contract Solidity code and execute it on the subtensor EVM. This `stake.sol` will, in turn, call the staking precompile that is already deployed in the subtensor EVM. +```solidity +function transferStake( + bytes32 destination_coldkey, + bytes32 hotkey, + uint256 origin_netuid, + uint256 destination_netuid, + uint256 amount +) external; +``` -Before you proceed, familiarize yourself with the Solidity code of the [`stake.sol`](https://github.com/opentensor/evm-bittensor/blob/main/solidity/stake.sol) smart contract. +### Stake Queries + +#### `getTotalColdkeyStake(bytes32 coldkey) returns (uint256)` +Get the total stake for a coldkey across all subnets. -1. Copy the text of [`stake.sol`](https://github.com/opentensor/evm-bittensor/blob/main/solidity/stake.sol) contract to Remix IDE. +```solidity +function getTotalColdkeyStake(bytes32 coldkey) external view returns (uint256); +``` -2. You will now convert your delegate hotkey ss58 from the above [Setup EVM localnet, subnet and delegate](#setup-evm-localnet-subnet-and-delegate) step into its corresponding public key. Use the [ss58.org](https://ss58.org/) site to obtain the public key for your delegate hotkey ss58. +#### `getTotalHotkeyStake(bytes32 hotkey) returns (uint256)` +Get the total stake for a hotkey across all subnets. -3. In the `stake.sol` text in Remix IDE, replace the `HOTKEY` constant on line 9, where it says `bytes32 constant HOTKEY = 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d;`, with your delegate hotkey's public key. +```solidity +function getTotalHotkeyStake(bytes32 hotkey) external view returns (uint256); +``` -4. Compile it in Remix IDE. +#### `getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) returns (uint256)` +Get the stake between a specific hotkey and coldkey in a subnet. -5. Connect Remix IDE to Injected Provider - Metamask and your Metamask address that has TAO balance. You will stake this TAO balance to the delegate hotkey's public key. +```solidity +function getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns (uint256); +``` -6. Execute the Stake contract method `stake_from_this_contract_to_alice` and pass 1e^9 to it (1 TAO). +#### `getTotalAlphaStaked(bytes32 hotkey, uint256 netuid) returns (uint256)` +Get the total amount of TAO staked by a hotkey in a specific subnet. -7. Check the stake balance of your delegate hotkey and confirm that it has increased by 1 TAO. +```solidity +function getTotalAlphaStaked(bytes32 hotkey, uint256 netuid) external view returns (uint256); +``` -## Use the staking precompile's ABI from your user account (staking as an individual use case) +#### `getAlphaStakedValidators(bytes32 hotkey, uint256 netuid) returns (bytes32[])` +Get a list of validator addresses that have staked to a specific hotkey in a subnet. -In this tutorial, you will interact directly with the staking precompile by using its ABI, and use your Metamask wallet as the source of TAO to stake. +```solidity +function getAlphaStakedValidators(bytes32 hotkey, uint256 netuid) external view returns (bytes32[]); +``` -1. Copy this below ABI of staking precompile contract into Remix IDE as a new file: +### Proxy Management - ```json - [ - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hotkey", - "type": "bytes32" - } - ], - "name": "addStake", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hotkey", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "removeStake", - "outputs": [], - "stateMutability": "payable", - "type": "function" - } - ] - ``` +#### `addProxy(bytes32 delegate)` +Add a proxy delegate for staking operations. -2. Copy staking precompile address `0x0000000000000000000000000000000000000801` to the **At Address** field in Remix IDE, and click **At Address** button. +```solidity +function addProxy(bytes32 delegate) external; +``` -3. Remix IDE will find the precompile at the precompile address on the subtensor EVM and show it in the list of deployed contracts. Expand the contract, then expand the `addStake` method, and paste the public key of your delegate hotkey into the `hotkey` field. Then click **transact** and wait for the transaction to be completed. +#### `removeProxy(bytes32 delegate)` +Remove a proxy delegate. -4. Follow these steps to see that the stake record is updated in [Polkadot JS app](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/chainstate): - - 1. Select **subtensorModule** + **stake** in the drop-down list. - 2. Paste the delegate hotkey account ID in the first parameter. - 3. Toggle **include option** OFF for the second parameter. - 4. Click the **+** button and find the new stake record. +```solidity +function removeProxy(bytes32 delegate) external; +``` + +## Example Usage + +Here's an example of how to use the staking precompile in a smart contract: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IStakingPrecompile { + function addStake(bytes32 hotkey, uint256 amount, uint256 netuid) external payable; + function removeStake(bytes32 hotkey, uint256 amount, uint256 netuid) external; + function getTotalColdkeyStake(bytes32 coldkey) external view returns (uint256); + function getTotalHotkeyStake(bytes32 hotkey) external view returns (uint256); + function getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns (uint256); + function getTotalAlphaStaked(bytes32 hotkey, uint256 netuid) external view returns (uint256); + function getAlphaStakedValidators(bytes32 hotkey, uint256 netuid) external view returns (bytes32[]); +} + +contract StakingManager { + address constant STAKING_PRECOMPILE = 0x805; + IStakingPrecompile staking = IStakingPrecompile(STAKING_PRECOMPILE); + + function addStakeToHotkey(bytes32 hotkey, uint256 amount, uint256 netuid) external payable { + staking.addStake{value: msg.value}(hotkey, amount, netuid); + } + + function getStakeInfo(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns ( + uint256 totalColdkeyStake, + uint256 totalHotkeyStake, + uint256 specificStake, + uint256 totalAlphaStaked, + bytes32[] memory validators + ) { + totalColdkeyStake = staking.getTotalColdkeyStake(coldkey); + totalHotkeyStake = staking.getTotalHotkeyStake(hotkey); + specificStake = staking.getStake(hotkey, coldkey, netuid); + totalAlphaStaked = staking.getTotalAlphaStaked(hotkey, netuid); + validators = staking.getAlphaStakedValidators(hotkey, netuid); + } +} +``` + +## Important Notes + +1. The `addStake` function is payable and requires TAO to be sent with the transaction. +2. All amounts are in RAO (1 TAO = 1e18 RAO). +3. The `netuid` parameter identifies the specific subnet for the operation. +4. Proxy operations require appropriate permissions. +5. Moving and transferring stakes may have additional restrictions based on network parameters. +6. Some functions may require specific permissions or conditions to be met. + +## Next Steps + +- Learn about [subnet management](/evm-tutorials/subnet-precompile) +- Understand [neuron operations](/evm-tutorials/neuron-precompile) +- Explore [metagraph interactions](/evm-tutorials/metagraph-precompile) From 89e9977e17e1ece5d085c74a97a5ab903e569e15 Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Thu, 15 May 2025 15:19:08 -0700 Subject: [PATCH 04/27] wip --- docs/evm-tutorials/evm-on-subtensor.md | 22 +++-------------- docs/evm-tutorials/index.md | 34 +++++++++++++++----------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/docs/evm-tutorials/evm-on-subtensor.md b/docs/evm-tutorials/evm-on-subtensor.md index cfa49fff9..63e652f0d 100644 --- a/docs/evm-tutorials/evm-on-subtensor.md +++ b/docs/evm-tutorials/evm-on-subtensor.md @@ -1,29 +1,17 @@ --- -title: "EVM on Subtensor" +title: "Bittensor vs Ethereum Smart Contracts" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# EVM on Subtensor +# Bittensor vs Ethereum Smart Contracts -Ethereum compatibility layer is now available on the subtensor. Using this EVM feature you can: -- Deploy and interact with any Ethereum smart contract, without any need to change it, on the subtensor blockchain. -- Access all the standard Ethereum JSON-RPC methods from this EVM compatibility layer on Bittensor. - -When this EVM feature is turned ON, it allows the subtensor blockchain to execute Ethereum-compatible smart contracts. - -:::danger EVM smart contract executes on subtensor -Note that all operations performed by the subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain. -::: - -This document explains in simple terms what this EVM on subtensor is and how it works. Head on over to the [EVM Tutorials](./index.md) to start learning how to use this feature. - -## Ethereum vs Bittensor smart contracts +This document explains how EVM for Bittensor is different from EVM for Ethereum. On the Ethereum network, nodes such as full nodes, validator nodes and archive nodes run the Ethereum Virtual Environment (EVM) run-time environment. Smart contracts operate under this EVM. See the below high-level diagram. -When we say “smart contracts on Bittensor” we refer to the new EVM compability feature in the Bittensor subtensor blockchain. When this EVM feature is turned ON, it allows the subtensor blockchain to execute Ethereum-compatible smart contracts. **Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain.** See the below diagram showing how smart contracts on subtensor work: +When we say “smart contracts on Bittensor” we refer to the new EVM compability feature in the Bittensor subtensor blockchain. When this EVM feature is turned ON, it allows the subtensor blockchain to execute Ethereum-compatible smart contracts. **Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain.** @@ -47,5 +35,3 @@ style={{width: 400}} /> - -Next, see [EVM Tutorials](./index.md) to start learning how to use this feature. diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index 96aa37142..dd4c4c70c 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -31,12 +31,23 @@ Full Ethereum virtual machine (EVM) compatibility is now available on subtensor - Interact with deployed smart contracts on the subtensor blockchain - Access standard Ethereum JSON-RPC methods from this EVM compatibility layer on [Subtensor](https://github.com/opentensor/subtensor), Bittensor's substrate blockchain. -## Before you proceed +:::tip notes +| note | description | +|---------|-------------| +| EVM smart contracts execute on **Bittensor, not Ethereum blockchain** | Operations performed by subtensor EVM are executed solely on the subtensor blockchain, *not* on the Ethereum blockchain. | +| 1 TAO = 1e18 on subtensor EVM | While working with the subtensor EVM, 1 TAO should be written as 1 followed by 18 zeroes, i.e., 1e18.

For [example](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58): `const value = BigInt(0.5 * 1e18).toString();`. | +::: +:::note networks +| | MAINNET | TESTNET | LOCALNET | +|:---------------------|:------------------------------------|:-------------------------------------|:-------------------------| +| **RPC URL** | https://lite.chain.opentensor.ai | https://test.chain.opentensor.ai | http://localhost:9944 | +| **Chain ID** | 964 | 945 | _see below_ | +| **Test TAO** | None | Available on request | Use Alice account | + +::: +See section [EVM Localnet with Metamask Wallet](./evm-localnet-with-metamask-wallet.md) for setting up a Local net. -Before you proceed to use EVM on subtensor, make a note of the following: -1. **EVM smart contract executes on subtensor**: The EVM feature allows the subtensor blockchain to execute Ethereum-compatible smart contracts. Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain. -2. **1 TAO = 1e18 on subtensor EVM**: While working with the subtensor EVM, 1 TAO should be written as 1 followed by 18 zeroes, i.e., 1e18. See this code example: [https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58). ## Available Precompiles @@ -73,11 +84,11 @@ The following precompiles are available on the Bittensor EVM: Run the below tutorials to learn how to use the EVM feature on the Bittensor blockchain. - + - From ce197d9cf72e3fcccb127d5ad5250dc2f18be5d3 Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Fri, 16 May 2025 11:48:02 -0700 Subject: [PATCH 05/27] wip --- docs/evm-tutorials/evm-on-subtensor.md | 4 ++-- .../evm-testnet-with-metamask-wallet.md | 2 +- docs/evm-tutorials/index.md | 21 +++++++++++-------- docs/local-build/create-subnet.md | 1 - .../managing-stake-btcli.md | 2 +- .../managing-stake-sdk.md | 2 +- sidebars.js | 2 +- 7 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/evm-tutorials/evm-on-subtensor.md b/docs/evm-tutorials/evm-on-subtensor.md index 63e652f0d..632b9f3dc 100644 --- a/docs/evm-tutorials/evm-on-subtensor.md +++ b/docs/evm-tutorials/evm-on-subtensor.md @@ -1,11 +1,11 @@ --- -title: "Bittensor vs Ethereum Smart Contracts" +title: "Ethereum vs Bittensor EVM Smart Contracts" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Bittensor vs Ethereum Smart Contracts +# Ethereum vs Bittensor EVM Smart Contracts This document explains how EVM for Bittensor is different from EVM for Ethereum. diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index 07a32050c..49a5a8f11 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -43,7 +43,7 @@ With the above steps, you have successfully configured your Metamask wallet with ## Step 3 Obtain TAO -Next, request testnet TAO in the Bittensor community Discord. +Next, request testnet TAO in the Bittensor community [Discord](https://discord.com/channels/799672011265015819/830068283314929684). ## Step 4. Copy Metamask wallet private key into config diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index dd4c4c70c..c9484227d 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -1,5 +1,5 @@ --- -title: "EVM smart contracts on Bittensor" +title: "Bittensor EVM Smart Contracts" --- import ThemedImage from '@theme/ThemedImage'; @@ -23,13 +23,9 @@ import { BiSolidNetworkChart } from "react-icons/bi"; import { FaMoneyBillTransfer } from "react-icons/fa6"; import { GrStakeholder } from "react-icons/gr"; -# EVM smart contracts on Bittensor +# Bittensor EVM Smart Contracts -Full Ethereum virtual machine (EVM) compatibility is now available on subtensor (the blockchain in Bittensor). This allows users to: - -- Deploy most EVM smart contracts on subtensor without changing the code -- Interact with deployed smart contracts on the subtensor blockchain -- Access standard Ethereum JSON-RPC methods from this EVM compatibility layer on [Subtensor](https://github.com/opentensor/subtensor), Bittensor's substrate blockchain. +Full Ethereum virtual machine (EVM) compatibility is now available on subtensor (the blockchain in Bittensor). This allows users to deploy most EVM smart contracts on subtensor without changing the code, interact with deployed smart contracts on the subtensor blockchain, and access standard Ethereum JSON-RPC methods. :::tip notes | note | description | @@ -38,13 +34,20 @@ Full Ethereum virtual machine (EVM) compatibility is now available on subtensor | 1 TAO = 1e18 on subtensor EVM | While working with the subtensor EVM, 1 TAO should be written as 1 followed by 18 zeroes, i.e., 1e18.

For [example](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58): `const value = BigInt(0.5 * 1e18).toString();`. | ::: :::note networks + +You can deploy smart contracts on Bittensor main net (aka 'finney'), test network, or on your own locally deployed Bittensor chain. +
+ Network details + + | | MAINNET | TESTNET | LOCALNET | |:---------------------|:------------------------------------|:-------------------------------------|:-------------------------| | **RPC URL** | https://lite.chain.opentensor.ai | https://test.chain.opentensor.ai | http://localhost:9944 | | **Chain ID** | 964 | 945 | _see below_ | -| **Test TAO** | None | Available on request | Use Alice account | - +| **Test TAO** | None | Available on request | Use [Alice account](../local-build/provision-wallets#access-the-alice-account) | +
::: + See section [EVM Localnet with Metamask Wallet](./evm-localnet-with-metamask-wallet.md) for setting up a Local net. diff --git a/docs/local-build/create-subnet.md b/docs/local-build/create-subnet.md index 66bc33b2c..5b55db0e6 100644 --- a/docs/local-build/create-subnet.md +++ b/docs/local-build/create-subnet.md @@ -15,7 +15,6 @@ Prerequisites: ## Create subnet -To access the handy pre-provisioned development "Alice" account on your local chain, use: ```shell btcli subnet create \ diff --git a/docs/staking-and-delegation/managing-stake-btcli.md b/docs/staking-and-delegation/managing-stake-btcli.md index 4859d6f6f..5c5567c9c 100644 --- a/docs/staking-and-delegation/managing-stake-btcli.md +++ b/docs/staking-and-delegation/managing-stake-btcli.md @@ -33,7 +33,7 @@ Test network tokens have no real value. Before managing liquidity on Bittensor m ## View TAO balance -To stake, you'll first need some TAO. Inquire in Discord to obtain TAO on Bittensor test network. +To stake, you'll first need some TAO. Inquire in [Discord](https://discord.com/channels/799672011265015819/830068283314929684) to obtain TAO on Bittensor test network. To ensure you are targeting the test network, run `btcli config set`, select network, and set it to `test`. diff --git a/docs/staking-and-delegation/managing-stake-sdk.md b/docs/staking-and-delegation/managing-stake-sdk.md index 433fe0ed5..fdc84c286 100644 --- a/docs/staking-and-delegation/managing-stake-sdk.md +++ b/docs/staking-and-delegation/managing-stake-sdk.md @@ -20,7 +20,7 @@ Minimum transaction amount for stake/unstake/move/transfer: 500,000 RAO or 0.000 ## Check your TAO balance -To stake, you'll first need some TAO. Inquire in Discord to obtain TAO on Bittensor test network. +To stake, you'll first need some TAO. Inquire in [Discord](https://discord.com/channels/799672011265015819/830068283314929684) to obtain TAO on Bittensor test network. :::danger The funds in a crypto wallet are only as secure as your private key and/or seed phrase, and the devices that have access to these. diff --git a/sidebars.js b/sidebars.js index cc7d7287d..82de1167c 100644 --- a/sidebars.js +++ b/sidebars.js @@ -190,7 +190,7 @@ const sidebars = { { type: "category", - label: "EVM smart contracts on Bittensor", + label: "Bittensor EVM Smart Contracts", link: {type: "doc", id: "evm-tutorials/index",}, collapsible: true, collapsed: true, From 0ff483d0774b7c8b616e63193576da517fbd02d6 Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Fri, 16 May 2025 12:49:53 -0700 Subject: [PATCH 06/27] wip --- .../evm-localnet-with-metamask-wallet.md | 4 +- .../evm-mainnet-with-metamask-wallet.md | 4 +- docs/evm-tutorials/evm-on-subtensor.md | 37 --------- .../evm-testnet-with-metamask-wallet.md | 4 +- docs/evm-tutorials/index.md | 82 ++++++++++++------- docs/evm-tutorials/install.md | 3 +- .../transfer-between-two-h160-accounts.md | 6 +- .../transfer-from-metamask-to-ss58.md | 6 +- sidebars.js | 43 +++++++--- 9 files changed, 99 insertions(+), 90 deletions(-) delete mode 100644 docs/evm-tutorials/evm-on-subtensor.md diff --git a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md index 856493d9e..06748b844 100644 --- a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md @@ -1,11 +1,11 @@ --- -title: "EVM Localnet with Metamask Wallet" +title: "Metamask with Local Chain" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# EVM Localnet with Metamask Wallet +# Metamask with Local Chain This tutorial is for how to set up your Metamask wallet to use with EVM localnet on Bittensor. You must run either this step or [EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet.md) tutorial before you can run other tutorials in this section. diff --git a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md index 7a7d2465e..6c63320bb 100644 --- a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md @@ -1,10 +1,10 @@ --- -title: "EVM Mainnet with Metamask Wallet" +title: "Metamask with Mainnet" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# EVM Mainnet with Metamask Wallet +# Metamask with Mainnet This tutorial is for how to set up your Metamask wallet to use with the Mainnet (finney) on Bittensor. You must run this step before you can run other tutorials in this section. diff --git a/docs/evm-tutorials/evm-on-subtensor.md b/docs/evm-tutorials/evm-on-subtensor.md deleted file mode 100644 index 632b9f3dc..000000000 --- a/docs/evm-tutorials/evm-on-subtensor.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: "Ethereum vs Bittensor EVM Smart Contracts" ---- - -import ThemedImage from '@theme/ThemedImage'; -import useBaseUrl from '@docusaurus/useBaseUrl'; - -# Ethereum vs Bittensor EVM Smart Contracts - -This document explains how EVM for Bittensor is different from EVM for Ethereum. - -On the Ethereum network, nodes such as full nodes, validator nodes and archive nodes run the Ethereum Virtual Environment (EVM) run-time environment. Smart contracts operate under this EVM. See the below high-level diagram. - -When we say “smart contracts on Bittensor” we refer to the new EVM compability feature in the Bittensor subtensor blockchain. When this EVM feature is turned ON, it allows the subtensor blockchain to execute Ethereum-compatible smart contracts. **Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain.** - - - - - - - - - diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index 49a5a8f11..1dd245b70 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -1,10 +1,10 @@ --- -title: "EVM Testnet with Metamask Wallet" +title: "Metamask with Testnet" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# EVM Testnet with Metamask Wallet +# Metamask with Testnet This tutorial is for how to set up your Metamask wallet to use with the testnet on Bittensor. You must run this step before you can run other tutorials in this section. diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index c9484227d..dfdb3a0ce 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -27,13 +27,9 @@ import { GrStakeholder } from "react-icons/gr"; Full Ethereum virtual machine (EVM) compatibility is now available on subtensor (the blockchain in Bittensor). This allows users to deploy most EVM smart contracts on subtensor without changing the code, interact with deployed smart contracts on the subtensor blockchain, and access standard Ethereum JSON-RPC methods. -:::tip notes -| note | description | -|---------|-------------| -| EVM smart contracts execute on **Bittensor, not Ethereum blockchain** | Operations performed by subtensor EVM are executed solely on the subtensor blockchain, *not* on the Ethereum blockchain. | -| 1 TAO = 1e18 on subtensor EVM | While working with the subtensor EVM, 1 TAO should be written as 1 followed by 18 zeroes, i.e., 1e18.

For [example](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58): `const value = BigInt(0.5 * 1e18).toString();`. | -::: -:::note networks +Bittensor EVM smart contracts are executed solely on the **Bittensor blockchain, *not* on the Ethereum blockchain.** + +## Networks You can deploy smart contracts on Bittensor main net (aka 'finney'), test network, or on your own locally deployed Bittensor chain.
@@ -45,18 +41,20 @@ You can deploy smart contracts on Bittensor main net (aka 'finney'), test networ | **RPC URL** | https://lite.chain.opentensor.ai | https://test.chain.opentensor.ai | http://localhost:9944 | | **Chain ID** | 964 | 945 | _see below_ | | **Test TAO** | None | Available on request | Use [Alice account](../local-build/provision-wallets#access-the-alice-account) | +|Set-up Guide|[EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet)|[EVM Localnet with Metamask Wallet](./evm-localnet-with-metamask-wallet.md) for setting up a Local net.|
-::: -See section [EVM Localnet with Metamask Wallet](./evm-localnet-with-metamask-wallet.md) for setting up a Local net. + + ## Available Precompiles The following precompiles are available on the Bittensor EVM: +
+ Standard Ethereum Precompiles -### Standard Ethereum Precompiles - `ECRecover` (0x1) - Recover the address associated with the public key from elliptic curve signature - `Sha256` (0x2) - SHA-256 hash function - `Ripemd160` (0x3) - RIPEMD-160 hash function @@ -64,8 +62,10 @@ The following precompiles are available on the Bittensor EVM: - `Modexp` (0x5) - Modular exponentiation - `Sha3FIPS256` (0x400) - SHA3-256 hash function (FIPS variant) - `ECRecoverPublicKey` (0x401) - Recover the public key from an elliptic curve signature +
+
+ Bittensor-Specific Precompiles -### Bittensor-Specific Precompiles - `Ed25519Verify` - Verify Ed25519 signatures - `BalanceTransfer` - Transfer TAO between accounts - `StakingPrecompile` @@ -83,30 +83,44 @@ The following precompiles are available on the Bittensor EVM: - `MetagraphPrecompile` - Interact with the metagraph - `NeuronPrecompile` - Manage neuron operations - UidLookupPrecompile +
-Run the below tutorials to learn how to use the EVM feature on the Bittensor blockchain. +## Ethereum vs Bittensor EVM Smart Contracts - - - - + +On the Ethereum network, nodes such as full nodes, validator nodes and archive nodes run the Ethereum Virtual Environment (EVM) run-time environment. Smart contracts operate under this EVM. See the below high-level diagram. + +When we say “smart contracts on Bittensor” we refer to the new EVM compability feature in the Bittensor subtensor blockchain. When this EVM feature is turned ON, it allows the subtensor blockchain to execute Ethereum-compatible smart contracts. **Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain.** + + + + + + + + + + + + body='Get started by installing dependencies first.' /> + + Date: Mon, 19 May 2025 11:09:07 -0700 Subject: [PATCH 07/27] wip --- .../evm-localnet-with-metamask-wallet.md | 2 +- .../evm-mainnet-with-metamask-wallet.md | 2 +- .../evm-testnet-with-metamask-wallet.md | 2 +- docs/evm-tutorials/examples.md | 39 +++++++++++++ docs/evm-tutorials/index.md | 55 ++++--------------- sidebars.js | 7 ++- 6 files changed, 58 insertions(+), 49 deletions(-) create mode 100644 docs/evm-tutorials/examples.md diff --git a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md index 06748b844..1fecbf7c6 100644 --- a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md @@ -7,7 +7,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Metamask with Local Chain -This tutorial is for how to set up your Metamask wallet to use with EVM localnet on Bittensor. You must run either this step or [EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet.md) tutorial before you can run other tutorials in this section. +This page covers how to set up your Metamask wallet to use with EVM localnet on Bittensor. You must run either this step or [EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet.md) tutorial before you can run other tutorials in this section. :::tip blog post: EVM on Bittensor If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. diff --git a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md index 6c63320bb..587ae9a2b 100644 --- a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md @@ -6,7 +6,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Metamask with Mainnet -This tutorial is for how to set up your Metamask wallet to use with the Mainnet (finney) on Bittensor. You must run this step before you can run other tutorials in this section. +This page covers how to set up your Metamask wallet to use with the Mainnet (finney) on Bittensor. You must run this step before you can run other tutorials in this section. :::tip blog post: EVM on Bittensor If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index 1dd245b70..257830d10 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -6,7 +6,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Metamask with Testnet -This tutorial is for how to set up your Metamask wallet to use with the testnet on Bittensor. You must run this step before you can run other tutorials in this section. +This page covers how to set up your Metamask wallet to use with the testnet on Bittensor. You must run this step before you can run other tutorials in this section. :::tip blog post: EVM on Bittensor If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md new file mode 100644 index 000000000..744ad39e4 --- /dev/null +++ b/docs/evm-tutorials/examples.md @@ -0,0 +1,39 @@ +--- +title: "Bittensor EVM: Examples and Precompiles" +--- + +# Bittensor EVM: Examples and Precompiles +## Available Precompiles + +The following precompiles are available on the Bittensor EVM: +
+ Standard Ethereum Precompiles + +- `ECRecover` (0x1) - Recover the address associated with the public key from elliptic curve signature +- `Sha256` (0x2) - SHA-256 hash function +- `Ripemd160` (0x3) - RIPEMD-160 hash function +- `Identity` (0x4) - Identity function (returns input data) +- `Modexp` (0x5) - Modular exponentiation +- `Sha3FIPS256` (0x400) - SHA3-256 hash function (FIPS variant) +- `ECRecoverPublicKey` (0x401) - Recover the public key from an elliptic curve signature +
+
+ Bittensor-Specific Precompiles + +- [`Ed25519Verify`](./ed25519-verify-precompile.md) - Verify Ed25519 signatures +- [`BalanceTransfer`](./transfer-between-two-h160-accounts.md) - Transfer TAO between accounts +- [`StakingPrecompile`](./staking-precompile.md) - Manage staking operations +- [`StakingPrecompileV2`](./staking-precompile.md) (0x805) - Main staking operations including: + - `addStake` - Add stake to a hotkey + - `removeStake` - Remove stake from a hotkey + - `moveStake` - Move stake between hotkeys + - `transferStake` - Transfer stake between coldkeys + - `getTotalColdkeyStake` - Get total stake for a coldkey + - `getTotalHotkeyStake` - Get total stake for a hotkey + - `getStake` - Get stake between specific hotkey and coldkey + - `addProxy` - Add a proxy delegate + - `removeProxy` - Remove a proxy delegate +- [`SubnetPrecompile`](./subnet-precompile.md) - Manage subnet operations +- [`MetagraphPrecompile`](./metagraph-precompile.md) - Interact with the metagraph +- [`NeuronPrecompile`](./neuron-precompile.md) - Manage neuron operations +
diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index dfdb3a0ce..7b8aff65e 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -29,6 +29,17 @@ Full Ethereum virtual machine (EVM) compatibility is now available on subtensor Bittensor EVM smart contracts are executed solely on the **Bittensor blockchain, *not* on the Ethereum blockchain.** +See: [Examples and Precompiles](./examples.md) + +The following Bittensor-specific precompiles are available: +- [Ed25519Verify](./ed25519-verify-precompile.md) - Verify Ed25519 signatures +- [BalanceTransfer](./transfer-between-two-h160-accounts.md) - Transfer TAO between accounts +- [StakingPrecompile](./staking-precompile.md) - Manage staking operations +- [StakingPrecompileV2](./staking-precompile.md) - Enhanced staking operations +- [SubnetPrecompile](./subnet-precompile.md) - Manage subnet operations +- [MetagraphPrecompile](./metagraph-precompile.md) - Interact with the metagraph +- [NeuronPrecompile](./neuron-precompile.md) - Manage neuron operations + ## Networks You can deploy smart contracts on Bittensor main net (aka 'finney'), test network, or on your own locally deployed Bittensor chain. @@ -44,53 +55,11 @@ You can deploy smart contracts on Bittensor main net (aka 'finney'), test networ |Set-up Guide|[EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet)|[EVM Localnet with Metamask Wallet](./evm-localnet-with-metamask-wallet.md) for setting up a Local net.| - - - - - -## Available Precompiles - -The following precompiles are available on the Bittensor EVM: -
- Standard Ethereum Precompiles - -- `ECRecover` (0x1) - Recover the address associated with the public key from elliptic curve signature -- `Sha256` (0x2) - SHA-256 hash function -- `Ripemd160` (0x3) - RIPEMD-160 hash function -- `Identity` (0x4) - Identity function (returns input data) -- `Modexp` (0x5) - Modular exponentiation -- `Sha3FIPS256` (0x400) - SHA3-256 hash function (FIPS variant) -- `ECRecoverPublicKey` (0x401) - Recover the public key from an elliptic curve signature -
-
- Bittensor-Specific Precompiles - -- `Ed25519Verify` - Verify Ed25519 signatures -- `BalanceTransfer` - Transfer TAO between accounts -- `StakingPrecompile` -- `StakingPrecompileV2` (0x805) - Main staking operations including: - - `addStake` - Add stake to a hotkey - - `removeStake` - Remove stake from a hotkey - - `moveStake` - Move stake between hotkeys - - `transferStake` - Transfer stake between coldkeys - - `getTotalColdkeyStake` - Get total stake for a coldkey - - `getTotalHotkeyStake` - Get total stake for a hotkey - - `getStake` - Get stake between specific hotkey and coldkey - - `addProxy` - Add a proxy delegate - - `removeProxy` - Remove a proxy delegate -- `SubnetPrecompile` - Manage subnet operations -- `MetagraphPrecompile` - Interact with the metagraph -- `NeuronPrecompile` - Manage neuron operations -- UidLookupPrecompile -
- ## Ethereum vs Bittensor EVM Smart Contracts - On the Ethereum network, nodes such as full nodes, validator nodes and archive nodes run the Ethereum Virtual Environment (EVM) run-time environment. Smart contracts operate under this EVM. See the below high-level diagram. -When we say “smart contracts on Bittensor” we refer to the new EVM compability feature in the Bittensor subtensor blockchain. When this EVM feature is turned ON, it allows the subtensor blockchain to execute Ethereum-compatible smart contracts. **Note that all operations performed by this new subtensor EVM feature are executed solely on the subtensor blockchain, not on the Ethereum blockchain.** +**Note that all operations performed by Bittensor EVM are executed solely on the Bittensor blockchain, not on the Ethereum blockchain.** diff --git a/sidebars.js b/sidebars.js index 2258ef61e..18a83fd63 100644 --- a/sidebars.js +++ b/sidebars.js @@ -189,10 +189,10 @@ const sidebars = { }, { type: 'category', - label: 'Bittensor EVM: Tooling and Configuration', + label: 'Bittensor EVM', link: {type: "doc", id: "evm-tutorials/index"}, items:[ - + "evm-tutorials/index", "evm-tutorials/install", "evm-tutorials/evm-testnet-with-metamask-wallet", "evm-tutorials/evm-localnet-with-metamask-wallet", @@ -204,9 +204,10 @@ const sidebars = { }, { type: 'category', - link: {type: "doc", id: "evm-tutorials/transfer-from-metamask-to-ss58"}, + link: {type: "doc", id: "evm-tutorials/examples"}, label: 'Bittensor EVM: Examples and Precompiles', items:[ + "evm-tutorials/examples", "evm-tutorials/transfer-from-metamask-to-ss58", "evm-tutorials/transfer-between-two-h160-accounts", "evm-tutorials/staking-precompile", From 4557dd12d28f4d361b3a17edb6a903e9941c0eee Mon Sep 17 00:00:00 2001 From: Michael Trestman Date: Tue, 20 May 2025 13:53:37 -0700 Subject: [PATCH 08/27] wip --- docs/evm-tutorials/index.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index 7b8aff65e..c2113c165 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -31,14 +31,6 @@ Bittensor EVM smart contracts are executed solely on the **Bittensor blockchain, See: [Examples and Precompiles](./examples.md) -The following Bittensor-specific precompiles are available: -- [Ed25519Verify](./ed25519-verify-precompile.md) - Verify Ed25519 signatures -- [BalanceTransfer](./transfer-between-two-h160-accounts.md) - Transfer TAO between accounts -- [StakingPrecompile](./staking-precompile.md) - Manage staking operations -- [StakingPrecompileV2](./staking-precompile.md) - Enhanced staking operations -- [SubnetPrecompile](./subnet-precompile.md) - Manage subnet operations -- [MetagraphPrecompile](./metagraph-precompile.md) - Interact with the metagraph -- [NeuronPrecompile](./neuron-precompile.md) - Manage neuron operations ## Networks From 2ef542ba8a85be2c5e006979eb3a0bfed82528b5 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Thu, 22 May 2025 10:00:58 -0700 Subject: [PATCH 09/27] wip --- .../ed25519-verify-precompile.md | 135 +++++++++++++++++- .../evm-localnet-with-metamask-wallet.md | 8 +- .../evm-mainnet-with-metamask-wallet.md | 4 +- .../evm-testnet-with-metamask-wallet.md | 4 +- docs/evm-tutorials/examples.md | 65 ++++----- .../hardhat-config-for-subtensor-evm.md | 4 +- docs/evm-tutorials/index.md | 4 +- .../remix-config-for-subtensor-evm.md | 4 +- 8 files changed, 180 insertions(+), 48 deletions(-) diff --git a/docs/evm-tutorials/ed25519-verify-precompile.md b/docs/evm-tutorials/ed25519-verify-precompile.md index 1aae5a448..20a3cc191 100644 --- a/docs/evm-tutorials/ed25519-verify-precompile.md +++ b/docs/evm-tutorials/ed25519-verify-precompile.md @@ -7,11 +7,12 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Ed25519 Verify Precompile -This precompile is deployed on the subtensor EVM at the address `0x0000000000000000000000000000000000000402`. This precompile allows you to verify an `ed25519` signature. +This smart contract is precompiled at Bittensor EVM address `0x0000000000000000000000000000000000000402`. +It allows you to verify an `ed25519` signature to confirm ownership of a `ss58` public key in EVM (for example, for a Bittensor wallets coldkey public key). -You can use this precompile to verify proof of `ss58` account ownership on the EVM side. For example, you may need to do such verification for an airdrop to TAO owners. While EVM functionality doesn't allow airdropping directly to `ss58` addresses (because EVM is using H160 address schema), one can implement an airdrop via claiming. An owner of `ss58` address eligible for an airdrop can send an EVM transaction which includes the proof of `ss58` address ownership, for example, a signed message, uniquely specific for a given airdrop. +For example, you may want to verify coldkey ownership before transferring to someone. EVM functionality doesn't allow transferring directly to a `ss58` address—like the public key of a bittensor coldkey, because EVM uses the H160 address schema. To bridge the gap, you can use this precompile to prove a claim of ownership. The owner of a coldkey can send an EVM transaction with a signed message, serving as proof of ownership of the coldkey's `ss58` address. -For a complete code example see [`ed25519-verify.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/ed25519-verify.js). +Below, we'll explore a complete code example. :::danger Stop. Did you install the dependencies? Before you proceed, make sure you finished the [Install](./install.md) step. @@ -44,4 +45,130 @@ This example demonstrates how to: 2. Verify the signature using the precompile contract. 3. Fail the verification of the signature using the corrupted message hash with the precompile contract. -4. Fail the verification of the corrupted signature with the precompile contract. \ No newline at end of file +4. Fail the verification of the corrupted signature with the precompile contract. + + +## Code example + +[On GitHub](https://github.com/opentensor/evm-bittensor/blob/main/examples/ed25519-verify.js). + +```js +// ed25519-verify.js +const { ethers } = require('ethers'); +const { Keyring } = require('@polkadot/keyring'); + +// PROTECT YOUR PRIVATE KEYS WELL, NEVER COMMIT THEM TO GITHUB OR SHARE WITH ANYONE +const { rpcUrl } = require('./config.js'); + +const provider = new ethers.JsonRpcProvider(rpcUrl); + +const IED25519VERIFY_ADDRESS = '0x0000000000000000000000000000000000000402'; +const IEd25519VerifyABI = [ + { + "inputs": [ + { "internalType": "bytes32", "name": "message", "type": "bytes32" }, + { "internalType": "bytes32", "name": "publicKey", "type": "bytes32" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "name": "verify", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "pure", + "type": "function" + } +]; + +async function main() { + const keyring = new Keyring({ type: 'ed25519' }); + const myAccount = keyring.addFromUri('//Alice'); + + ////////////////////////////////////////////////////////////////////// + // Generate a signature + + // Your message to sign + const message = 'Sign this message'; + const messageU8a = new TextEncoder().encode(message); + const messageHex = ethers.hexlify(messageU8a); // Convert message to hex string + const messageHash = ethers.keccak256(messageHex); // Hash the message to fit into bytes32 + console.log(`messageHash = ${messageHash}`); + const hashedMessageBytes = hexToBytes(messageHash); + + // Sign the message + const signature = myAccount.sign(hashedMessageBytes); + console.log(`Signature: ${bytesToHex(signature)}`); + + // Verify the signature locally + const isValid = myAccount.verify(hashedMessageBytes, signature, myAccount.publicKey); + console.log(`Is the signature valid? ${isValid}`); + + ////////////////////////////////////////////////////////////////////// + // Verify the signature using the precompile contract + + const publicKeyBytes = bytesToHex(myAccount.publicKey); + console.log(`publicKeyBytes = ${publicKeyBytes}`); + + // Split signture into Commitment (R) and response (s) + let r = signature.slice(0, 32); // Commitment, a.k.a. "r" - first 32 bytes + let s = signature.slice(32, 64); // Response, a.k.a. "s" - second 32 bytes + let rBytes = bytesToHex(r); + let sBytes = bytesToHex(s); + const ed25519Contract = new ethers.Contract(IED25519VERIFY_ADDRESS, IEd25519VerifyABI, provider); + const isPrecompileValid = await ed25519Contract.verify(messageHash, publicKeyBytes, rBytes, sBytes); + console.log(`Is the signature valid according to the smart contract? ${isPrecompileValid}`); + + ////////////////////////////////////////////////////////////////////// + // Verify the signature for bad data using the precompile contract + + let brokenHashedMessageBytes = hashedMessageBytes; + brokenHashedMessageBytes[0] = (brokenHashedMessageBytes[0] + 1) % 0xff; + const brokenMessageHash = bytesToHex(brokenHashedMessageBytes); + console.log(`brokenMessageHash = ${brokenMessageHash}`); + const isPrecompileValidBadData = await ed25519Contract.verify(brokenMessageHash, publicKeyBytes, rBytes, sBytes); + console.log(`Is the signature valid according to the smart contract for broken data? ${isPrecompileValidBadData}`); + + ////////////////////////////////////////////////////////////////////// + // Verify the bad signature for good data using the precompile contract + + let brokenR = r; + brokenR[0] = (brokenR[0] + 1) % 0xff; + rBytes = bytesToHex(r); + const isPrecompileValidBadSignature = await ed25519Contract.verify(messageHash, publicKeyBytes, rBytes, sBytes); + console.log(`Is the signature valid according to the smart contract for broken signature? ${isPrecompileValidBadSignature}`); +} + +main().catch(console.error); + +function hexToBytes(hex) { + // Remove the '0x' prefix if it exists + if (hex.startsWith('0x')) { + hex = hex.slice(2); + } + + // Initialize the array + var bytes = new Uint8Array(hex.length / 2); + + // Loop through each pair of characters + for (var i = 0; i < bytes.length; i++) { + // Convert the pair of characters to a byte + bytes[i] = parseInt(hex.substr(i * 2, 2), 16); + } + + return bytes; +} + +function bytesToHex(bytes) { + // Initialize the hex string + var hex = []; + + // Loop through each byte + for (var i = 0; i < bytes.length; i++) { + // Convert each byte to a hex string and add it to the array + // Ensure it is two digits by padding with a zero if necessary + hex.push((bytes[i] >>> 4).toString(16)); + hex.push((bytes[i] & 0xF).toString(16)); + } + + // Join all hex string parts into one string + return '0x' + hex.join(''); +} +``` \ No newline at end of file diff --git a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md index 1fecbf7c6..ed0862321 100644 --- a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md @@ -1,13 +1,15 @@ --- -title: "Metamask with Local Chain" +title: "EVM on Local Chain" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Metamask with Local Chain +# EVM on Local Chain -This page covers how to set up your Metamask wallet to use with EVM localnet on Bittensor. You must run either this step or [EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet.md) tutorial before you can run other tutorials in this section. +This page covers getting set up to use EVM on a locally deployed Bittensor blockchain. + +Consider first trying [EVM with Bittensor testnet](./evm-testnet-with-metamask-wallet.md). This allows you to try EVM without having to deploy a blockchain locally, but you will have to obtain testnet TAO by inquiring in discord, or by completing the [BTCLI playground](../btcli/btcli-playground)challenge to obtain testnet TAO. :::tip blog post: EVM on Bittensor If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. diff --git a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md index 587ae9a2b..78118255b 100644 --- a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md @@ -1,10 +1,10 @@ --- -title: "Metamask with Mainnet" +title: "EVM on Mainnet" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Metamask with Mainnet +# EVM on Mainnet This page covers how to set up your Metamask wallet to use with the Mainnet (finney) on Bittensor. You must run this step before you can run other tutorials in this section. diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index 257830d10..b3079c294 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -1,10 +1,10 @@ --- -title: "Metamask with Testnet" +title: "EVM on Testnet" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Metamask with Testnet +# EVM on Testnet This page covers how to set up your Metamask wallet to use with the testnet on Bittensor. You must run this step before you can run other tutorials in this section. diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md index 744ad39e4..841b99fc8 100644 --- a/docs/evm-tutorials/examples.md +++ b/docs/evm-tutorials/examples.md @@ -5,35 +5,36 @@ title: "Bittensor EVM: Examples and Precompiles" # Bittensor EVM: Examples and Precompiles ## Available Precompiles -The following precompiles are available on the Bittensor EVM: -
- Standard Ethereum Precompiles - -- `ECRecover` (0x1) - Recover the address associated with the public key from elliptic curve signature -- `Sha256` (0x2) - SHA-256 hash function -- `Ripemd160` (0x3) - RIPEMD-160 hash function -- `Identity` (0x4) - Identity function (returns input data) -- `Modexp` (0x5) - Modular exponentiation -- `Sha3FIPS256` (0x400) - SHA3-256 hash function (FIPS variant) -- `ECRecoverPublicKey` (0x401) - Recover the public key from an elliptic curve signature -
-
- Bittensor-Specific Precompiles - -- [`Ed25519Verify`](./ed25519-verify-precompile.md) - Verify Ed25519 signatures -- [`BalanceTransfer`](./transfer-between-two-h160-accounts.md) - Transfer TAO between accounts -- [`StakingPrecompile`](./staking-precompile.md) - Manage staking operations -- [`StakingPrecompileV2`](./staking-precompile.md) (0x805) - Main staking operations including: - - `addStake` - Add stake to a hotkey - - `removeStake` - Remove stake from a hotkey - - `moveStake` - Move stake between hotkeys - - `transferStake` - Transfer stake between coldkeys - - `getTotalColdkeyStake` - Get total stake for a coldkey - - `getTotalHotkeyStake` - Get total stake for a hotkey - - `getStake` - Get stake between specific hotkey and coldkey - - `addProxy` - Add a proxy delegate - - `removeProxy` - Remove a proxy delegate -- [`SubnetPrecompile`](./subnet-precompile.md) - Manage subnet operations -- [`MetagraphPrecompile`](./metagraph-precompile.md) - Interact with the metagraph -- [`NeuronPrecompile`](./neuron-precompile.md) - Manage neuron operations -
+The following precompiles are available on the Bittensor EVM. + +Code examples used throughout are provided by OTF, and come from [this repository.](https://github.com/opentensor/evm-bittensor/tree/main/examples) + +## Standard Ethereum Precompiles + +- `ECRecover` (0x1): Recover the address associated with the public key from elliptic curve signature +- `Sha256` (0x2): SHA-256 hash function +- `Ripemd160` (0x3): RIPEMD-160 hash function +- `Identity` (0x4): Identity function (returns input data) +- `Modexp` (0x5): Modular exponentiation +- `Sha3FIPS256` (0x400): SHA3-256 hash function (FIPS variant) +- `ECRecoverPublicKey` (0x401): Recover the public key from an elliptic curve signature + +## Bittensor-Specific Precompiles + +- [`Ed25519Verify`](./ed25519-verify-precompile.md): Verify Ed25519 signatures +- [`BalanceTransfer`](./transfer-between-two-h160-accounts.md): Transfer TAO between accounts +- [`StakingPrecompile`](./staking-precompile.md): Manage staking operations +- [`StakingPrecompileV2`](./staking-precompile.md) (0x805): Main staking operations including: + - `addStake`: Add stake to a hotkey + - `removeStake`: Remove stake from a hotkey + - `moveStake`: Move stake between hotkeys + - `transferStake`: Transfer stake between coldkeys + - `getTotalColdkeyStake`: Get total stake for a coldkey + - `getTotalHotkeyStake`: Get total stake for a hotkey + - `getStake`: Get stake between specific hotkey and coldkey + - `addProxy`: Add a proxy delegate + - `removeProxy`: Remove a proxy delegate +- [`SubnetPrecompile`](./subnet-precompile.md): Manage subnet operations +- [`MetagraphPrecompile`](./metagraph-precompile.md): Interact with the metagraph +- [`NeuronPrecompile`](./neuron-precompile.md): Manage neuron operations + diff --git a/docs/evm-tutorials/hardhat-config-for-subtensor-evm.md b/docs/evm-tutorials/hardhat-config-for-subtensor-evm.md index 0cca19457..6443faff7 100644 --- a/docs/evm-tutorials/hardhat-config-for-subtensor-evm.md +++ b/docs/evm-tutorials/hardhat-config-for-subtensor-evm.md @@ -1,11 +1,11 @@ --- -title: "Hardhat Configuration for Subtensor EVM" +title: "Configuring Hardhat" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Hardhat Configuration for Subtensor EVM +# Configuring Hardhat You can use [Hardhat](https://hardhat.org/) development environment for the EVM feature on subtensor. The Hardhat networks can be configured using the `hardhat.config.ts` file, as shown below. diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index c2113c165..47d945e5b 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -29,7 +29,9 @@ Full Ethereum virtual machine (EVM) compatibility is now available on subtensor Bittensor EVM smart contracts are executed solely on the **Bittensor blockchain, *not* on the Ethereum blockchain.** -See: [Examples and Precompiles](./examples.md) +See: +- [Examples and Precompiles](./examples.md) +- Getting started with [Bittensor EVM on Testnet](./evm-testnet-with-metamask-wallet) ## Networks diff --git a/docs/evm-tutorials/remix-config-for-subtensor-evm.md b/docs/evm-tutorials/remix-config-for-subtensor-evm.md index 0bb8cf32d..af7649386 100644 --- a/docs/evm-tutorials/remix-config-for-subtensor-evm.md +++ b/docs/evm-tutorials/remix-config-for-subtensor-evm.md @@ -1,11 +1,11 @@ --- -title: "Remix IDE Configuration for Subtensor EVM" +title: "Configuring Remix IDE" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Remix IDE Configuration for Subtensor EVM +# Configuring Remix IDE You can use [Remix IDE](https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=cancun&version=soljson-v0.8.24+commit.e11b9ed9.js) for the EVM feature on subtensor. The link above automatically configures Remix to use EVM Version **Cancun** that matches **Solidity 0.8.24**. From b4f22d731abadfbefccdab827c4cd549a2a0d59d Mon Sep 17 00:00:00 2001 From: michael trestman Date: Thu, 22 May 2025 11:11:16 -0700 Subject: [PATCH 10/27] wip --- .../ed25519-verify-precompile.md | 54 +++++++++++-------- .../evm-testnet-with-metamask-wallet.md | 24 ++++++--- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/docs/evm-tutorials/ed25519-verify-precompile.md b/docs/evm-tutorials/ed25519-verify-precompile.md index 20a3cc191..bef9f88a3 100644 --- a/docs/evm-tutorials/ed25519-verify-precompile.md +++ b/docs/evm-tutorials/ed25519-verify-precompile.md @@ -7,18 +7,19 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Ed25519 Verify Precompile -This smart contract is precompiled at Bittensor EVM address `0x0000000000000000000000000000000000000402`. -It allows you to verify an `ed25519` signature to confirm ownership of a `ss58` public key in EVM (for example, for a Bittensor wallets coldkey public key). +The Ed25519 Verify Precompile allows EVM smart contracts to verify Ed25519 signatures, which are commonly used in Substrate-based chains like Bittensor. This is essential for bridging identity and ownership between Substrate and EVM ecosystems. For example, you may want to verify coldkey ownership before transferring to someone. EVM functionality doesn't allow transferring directly to a `ss58` address—like the public key of a Bittensor coldkey—because EVM uses the H160 address schema. To bridge the gap, you can use this precompile to prove a claim of ownership. The owner of a coldkey can send an EVM transaction with a signed message, serving as proof of ownership of the coldkey's `ss58` address. -For example, you may want to verify coldkey ownership before transferring to someone. EVM functionality doesn't allow transferring directly to a `ss58` address—like the public key of a bittensor coldkey, because EVM uses the H160 address schema. To bridge the gap, you can use this precompile to prove a claim of ownership. The owner of a coldkey can send an EVM transaction with a signed message, serving as proof of ownership of the coldkey's `ss58` address. +## Prerequisites -Below, we'll explore a complete code example. +- **Node.js** (v16 or later recommended) +- **npm** or **yarn** +- [Clone the Bittensor EVM examples repo](./install.md) +- [Get set up for using EVM wallet on testnet](./evm-testnet-with-metamask-wallet) +- [Install](./install) the EVM-Bittensor repo, containing scripts and examples. -:::danger Stop. Did you install the dependencies? -Before you proceed, make sure you finished the [Install](./install.md) step. -::: +A healthy node will return a JSON response with the latest block number. If you get a connection error or no response, the node is down or the URL is incorrect. -## Run +## Example Navigate to the `examples` directory of the EVM-Bittensor repo: @@ -34,26 +35,16 @@ To run this precompile, execute: This example demonstrates how to: 1. Sign an arbitrary message with `ed25519` key. - - Any substrate keyring can be initialized as `ed25519` with the same seed phrase or private key as used for signing subtensor transactions, even if they are usually used to create `sr25519` signatures. - - The precompile only allows verification of 32-byte messages. However, the arbitrary message can be converted into 32-byte message by calculating the message hash (like it is done in this below example): - - ```javascript - const messageHash = ethers.keccak256(messageHex); // Hash the message to fit into bytes32 - ``` - 2. Verify the signature using the precompile contract. -3. Fail the verification of the signature using the corrupted message hash with the precompile contract. -4. Fail the verification of the corrupted signature with the precompile contract. - +3. Fail the verification of the signature using a corrupted message hash with the precompile contract. +4. Fail the verification of a corrupted signature with the precompile contract. -## Code example [On GitHub](https://github.com/opentensor/evm-bittensor/blob/main/examples/ed25519-verify.js). +
+ Full code ```js -// ed25519-verify.js const { ethers } = require('ethers'); const { Keyring } = require('@polkadot/keyring'); @@ -171,4 +162,23 @@ function bytesToHex(bytes) { // Join all hex string parts into one string return '0x' + hex.join(''); } +``` +
+## Example Output + +``` +node ed25519-verify.js +@polkadot/util has multiple versions, ensure that there is only one installed. +Either remove and explicitly install matching versions or dedupe using your package manager. +The following conflicting packages were found: + cjs 12.2.1 node_modules/@polkadot/keyring/node_modules/@polkadot/util/cjs + cjs 13.5.1 node_modules/@polkadot/util/cjs +messageHash = 0xd6ce89c7d4f347455c7dddf19b42e0357edd7587b73b81b384810253c3c3c8ff +Signature: 0x35c3c28c3470ea348343cea4881bd353843236df73a04300261cb86411fe88a05a196842849eb1ef4335b1f171a70e74d2d4c8d3b71ad6a41b6fa48afec85b01 +Is the signature valid? true +publicKeyBytes = 0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee +Is the signature valid according to the smart contract? true +brokenMessageHash = 0xd7ce89c7d4f347455c7dddf19b42e0357edd7587b73b81b384810253c3c3c8ff +Is the signature valid according to the smart contract for broken data? false +Is the signature valid according to the smart contract for broken signature? false ``` \ No newline at end of file diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index b3079c294..8e787ab01 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -17,13 +17,25 @@ Key values: - **EVM Subtensor Chain ID:** `945` (UTF-8 encoded alpha character) - **Opentensor EVM-Bittensor GitHub repo:** `https://github.com/opentensor/evm-bittensor/tree/main` +## Connect to EVM Testnet -## Step 1. Create a Metamask wallet +Confirm the EVM node is online and accessible. You can check the node status independently using `curl` or similar tools: + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + https://test.chain.opentensor.ai +``` +```console +{"jsonrpc":"2.0","id":1,"result":"0x460943"} +``` +## Create a Metamask wallet 1. If you don't already have it, [install Metamask wallet](https://metamask.io/download/) browser extension. 2. Create a new account. -### Step 2. Add testnet to Metamask +### Add testnet to Metamask Add the testnet to Metamask from within the Metamask wallet. Follow the below steps: @@ -41,15 +53,11 @@ Add the testnet to Metamask from within the Metamask wallet. Follow the below st With the above steps, you have successfully configured your Metamask wallet with the testnet. -## Step 3 Obtain TAO +## Obtain TAO Next, request testnet TAO in the Bittensor community [Discord](https://discord.com/channels/799672011265015819/830068283314929684). -## Step 4. Copy Metamask wallet private key into config - -:::danger Stop. Did you install the dependencies? -Before you proceed, make sure you finished the [Install](./install.md) step. -::: +## Copy Metamask wallet private key into config In this step you will copy the private key from your Metamask wallet account and paste it into the configuration file in the repo. This step will ensure that you are not prompted with password each and every step as you run these tutorials. From 215dfa9d9caf903c2a13aa5655db075f5cbbffdb Mon Sep 17 00:00:00 2001 From: michael trestman Date: Wed, 28 May 2025 13:26:01 -0700 Subject: [PATCH 11/27] wip --- docs/bittensor-networks.md | 2 +- docs/evm-tutorials/address-conversion.md | 120 ++++++++++ docs/evm-tutorials/config.js | 18 ++ .../ed25519-verify-precompile.md | 6 +- .../evm-localnet-with-metamask-wallet.md | 4 - .../evm-mainnet-with-metamask-wallet.md | 3 - .../evm-testnet-with-metamask-wallet.md | 4 - docs/evm-tutorials/examples.md | 4 + docs/evm-tutorials/index.md | 6 +- docs/evm-tutorials/staking-precompile.md | 206 +++++++----------- .../transfer-from-metamask-to-ss58.md | 165 +++++++------- .../transfer-from-metamask-to-ss58EDGE.md | 128 +++++++++++ docs/local-build/create-subnet.md | 12 +- docs/local-build/deploy.md | 2 +- docs/local-build/mine-validate.md | 10 +- docs/local-build/provision-wallets.md | 2 +- docs/reference/_bittensor-api-ref.md | 2 +- docs/subnets/create-a-subnet.md | 4 +- sidebars.js | 14 +- 19 files changed, 460 insertions(+), 252 deletions(-) create mode 100644 docs/evm-tutorials/address-conversion.md create mode 100644 docs/evm-tutorials/config.js create mode 100644 docs/evm-tutorials/transfer-from-metamask-to-ss58EDGE.md diff --git a/docs/bittensor-networks.md b/docs/bittensor-networks.md index fefbd67db..1d24d1d69 100644 --- a/docs/bittensor-networks.md +++ b/docs/bittensor-networks.md @@ -9,7 +9,7 @@ The below table presents Bittensor networks and a few details: | DESCRIPTION | MAINNET | TESTNET | DEVNET | |:---------------------|:------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------| | **Chain URL** | wss://entrypoint-finney.opentensor.ai:443 | wss://test.finney.opentensor.ai:443 | wss://dev.chain.opentensor.ai:443 | -| **Example Usage** | Default | `btcli wallet swap_hotkey --subtensor.chain_endpoint wss://dev.chain.opentensor.ai:443` **or** `btcli wallet swap_hotkey --subtensor.network test` | `btcli wallet swap_hotkey --subtensor.chain_endpoint wss://dev.chain.opentensor.ai:443` | +| **Example Usage** | Default | `btcli wallet swap_hotkey --network wss://dev.chain.opentensor.ai:443` | `btcli wallet swap_hotkey --network wss://dev.chain.opentensor.ai:443` | | **Block processing** | One block every 12 seconds | One block every 12 seconds | One block every 12 seconds | | **Mainnet Archive** | wss://archive.chain.opentensor.ai:443 | None | None | | **Mainnet Lite** | wss://lite.chain.opentensor.ai:443 | None | None | diff --git a/docs/evm-tutorials/address-conversion.md b/docs/evm-tutorials/address-conversion.md new file mode 100644 index 000000000..efb86cdb7 --- /dev/null +++ b/docs/evm-tutorials/address-conversion.md @@ -0,0 +1,120 @@ +--- +title: "Converting Ethereum and Substrate Addresses" +--- + +# Converting Ethereum and Substrate Addresses + +This tutorial demonstrates how to convert between Ethereum (H160) and Substrate (SS58) addresses in the Bittensor EVM environment. + +When working with Bittensor's EVM implementation, you may need to convert between Ethereum-style addresses (H160) and Substrate-style addresses (SS58). This is particularly useful when interacting with both EVM and native Substrate functionality. + +This conversion is particularly useful when: +- Interacting with both EVM and native Substrate contracts +- Managing accounts that need to work across both environments +- Verifying addresses across different address formats +- Integrating EVM-based applications with native Bittensor functionality + +## Procedure + +### 1. Create Wallet with MetaMask + +1. Install MetaMask 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://evm.bittensor.com` + - Chain ID: 3636 + - Currency Symbol: TAO + - Block Explorer URL: `https://evm.bittensor.com` + +### 2. Convert Address for Bittensor + +1. Clone the EVM examples repository: + ```bash + git clone https://github.com/opentensor/evm-bittensor.git + cd evm-bittensor/examples + ``` + +2. Install dependencies: + ```bash + npm install + ``` + +3. Run the conversion script with your MetaMask address: + ```bash + node convert-address.js + ``` + +4. Note down the SS58 address output by the script - this is your Bittensor address + +### 3. Transfer TAO to EVM Wallet + +1. Use `btcli` to transfer TAO to your SS58 address: + ```bash + btcli root transfer --amount 1.0 --dest + ``` + +2. Wait for the transfer to complete (usually takes a few blocks) + +### 4. 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**: +- [EVM examples repo](https://github.com/opentensor/evm-bittensor) +- [Address mapping](https://github.com/opentensor/evm-bittensor/blob/main/examples/address-mapping.js) +- [Convert address](https://github.com/opentensor/evm-bittensor/blob/main/examples/convert-address.js) + +```javascript +//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); +``` + +```javascript +// 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; +} +``` + +### Step-by-Step Explanation + +1. **Prefix Addition**: The function adds an 'evm:' prefix to distinguish EVM addresses +2. **Byte Conversion**: + - Converts the prefix to bytes using TextEncoder + - Converts the Ethereum address to bytes using hexToU8a +3. **Combination**: Creates a new Uint8Array containing both the prefix and address bytes +4. **Hashing**: Uses Blake2b (via blake2AsU8a) to create a deterministic hash of the combined bytes +5. **SS58 Encoding**: Finally encodes the hash as an SS58 address using network ID 42 (Bittensor's network ID) + diff --git a/docs/evm-tutorials/config.js b/docs/evm-tutorials/config.js new file mode 100644 index 000000000..36f30299f --- /dev/null +++ b/docs/evm-tutorials/config.js @@ -0,0 +1,18 @@ +// PROTECT YOUR PRIVATE KEYS WELL, NEVER COMMIT THEM TO GITHUB OR SHARE WITH ANYONE +const ethPrivateKey = "0xC3467d8BA8F76018F39a98996bf5677E16b33755"; +const subSeed = "//Alice"; +const rpcUrlLocal = 'http://127.0.0.1:9946'; +const rpcUrlTestnet = 'https://test.chain.opentensor.ai'; +const wsUrlLocal = 'ws://127.0.0.1:9946'; +const wsUrlTestnet = 'wss://evm-testnet.dev.opentensor.ai'; + +module.exports = { + ethPrivateKey, + subSeed, + rpcUrl: rpcUrlTestnet, + wsUrl: wsUrlTestnet, +} + +module.exports = { + rpcUrl: 'https://test.chain.opentensor.ai', + }; \ No newline at end of file diff --git a/docs/evm-tutorials/ed25519-verify-precompile.md b/docs/evm-tutorials/ed25519-verify-precompile.md index bef9f88a3..272e32896 100644 --- a/docs/evm-tutorials/ed25519-verify-precompile.md +++ b/docs/evm-tutorials/ed25519-verify-precompile.md @@ -1,11 +1,11 @@ --- -title: "Ed25519 Verify Precompile" +title: "Verify Address Precompile" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Ed25519 Verify Precompile +# Verify Address Precompile The Ed25519 Verify Precompile allows EVM smart contracts to verify Ed25519 signatures, which are commonly used in Substrate-based chains like Bittensor. This is essential for bridging identity and ownership between Substrate and EVM ecosystems. For example, you may want to verify coldkey ownership before transferring to someone. EVM functionality doesn't allow transferring directly to a `ss58` address—like the public key of a Bittensor coldkey—because EVM uses the H160 address schema. To bridge the gap, you can use this precompile to prove a claim of ownership. The owner of a coldkey can send an EVM transaction with a signed message, serving as proof of ownership of the coldkey's `ss58` address. @@ -17,8 +17,6 @@ The Ed25519 Verify Precompile allows EVM smart contracts to verify Ed25519 signa - [Get set up for using EVM wallet on testnet](./evm-testnet-with-metamask-wallet) - [Install](./install) the EVM-Bittensor repo, containing scripts and examples. -A healthy node will return a JSON response with the latest block number. If you get a connection error or no response, the node is down or the URL is incorrect. - ## Example Navigate to the `examples` directory of the EVM-Bittensor repo: diff --git a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md index ed0862321..0b5857d7c 100644 --- a/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-localnet-with-metamask-wallet.md @@ -11,10 +11,6 @@ This page covers getting set up to use EVM on a locally deployed Bittensor block Consider first trying [EVM with Bittensor testnet](./evm-testnet-with-metamask-wallet.md). This allows you to try EVM without having to deploy a blockchain locally, but you will have to obtain testnet TAO by inquiring in discord, or by completing the [BTCLI playground](../btcli/btcli-playground)challenge to obtain testnet TAO. -:::tip blog post: EVM on Bittensor -If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. -::: - Key values: - **EVM Subtensor Mainnet Chain ID:**: `964` (UTF-8 encoded TAO symbol) - **EVM Subtensor Testnet Chain ID:**: `945` (UTF-8 encoded alpha character) diff --git a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md index 78118255b..244ac83ed 100644 --- a/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-mainnet-with-metamask-wallet.md @@ -8,9 +8,6 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; This page covers how to set up your Metamask wallet to use with the Mainnet (finney) on Bittensor. You must run this step before you can run other tutorials in this section. -:::tip blog post: EVM on Bittensor -If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. -::: Key values: - The **Bittensor Mainnet URL:** `https://lite.chain.opentensor.ai` diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index 8e787ab01..25b69909b 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -8,10 +8,6 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; This page covers how to set up your Metamask wallet to use with the testnet on Bittensor. You must run this step before you can run other tutorials in this section. -:::tip blog post: EVM on Bittensor -If you are new to EVM, try this [blog post](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) for a simplified explanation. -::: - Key values: - The **Bittensor Testnet URL:** `https://test.chain.opentensor.ai` - **EVM Subtensor Chain ID:** `945` (UTF-8 encoded alpha character) diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md index 841b99fc8..120db8c65 100644 --- a/docs/evm-tutorials/examples.md +++ b/docs/evm-tutorials/examples.md @@ -9,6 +9,10 @@ The following precompiles are available on the Bittensor EVM. Code examples used throughout are provided by OTF, and come from [this repository.](https://github.com/opentensor/evm-bittensor/tree/main/examples) +## Tutorials and Examples + +- [Converting Between Ethereum and Substrate Addresses](./address-conversion.md): Learn how to convert between H160 and SS58 address formats + ## Standard Ethereum Precompiles - `ECRecover` (0x1): Recover the address associated with the public key from elliptic curve signature diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index 47d945e5b..d3ed8a2ba 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -31,8 +31,10 @@ Bittensor EVM smart contracts are executed solely on the **Bittensor blockchain, See: - [Examples and Precompiles](./examples.md) -- Getting started with [Bittensor EVM on Testnet](./evm-testnet-with-metamask-wallet) - +- [EVM on Testnet](./evm-testnet-with-metamask-wallet) +- [EVM on Local Chain](./evm-localnet-with-metamask-wallet) +- [EVM on Mainnet](./evm-mainnet-with-metamask-wallet) +- [OTF Blogpost: EVM on Bittensor](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) ## Networks diff --git a/docs/evm-tutorials/staking-precompile.md b/docs/evm-tutorials/staking-precompile.md index 0385e2bd7..8a0367fc7 100644 --- a/docs/evm-tutorials/staking-precompile.md +++ b/docs/evm-tutorials/staking-precompile.md @@ -7,163 +7,107 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Staking Precompile -The staking precompile allows you to interact with staking operations on the Bittensor network through smart contracts. This precompile provides functionality for adding and removing stakes, moving stakes between hotkeys, and querying stake information. +Staking precompile allows Ethereum code to interact with the staking feature of subtensor. For example, by using the staking precompile, the subtensor methods [`add_stake`](https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/staking/add_stake.rs) or [`remove_stake`](https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/staking/remove_stake.rs) can be called in order to delegate stake to a hotkey or undelegate stake from a hotkey. -## Precompile Address +In this tutorial you will learn how to interact with staking precompile in two ways: -The staking precompile is available at address `0x805` (2053 in decimal). +1. Call the staking precompile from another smart contract. +2. Use the staking precompile's ABI and your Metamask wallet to call the staking precompile on EVM localnet. You will use [Remix IDE](https://remix.ethereum.org/) for this. -## Available Functions +## Prerequisites -### Stake Management +1. Read [EVM on Subtensor](./) for a basic introduction to Bittensor EVM +1. You should also be comfortable using [Remix IDE](https://remix.ethereum.org/). -#### `addStake(bytes32 hotkey, uint256 amount, uint256 netuid)` -Add stake to a hotkey in a specific subnet. This is a payable function that requires TAO to be sent with the transaction. +## Setup EVM localnet, subnet and delegate -```solidity -function addStake(bytes32 hotkey, uint256 amount, uint256 netuid) external payable; -``` +1. [Launch EVM localnet](./evm-localnet-with-metamask-wallet.md). Also, follow the instructions of running local chain all the way so that you have a Metamask address with some TAO balance. -#### `removeStake(bytes32 hotkey, uint256 amount, uint256 netuid)` -Remove stake from a hotkey in a specific subnet. +2. On this EVM localnet create one subnet and a delegate hotkey. The commands below will create a subnet, register a neuron and nominate your hotkey as a delegate, in that order: -```solidity -function removeStake(bytes32 hotkey, uint256 amount, uint256 netuid) external; +```sh +btcli subnet create --network ws://127.0.0.1:9944 +btcli subnet register --network ws://127.0.0.1:9944 ``` -#### `moveStake(bytes32 origin_hotkey, bytes32 destination_hotkey, uint256 origin_netuid, uint256 destination_netuid, uint256 amount)` -Move stake from one hotkey to another, potentially across different subnets. - -```solidity -function moveStake( - bytes32 origin_hotkey, - bytes32 destination_hotkey, - uint256 origin_netuid, - uint256 destination_netuid, - uint256 amount -) external; -``` +3. Save the delegate hotkey address. You will use this in the staking pool use case below. -#### `transferStake(bytes32 destination_coldkey, bytes32 hotkey, uint256 origin_netuid, uint256 destination_netuid, uint256 amount)` -Transfer stake from one coldkey to another, potentially across different subnets. - -```solidity -function transferStake( - bytes32 destination_coldkey, - bytes32 hotkey, - uint256 origin_netuid, - uint256 destination_netuid, - uint256 amount -) external; -``` +4. Disable staking rate limits by setting `targetStakesPerInterval` to 1000. Follow these below steps: + - Open the Polkadot JS app using [this link with encoded transaction](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics/decode/0x0c00132fe803000000000000). + - Click on **Submission** tab. + - From the **using the selected account** field, select **ALICE**. + - Click on **Submit Transaction** at the bottom right. This will open the **authorize transaction** window. + - On this **authorize transaction** window, make sure the **sign and submit** toggle is ON and click on the **Sign and Submit** on the bottom right. -### Stake Queries +## Call the staking precompile from another smart contract (staking pool use case) -#### `getTotalColdkeyStake(bytes32 coldkey) returns (uint256)` -Get the total stake for a coldkey across all subnets. +In this interaction you will compile [`stake.sol`](https://github.com/opentensor/evm-bittensor/blob/main/solidity/stake.sol), a smart contract Solidity code and execute it on the subtensor EVM. This `stake.sol` will, in turn, call the staking precompile that is already deployed in the subtensor EVM. -```solidity -function getTotalColdkeyStake(bytes32 coldkey) external view returns (uint256); -``` +Before you proceed, familiarize yourself with the Solidity code of the [`stake.sol`](https://github.com/opentensor/evm-bittensor/blob/main/solidity/stake.sol) smart contract. -#### `getTotalHotkeyStake(bytes32 hotkey) returns (uint256)` -Get the total stake for a hotkey across all subnets. +1. Copy the text of [`stake.sol`](https://github.com/opentensor/evm-bittensor/blob/main/solidity/stake.sol) contract to Remix IDE. -```solidity -function getTotalHotkeyStake(bytes32 hotkey) external view returns (uint256); -``` +2. You will now convert your delegate hotkey ss58 from the above [Setup EVM localnet, subnet and delegate](#setup-evm-localnet-subnet-and-delegate) step into its corresponding public key. Use the [ss58.org](https://ss58.org/) site to obtain the public key for your delegate hotkey ss58. -#### `getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) returns (uint256)` -Get the stake between a specific hotkey and coldkey in a subnet. +3. In the `stake.sol` text in Remix IDE, replace the `HOTKEY` constant on line 9, where it says `bytes32 constant HOTKEY = 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d;`, with your delegate hotkey's public key. -```solidity -function getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns (uint256); -``` +4. Compile it in Remix IDE. -#### `getTotalAlphaStaked(bytes32 hotkey, uint256 netuid) returns (uint256)` -Get the total amount of TAO staked by a hotkey in a specific subnet. +5. Connect Remix IDE to Injected Provider - Metamask and your Metamask address that has TAO balance. You will stake this TAO balance to the delegate hotkey's public key. -```solidity -function getTotalAlphaStaked(bytes32 hotkey, uint256 netuid) external view returns (uint256); -``` +6. Execute the Stake contract method `stake_from_this_contract_to_alice` and pass 1e^9 to it (1 TAO). -#### `getAlphaStakedValidators(bytes32 hotkey, uint256 netuid) returns (bytes32[])` -Get a list of validator addresses that have staked to a specific hotkey in a subnet. +7. Check the stake balance of your delegate hotkey and confirm that it has increased by 1 TAO. -```solidity -function getAlphaStakedValidators(bytes32 hotkey, uint256 netuid) external view returns (bytes32[]); -``` +## Use the staking precompile's ABI from your user account (staking as an individual use case) -### Proxy Management +In this tutorial, you will interact directly with the staking precompile by using its ABI, and use your Metamask wallet as the source of TAO to stake. -#### `addProxy(bytes32 delegate)` -Add a proxy delegate for staking operations. - -```solidity -function addProxy(bytes32 delegate) external; -``` - -#### `removeProxy(bytes32 delegate)` -Remove a proxy delegate. - -```solidity -function removeProxy(bytes32 delegate) external; -``` - -## Example Usage - -Here's an example of how to use the staking precompile in a smart contract: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IStakingPrecompile { - function addStake(bytes32 hotkey, uint256 amount, uint256 netuid) external payable; - function removeStake(bytes32 hotkey, uint256 amount, uint256 netuid) external; - function getTotalColdkeyStake(bytes32 coldkey) external view returns (uint256); - function getTotalHotkeyStake(bytes32 hotkey) external view returns (uint256); - function getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns (uint256); - function getTotalAlphaStaked(bytes32 hotkey, uint256 netuid) external view returns (uint256); - function getAlphaStakedValidators(bytes32 hotkey, uint256 netuid) external view returns (bytes32[]); -} - -contract StakingManager { - address constant STAKING_PRECOMPILE = 0x805; - IStakingPrecompile staking = IStakingPrecompile(STAKING_PRECOMPILE); - - function addStakeToHotkey(bytes32 hotkey, uint256 amount, uint256 netuid) external payable { - staking.addStake{value: msg.value}(hotkey, amount, netuid); - } - - function getStakeInfo(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns ( - uint256 totalColdkeyStake, - uint256 totalHotkeyStake, - uint256 specificStake, - uint256 totalAlphaStaked, - bytes32[] memory validators - ) { - totalColdkeyStake = staking.getTotalColdkeyStake(coldkey); - totalHotkeyStake = staking.getTotalHotkeyStake(hotkey); - specificStake = staking.getStake(hotkey, coldkey, netuid); - totalAlphaStaked = staking.getTotalAlphaStaked(hotkey, netuid); - validators = staking.getAlphaStakedValidators(hotkey, netuid); - } -} -``` +1. Copy this below ABI of staking precompile contract into Remix IDE as a new file: -## Important Notes + ```json + [ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hotkey", + "type": "bytes32" + } + ], + "name": "addStake", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hotkey", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "removeStake", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ] + ``` -1. The `addStake` function is payable and requires TAO to be sent with the transaction. -2. All amounts are in RAO (1 TAO = 1e18 RAO). -3. The `netuid` parameter identifies the specific subnet for the operation. -4. Proxy operations require appropriate permissions. -5. Moving and transferring stakes may have additional restrictions based on network parameters. -6. Some functions may require specific permissions or conditions to be met. +2. Copy staking precompile address `0x0000000000000000000000000000000000000801` to the **At Address** field in Remix IDE, and click **At Address** button. -## Next Steps +3. Remix IDE will find the precompile at the precompile address on the subtensor EVM and show it in the list of deployed contracts. Expand the contract, then expand the `addStake` method, and paste the public key of your delegate hotkey into the `hotkey` field. Then click **transact** and wait for the transaction to be completed. -- Learn about [subnet management](/evm-tutorials/subnet-precompile) -- Understand [neuron operations](/evm-tutorials/neuron-precompile) -- Explore [metagraph interactions](/evm-tutorials/metagraph-precompile) +4. Follow these steps to see that the stake record is updated in [Polkadot JS app](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/chainstate): + 1. Select **subtensorModule** + **stake** in the drop-down list. + 2. Paste the delegate hotkey account ID in the first parameter. + 3. Toggle **include option** OFF for the second parameter. + 4. Click the **+** button and find the new stake record. diff --git a/docs/evm-tutorials/transfer-from-metamask-to-ss58.md b/docs/evm-tutorials/transfer-from-metamask-to-ss58.md index 955901522..f7dafb785 100644 --- a/docs/evm-tutorials/transfer-from-metamask-to-ss58.md +++ b/docs/evm-tutorials/transfer-from-metamask-to-ss58.md @@ -1,137 +1,142 @@ --- -title: "Transfer from Metamask to SS58 address" +title: "Transfer TAO from Metamask to SS58 Address" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Transfer from Metamask to SS58 address +# Transfer TAO from Metamask to SS58 Address -In this tutorial you will learn how to transfer TAO from your Metamask wallet to your Bittensor SS58 address for a coldkey (wallet) or a hotkey. You will learn how to do this via two different methods: +In this tutorial you will learn how to transfer TAO from your Metamask wallet to your Bittensor SS58 address for a coldkey (wallet) or a hotkey. There are two different options: -- **Method 1:** Transfer using a precompiled contract. -- **Method 2:** Transfer using the `withdraw` extrinsic in the `evm` pallet in subtensor blockchain. +- [**Option 1:** Transfer using a precompiled contract](#option-1-transfer-using-a-precompiled-contract). +- [**Option 2:** Transfer using the `withdraw` extrinsic in the `evm` pallet in subtensor blockchain](#option-2-transfer-using-the-withdraw-extrinsic-in-the-subtensor-evm-pallet). -## Prerequisite +## Prerequisites -:::danger stop, did you set up your Metamask wallet for EVM? -You must run [EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet.md) tutorial before you can run this tutorial. -::: +- **Node.js** (v16 or later recommended) +- **npm** or **yarn** +- [Clone the Bittensor EVM examples repo](./install.md) +- [Get set up for using EVM wallet on testnet](./evm-testnet-with-metamask-wallet) +- [Install](./install) the EVM-Bittensor repo, containing scripts and examples. + + +## Option 1: Transfer using a Precompiled Contract + +**Best for:** Most users. You do NOT need the private key or seed for your SS58 address. -## Method 1: Transfer using a precompiled contract +This option uses a precompiled contract to transfer TAO from your Metamask wallet to any SS58 address (coldkey or hotkey). -The private key or the seed for your SS58 is **not required** for this method. +### Configure the destination address -This step will transfer 0.5 TAO to your `ss58` destination address specified in the [`withdraw.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js) file. Look for the following lines in this file: +Open [`withdraw.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js) in the EVM-Bittensor repo. Find the following line: -```javascript +```js // Destination address can be replaced with any ss58 address here: const destinationAddress = account.address; ``` -and provide your `ss58` destination address as shown below: +Replace it with your own SS58 address: -```javascript +```js const destinationAddress = "5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y"; ``` -:::danger Stop. Did you install the dependencies? -Before you proceed, make sure you finished the [Install](./install.md) step. -::: - -Next, navigate to the `examples` directory of the EVM-Bittensor repo: - ```bash - cd examples - ``` -Run: +### Run the transfer script ```bash node transfer.js ``` -:::tip -In Bittensor EVM, 1 TAO should be written as $1e18$ - -For [example](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58): `const value = BigInt(0.5 * 1e18).toString();` +:::tip 1 TAO = 1e18 +In Bittensor EVM, 1 TAO is written as `1e18` (just like on Ethereum). For example, to send 0.5 TAO: +```js +const value = BigInt(0.5 * 1e18).toString(); +``` ::: -Then, run: +### Run the withdraw script ```bash node withdraw.js ``` -You will see the output similar to below, indicating a successful transfer of TAO from your Metamask account to your `ss58` destination address: +You should see output similar to: ```bash showLineNumbers node withdraw.js 2024-10-07 15:34:58 REGISTRY: Unknown signed extensions SubtensorSignedExtension, CommitmentsSignedExtension found, treating them as no-effect -2024-10-07 15:34:58 API/INIT: RPC methods not decorated: chainHead_v1_body, chainHead_v1_call, chainHead_v1_continue, chainHead_v1_follow, chainHead_v1_header, chainHead_v1_stopOperation, chainHead_v1_storage, chainHead_v1_unfollow, chainHead_v1_unpin, chainSpec_v1_chainName, chainSpec_v1_genesisHash, chainSpec_v1_properties, debug_getBadBlocks, debug_getRawBlock, debug_getRawHeader, debug_getRawReceipts, debug_getRawTransaction, delegateInfo_getDelegate, delegateInfo_getDelegated, delegateInfo_getDelegates, eth_getBlockReceipts, neuronInfo_getNeuron, neuronInfo_getNeuronLite, neuronInfo_getNeurons, neuronInfo_getNeuronsLite, subnetInfo_getLockCost, subnetInfo_getSubnetHyperparams, subnetInfo_getSubnetInfo, subnetInfo_getSubnetInfo_v2, subnetInfo_getSubnetsInf_v2, subnetInfo_getSubnetsInfo, transactionWatch_v1_submitAndWatch, transactionWatch_v1_unwatch, transaction_v1_broadcast, transaction_v1_stop -2024-10-07 15:34:58 API/INIT: node-subtensor/302: Not decorating unknown runtime apis: 0x42e62be4a39e5b60/1, 0x806df4ccaa9ed485/1, 0x8375104b299b74c5/1, 0x5d1fbfbe852f2807/1, 0xc6886e2f8e598b0a/1 +... Sending balance to ss58 address: 5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y pubk = f873b72b75b9029397edceaa04cf08cc97909c8b6304f2ccc3593641bf92e97c -Transaction response: ContractTransactionResponse { - provider: JsonRpcProvider {}, - blockNumber: null, - blockHash: null, - index: undefined, - hash: '0x4f3bde9e678d7307f2c07dd3212d6920db8e2af8ade052a823b3ad1f28ddc221', - type: 2, - to: '0x0000000000000000000000000000000000000800', - from: '0x709615c655B24919F48B365D292521EFcC74467B', - nonce: 0, - gasLimit: 21576n, - gasPrice: undefined, - maxPriorityFeePerGas: 0n, - maxFeePerGas: 20000000000n, - maxFeePerBlobGas: null, - data: '0xcd6f4eb1f873b72b75b9029397edceaa04cf08cc97909c8b6304f2ccc3593641bf92e97c', - value: 500000000000000000n, - chainId: 945n, - signature: Signature { r: "0xc8cf1d54513eb26ee13ca8e001201e918d50593ce6efd4ceee6645ec1879f183", s: "0x6594fe686ecac6131b536b9ff5277f40da1d12ab6c2a269693029c58cef8417d", yParity: 0, networkV: null }, - accessList: [], - blobVersionedHashes: null -} +Transaction response: ContractTransactionResponse { ... } Transaction confirmed. ``` -In the above example, a coldkey `ss58` address `5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y` (line 5 in the above log) is used as a destination address. The Metamask wallet address used is: `0x709615c655B24919F48B365D292521EFcC74467B` (line 15 in the above log). +:::info +The `ss58` address is your destination (coldkey or hotkey). The `from` address is your Metamask wallet. +::: + +### Check your SS58 balance -Finally, use the below `btcli` command to check the balance of your `ss58` address (the below `--ss58` option is supported in BTCLI 8.2.0 or later versions): +Use the Bittensor CLI to check your new balance: ```bash btcli wallet balance --ss58 5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y ``` -## Method 2: Transfer using `withdraw` extrinsic in subtensor `evm` pallet +## Option 2: Transfer using the `withdraw` Extrinsic in the Subtensor EVM Pallet -You will need the private key for your SS58 for this method. +**Best for:** Advanced users. You WILL need the private key for your SS58 address. -1. Copy your `ss58` address (for example: `5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`). You need the private key for this address setup in Polkadot JS extension. -2. Paste it into `ss58Address` in main function in [`withdraw-address.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw-address.js) script. +This option uses the `withdraw` extrinsic in the EVM pallet, allowing you to transfer from an EVM address to an SS58 address using Polkadot.js Apps. -3. Next, navigate to the `examples` directory of the EVM-Bittensor repo: +### Copy your SS58 address - ```bash - cd examples - ``` +For example: `5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`. You will need the private key for this address set up in the Polkadot.js extension. -4. Run: +### Edit the destination in the script - ```bash - node withdraw-address.js - ``` +Open [`withdraw-address.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw-address.js) and set your SS58 address: + +```js +const ss58Address = ""; +``` -5. Copy the "Ethereum mirror:" output address. -6. Transfer the amount to this address that you wish to transfer using Metamask. Make sure to clear activity tab data if you restarted the network previously: **Settings** > **Advanced** > **Clear activity tab data**. -7. Make sure your destination address is funded to run a transaction. -8. Open the **Extrisics** section in Polkadot JS app: [https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftest.chain.opentensor.ai%3A443#/extrinsics](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftest.chain.opentensor.ai%3A443#/extrinsics). -9. Select `evm` pallet and `withdraw` extrinsic. -10. Paste the "Ethereum mirror" output address into address field. -11. Put the amount you are transferring into amount field. Note that Metamask balances are by 10^9 lower than Polkadot Apps UI balances because Metamask will not respect 10^9 decimals for native currency before we have a corresponding PR to https://github.com/ethereum-lists merged. -12. Submit the transaction. -13. Finally, use the below `btcli` command to check the balance of your `ss58` address (the below `--ss58` option is supported in BTCLI 8.2.0 or later versions): +### Run the withdraw-address script + +```bash +node withdraw-address.js +``` - ```bash - btcli wallet balance --ss58 - ``` +### Copy the "Ethereum mirror" output address + +The script will output an "Ethereum mirror" address. Copy this address. + +### Transfer TAO to the mirror address using Metamask + +- Open Metamask and send the desired amount of TAO to the mirror address. +- If you restarted the network, clear Metamask's activity tab data: **Settings > Advanced > Clear activity tab data**. + +### Ensure your destination address is funded + +Make sure the destination address has enough TAO to pay for transaction fees. + +### Open the Extrinsics page in Polkadot.js Apps + +[Polkadot.js Apps Extrinsics](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftest.chain.opentensor.ai%3A443#/extrinsics) + +### Submit the withdraw extrinsic + +- Select the `evm` pallet and `withdraw` extrinsic. +- Paste the "Ethereum mirror" address into the address field. +- Enter the amount you are transferring. +- Note: Metamask balances are by 10^9 lower than Polkadot Apps UI balances (Metamask does not respect 10^9 decimals for native currency). + +### Submit the transaction + +### Check your SS58 balance + +```bash +btcli wallet balance --ss58 +``` diff --git a/docs/evm-tutorials/transfer-from-metamask-to-ss58EDGE.md b/docs/evm-tutorials/transfer-from-metamask-to-ss58EDGE.md new file mode 100644 index 000000000..1774226b9 --- /dev/null +++ b/docs/evm-tutorials/transfer-from-metamask-to-ss58EDGE.md @@ -0,0 +1,128 @@ +--- +title: "Transfer from Metamask to SS58 address" +--- +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +# Transfer from Metamask to SS58 address + +In this tutorial you will learn how to transfer TAO from your Metamask wallet to your Bittensor SS58 address for a coldkey (wallet) or a hotkey. You will learn how to do this via two different methods: + +- **Method 1:** Transfer using a precompiled contract. +- **Method 2:** Transfer using the `withdraw` extrinsic in the `evm` pallet in subtensor blockchain. + +## Prerequisite + +:::danger stop, did you set up your Metamask wallet for EVM? +You must run [EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet.md) tutorial before you can run this tutorial. +::: + +## Method 1: Transfer using a precompiled contract + +The private key or the seed for your SS58 is **not required** for this method. + +This step will transfer 0.5 TAO to your `ss58` destination address specified in the [`withdraw.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js) file. Look for the following lines in this file: + +```javascript +// Destination address can be replaced with any ss58 address here: +const destinationAddress = account.address; +``` + +and provide your `ss58` destination address as shown below: + +```javascript +const destinationAddress = "5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y"; +``` + +Run: + +```bash +node transfer.js +``` + +:::tip +In Bittensor EVM, 1 TAO should be written as $1e18$ + +For [example](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw.js#L58): `const value = BigInt(0.5 * 1e18).toString();` +::: + +Then, run: + +```bash +node withdraw.js +``` + +You will see the output similar to below, indicating a successful transfer of TAO from your Metamask account to your `ss58` destination address: + +```bash showLineNumbers +node withdraw.js +2024-10-07 15:34:58 REGISTRY: Unknown signed extensions SubtensorSignedExtension, CommitmentsSignedExtension found, treating them as no-effect +2024-10-07 15:34:58 API/INIT: RPC methods not decorated: chainHead_v1_body, chainHead_v1_call, chainHead_v1_continue, chainHead_v1_follow, chainHead_v1_header, chainHead_v1_stopOperation, chainHead_v1_storage, chainHead_v1_unfollow, chainHead_v1_unpin, chainSpec_v1_chainName, chainSpec_v1_genesisHash, chainSpec_v1_properties, debug_getBadBlocks, debug_getRawBlock, debug_getRawHeader, debug_getRawReceipts, debug_getRawTransaction, delegateInfo_getDelegate, delegateInfo_getDelegated, delegateInfo_getDelegates, eth_getBlockReceipts, neuronInfo_getNeuron, neuronInfo_getNeuronLite, neuronInfo_getNeurons, neuronInfo_getNeuronsLite, subnetInfo_getLockCost, subnetInfo_getSubnetHyperparams, subnetInfo_getSubnetInfo, subnetInfo_getSubnetInfo_v2, subnetInfo_getSubnetsInf_v2, subnetInfo_getSubnetsInfo, transactionWatch_v1_submitAndWatch, transactionWatch_v1_unwatch, transaction_v1_broadcast, transaction_v1_stop +2024-10-07 15:34:58 API/INIT: node-subtensor/302: Not decorating unknown runtime apis: 0x42e62be4a39e5b60/1, 0x806df4ccaa9ed485/1, 0x8375104b299b74c5/1, 0x5d1fbfbe852f2807/1, 0xc6886e2f8e598b0a/1 +Sending balance to ss58 address: 5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y +pubk = f873b72b75b9029397edceaa04cf08cc97909c8b6304f2ccc3593641bf92e97c +Transaction response: ContractTransactionResponse { + provider: JsonRpcProvider {}, + blockNumber: null, + blockHash: null, + index: undefined, + hash: '0x4f3bde9e678d7307f2c07dd3212d6920db8e2af8ade052a823b3ad1f28ddc221', + type: 2, + to: '0x0000000000000000000000000000000000000800', + from: '0x709615c655B24919F48B365D292521EFcC74467B', + nonce: 0, + gasLimit: 21576n, + gasPrice: undefined, + maxPriorityFeePerGas: 0n, + maxFeePerGas: 20000000000n, + maxFeePerBlobGas: null, + data: '0xcd6f4eb1f873b72b75b9029397edceaa04cf08cc97909c8b6304f2ccc3593641bf92e97c', + value: 500000000000000000n, + chainId: 945n, + signature: Signature { r: "0xc8cf1d54513eb26ee13ca8e001201e918d50593ce6efd4ceee6645ec1879f183", s: "0x6594fe686ecac6131b536b9ff5277f40da1d12ab6c2a269693029c58cef8417d", yParity: 0, networkV: null }, + accessList: [], + blobVersionedHashes: null +} +Transaction confirmed. +``` + +In the above example, a coldkey `ss58` address `5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y` (line 5 in the above log) is used as a destination address. The Metamask wallet address used is: `0x709615c655B24919F48B365D292521EFcC74467B` (line 15 in the above log). + +Finally, use the below `btcli` command to check the balance of your `ss58` address (the below `--ss58` option is supported in BTCLI 8.2.0 or later versions): + +```bash +btcli wallet balance --ss58 5HgU7B3xfSfisR1A7wDMt7FHX5Uizj6xtWWHwhwJMZSrdN7y +``` + +## Method 2: Transfer using `withdraw` extrinsic in subtensor `evm` pallet + +You will need the private key for your SS58 for this method. + +1. Copy your `ss58` address (for example: `5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`). You need the private key for this address setup in Polkadot JS extension. +2. Paste it into `ss58Address` in main function in [`withdraw-address.js`](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw-address.js) script. + +3. Next, navigate to the `examples` directory of the EVM-Bittensor repo: + + ```bash + cd examples + ``` + +4. Run: + + ```bash + node withdraw-address.js + ``` + +5. Copy the "Ethereum mirror:" output address. +6. Transfer the amount to this address that you wish to transfer using Metamask. Make sure to clear activity tab data if you restarted the network previously: **Settings** > **Advanced** > **Clear activity tab data**. +7. Make sure your destination address is funded to run a transaction. +8. Open the **Extrisics** section in Polkadot JS app: [https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftest.chain.opentensor.ai%3A443#/extrinsics](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftest.chain.opentensor.ai%3A443#/extrinsics). +9. Select `evm` pallet and `withdraw` extrinsic. +10. Paste the "Ethereum mirror" output address into address field. +11. Put the amount you are transferring into amount field. Note that Metamask balances are by 10^9 lower than Polkadot Apps UI balances because Metamask will not respect 10^9 decimals for native currency before we have a corresponding PR to https://github.com/ethereum-lists merged. +12. Submit the transaction. +13. Finally, use the below `btcli` command to check the balance of your `ss58` address (the below `--ss58` option is supported in BTCLI 8.2.0 or later versions): + + ```bash + btcli wallet balance --ss58 + ``` diff --git a/docs/local-build/create-subnet.md b/docs/local-build/create-subnet.md index 5b55db0e6..2801d3160 100644 --- a/docs/local-build/create-subnet.md +++ b/docs/local-build/create-subnet.md @@ -20,7 +20,7 @@ Prerequisites: btcli subnet create \ --subnet-name awesome-first-subnet \ --wallet.name sn-creator \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` ### Trouble shoot #### Insufficient funds @@ -41,7 +41,7 @@ btcli wallet transfer \ --amount 1001 \ --wallet.name alice \ --destination "5C9xw4..." \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` @@ -98,7 +98,7 @@ To remedy your liquidity shortfall, transfer $\tau$ from the Alice account and t --amount 1001 \ --wallet.name alice \ --destination "5GVsCAY6RuSuoAA1E77xsHJ9PjdZJjJrRkNFDxVtRKPnw7TR" \ - --subtensor.chain_endpoint ws://127.0.0.1:9945 + --network ws://127.0.0.1:9945 ``` ```shell @@ -118,7 +118,7 @@ For example: btcli subnet create \ --subnet-name awesome-first-subnet \ --wallet.name sn-creator \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` ```console Subnet burn cost: τ 1,000.0000 @@ -134,7 +134,7 @@ Decrypting... btcli subnet create \ --subnet-name awesome-second-subnet \ --wallet.name sn-creator \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` ```console @@ -152,7 +152,7 @@ Decrypting... ```shell btcli subnet list \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` ```console Subnets diff --git a/docs/local-build/deploy.md b/docs/local-build/deploy.md index 690a95bf0..0791ac1df 100644 --- a/docs/local-build/deploy.md +++ b/docs/local-build/deploy.md @@ -91,7 +91,7 @@ Ensure your local chain is working by checking the list of subnets. Note the use of the `--chain_endpoint` flag to target the local chain, rather than, say, test network ```shell - btcli subnet list --subtensor.chain_endpoint ws://127.0.0.1:9945 + btcli subnet list --network ws://127.0.0.1:9945 btcli subnet list --network test ``` diff --git a/docs/local-build/mine-validate.md b/docs/local-build/mine-validate.md index 9c0efd443..1f85dfab8 100644 --- a/docs/local-build/mine-validate.md +++ b/docs/local-build/mine-validate.md @@ -21,14 +21,14 @@ Register the subnet miner and validator with the following commands: btcli subnet register \ --wallet.name validator \ --wallet.hotkey default \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` ```bash btcli subnet register \ --netuid 2 \ --wallet.name miner \ --wallet.hotkey default \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` @@ -47,7 +47,7 @@ btcli wallet transfer \ --amount 11 \ --wallet.name alice \ --destination "5EEy34..." \ ---subtensor.chain_endpoint ws://127.0.0.1:9945 +--network ws://127.0.0.1:9945 ``` @@ -82,9 +82,9 @@ Balance: Confirm your registration on the subnet with the following command: ```shell -btcli wallet overview --wallet.name validator --subtensor.chain_endpoint ws://127.0.0.1:9945 +btcli wallet overview --wallet.name validator --network ws://127.0.0.1:9945 -btcli wallet overview --wallet.name miner --subtensor.chain_endpoint ws://127.0.0.1:9945 +btcli wallet overview --wallet.name miner --network ws://127.0.0.1:9945 ``` diff --git a/docs/local-build/provision-wallets.md b/docs/local-build/provision-wallets.md index 89611deee..3ba4cb238 100644 --- a/docs/local-build/provision-wallets.md +++ b/docs/local-build/provision-wallets.md @@ -18,7 +18,7 @@ btcli wallet create --uri alice Confirm Alice's massive $\tau$ bag. ```shell - btcli w balance --wallet.name alice --subtensor.chain_endpoint ws://127.0.0.1:9945 + btcli w balance --wallet.name alice --network ws://127.0.0.1:9945 ``` ```console diff --git a/docs/reference/_bittensor-api-ref.md b/docs/reference/_bittensor-api-ref.md index b24194346..15900f68a 100644 --- a/docs/reference/_bittensor-api-ref.md +++ b/docs/reference/_bittensor-api-ref.md @@ -14,7 +14,7 @@ The `Subtensor` is utilized for managing interactions with the subtensor chain. # Creating a default chain connection to remote finney instance. sub = bt.subtensor() -# Parsing --subtensor.network and --subtensor.chain_endpoint from the command line +# Parsing --subtensor.network and --network from the command line sub = bt.subtensor( config = bt.subtensor.config() ) # Connecting subtensor's default local entrypoint "ws://127.0.0.1:9944" diff --git a/docs/subnets/create-a-subnet.md b/docs/subnets/create-a-subnet.md index caa4ffbfa..398c867e7 100644 --- a/docs/subnets/create-a-subnet.md +++ b/docs/subnets/create-a-subnet.md @@ -56,7 +56,7 @@ If you have not already done so, create Bittensor wallet(s) using the steps desc You will need tokens to register the subnet (which you will create below) on your local blockchain. Run the following command to mint faucet tokens (fake TAO). ```bash -btcli wallet faucet --wallet.name --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli wallet faucet --wallet.name --network ws://127.0.0.1:9946 ``` Output: ```bash @@ -68,7 +68,7 @@ Output: Run the below command to create a new subnet on your local chain. The cost will be exactly τ100.000000000 for the first subnet you create. ```bash -btcli subnet create --wallet.name owner --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli subnet create --wallet.name owner --network ws://127.0.0.1:9946 ``` Output: ```bash diff --git a/sidebars.js b/sidebars.js index 71b98fef0..f33ebf78b 100644 --- a/sidebars.js +++ b/sidebars.js @@ -207,13 +207,13 @@ const sidebars = { label: 'Bittensor EVM: Examples and Precompiles', items:[ "evm-tutorials/examples", - "evm-tutorials/transfer-from-metamask-to-ss58", - "evm-tutorials/transfer-between-two-h160-accounts", - "evm-tutorials/staking-precompile", - "evm-tutorials/ed25519-verify-precompile", - "evm-tutorials/subnet-precompile", - "evm-tutorials/metagraph-precompile", - "evm-tutorials/neuron-precompile", + "evm-tutorials/ed25519-verify-precompile", + "evm-tutorials/transfer-from-metamask-to-ss58", + "evm-tutorials/transfer-between-two-h160-accounts", + "evm-tutorials/staking-precompile", + "evm-tutorials/subnet-precompile", + "evm-tutorials/metagraph-precompile", + "evm-tutorials/neuron-precompile", ] }, // { From 7676dc710aa21d6f6f253174922ef5d65f097499 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Wed, 28 May 2025 14:39:30 -0700 Subject: [PATCH 12/27] wip --- docs/evm-tutorials/address-conversion.md | 2 +- sidebars.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/evm-tutorials/address-conversion.md b/docs/evm-tutorials/address-conversion.md index efb86cdb7..a08505a44 100644 --- a/docs/evm-tutorials/address-conversion.md +++ b/docs/evm-tutorials/address-conversion.md @@ -1,5 +1,5 @@ --- -title: "Converting Ethereum and Substrate Addresses" +title: "Ethereum (H160) to Substrate (SS58) Address Converstion" --- # Converting Ethereum and Substrate Addresses diff --git a/sidebars.js b/sidebars.js index f33ebf78b..e2e328a30 100644 --- a/sidebars.js +++ b/sidebars.js @@ -207,6 +207,7 @@ const sidebars = { label: 'Bittensor EVM: Examples and Precompiles', items:[ "evm-tutorials/examples", + "evm-tutorials/address-conversion", "evm-tutorials/ed25519-verify-precompile", "evm-tutorials/transfer-from-metamask-to-ss58", "evm-tutorials/transfer-between-two-h160-accounts", @@ -214,6 +215,7 @@ const sidebars = { "evm-tutorials/subnet-precompile", "evm-tutorials/metagraph-precompile", "evm-tutorials/neuron-precompile", + ] }, // { From 60548e037c5a5355f6c9ba8e1afb0ecbe8d8e587 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Wed, 28 May 2025 14:53:14 -0700 Subject: [PATCH 13/27] wip --- docs/evm-tutorials/address-conversion.md | 4 +-- docs/evm-tutorials/examples.md | 32 +++++++++++++++++++++++- docs/evm-tutorials/index.md | 15 ----------- docs/evm-tutorials/subtensor-networks.md | 4 +-- sidebars.js | 3 ++- 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/docs/evm-tutorials/address-conversion.md b/docs/evm-tutorials/address-conversion.md index a08505a44..c0ed3ba01 100644 --- a/docs/evm-tutorials/address-conversion.md +++ b/docs/evm-tutorials/address-conversion.md @@ -22,8 +22,8 @@ This conversion is particularly useful when: 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://evm.bittensor.com` - - Chain ID: 3636 + - RPC URL: `https://test.chain.opentensor.ai` + - Chain ID: 945 - Currency Symbol: TAO - Block Explorer URL: `https://evm.bittensor.com` diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md index 120db8c65..1988daab0 100644 --- a/docs/evm-tutorials/examples.md +++ b/docs/evm-tutorials/examples.md @@ -3,13 +3,43 @@ title: "Bittensor EVM: Examples and Precompiles" --- # Bittensor EVM: Examples and Precompiles + ## Available Precompiles The following precompiles are available on the Bittensor EVM. Code examples used throughout are provided by OTF, and come from [this repository.](https://github.com/opentensor/evm-bittensor/tree/main/examples) -## Tutorials and Examples +
+ Install Examples Repo + +Before you can run any EVM tutorials, you must install the dependencies. Follow the below steps: + +1. Clone the Opentensor EVM-Bittensor GitHub repo: + + ```bash + git clone https://github.com/opentensor/evm-bittensor.git + ``` + +2. Navigate to `evm-bittensor` directory: + + ```bash + cd evm-bittensor + ``` + +3. Install the dependencies: + + ```bash + npm install + ``` +
+ + + + + + +## Examples - [Converting Between Ethereum and Substrate Addresses](./address-conversion.md): Learn how to convert between H160 and SS58 address formats diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index d3ed8a2ba..ec1727217 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -36,21 +36,6 @@ See: - [EVM on Mainnet](./evm-mainnet-with-metamask-wallet) - [OTF Blogpost: EVM on Bittensor](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) -## Networks - -You can deploy smart contracts on Bittensor main net (aka 'finney'), test network, or on your own locally deployed Bittensor chain. -
- Network details - - -| | MAINNET | TESTNET | LOCALNET | -|:---------------------|:------------------------------------|:-------------------------------------|:-------------------------| -| **RPC URL** | https://lite.chain.opentensor.ai | https://test.chain.opentensor.ai | http://localhost:9944 | -| **Chain ID** | 964 | 945 | _see below_ | -| **Test TAO** | None | Available on request | Use [Alice account](../local-build/provision-wallets#access-the-alice-account) | -|Set-up Guide|[EVM Testnet with Metamask Wallet](./evm-testnet-with-metamask-wallet)|[EVM Localnet with Metamask Wallet](./evm-localnet-with-metamask-wallet.md) for setting up a Local net.| -
- ## Ethereum vs Bittensor EVM Smart Contracts On the Ethereum network, nodes such as full nodes, validator nodes and archive nodes run the Ethereum Virtual Environment (EVM) run-time environment. Smart contracts operate under this EVM. See the below high-level diagram. diff --git a/docs/evm-tutorials/subtensor-networks.md b/docs/evm-tutorials/subtensor-networks.md index b9947cb97..6178ef3d8 100644 --- a/docs/evm-tutorials/subtensor-networks.md +++ b/docs/evm-tutorials/subtensor-networks.md @@ -1,11 +1,11 @@ --- -title: "Subtensor Networks" +title: "EVM Network Details" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; -# Subtensor Networks +# EVM Network Details | DESCRIPTION | MAINNET | TESTNET | LOCALNET | |:---------------------|:------------------------------------|:-------------------------------------|:-------------------------| diff --git a/sidebars.js b/sidebars.js index e2e328a30..daf21ec1f 100644 --- a/sidebars.js +++ b/sidebars.js @@ -192,7 +192,8 @@ const sidebars = { link: {type: "doc", id: "evm-tutorials/index"}, items:[ "evm-tutorials/index", - "evm-tutorials/install", + "evm-tutorials/subtensor-networks", + "evm-tutorials/evm-testnet-with-metamask-wallet", "evm-tutorials/evm-localnet-with-metamask-wallet", "evm-tutorials/evm-mainnet-with-metamask-wallet", From 8545fe62450d7fee655b2dd6ead1fc32958e7ca6 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Wed, 28 May 2025 17:26:31 -0700 Subject: [PATCH 14/27] wip --- docs/evm-tutorials/config.js | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 docs/evm-tutorials/config.js diff --git a/docs/evm-tutorials/config.js b/docs/evm-tutorials/config.js deleted file mode 100644 index 36f30299f..000000000 --- a/docs/evm-tutorials/config.js +++ /dev/null @@ -1,18 +0,0 @@ -// PROTECT YOUR PRIVATE KEYS WELL, NEVER COMMIT THEM TO GITHUB OR SHARE WITH ANYONE -const ethPrivateKey = "0xC3467d8BA8F76018F39a98996bf5677E16b33755"; -const subSeed = "//Alice"; -const rpcUrlLocal = 'http://127.0.0.1:9946'; -const rpcUrlTestnet = 'https://test.chain.opentensor.ai'; -const wsUrlLocal = 'ws://127.0.0.1:9946'; -const wsUrlTestnet = 'wss://evm-testnet.dev.opentensor.ai'; - -module.exports = { - ethPrivateKey, - subSeed, - rpcUrl: rpcUrlTestnet, - wsUrl: wsUrlTestnet, -} - -module.exports = { - rpcUrl: 'https://test.chain.opentensor.ai', - }; \ No newline at end of file From ceb65b521a9d029ab206e3cc06b9ad55bec49730 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Thu, 29 May 2025 10:45:38 -0700 Subject: [PATCH 15/27] wip --- ...-conversion.md => convert-h160-to-ss58.md} | 4 +- docs/evm-tutorials/convert-ss58-to-h160.md | 18 ++++ docs/evm-tutorials/examples.md | 3 +- docs/evm-tutorials/withdraw-from-alice.md | 97 +++++++++++++++++++ sidebars.js | 3 +- 5 files changed, 121 insertions(+), 4 deletions(-) rename docs/evm-tutorials/{address-conversion.md => convert-h160-to-ss58.md} (97%) create mode 100644 docs/evm-tutorials/convert-ss58-to-h160.md create mode 100644 docs/evm-tutorials/withdraw-from-alice.md diff --git a/docs/evm-tutorials/address-conversion.md b/docs/evm-tutorials/convert-h160-to-ss58.md similarity index 97% rename from docs/evm-tutorials/address-conversion.md rename to docs/evm-tutorials/convert-h160-to-ss58.md index c0ed3ba01..e22a76f8f 100644 --- a/docs/evm-tutorials/address-conversion.md +++ b/docs/evm-tutorials/convert-h160-to-ss58.md @@ -1,8 +1,8 @@ --- -title: "Ethereum (H160) to Substrate (SS58) Address Converstion" +title: "Convert Ethereum (H160) Address to Substrate (SS58)" --- -# Converting Ethereum and Substrate Addresses +# Convert Ethereum (H160) Address to Substrate (SS58) This tutorial demonstrates how to convert between Ethereum (H160) and Substrate (SS58) addresses in the Bittensor EVM environment. diff --git a/docs/evm-tutorials/convert-ss58-to-h160.md b/docs/evm-tutorials/convert-ss58-to-h160.md new file mode 100644 index 000000000..c1cb72b16 --- /dev/null +++ b/docs/evm-tutorials/convert-ss58-to-h160.md @@ -0,0 +1,18 @@ +--- +title: "Convert Substrate (SS58) Address to Ethereum (H160)" +--- + +# Convert Substrate (SS58) Address to Ethereum (H160) + + +## Procedure + +## Conversion Script + +Below is the code used above for the conversion. + +**Source code**: +- [EVM examples repo](https://github.com/opentensor/evm-bittensor) +- [Address mapping](https://github.com/opentensor/evm-bittensor/blob/main/examples/address-mapping.js) +- [Convert address](https://github.com/opentensor/evm-bittensor/blob/main/examples/convert-address.js) + diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md index 1988daab0..9488fc97b 100644 --- a/docs/evm-tutorials/examples.md +++ b/docs/evm-tutorials/examples.md @@ -41,7 +41,8 @@ Before you can run any EVM tutorials, you must install the dependencies. Follow ## Examples -- [Converting Between Ethereum and Substrate Addresses](./address-conversion.md): Learn how to convert between H160 and SS58 address formats +- [Convert Ethereum (H160) Address to Substrate (SS58)](./convert-h160-to-ss58): Learn how to convert between H160 and SS58 address formats +- [Converting Between Ethereum and Substrate Addresses](./convert-h160-to-ss58): Learn how to convert between H160 and SS58 address formats ## Standard Ethereum Precompiles diff --git a/docs/evm-tutorials/withdraw-from-alice.md b/docs/evm-tutorials/withdraw-from-alice.md new file mode 100644 index 000000000..6cb311e79 --- /dev/null +++ b/docs/evm-tutorials/withdraw-from-alice.md @@ -0,0 +1,97 @@ +--- +title: "Withdraw TAO from Alice Account (Local Development)" +--- + +# Withdraw TAO from Alice Account (Local Development) + +The 'Alice' account is provisioned with a large bag of TAO to newly create Subtensor chains. +This page shows how to withdraw TAO to your wallet using a transaction that requires root permissions, and therefore is only available in local development. + +## Procedure + +## Script + +**Source code**: + +- [EVM examples repo](https://github.com/opentensor/evm-bittensor) + +```javascript +const { ethers } = require('ethers'); +const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api'); +const { convertH160ToSS58 } = require('./address-mapping.js'); + +// PROTECT YOUR PRIVATE KEYS WELL, NEVER COMMIT THEM TO GITHUB OR SHARE WITH ANYONE +const { ethPrivateKey, subSeed, rpcUrl, wsUrl } = require('./config.js'); + +function sendTransaction(api, call, signer) { + return new Promise((resolve, reject) => { + let unsubscribed = false; + + const unsubscribe = call.signAndSend(signer, ({ status, events, dispatchError }) => { + const safelyUnsubscribe = () => { + if (!unsubscribed) { + unsubscribed = true; + unsubscribe.then(() => {}) + .catch(error => console.error('Failed to unsubscribe:', error)); + } + }; + + // Check for transaction errors + if (dispatchError) { + let errout = dispatchError.toString(); + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const decoded = api.registry.findMetaError(dispatchError.asModule); + const { docs, name, section } = decoded; + errout = `${name}: ${docs}`; + } + safelyUnsubscribe(); + reject(Error(errout)); + } + // Log and resolve when the transaction is included in a block + if (status.isInBlock) { + safelyUnsubscribe(); + resolve(status.asInBlock); + } + }).catch((error) => { + reject(error); + }); + }); +} + +async function main() { + const wsProvider = new WsProvider(wsUrl); + const api = await ApiPromise.create({ provider: wsProvider }); + const keyring = new Keyring({ type: 'sr25519' }); + + const sender = keyring.addFromUri(subSeed); // Your sender's private key/seed + + // Get ethereum address that matches the private key from the secrets file + const provider = new ethers.JsonRpcProvider(rpcUrl); + const signer = new ethers.Wallet(ethPrivateKey, provider); + const recipientEthereumAddress = signer.address; + + const ss58Address = convertH160ToSS58(recipientEthereumAddress); + console.log(`Mirror: ${ss58Address}`); + // Amount to send: 1 TAO on Substrate side = 1*10^9 + const amount = "1000000000"; + + // Alice funds herself with 1M TAO + const txSudoSetBalance = api.tx.sudo.sudo( + api.tx.balances.forceSetBalance(sender.address, "1000000000000000") + ); + await sendTransaction(api, txSudoSetBalance, sender); + console.log('Balace force-set'); + + // Create a transfer transaction + const transfer = api.tx.balances.transferKeepAlive(ss58Address, amount); + + // Sign and send the transaction + await sendTransaction(api, transfer, sender); + console.log(`Transfer sent to ${recipientEthereumAddress} (its ss58 mirror address is: ${ss58Address})`); + await api.disconnect(); +} + +main().catch(console.error); + +``` diff --git a/sidebars.js b/sidebars.js index daf21ec1f..b3de11596 100644 --- a/sidebars.js +++ b/sidebars.js @@ -208,7 +208,8 @@ const sidebars = { label: 'Bittensor EVM: Examples and Precompiles', items:[ "evm-tutorials/examples", - "evm-tutorials/address-conversion", + "evm-tutorials/convert-h160-to-ss58", + "evm-tutorials/convert-ss58-to-h160", "evm-tutorials/ed25519-verify-precompile", "evm-tutorials/transfer-from-metamask-to-ss58", "evm-tutorials/transfer-between-two-h160-accounts", From 7fecaf69880d439c7e3b31a762dcfd7a22c1b1ec Mon Sep 17 00:00:00 2001 From: michael trestman Date: Thu, 29 May 2025 15:12:21 -0700 Subject: [PATCH 16/27] wip --- docs/evm-tutorials/_create-mm-wallet.mdx | 21 + docs/evm-tutorials/_install.mdx | 38 ++ docs/evm-tutorials/convert-h160-to-ss58.md | 37 +- docs/evm-tutorials/convert-ss58-to-h160.md | 2 - docs/evm-tutorials/examples.md | 29 +- docs/evm-tutorials/subnet-precompile.md | 490 +++++++++++++++------ docs/evm-tutorials/withdraw-from-alice.md | 47 +- sidebars.js | 1 + 8 files changed, 486 insertions(+), 179 deletions(-) create mode 100644 docs/evm-tutorials/_create-mm-wallet.mdx create mode 100644 docs/evm-tutorials/_install.mdx diff --git a/docs/evm-tutorials/_create-mm-wallet.mdx b/docs/evm-tutorials/_create-mm-wallet.mdx new file mode 100644 index 000000000..155859bb5 --- /dev/null +++ b/docs/evm-tutorials/_create-mm-wallet.mdx @@ -0,0 +1,21 @@ +import React from 'react'; + +export const CreatePartial = () => ( + <> +

Create Wallet with MetaMask

+ +
    +
  1. Install MetaMask browser extension if you haven't already.
  2. +
  3. Create a new account or import an existing one.
  4. +
  5. 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: https://evm.bittensor.com
    • +
    +
  6. +
+ +); \ No newline at end of file diff --git a/docs/evm-tutorials/_install.mdx b/docs/evm-tutorials/_install.mdx new file mode 100644 index 000000000..2a39b3092 --- /dev/null +++ b/docs/evm-tutorials/_install.mdx @@ -0,0 +1,38 @@ +export const InstallPartial = () => ( + <> +

Install the EVM Examples repo

+

+ Before you can run any EVM tutorials, you must install the dependencies. Follow the below steps: +

+ +
    +
  1. + Clone the Opentensor EVM-Bittensor GitHub repo: +

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

    +
  2. + +
  3. + Navigate to evm-bittensor directory: +

    + + cd evm-bittensor + +

    +
  4. + +
  5. + Install the dependencies: + + + npm install + + +
  6. +
+ + +); \ No newline at end of file diff --git a/docs/evm-tutorials/convert-h160-to-ss58.md b/docs/evm-tutorials/convert-h160-to-ss58.md index e22a76f8f..e7cf51d02 100644 --- a/docs/evm-tutorials/convert-h160-to-ss58.md +++ b/docs/evm-tutorials/convert-h160-to-ss58.md @@ -1,6 +1,9 @@ --- title: "Convert Ethereum (H160) Address to Substrate (SS58)" --- +import { InstallPartial } from "./_install.mdx"; +import { CreatePartial } from "./_create-mm-wallet.mdx"; + # Convert Ethereum (H160) Address to Substrate (SS58) @@ -16,36 +19,22 @@ This conversion is particularly useful when: ## Procedure -### 1. Create Wallet with MetaMask + -1. Install MetaMask 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: `https://evm.bittensor.com` + -### 2. Convert Address for Bittensor -1. Clone the EVM examples repository: - ```bash - git clone https://github.com/opentensor/evm-bittensor.git - cd evm-bittensor/examples - ``` +## Set your config -2. Install dependencies: - ```bash - npm install - ``` -3. Run the conversion script with your MetaMask address: - ```bash - node convert-address.js - ``` +### Convert Address for Bittensor + +Run the conversion script with your MetaMask address: +```bash +node convert-address.js +``` -4. Note down the SS58 address output by the script - this is your Bittensor address +Note down the SS58 address output by the script - this is your Bittensor address ### 3. Transfer TAO to EVM Wallet diff --git a/docs/evm-tutorials/convert-ss58-to-h160.md b/docs/evm-tutorials/convert-ss58-to-h160.md index c1cb72b16..ccc63a51c 100644 --- a/docs/evm-tutorials/convert-ss58-to-h160.md +++ b/docs/evm-tutorials/convert-ss58-to-h160.md @@ -13,6 +13,4 @@ Below is the code used above for the conversion. **Source code**: - [EVM examples repo](https://github.com/opentensor/evm-bittensor) -- [Address mapping](https://github.com/opentensor/evm-bittensor/blob/main/examples/address-mapping.js) -- [Convert address](https://github.com/opentensor/evm-bittensor/blob/main/examples/convert-address.js) diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md index 9488fc97b..a6b5fb9d6 100644 --- a/docs/evm-tutorials/examples.md +++ b/docs/evm-tutorials/examples.md @@ -2,6 +2,8 @@ title: "Bittensor EVM: Examples and Precompiles" --- +import { InstallPartial } from "./_install.mdx"; + # Bittensor EVM: Examples and Precompiles ## Available Precompiles @@ -10,33 +12,8 @@ The following precompiles are available on the Bittensor EVM. Code examples used throughout are provided by OTF, and come from [this repository.](https://github.com/opentensor/evm-bittensor/tree/main/examples) -
- Install Examples Repo - -Before you can run any EVM tutorials, you must install the dependencies. Follow the below steps: - -1. Clone the Opentensor EVM-Bittensor GitHub repo: - - ```bash - git clone https://github.com/opentensor/evm-bittensor.git - ``` - -2. Navigate to `evm-bittensor` directory: - - ```bash - cd evm-bittensor - ``` - -3. Install the dependencies: - - ```bash - npm install - ``` -
- - - + ## Examples diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md index ea351a47f..13aecf589 100644 --- a/docs/evm-tutorials/subnet-precompile.md +++ b/docs/evm-tutorials/subnet-precompile.md @@ -13,141 +13,383 @@ The subnet precompile allows you to interact with subnet operations on the Bitte The subnet precompile is available at address `0x803` (2051 in decimal). -## Available Functions -### Network Registration - -#### `registerNetwork(bytes32 hotkey)` -Register a new network with a hotkey. This is a payable function that requires TAO to be sent with the transaction. +## Example Scripts + +### Javascript +```js +const { ethers, assert } = require("ethers"); +const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); +const { convertH160ToSS58 } = require("./address-mapping.js"); +const { decodeAddress } = require("@polkadot/util-crypto"); + +// PROTECT YOUR PRIVATE KEYS WELL, NEVER COMMIT THEM TO GITHUB OR SHARE WITH ANYONE +const { ethPrivateKey, subSeed, rpcUrl, wsUrl } = require("./config.js"); +const amount1TAO = BigInt("1000000000"); +// Connect to the Subtensor node +const provider = new ethers.JsonRpcProvider(rpcUrl); + +function sendTransaction(api, call, signer) { + return new Promise((resolve, reject) => { + let unsubscribed = false; + + const unsubscribe = call + .signAndSend(signer, ({ status, events, dispatchError }) => { + const safelyUnsubscribe = () => { + if (!unsubscribed) { + unsubscribed = true; + unsubscribe + .then(() => {}) + .catch((error) => console.error("Failed to unsubscribe:", error)); + } + }; + + // Check for transaction errors + if (dispatchError) { + let errout = dispatchError.toString(); + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const decoded = api.registry.findMetaError(dispatchError.asModule); + const { docs, name, section } = decoded; + errout = `${name}: ${docs}`; + } + safelyUnsubscribe(); + reject(Error(errout)); + } + // Log and resolve when the transaction is included in a block + if (status.isInBlock) { + safelyUnsubscribe(); + resolve(status.asInBlock); + } + }) + .catch((error) => { + reject(error); + }); + }); +} -```solidity -function registerNetwork(bytes32 hotkey) external payable; -``` +// for set +const subnet_contract_abi = [ + { + inputs: [ + { + internalType: "address", + name: "initialOwner", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + inputs: [ + { + internalType: "uint16", + name: "netuid", + type: "uint16", + }, + ], + name: "getHyperParameter", + outputs: [ + { + internalType: "uint64", + name: "", + type: "uint64", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "subnetName", + type: "bytes", + }, + { + internalType: "bytes", + name: "githubRepo", + type: "bytes", + }, + { + internalType: "bytes", + name: "subnetContact", + type: "bytes", + }, + ], + name: "registerNetwork", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint16", + name: "netuid", + type: "uint16", + }, + { + internalType: "uint64", + name: "value", + type: "uint64", + }, + ], + name: "setHyperParameter", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; + +// compile with evm version 0.8.3 +const subnet_contract_bytecode = + "0x608060405234801561001057600080fd5b50604051610e6d380380610e6d8339818101604052810190610032919061015c565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561006d57600080fd5b61007c8161008360201b60201c565b50506101ce565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050610156816101b7565b92915050565b60006020828403121561016e57600080fd5b600061017c84828501610147565b91505092915050565b600061019082610197565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6101c081610185565b81146101cb57600080fd5b50565b610c90806101dd6000396000f3fe6080604052600436106100555760003560e01c8063290212c11461005a578063715018a614610076578063786fede51461008d57806378b63cb6146100ca5780638da5cb5b146100e6578063f2fde38b14610111575b600080fd5b610074600480360381019061006f919061077b565b61013a565b005b34801561008257600080fd5b5061008b610279565b005b34801561009957600080fd5b506100b460048036038101906100af9190610812565b61028d565b6040516100c19190610a3c565b60405180910390f35b6100e460048036038101906100df919061083b565b6103df565b005b3480156100f257600080fd5b506100fb61051a565b6040516101089190610971565b60405180910390f35b34801561011d57600080fd5b5061013860048036038101906101339190610752565b610543565b005b610142610591565b60006108039050600061080373ffffffffffffffffffffffffffffffffffffffff163463290212c160e01b8787876040516024016101829392919061098c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101ec919061095a565b60006040518083038185875af1925050503d8060008114610229576040519150601f19603f3d011682016040523d82523d6000602084013e61022e565b606091505b5050905080610272576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610269906109d8565b60405180910390fd5b5050505050565b610281610591565b61028b60006105d2565b565b600080610803905060008061080373ffffffffffffffffffffffffffffffffffffffff16637444dadc60e01b866040516024016102ca91906109f8565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610334919061095a565b6000604051808303816000865af19150503d8060008114610371576040519150601f19603f3d011682016040523d82523d6000602084013e610376565b606091505b5091509150816103bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103b2906109d8565b60405180910390fd5b6000818060200190518101906103d19190610877565b905080945050505050919050565b6103e7610591565b60006108039050600061080373ffffffffffffffffffffffffffffffffffffffff1663b38e0bbe60e01b8585604051602401610424929190610a13565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161048e919061095a565b6000604051808303816000865af19150503d80600081146104cb576040519150601f19603f3d011682016040523d82523d6000602084013e6104d0565b606091505b5050905080610514576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161050b906109d8565b60405180910390fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054b610591565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561058557600080fd5b61058e816105d2565b50565b3373ffffffffffffffffffffffffffffffffffffffff166105b061051a565b73ffffffffffffffffffffffffffffffffffffffff16146105d057600080fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60006106a96106a484610a7c565b610a57565b9050828152602081018484840111156106c157600080fd5b6106cc848285610b39565b509392505050565b6000813590506106e381610c15565b92915050565b600082601f8301126106fa57600080fd5b813561070a848260208601610696565b91505092915050565b60008135905061072281610c2c565b92915050565b60008135905061073781610c43565b92915050565b60008151905061074c81610c43565b92915050565b60006020828403121561076457600080fd5b6000610772848285016106d4565b91505092915050565b60008060006060848603121561079057600080fd5b600084013567ffffffffffffffff8111156107aa57600080fd5b6107b6868287016106e9565b935050602084013567ffffffffffffffff8111156107d357600080fd5b6107df868287016106e9565b925050604084013567ffffffffffffffff8111156107fc57600080fd5b610808868287016106e9565b9150509250925092565b60006020828403121561082457600080fd5b600061083284828501610713565b91505092915050565b6000806040838503121561084e57600080fd5b600061085c85828601610713565b925050602061086d85828601610728565b9150509250929050565b60006020828403121561088957600080fd5b60006108978482850161073d565b91505092915050565b6108a981610ae5565b82525050565b60006108ba82610aad565b6108c48185610ab8565b93506108d4818560208601610b48565b6108dd81610bdb565b840191505092915050565b60006108f382610aad565b6108fd8185610ac9565b935061090d818560208601610b48565b80840191505092915050565b6000610926601283610ad4565b915061093182610bec565b602082019050919050565b61094581610af7565b82525050565b61095481610b25565b82525050565b600061096682846108e8565b915081905092915050565b600060208201905061098660008301846108a0565b92915050565b600060608201905081810360008301526109a681866108af565b905081810360208301526109ba81856108af565b905081810360408301526109ce81846108af565b9050949350505050565b600060208201905081810360008301526109f181610919565b9050919050565b6000602082019050610a0d600083018461093c565b92915050565b6000604082019050610a28600083018561093c565b610a35602083018461094b565b9392505050565b6000602082019050610a51600083018461094b565b92915050565b6000610a61610a72565b9050610a6d8282610b7b565b919050565b6000604051905090565b600067ffffffffffffffff821115610a9757610a96610bac565b5b610aa082610bdb565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000610af082610b05565b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600067ffffffffffffffff82169050919050565b82818337600083830152505050565b60005b83811015610b66578082015181840152602081019050610b4b565b83811115610b75576000848401525b50505050565b610b8482610bdb565b810181811067ffffffffffffffff82111715610ba357610ba2610bac565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f5375626e65742063616c6c206661696c65640000000000000000000000000000600082015250565b610c1e81610ae5565b8114610c2957600080fd5b50565b610c3581610af7565b8114610c4057600080fd5b50565b610c4c81610b25565b8114610c5757600080fd5b5056fea26469706673582212200e657685be0d4a155c28ec7471273753d1c625c562f268b2efdf0a8b2c7e4dbe64736f6c63430008030033"; + +// Create a signer +const privateKey = ethPrivateKey; // DO NOT HARDCODE YOUR PRIVATE KEY IN PRODUCTION +const signer = new ethers.Wallet(privateKey, provider); + +async function createSubnetGetSetParameter() { + try { + // Substrate ss58 address that will receive the transfer + const wsProvider = new WsProvider(wsUrl); + const api = await ApiPromise.create({ provider: wsProvider }); + const keyring = new Keyring({ type: "sr25519" }); + const account = keyring.addFromUri(subSeed); // Your Substrate address private key/seed + + // Destination address can be replaced with any ss58 address here: + const destinationAddress = account.address; + + // Get the substrate address public key + const pubk = decodeAddress(destinationAddress); + const hex = Array.from(pubk, (byte) => + byte.toString(16).padStart(2, "0") + ).join(""); + + const signer = new ethers.Wallet(ethPrivateKey, provider); + + const ss58mirror = convertH160ToSS58(signer.address); + let txSudoSetBalance = api.tx.sudo.sudo( + api.tx.balances.forceSetBalance(ss58mirror, BigInt(1e18).toString()) + ); + await sendTransaction(api, txSudoSetBalance, account); + + const txSudoSetWhitelist = api.tx.sudo.sudo( + api.tx.evm.setWhitelist([signer.address]) + ); + + await sendTransaction(api, txSudoSetWhitelist, account); + + const contractFactory = new ethers.ContractFactory( + subnet_contract_abi, + subnet_contract_bytecode, + signer + ); + + const subnet_contract = await contractFactory.deploy(signer.address); + await subnet_contract.waitForDeployment(); + + console.log("deployed contract address: ", subnet_contract.target); + + txSudoSetBalance = api.tx.sudo.sudo( + api.tx.balances.forceSetBalance( + convertH160ToSS58(subnet_contract.target), + BigInt(1e16).toString() + ) + ); + await sendTransaction(api, txSudoSetBalance, account); + + let totalNetwork = Number(await api.query.subtensorModule.totalNetworks()); + console.log("total networks is ", totalNetwork); + + // there are predefined network 0 and 3. + let netuid; + if (totalNetwork > 3) { + netuid = totalNetwork; + } else { + netuid = totalNetwork - 1; + } -#### `registerNetwork(bytes32 hotkey, string subnet_name, string github_repo, string subnet_contact, string subnet_url, string discord, string description, string additional)` -Register a new network with a hotkey and identity information. This is a payable function that requires TAO to be sent with the transaction. - -```solidity -function registerNetwork( - bytes32 hotkey, - string subnet_name, - string github_repo, - string subnet_contact, - string subnet_url, - string discord, - string description, - string additional -) external payable; -``` + const encoder = new TextEncoder(); + + let tx = await subnet_contract.registerNetwork( + encoder.encode("name"), + encoder.encode("repo"), + encoder.encode("contact") + ); + await tx.wait(); + + // the network owner is the deployed contract, not the signer + const networkOwner = ( + await api.query.subtensorModule.subnetOwner(netuid) + ).toHuman(); + console.log("networkOwner is ", networkOwner); + + tx = await subnet_contract.setHyperParameter(netuid, 255); + await tx.wait(); + + // get parameter from chain + let parameter = Number( + await api.query.subtensorModule.servingRateLimit(netuid) + ); + + assert(parameter == 255); + + // get paramter from contract + parameter = await subnet_contract.getHyperParameter(netuid); + + // check total networks after registration + console.log( + "total networks is ", + (await api.query.subtensorModule.totalNetworks()).toHuman() + ); + + process.exit(0); + } catch (error) { + console.error("Error:", error); + process.exit(0); + } +} -### Network Parameters - -The subnet precompile provides getter and setter functions for various network parameters: - -#### Rate Limits -- `getServingRateLimit(uint16 netuid) returns (uint64)` -- `setServingRateLimit(uint16 netuid, uint64 serving_rate_limit)` - -#### Difficulty Settings -- `getMinDifficulty(uint16 netuid) returns (uint64)` -- `setMinDifficulty(uint16 netuid, uint64 min_difficulty)` -- `getMaxDifficulty(uint16 netuid) returns (uint64)` -- `setMaxDifficulty(uint16 netuid, uint64 max_difficulty)` -- `getDifficulty(uint16 netuid) returns (uint64)` -- `setDifficulty(uint16 netuid, uint64 difficulty)` - -#### Weights Management -- `getWeightsVersionKey(uint16 netuid) returns (uint64)` -- `setWeightsVersionKey(uint16 netuid, uint64 weights_version_key)` -- `getWeightsSetRateLimit(uint16 netuid) returns (uint64)` -- `setWeightsSetRateLimit(uint16 netuid, uint64 weights_set_rate_limit)` -- `getMaxWeightLimit(uint16 netuid) returns (uint16)` -- `setMaxWeightLimit(uint16 netuid, uint16 max_weight_limit)` -- `getMinAllowedWeights(uint16 netuid) returns (uint16)` -- `setMinAllowedWeights(uint16 netuid, uint16 min_allowed_weights)` - -#### Network Settings -- `getImmunityPeriod(uint16 netuid) returns (uint16)` -- `setImmunityPeriod(uint16 netuid, uint16 immunity_period)` -- `getKappa(uint16 netuid) returns (uint16)` -- `setKappa(uint16 netuid, uint16 kappa)` -- `getRho(uint16 netuid) returns (uint16)` -- `setRho(uint16 netuid, uint16 rho)` -- `getActivityCutoff(uint16 netuid) returns (uint16)` -- `setActivityCutoff(uint16 netuid, uint16 activity_cutoff)` - -#### Registration Settings -- `getNetworkRegistrationAllowed(uint16 netuid) returns (bool)` -- `setNetworkRegistrationAllowed(uint16 netuid, bool registration_allowed)` -- `getNetworkPowRegistrationAllowed(uint16 netuid) returns (bool)` -- `setNetworkPowRegistrationAllowed(uint16 netuid, bool registration_allowed)` - -#### Burn Settings -- `getMinBurn(uint16 netuid) returns (uint64)` -- `setMinBurn(uint16 netuid, uint64 min_burn)` -- `getMaxBurn(uint16 netuid) returns (uint64)` -- `setMaxBurn(uint16 netuid, uint64 max_burn)` - -#### Bonds and Alpha Settings -- `getBondsMovingAverage(uint16 netuid) returns (uint64)` -- `setBondsMovingAverage(uint16 netuid, uint64 bonds_moving_average)` -- `getAlphaValues(uint16 netuid) returns (uint16, uint16)` -- `setAlphaValues(uint16 netuid, uint16 alpha_low, uint16 alpha_high)` - -#### Commit-Reveal Settings -- `getCommitRevealWeightsEnabled(uint16 netuid) returns (bool)` -- `setCommitRevealWeightsEnabled(uint16 netuid, bool enabled)` -- `getCommitRevealWeightsInterval(uint16 netuid) returns (uint64)` -- `setCommitRevealWeightsInterval(uint16 netuid, uint64 interval)` - -#### Liquid Alpha Settings -- `getLiquidAlphaEnabled(uint16 netuid) returns (bool)` -- `setLiquidAlphaEnabled(uint16 netuid, bool enabled)` - -#### Transfer Settings -- `toggleTransfers(uint16 netuid, bool toggle)` - -## Example Usage - -Here's an example of how to use the subnet precompile in a smart contract: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface ISubnetPrecompile { - function registerNetwork(bytes32 hotkey) external payable; - function getDifficulty(uint16 netuid) external view returns (uint64); - function setDifficulty(uint16 netuid, uint64 difficulty) external; +async function main() { + await createSubnetCheckEmission(); } -contract SubnetManager { - address constant SUBNET_PRECOMPILE = 0x803; - ISubnetPrecompile subnet = ISubnetPrecompile(SUBNET_PRECOMPILE); +main().catch(console.error); + +``` +### Solidity +```sol +// SPDX-License-Identifier: GPL-3.0 +// +// This example demonstrates calling of ISubnet precompile +// from another smart contract + +pragma solidity ^0.8.3; +import "@openzeppelin/contracts/access/Ownable.sol"; + +address constant ISUBTENSOR_SUBNET_ADDRESS = 0x0000000000000000000000000000000000000803; + +interface ISubnet { + /// Registers a new network without specifying details. + // function registerNetwork() external payable; + /// Registers a new network with specified subnet name, GitHub repository, and contact information. + function registerNetwork( + bytes memory subnetName, + bytes memory githubRepo, + bytes memory subnetContact + ) external payable; + + function getServingRateLimit(uint16 netuid) external view returns (uint64); + + function setServingRateLimit( + uint16 netuid, + uint64 servingRateLimit + ) external payable; +} - function registerNewNetwork(bytes32 hotkey) external payable { - subnet.registerNetwork{value: msg.value}(hotkey); +contract Subnet is Ownable { + constructor(address initialOwner) Ownable(initialOwner) {} + + function registerNetwork( + bytes memory subnetName, + bytes memory githubRepo, + bytes memory subnetContact + ) external payable onlyOwner { + ISubnet subnetPrecompile = ISubnet(ISUBTENSOR_SUBNET_ADDRESS); + (bool success, ) = ISUBTENSOR_SUBNET_ADDRESS.call{value: msg.value}( + abi.encodeWithSelector( + subnetPrecompile.registerNetwork.selector, + subnetName, + githubRepo, + subnetContact + ) + ); + require(success, "Subnet call failed"); } - function getNetworkDifficulty(uint16 netuid) external view returns (uint64) { - return subnet.getDifficulty(netuid); + function setHyperParameter( + uint16 netuid, + uint64 value + ) external payable onlyOwner { + ISubnet subnetPrecompile = ISubnet(ISUBTENSOR_SUBNET_ADDRESS); + (bool success, ) = ISUBTENSOR_SUBNET_ADDRESS.call( + abi.encodeWithSelector( + subnetPrecompile.setServingRateLimit.selector, + netuid, + value + ) + ); + require(success, "Subnet call failed"); } - function updateNetworkDifficulty(uint16 netuid, uint64 newDifficulty) external { - subnet.setDifficulty(netuid, newDifficulty); + function getHyperParameter(uint16 netuid) public returns (uint64) { + ISubnet subnetPrecompile = ISubnet(ISUBTENSOR_SUBNET_ADDRESS); + (bool success, bytes memory data) = ISUBTENSOR_SUBNET_ADDRESS.call( + abi.encodeWithSelector( + subnetPrecompile.getServingRateLimit.selector, + netuid + ) + ); + require(success, "Subnet call failed"); + + uint64 value = abi.decode(data, (uint64)); + return value; } } -``` - -## Important Notes -1. Most setter functions require admin privileges to execute. -2. The `registerNetwork` functions are payable and require TAO to be sent with the transaction. -3. All network parameters are specific to a subnet identified by its `netuid`. -4. Some functions may be restricted based on network permissions and governance settings. - -## Next Steps - -- Learn about [staking operations](/evm-tutorials/staking-precompile) -- Understand [neuron management](/evm-tutorials/neuron-precompile) -- Explore [metagraph interactions](/evm-tutorials/metagraph-precompile) \ No newline at end of file +``` diff --git a/docs/evm-tutorials/withdraw-from-alice.md b/docs/evm-tutorials/withdraw-from-alice.md index 6cb311e79..d2cd15ce9 100644 --- a/docs/evm-tutorials/withdraw-from-alice.md +++ b/docs/evm-tutorials/withdraw-from-alice.md @@ -2,14 +2,55 @@ title: "Withdraw TAO from Alice Account (Local Development)" --- +import { InstallPartial } from "./_install.mdx"; +import { CreatePartial } from "./_create-mm-wallet.mdx"; + # Withdraw TAO from Alice Account (Local Development) -The 'Alice' account is provisioned with a large bag of TAO to newly create Subtensor chains. -This page shows how to withdraw TAO to your wallet using a transaction that requires root permissions, and therefore is only available in local development. +Every locally deployed dev-mode blockchain comes provisioned with an 'Alice' account holding a large bag of TAO. + +This page shows how to withdraw TAO to your wallet, using a transaction that requires root permissions, and therefore is only available in local development. + +## Prerequesites + +[Deploy a Subtensor Blockchain locally](../local-build/deploy) + ## Procedure -## Script +1. + +1. + +### Configure your request + +The withdraw.js script expects your configuration to be available in config.js. +Select the local configuration options for `rpcURL` and `wsUrl`. + +:::danger +Handle your private keys with care. Do not commit them to Github. +::: +``` +// PROTECT YOUR PRIVATE KEYS WELL, NEVER COMMIT THEM TO GITHUB OR SHARE WITH ANYONE +const ethPrivateKey = ; +const subSeed = "//Alice"; +const rpcUrlLocal = 'http://127.0.0.1:9946'; +const rpcUrlTestnet = 'https://test.chain.opentensor.ai'; +const wsUrlLocal = 'ws://127.0.0.1:9946'; +const wsUrlTestnet = 'wss://test.chain.opentensor.ai'; + +module.exports = { + ethPrivateKey, + subSeed, + rpcUrl: rpcUrlLocal, + wsUrl: wsUrlLocal, +} +``` +### Run the script + +```bash +node withdraw.js +``` **Source code**: diff --git a/sidebars.js b/sidebars.js index b3de11596..dc4c24ac0 100644 --- a/sidebars.js +++ b/sidebars.js @@ -217,6 +217,7 @@ const sidebars = { "evm-tutorials/subnet-precompile", "evm-tutorials/metagraph-precompile", "evm-tutorials/neuron-precompile", + "evm-tutorials/withdraw-from-alice", ] }, From 0b21841156043b504c9863b431c4dfa62eeaa732 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Thu, 29 May 2025 15:41:15 -0700 Subject: [PATCH 17/27] wip --- docs/evm-tutorials/metagraph-precompile.md | 188 --------------------- docs/evm-tutorials/neuron-precompile.md | 182 -------------------- docs/evm-tutorials/subnet-precompile.md | 1 - 3 files changed, 371 deletions(-) diff --git a/docs/evm-tutorials/metagraph-precompile.md b/docs/evm-tutorials/metagraph-precompile.md index cfbc41c93..606a0987a 100644 --- a/docs/evm-tutorials/metagraph-precompile.md +++ b/docs/evm-tutorials/metagraph-precompile.md @@ -9,193 +9,5 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; The metagraph precompile allows you to query information about neurons, their relationships, and network state in the Bittensor network. This precompile provides read-only access to the metagraph data through smart contracts. -## Precompile Address -The metagraph precompile is available at address `0x802` (2050 in decimal). -## Available Functions - -### Network Statistics - -#### `getUidCount(uint16 netuid) returns (uint16)` -Get the total number of UIDs (neurons) in a subnet. - -```solidity -function getUidCount(uint16 netuid) external view returns (uint16); -``` - -### Neuron Information - -#### `getStake(uint16 netuid, uint16 uid) returns (uint64)` -Get the total stake of a neuron in a subnet. - -```solidity -function getStake(uint16 netuid, uint16 uid) external view returns (uint64); -``` - -#### `getRank(uint16 netuid, uint16 uid) returns (uint16)` -Get the rank of a neuron in a subnet. - -```solidity -function getRank(uint16 netuid, uint16 uid) external view returns (uint16); -``` - -#### `getTrust(uint16 netuid, uint16 uid) returns (uint16)` -Get the trust score of a neuron in a subnet. - -```solidity -function getTrust(uint16 netuid, uint16 uid) external view returns (uint16); -``` - -#### `getConsensus(uint16 netuid, uint16 uid) returns (uint16)` -Get the consensus score of a neuron in a subnet. - -```solidity -function getConsensus(uint16 netuid, uint16 uid) external view returns (uint16); -``` - -#### `getIncentive(uint16 netuid, uint16 uid) returns (uint16)` -Get the incentive score of a neuron in a subnet. - -```solidity -function getIncentive(uint16 netuid, uint16 uid) external view returns (uint16); -``` - -#### `getDividends(uint16 netuid, uint16 uid) returns (uint16)` -Get the dividends of a neuron in a subnet. - -```solidity -function getDividends(uint16 netuid, uint16 uid) external view returns (uint16); -``` - -#### `getEmission(uint16 netuid, uint16 uid) returns (uint64)` -Get the emission of a neuron in a subnet. - -```solidity -function getEmission(uint16 netuid, uint16 uid) external view returns (uint64); -``` - -#### `getVtrust(uint16 netuid, uint16 uid) returns (uint16)` -Get the validator trust score of a neuron in a subnet. - -```solidity -function getVtrust(uint16 netuid, uint16 uid) external view returns (uint16); -``` - -### Neuron Status - -#### `getValidatorStatus(uint16 netuid, uint16 uid) returns (bool)` -Check if a neuron is a validator in a subnet. - -```solidity -function getValidatorStatus(uint16 netuid, uint16 uid) external view returns (bool); -``` - -#### `getLastUpdate(uint16 netuid, uint16 uid) returns (uint64)` -Get the timestamp of the last update for a neuron in a subnet. - -```solidity -function getLastUpdate(uint16 netuid, uint16 uid) external view returns (uint64); -``` - -#### `getIsActive(uint16 netuid, uint16 uid) returns (bool)` -Check if a neuron is active in a subnet. - -```solidity -function getIsActive(uint16 netuid, uint16 uid) external view returns (bool); -``` - -### Neuron Keys - -#### `getHotkey(uint16 netuid, uint16 uid) returns (bytes32)` -Get the hotkey of a neuron in a subnet. - -```solidity -function getHotkey(uint16 netuid, uint16 uid) external view returns (bytes32); -``` - -#### `getColdkey(uint16 netuid, uint16 uid) returns (bytes32)` -Get the coldkey of a neuron in a subnet. - -```solidity -function getColdkey(uint16 netuid, uint16 uid) external view returns (bytes32); -``` - -### Axon Information - -#### `getAxon(uint16 netuid, uint16 uid) returns (AxonInfo)` -Get the axon information of a neuron in a subnet. - -```solidity -struct AxonInfo { - uint64 block; - uint32 version; - uint128 ip; - uint16 port; - uint8 ip_type; - uint8 protocol; -} - -function getAxon(uint16 netuid, uint16 uid) external view returns (AxonInfo); -``` - -## Example Usage - -Here's an example of how to use the metagraph precompile in a smart contract: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IMetagraphPrecompile { - struct AxonInfo { - uint64 block; - uint32 version; - uint128 ip; - uint16 port; - uint8 ip_type; - uint8 protocol; - } - - function getUidCount(uint16 netuid) external view returns (uint16); - function getStake(uint16 netuid, uint16 uid) external view returns (uint64); - function getRank(uint16 netuid, uint16 uid) external view returns (uint16); - function getHotkey(uint16 netuid, uint16 uid) external view returns (bytes32); - function getAxon(uint16 netuid, uint16 uid) external view returns (AxonInfo); -} - -contract MetagraphQuerier { - address constant METAGRAPH_PRECOMPILE = 0x802; - IMetagraphPrecompile metagraph = IMetagraphPrecompile(METAGRAPH_PRECOMPILE); - - function getNeuronInfo(uint16 netuid, uint16 uid) external view returns ( - uint64 stake, - uint16 rank, - bytes32 hotkey, - IMetagraphPrecompile.AxonInfo memory axon - ) { - stake = metagraph.getStake(netuid, uid); - rank = metagraph.getRank(netuid, uid); - hotkey = metagraph.getHotkey(netuid, uid); - axon = metagraph.getAxon(netuid, uid); - } - - function getNetworkStats(uint16 netuid) external view returns (uint16 totalNeurons) { - totalNeurons = metagraph.getUidCount(netuid); - } -} -``` - -## Important Notes - -1. All functions in the metagraph precompile are view functions and do not modify state. -2. The precompile provides read-only access to the metagraph data. -3. All queries are specific to a subnet identified by its `netuid`. -4. The `uid` parameter must be valid for the specified subnet. -5. Some functions may return default values or revert if the neuron is not found. - -## Next Steps - -- Learn about [staking operations](/evm-tutorials/staking-precompile) -- Understand [subnet management](/evm-tutorials/subnet-precompile) -- Explore [neuron operations](/evm-tutorials/neuron-precompile) \ No newline at end of file diff --git a/docs/evm-tutorials/neuron-precompile.md b/docs/evm-tutorials/neuron-precompile.md index 2bec674d4..45f32eb73 100644 --- a/docs/evm-tutorials/neuron-precompile.md +++ b/docs/evm-tutorials/neuron-precompile.md @@ -8,185 +8,3 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Neuron Precompile The neuron precompile allows you to interact with neuron operations on the Bittensor network through smart contracts. This precompile provides functionality for setting weights, registering neurons, and serving axons. - -## Precompile Address - -The neuron precompile is available at address `0x804` (2052 in decimal). - -## Available Functions - -### Weight Management - -#### `setWeights(uint16 netuid, uint16[] dests, uint16[] weights, uint64 version_key)` -Set weights for multiple destination neurons in a subnet. This is a payable function. - -```solidity -function setWeights( - uint16 netuid, - uint16[] dests, - uint16[] weights, - uint64 version_key -) external payable; -``` - -#### `commitWeights(uint16 netuid, bytes32 commit_hash)` -Commit weights for a subnet using a hash. This is a payable function. - -```solidity -function commitWeights(uint16 netuid, bytes32 commit_hash) external payable; -``` - -#### `revealWeights(uint16 netuid, uint16[] uids, uint16[] values, uint16[] salt, uint64 version_key)` -Reveal previously committed weights for a subnet. This is a payable function. - -```solidity -function revealWeights( - uint16 netuid, - uint16[] uids, - uint16[] values, - uint16[] salt, - uint64 version_key -) external payable; -``` - -### Neuron Registration - -#### `burnedRegister(uint16 netuid, bytes32 hotkey)` -Register a new neuron in a subnet by burning TAO. This is a payable function. - -```solidity -function burnedRegister(uint16 netuid, bytes32 hotkey) external payable; -``` - -### Axon Serving - -#### `serveAxon(uint16 netuid, uint32 version, uint128 ip, uint16 port, uint8 ip_type, uint8 protocol, uint8 placeholder1, uint8 placeholder2)` -Serve an axon for a neuron in a subnet. This is a payable function. - -```solidity -function serveAxon( - uint16 netuid, - uint32 version, - uint128 ip, - uint16 port, - uint8 ip_type, - uint8 protocol, - uint8 placeholder1, - uint8 placeholder2 -) external payable; -``` - -#### `serveAxonTls(uint16 netuid, uint32 version, uint128 ip, uint16 port, uint8 ip_type, uint8 protocol, uint8 placeholder1, uint8 placeholder2, bytes certificate)` -Serve a TLS-enabled axon for a neuron in a subnet. This is a payable function. - -```solidity -function serveAxonTls( - uint16 netuid, - uint32 version, - uint128 ip, - uint16 port, - uint8 ip_type, - uint8 protocol, - uint8 placeholder1, - uint8 placeholder2, - bytes certificate -) external payable; -``` - -#### `servePrometheus(uint16 netuid, uint32 version, uint128 ip, uint16 port, uint8 ip_type)` -Serve a Prometheus endpoint for a neuron in a subnet. This is a payable function. - -```solidity -function servePrometheus( - uint16 netuid, - uint32 version, - uint128 ip, - uint16 port, - uint8 ip_type -) external payable; -``` - -## Example Usage - -Here's an example of how to use the neuron precompile in a smart contract: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface INeuronPrecompile { - function setWeights( - uint16 netuid, - uint16[] calldata dests, - uint16[] calldata weights, - uint64 version_key - ) external payable; - - function burnedRegister(uint16 netuid, bytes32 hotkey) external payable; - - function serveAxon( - uint16 netuid, - uint32 version, - uint128 ip, - uint16 port, - uint8 ip_type, - uint8 protocol, - uint8 placeholder1, - uint8 placeholder2 - ) external payable; -} - -contract NeuronManager { - address constant NEURON_PRECOMPILE = 0x804; - INeuronPrecompile neuron = INeuronPrecompile(NEURON_PRECOMPILE); - - function setNeuronWeights( - uint16 netuid, - uint16[] calldata dests, - uint16[] calldata weights, - uint64 version_key - ) external payable { - neuron.setWeights{value: msg.value}(netuid, dests, weights, version_key); - } - - function registerNeuron(uint16 netuid, bytes32 hotkey) external payable { - neuron.burnedRegister{value: msg.value}(netuid, hotkey); - } - - function serveNeuronAxon( - uint16 netuid, - uint32 version, - uint128 ip, - uint16 port, - uint8 ip_type, - uint8 protocol - ) external payable { - neuron.serveAxon{value: msg.value}( - netuid, - version, - ip, - port, - ip_type, - protocol, - 0, // placeholder1 - 0 // placeholder2 - ); - } -} -``` - -## Important Notes - -1. Most functions in the neuron precompile are payable and require TAO to be sent with the transaction. -2. The `setWeights` function requires the `dests` and `weights` arrays to be of equal length. -3. The `revealWeights` function requires the `uids`, `values`, and `salt` arrays to be of equal length. -4. All operations are specific to a subnet identified by its `netuid`. -5. The `version_key` parameter is used to track different versions of weights. -6. The `ip_type` parameter in axon serving functions determines the type of IP address (IPv4 or IPv6). -7. The `protocol` parameter in axon serving functions determines the communication protocol. - -## Next Steps - -- Learn about [staking operations](/evm-tutorials/staking-precompile) -- Understand [subnet management](/evm-tutorials/subnet-precompile) -- Explore [metagraph interactions](/evm-tutorials/metagraph-precompile) \ No newline at end of file diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md index 13aecf589..53682ff99 100644 --- a/docs/evm-tutorials/subnet-precompile.md +++ b/docs/evm-tutorials/subnet-precompile.md @@ -13,7 +13,6 @@ The subnet precompile allows you to interact with subnet operations on the Bitte The subnet precompile is available at address `0x803` (2051 in decimal). - ## Example Scripts ### Javascript From fd388f1768ea47a44924ff77762dcec6caec1efb Mon Sep 17 00:00:00 2001 From: michael trestman Date: Fri, 30 May 2025 07:20:23 -0700 Subject: [PATCH 18/27] wip --- docs/evm-tutorials/examples.md | 4 +- docs/evm-tutorials/metagraph-precompile.md | 467 ++++++++++++++- docs/evm-tutorials/neuron-precompile.md | 292 +++++++++- docs/evm-tutorials/subnet-precompile.md | 540 +++++++++++++++++- docs/learn/anatomy-of-incentive-mechanism.md | 4 +- ...ittensor-building-blocks.md => neurons.md} | 0 docs/subnets/walkthrough-prompting.md | 2 +- docs/tutorials/ocr-subnet-tutorial.md | 4 +- sidebars.js | 2 +- 9 files changed, 1303 insertions(+), 12 deletions(-) rename docs/learn/{bittensor-building-blocks.md => neurons.md} (100%) diff --git a/docs/evm-tutorials/examples.md b/docs/evm-tutorials/examples.md index a6b5fb9d6..ec58b7c87 100644 --- a/docs/evm-tutorials/examples.md +++ b/docs/evm-tutorials/examples.md @@ -8,11 +8,11 @@ import { InstallPartial } from "./_install.mdx"; ## Available Precompiles -The following precompiles are available on the Bittensor EVM. +The following precompiled smart contracts are available on the Bittensor EVM. +The source code can be found [on GitHub](https://github.com/opentensor/subtensor/blob/main/precompiles). Code examples used throughout are provided by OTF, and come from [this repository.](https://github.com/opentensor/evm-bittensor/tree/main/examples) - diff --git a/docs/evm-tutorials/metagraph-precompile.md b/docs/evm-tutorials/metagraph-precompile.md index 606a0987a..e77dd5f64 100644 --- a/docs/evm-tutorials/metagraph-precompile.md +++ b/docs/evm-tutorials/metagraph-precompile.md @@ -7,7 +7,472 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Metagraph Precompile -The metagraph precompile allows you to query information about neurons, their relationships, and network state in the Bittensor network. This precompile provides read-only access to the metagraph data through smart contracts. +The metagraph precompile allows you to query information about neurons, their relationships, and network state in the Bittensor network. This precompile provides read-only access to the metagraph data through smart contracts at precompile address `2050`. + +## Overview + +The metagraph precompile is a powerful tool that enables smart contracts to interact with the Bittensor network's metagraph data. It provides access to various metrics and information about neurons including stakes, ranks, trust scores, consensus values, and more. + +All functions in this precompile are view-only operations that don't modify state and consume minimal gas. + +## Function Reference + +### Network Information + +#### `getUidCount(uint16 netuid) → uint16` + +Returns the total number of UIDs (neurons) in a specific subnetwork. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID to query + +**Returns:** +- `uint16`: Total count of neurons in the subnetwork + +**Example:** +```solidity +// Get the number of neurons in subnetwork 1 +uint16 neuronCount = IMetagraph(METAGRAPH_PRECOMPILE).getUidCount(1); +``` + +### Token and Consensus Metrics + +#### `getStake(uint16 netuid, uint16 uid) → uint64` + +Retrieves the total stake amount for a specific neuron. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint64`: Total stake amount for the neuron's hotkey + +**Errors:** +- Reverts with `InvalidRange` if the UID doesn't exist in the network + +**Example:** +```solidity +// Get stake for neuron with UID 5 in subnetwork 1 +uint64 stake = IMetagraph(METAGRAPH_PRECOMPILE).getStake(1, 5); +``` + +#### `getEmission(uint16 netuid, uint16 uid) → uint64` + +Gets the emission value for a specific neuron, representing its reward allocation. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint64`: Emission value for the neuron + +**Example:** +```solidity +// Get emission for neuron with UID 10 in subnetwork 1 +uint64 emission = IMetagraph(METAGRAPH_PRECOMPILE).getEmission(1, 10); +``` + +#### `getRank(uint16 netuid, uint16 uid) → uint16` + +Returns the rank score of a neuron, indicating its performance relative to others. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint16`: Rank score of the neuron + +**Example:** +```solidity +// Get rank for neuron with UID 3 in subnetwork 1 +uint16 rank = IMetagraph(METAGRAPH_PRECOMPILE).getRank(1, 3); +``` + +#### `getTrust(uint16 netuid, uint16 uid) → uint16` + +Retrieves the trust score of a neuron, representing how much other neurons trust its outputs. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint16`: Trust score of the neuron + +**Example:** +```solidity +// Get trust score for neuron with UID 7 in subnetwork 1 +uint16 trust = IMetagraph(METAGRAPH_PRECOMPILE).getTrust(1, 7); +``` + +#### `getConsensus(uint16 netuid, uint16 uid) → uint16` + +Gets the consensus score of a neuron, indicating agreement with network consensus. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint16`: Consensus score of the neuron + +**Example:** +```solidity +// Get consensus score for neuron with UID 12 in subnetwork 1 +uint16 consensus = IMetagraph(METAGRAPH_PRECOMPILE).getConsensus(1, 12); +``` + +#### `getIncentive(uint16 netuid, uint16 uid) → uint16` + +Returns the incentive score of a neuron, representing its contribution to the network. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint16`: Incentive score of the neuron + +**Example:** +```solidity +// Get incentive score for neuron with UID 8 in subnetwork 1 +uint16 incentive = IMetagraph(METAGRAPH_PRECOMPILE).getIncentive(1, 8); +``` + +#### `getDividends(uint16 netuid, uint16 uid) → uint16` + +Retrieves the dividends score of a neuron, indicating its reward distribution. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint16`: Dividends score of the neuron + +**Example:** +```solidity +// Get dividends score for neuron with UID 15 in subnetwork 1 +uint16 dividends = IMetagraph(METAGRAPH_PRECOMPILE).getDividends(1, 15); +``` + +### Validator-Specific Functions + +#### `getVtrust(uint16 netuid, uint16 uid) → uint16` + +Gets the validator trust score for a neuron, specific to validator operations. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint16`: Validator trust score + +**Example:** +```solidity +// Get validator trust for neuron with UID 2 in subnetwork 1 +uint16 vtrust = IMetagraph(METAGRAPH_PRECOMPILE).getVtrust(1, 2); +``` + +#### `getValidatorStatus(uint16 netuid, uint16 uid) → bool` + +Checks if a neuron has validator permit status. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `bool`: True if the neuron has validator permissions, false otherwise + +**Example:** +```solidity +// Check if neuron with UID 1 is a validator in subnetwork 1 +bool isValidator = IMetagraph(METAGRAPH_PRECOMPILE).getValidatorStatus(1, 1); +``` + +### Neuron State Information + +#### `getLastUpdate(uint16 netuid, uint16 uid) → uint64` + +Returns the block number of the last update for a neuron. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `uint64`: Block number of the last update + +**Example:** +```solidity +// Get last update block for neuron with UID 6 in subnetwork 1 +uint64 lastUpdate = IMetagraph(METAGRAPH_PRECOMPILE).getLastUpdate(1, 6); +``` + +#### `getIsActive(uint16 netuid, uint16 uid) → bool` + +Checks if a neuron is currently active in the network. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `bool`: True if the neuron is active, false otherwise + +**Example:** +```solidity +// Check if neuron with UID 9 is active in subnetwork 1 +bool isActive = IMetagraph(METAGRAPH_PRECOMPILE).getIsActive(1, 9); +``` + +### Network Connection Information + +#### `getAxon(uint16 netuid, uint16 uid) → AxonInfo` + +Retrieves the axon information for a neuron, including network connection details. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `AxonInfo`: Struct containing axon connection information + +**AxonInfo Structure:** +```solidity +struct AxonInfo { + uint64 block; // Block number when axon was registered + uint32 version; // Protocol version + uint128 ip; // IP address (IPv4 or IPv6) + uint16 port; // Port number + uint8 ip_type; // IP type (4 for IPv4, 6 for IPv6) + uint8 protocol; // Protocol type +} +``` + +**Errors:** +- Reverts with "hotkey not found" if the neuron doesn't exist + +**Example:** +```solidity +// Get axon info for neuron with UID 4 in subnetwork 1 +IMetagraph.AxonInfo memory axon = IMetagraph(METAGRAPH_PRECOMPILE).getAxon(1, 4); +uint128 ip = axon.ip; +uint16 port = axon.port; +``` + +### Key Management + +#### `getHotkey(uint16 netuid, uint16 uid) → bytes32` + +Returns the hotkey (public key) associated with a neuron. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `bytes32`: The hotkey as a 32-byte hash + +**Errors:** +- Reverts with `InvalidRange` if the UID doesn't exist + +**Example:** +```solidity +// Get hotkey for neuron with UID 11 in subnetwork 1 +bytes32 hotkey = IMetagraph(METAGRAPH_PRECOMPILE).getHotkey(1, 11); +``` + +#### `getColdkey(uint16 netuid, uint16 uid) → bytes32` + +Returns the coldkey (owner key) associated with a neuron's hotkey. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `uid` (uint16): The unique identifier of the neuron + +**Returns:** +- `bytes32`: The coldkey as a 32-byte hash + +**Errors:** +- Reverts with `InvalidRange` if the UID doesn't exist + +**Example:** +```solidity +// Get coldkey for neuron with UID 13 in subnetwork 1 +bytes32 coldkey = IMetagraph(METAGRAPH_PRECOMPILE).getColdkey(1, 13); +``` + +## Interface Definition + +Here's the complete Solidity interface for the Metagraph Precompile: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IMetagraph { + struct AxonInfo { + uint64 block; + uint32 version; + uint128 ip; + uint16 port; + uint8 ip_type; + uint8 protocol; + } + + // Network information + function getUidCount(uint16 netuid) external view returns (uint16); + + // Financial metrics + function getStake(uint16 netuid, uint16 uid) external view returns (uint64); + function getEmission(uint16 netuid, uint16 uid) external view returns (uint64); + + // Performance metrics + function getRank(uint16 netuid, uint16 uid) external view returns (uint16); + function getTrust(uint16 netuid, uint16 uid) external view returns (uint16); + function getConsensus(uint16 netuid, uint16 uid) external view returns (uint16); + function getIncentive(uint16 netuid, uint16 uid) external view returns (uint16); + function getDividends(uint16 netuid, uint16 uid) external view returns (uint16); + + // Validator functions + function getVtrust(uint16 netuid, uint16 uid) external view returns (uint16); + function getValidatorStatus(uint16 netuid, uint16 uid) external view returns (bool); + + // State information + function getLastUpdate(uint16 netuid, uint16 uid) external view returns (uint64); + function getIsActive(uint16 netuid, uint16 uid) external view returns (bool); + + // Network connection + function getAxon(uint16 netuid, uint16 uid) external view returns (AxonInfo memory); + + // Key management + function getHotkey(uint16 netuid, uint16 uid) external view returns (bytes32); + function getColdkey(uint16 netuid, uint16 uid) external view returns (bytes32); +} +``` + +## Usage Examples + +### Basic Neuron Information Query + +```solidity +contract NeuronAnalyzer { + IMetagraph constant METAGRAPH = IMetagraph(0x0000000000000000000000000000000000000802); + + function analyzeNeuron(uint16 netuid, uint16 uid) external view returns ( + uint64 stake, + uint16 rank, + uint16 trust, + bool isActive, + bool isValidator + ) { + stake = METAGRAPH.getStake(netuid, uid); + rank = METAGRAPH.getRank(netuid, uid); + trust = METAGRAPH.getTrust(netuid, uid); + isActive = METAGRAPH.getIsActive(netuid, uid); + isValidator = METAGRAPH.getValidatorStatus(netuid, uid); + } +} +``` + +### Network Statistics + +```solidity +contract NetworkStats { + IMetagraph constant METAGRAPH = IMetagraph(0x0000000000000000000000000000000000000802); + + function getNetworkOverview(uint16 netuid) external view returns ( + uint16 totalNeurons, + uint64 totalStake, + uint16 activeNeurons + ) { + totalNeurons = METAGRAPH.getUidCount(netuid); + + for (uint16 i = 0; i < totalNeurons; i++) { + totalStake += METAGRAPH.getStake(netuid, i); + if (METAGRAPH.getIsActive(netuid, i)) { + activeNeurons++; + } + } + } +} +``` + +### Validator Tracking + +```solidity +contract ValidatorTracker { + IMetagraph constant METAGRAPH = IMetagraph(0x0000000000000000000000000000000000000802); + + function getValidators(uint16 netuid) external view returns (uint16[] memory) { + uint16 totalNeurons = METAGRAPH.getUidCount(netuid); + uint16[] memory validators = new uint16[](totalNeurons); + uint16 validatorCount = 0; + + for (uint16 i = 0; i < totalNeurons; i++) { + if (METAGRAPH.getValidatorStatus(netuid, i)) { + validators[validatorCount] = i; + validatorCount++; + } + } + + // Resize array to actual validator count + assembly { + mstore(validators, validatorCount) + } + + return validators; + } +} +``` + +## Error Handling + +The metagraph precompile can throw the following errors: + +- **InvalidRange**: Thrown when querying a UID that doesn't exist in the specified network +- **"hotkey not found"**: Thrown when trying to get axon information for a non-existent neuron + +Always handle these errors appropriately in your smart contracts: + +```solidity +contract SafeMetagraphQuery { + IMetagraph constant METAGRAPH = IMetagraph(0x0000000000000000000000000000000000000802); + + function safeGetStake(uint16 netuid, uint16 uid) external view returns (uint64, bool) { + try METAGRAPH.getStake(netuid, uid) returns (uint64 stake) { + return (stake, true); + } catch { + return (0, false); + } + } +} +``` + +## Gas Considerations + +All metagraph precompile functions are view functions that don't modify state. They have very low gas costs, typically: + +- Simple queries (rank, trust, etc.): ~2,100 gas +- Complex queries (axon info): ~3,000 gas +- Key lookups: ~2,500 gas + +This makes them suitable for frequent queries and batch operations within smart contracts. + +## Best Practices + +1. **Batch Queries**: When querying multiple neurons, consider batching operations to reduce transaction costs +2. **Cache Results**: If querying the same data multiple times, consider caching results within your contract +3. **Error Handling**: Always implement proper error handling for edge cases +4. **Network Validation**: Validate that the netuid exists before querying UIDs +5. **UID Bounds Checking**: Ensure UIDs are within the valid range (0 to getUidCount - 1) diff --git a/docs/evm-tutorials/neuron-precompile.md b/docs/evm-tutorials/neuron-precompile.md index 45f32eb73..5118f00ab 100644 --- a/docs/evm-tutorials/neuron-precompile.md +++ b/docs/evm-tutorials/neuron-precompile.md @@ -7,4 +7,294 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Neuron Precompile -The neuron precompile allows you to interact with neuron operations on the Bittensor network through smart contracts. This precompile provides functionality for setting weights, registering neurons, and serving axons. + +This precompile enables full management of neurons (miner and validator nodes) through smart contracts, from registration to weight setting to service configuration. + +See [Understanding Neurons](../learn/neurons.md). + + +:::info +Payable functions require tokens for execution +::: + + +## Precompile Address + +The neuron precompile is available at address `0x804` (2052 in decimal). + +## Available Functions + +The neuron precompile provides the following core functions for neuron management: + +### Weight Management + +#### `setWeights` +Set weights (rankings) for miners on the subnet. See [Requirements for validation](../validators/#requirements-for-validation) + +**Function Signature:** +```solidity +function setWeights( + uint16 netuid, + uint16[] memory dests, + uint16[] memory weights, + uint64 versionKey +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID where the neuron is registered +- `dests` (uint16[]): Array of destination neuron UIDs to assign weights to +- `weights` (uint16[]): Array of weight values corresponding to each destination UID +- `versionKey` (uint64): Version key for weight compatibility and validation + +**Description:** +This function allows a neuron to set weights on other neurons in the same subnet. The weights represent how much value or trust this neuron assigns to others, which is crucial for the Bittensor consensus mechanism. + +#### `commitWeights` +Commits weights using a hash commitment scheme for privacy and security. + +**Function Signature:** +```solidity +function commitWeights( + uint16 netuid, + bytes32 commitHash +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID where the neuron is registered +- `commitHash` (bytes32): Hash commitment of the weights to be revealed later + +**Description:** +This function implements a commit-reveal scheme for setting weights. The neuron first commits a hash of their weights, then later reveals the actual weights. This prevents front-running and manipulation of the weight-setting process. + +#### `revealWeights` +Reveals previously committed weights by providing the original data that produces the committed hash. + +**Function Signature:** +```solidity +function revealWeights( + uint16 netuid, + uint16[] memory uids, + uint16[] memory values, + uint16[] memory salt, + uint64 versionKey +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID where the neuron is registered +- `uids` (uint16[]): Array of neuron UIDs that weights are being set for +- `values` (uint16[]): Array of weight values for each corresponding UID +- `salt` (uint16[]): Salt values used in the original hash commitment +- `versionKey` (uint64): Version key for weight compatibility + +**Description:** +This function completes the commit-reveal process by revealing the actual weights that were previously committed. The provided data must hash to the previously committed hash for the transaction to succeed. + +### Neuron Registration + +Neuron registration is the process of joining a subnet and becoming part of the neural network structure described in [Understanding Neurons](../learn/neurons.md). + +#### `burnedRegister` +Registers a neuron in a subnet by burning TAO tokens. + +**Function Signature:** +```solidity +function burnedRegister( + uint16 netuid, + bytes32 hotkey +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID to register the neuron in +- `hotkey` (bytes32): The hotkey public key (32 bytes) of the neuron to register + +**Description:** +This function registers a new neuron in the specified subnet by burning a certain amount of TAO tokens. The amount burned depends on the current network conditions and subnet parameters. The hotkey represents the neuron's identity on the network. + +### Axon Services + +#### `serveAxon` +Configures and serves an axon endpoint for the neuron. + +**Function Signature:** +```solidity +function serveAxon( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2 +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID where the neuron is serving +- `version` (uint32): Version of the axon service +- `ip` (uint128): IP address of the axon service (supports both IPv4 and IPv6) +- `port` (uint16): Port number where the axon is listening +- `ipType` (uint8): Type of IP address (4 for IPv4, 6 for IPv6) +- `protocol` (uint8): Network protocol identifier +- `placeholder1` (uint8): Reserved for future use +- `placeholder2` (uint8): Reserved for future use + +**Description:** +This function allows a neuron to announce its axon service endpoint to the network. An axon is the service interface that other neurons can connect to for communication and inference requests using the dendrite-axon protocol. + +#### `serveAxonTls` +Configures and serves an axon endpoint with TLS/SSL security. + +**Function Signature:** +```solidity +function serveAxonTls( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2, + bytes memory certificate +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID where the neuron is serving +- `version` (uint32): Version of the axon service +- `ip` (uint128): IP address of the axon service +- `port` (uint16): Port number where the axon is listening +- `ipType` (uint8): Type of IP address (4 for IPv4, 6 for IPv6) +- `protocol` (uint8): Network protocol identifier +- `placeholder1` (uint8): Reserved for future use +- `placeholder2` (uint8): Reserved for future use +- `certificate` (bytes): TLS/SSL certificate data for secure connections + +**Description:** +Similar to `serveAxon`, but includes TLS certificate information for secure encrypted communication. This is recommended for production environments where data privacy and security are important. + +#### `servePrometheus` +Configures a Prometheus metrics endpoint for the neuron. + +**Function Signature:** +```solidity +function servePrometheus( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType +) external payable +``` + +**Parameters:** +- `netuid` (uint16): The subnet ID where the neuron is serving +- `version` (uint32): Version of the Prometheus service +- `ip` (uint128): IP address where Prometheus metrics are served +- `port` (uint16): Port number for the Prometheus endpoint +- `ipType` (uint8): Type of IP address (4 for IPv4, 6 for IPv6) + +**Description:** +This function allows a neuron to expose a Prometheus metrics endpoint for monitoring and observability. Prometheus metrics can include performance data, request counts, and other operational metrics. + +## Usage Examples + +### Setting Weights Example + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface INeuron { + function setWeights( + uint16 netuid, + uint16[] memory dests, + uint16[] memory weights, + uint64 versionKey + ) external payable; +} + +contract WeightSetter { + address constant NEURON_PRECOMPILE = 0x0000000000000000000000000000000000000804; + + function setMyWeights() external { + uint16 netuid = 1; // Subnet ID + uint16[] memory dests = new uint16[](3); + dests[0] = 0; // UID 0 + dests[1] = 1; // UID 1 + dests[2] = 2; // UID 2 + + uint16[] memory weights = new uint16[](3); + weights[0] = 100; // Weight for UID 0 + weights[1] = 200; // Weight for UID 1 + weights[2] = 150; // Weight for UID 2 + + uint64 versionKey = 1; + + INeuron(NEURON_PRECOMPILE).setWeights(netuid, dests, weights, versionKey); + } +} +``` + +### Registering a Neuron Example + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface INeuron { + function burnedRegister(uint16 netuid, bytes32 hotkey) external payable; +} + +contract NeuronRegistrar { + address constant NEURON_PRECOMPILE = 0x0000000000000000000000000000000000000804; + + function registerNeuron(uint16 subnetId, bytes32 hotkeyPubkey) external payable { + INeuron(NEURON_PRECOMPILE).burnedRegister{value: msg.value}(subnetId, hotkeyPubkey); + } +} +``` + +### Serving an Axon Example + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface INeuron { + function serveAxon( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2 + ) external payable; +} + +contract AxonService { + address constant NEURON_PRECOMPILE = 0x0000000000000000000000000000000000000804; + + function startAxonService() external { + uint16 netuid = 1; + uint32 version = 1; + uint128 ip = uint128(0x7f000001); // 127.0.0.1 in hex + uint16 port = 8080; + uint8 ipType = 4; // IPv4 + uint8 protocol = 1; + uint8 placeholder1 = 0; + uint8 placeholder2 = 0; + + INeuron(NEURON_PRECOMPILE).serveAxon( + netuid, version, ip, port, ipType, protocol, placeholder1, placeholder2 + ); + } +} +``` diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md index 53682ff99..14ca336d3 100644 --- a/docs/evm-tutorials/subnet-precompile.md +++ b/docs/evm-tutorials/subnet-precompile.md @@ -13,6 +13,540 @@ The subnet precompile allows you to interact with subnet operations on the Bitte The subnet precompile is available at address `0x803` (2051 in decimal). +## Available Functions + +The subnet precompile provides comprehensive functionality for subnet management and configuration. All functions are categorized below: + +### Network Registration + +#### `registerNetwork` +Registers a new subnet without additional identity information. + +**Parameters:** +- `hotkey` (bytes32): The hotkey (32 bytes) that will own the network + +**Returns:** +- None (payable function) + +**Description:** +Registers a new subnet on the Bittensor network. The caller becomes the subnet owner and can manage subnet parameters. + +#### `registerNetworkWithIdentity` +Registers a new subnet with detailed identity information. + +**Parameters:** +- `hotkey` (bytes32): The hotkey that will own the network +- `subnetName` (string): Name of the subnet (max 256 chars) +- `githubRepo` (string): GitHub repository URL (max 1024 chars) +- `subnetContact` (string): Contact information (max 1024 chars) +- `subnetUrl` (string): Subnet website URL (max 1024 chars) +- `discord` (string): Discord server invite (max 256 chars) +- `description` (string): Subnet description (max 1024 chars) +- `additional` (string): Additional information (max 1024 chars) + +**Returns:** +- None (payable function) + +**Description:** +Registers a new subnet with comprehensive identity metadata that helps users understand the subnet's purpose and how to interact with it. + +### Rate Limiting + +#### `getServingRateLimit` +Gets the serving rate limit for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The serving rate limit value + +#### `setServingRateLimit` +Sets the serving rate limit for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `servingRateLimit` (uint64): The new serving rate limit value + +**Returns:** +- None (payable function) + +### Difficulty Management + +#### `getMinDifficulty` +Gets the minimum difficulty for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The minimum difficulty value + +#### `setMinDifficulty` +Sets the minimum difficulty for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `minDifficulty` (uint64): The new minimum difficulty value + +**Returns:** +- None (payable function) + +#### `getMaxDifficulty` +Gets the maximum difficulty for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The maximum difficulty value + +#### `setMaxDifficulty` +Sets the maximum difficulty for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `maxDifficulty` (uint64): The new maximum difficulty value + +**Returns:** +- None (payable function) + +#### `getDifficulty` +Gets the current difficulty for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The current difficulty value + +#### `setDifficulty` +Sets the current difficulty for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `difficulty` (uint64): The new difficulty value + +**Returns:** +- None (payable function) + +### Weight Management + +#### `getWeightsVersionKey` +Gets the weights version key for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The weights version key value + +#### `setWeightsVersionKey` +Sets the weights version key for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `weightsVersionKey` (uint64): The new weights version key value + +**Returns:** +- None (payable function) + +#### `getWeightsSetRateLimit` +Gets the weights set rate limit for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The weights set rate limit value + +#### `setWeightsSetRateLimit` ⚠️ **DEPRECATED** +Sets the weights set rate limit for a subnet. **This function is deprecated. Subnet owners cannot set weight setting rate limits.** + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `weightsSetRateLimit` (uint64): The weights set rate limit value (ignored) + +**Returns:** +- None (payable function) + +**Description:** +This function still exists for backward compatibility but performs no operation and returns successfully. + +#### `getMaxWeightLimit` +Gets the maximum weight limit for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The maximum weight limit value + +#### `setMaxWeightLimit` +Sets the maximum weight limit for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `maxWeightLimit` (uint16): The new maximum weight limit value + +**Returns:** +- None (payable function) + +#### `getMinAllowedWeights` +Gets the minimum allowed weights for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The minimum allowed weights value + +#### `setMinAllowedWeights` +Sets the minimum allowed weights for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `minAllowedWeights` (uint16): The new minimum allowed weights value + +**Returns:** +- None (payable function) + +### Consensus Parameters + +#### `getAdjustmentAlpha` +Gets the adjustment alpha parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The adjustment alpha value + +#### `setAdjustmentAlpha` +Sets the adjustment alpha parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `adjustmentAlpha` (uint64): The new adjustment alpha value + +**Returns:** +- None (payable function) + +#### `getKappa` +Gets the kappa parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The kappa value + +#### `setKappa` +Sets the kappa parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `kappa` (uint16): The new kappa value + +**Returns:** +- None (payable function) + +#### `getRho` +Gets the rho parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The rho value + +#### `setRho` +Sets the rho parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `rho` (uint16): The new rho value + +**Returns:** +- None (payable function) + +#### `getAlphaSigmoidSteepness` +Gets the alpha sigmoid steepness parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The alpha sigmoid steepness value + +#### `setAlphaSigmoidSteepness` +Sets the alpha sigmoid steepness parameter for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `steepness` (uint16): The new alpha sigmoid steepness value + +**Returns:** +- None (payable function) + +#### `getAlphaValues` +Gets the alpha low and high values for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The alpha low value +- `uint16`: The alpha high value + +#### `setAlphaValues` +Sets the alpha low and high values for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `alphaLow` (uint16): The new alpha low value +- `alphaHigh` (uint16): The new alpha high value + +**Returns:** +- None (payable function) + +### Network Activity + +#### `getImmunityPeriod` +Gets the immunity period for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The immunity period value + +#### `setImmunityPeriod` +Sets the immunity period for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `immunityPeriod` (uint16): The new immunity period value + +**Returns:** +- None (payable function) + +#### `getActivityCutoff` +Gets the activity cutoff for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint16`: The activity cutoff value + +#### `setActivityCutoff` +Sets the activity cutoff for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `activityCutoff` (uint16): The new activity cutoff value + +**Returns:** +- None (payable function) + +### Registration Control + +#### `getNetworkRegistrationAllowed` +Gets whether network registration is allowed for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `bool`: Whether network registration is allowed + +#### `setNetworkRegistrationAllowed` +Sets whether network registration is allowed for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `registrationAllowed` (bool): Whether to allow network registration + +**Returns:** +- None (payable function) + +#### `getNetworkPowRegistrationAllowed` +Gets whether PoW registration is allowed for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `bool`: Whether PoW registration is allowed + +#### `setNetworkPowRegistrationAllowed` +Sets whether PoW registration is allowed for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `registrationAllowed` (bool): Whether to allow PoW registration + +**Returns:** +- None (payable function) + +### Burn Management + +#### `getMinBurn` +Gets the minimum burn amount for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The minimum burn amount + +#### `setMinBurn` ⚠️ **DEPRECATED** +Sets the minimum burn amount for a subnet. **This function is deprecated. Subnet owners cannot set the minimum burn anymore.** + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `minBurn` (uint64): The minimum burn amount (ignored) + +**Returns:** +- None (payable function) + +**Description:** +This function still exists for backward compatibility but performs no operation and returns successfully. + +#### `getMaxBurn` +Gets the maximum burn amount for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The maximum burn amount + +#### `setMaxBurn` ⚠️ **DEPRECATED** +Sets the maximum burn amount for a subnet. **This function is deprecated. Subnet owners cannot set the maximum burn anymore.** + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `maxBurn` (uint64): The maximum burn amount (ignored) + +**Returns:** +- None (payable function) + +**Description:** +This function still exists for backward compatibility but performs no operation and returns successfully. + +### Bonds and Moving Averages + +#### `getBondsMovingAverage` +Gets the bonds moving average for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The bonds moving average value + +#### `setBondsMovingAverage` +Sets the bonds moving average for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `bondsMovingAverage` (uint64): The new bonds moving average value + +**Returns:** +- None (payable function) + +### Feature Toggles + +#### `getCommitRevealWeightsEnabled` +Gets whether commit-reveal weights are enabled for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `bool`: Whether commit-reveal weights are enabled + +#### `setCommitRevealWeightsEnabled` +Sets whether commit-reveal weights are enabled for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `enabled` (bool): Whether to enable commit-reveal weights + +**Returns:** +- None (payable function) + +#### `getCommitRevealWeightsInterval` +Gets the commit-reveal weights interval for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `uint64`: The commit-reveal weights interval value + +#### `setCommitRevealWeightsInterval` +Sets the commit-reveal weights interval for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `interval` (uint64): The new commit-reveal weights interval value + +**Returns:** +- None (payable function) + +#### `getLiquidAlphaEnabled` +Gets whether liquid alpha is enabled for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `bool`: Whether liquid alpha is enabled + +#### `setLiquidAlphaEnabled` +Sets whether liquid alpha is enabled for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `enabled` (bool): Whether to enable liquid alpha + +**Returns:** +- None (payable function) + +#### `getYuma3Enabled` +Gets whether Yuma3 consensus is enabled for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID + +**Returns:** +- `bool`: Whether Yuma3 consensus is enabled + +#### `setYuma3Enabled` +Sets whether Yuma3 consensus is enabled for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `enabled` (bool): Whether to enable Yuma3 consensus + +**Returns:** +- None (payable function) + +### Transfer Control + +#### `toggleTransfers` +Toggles transfers on/off for a subnet. + +**Parameters:** +- `netuid` (uint16): The subnetwork ID +- `toggle` (bool): Whether to enable or disable transfers + +**Returns:** +- None (payable function) + ## Example Scripts ### Javascript @@ -196,7 +730,7 @@ const subnet_contract_abi = [ // compile with evm version 0.8.3 const subnet_contract_bytecode = - "0x608060405234801561001057600080fd5b50604051610e6d380380610e6d8339818101604052810190610032919061015c565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561006d57600080fd5b61007c8161008360201b60201c565b50506101ce565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050610156816101b7565b92915050565b60006020828403121561016e57600080fd5b600061017c84828501610147565b91505092915050565b600061019082610197565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6101c081610185565b81146101cb57600080fd5b50565b610c90806101dd6000396000f3fe6080604052600436106100555760003560e01c8063290212c11461005a578063715018a614610076578063786fede51461008d57806378b63cb6146100ca5780638da5cb5b146100e6578063f2fde38b14610111575b600080fd5b610074600480360381019061006f919061077b565b61013a565b005b34801561008257600080fd5b5061008b610279565b005b34801561009957600080fd5b506100b460048036038101906100af9190610812565b61028d565b6040516100c19190610a3c565b60405180910390f35b6100e460048036038101906100df919061083b565b6103df565b005b3480156100f257600080fd5b506100fb61051a565b6040516101089190610971565b60405180910390f35b34801561011d57600080fd5b5061013860048036038101906101339190610752565b610543565b005b610142610591565b60006108039050600061080373ffffffffffffffffffffffffffffffffffffffff163463290212c160e01b8787876040516024016101829392919061098c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101ec919061095a565b60006040518083038185875af1925050503d8060008114610229576040519150601f19603f3d011682016040523d82523d6000602084013e61022e565b606091505b5050905080610272576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610269906109d8565b60405180910390fd5b5050505050565b610281610591565b61028b60006105d2565b565b600080610803905060008061080373ffffffffffffffffffffffffffffffffffffffff16637444dadc60e01b866040516024016102ca91906109f8565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610334919061095a565b6000604051808303816000865af19150503d8060008114610371576040519150601f19603f3d011682016040523d82523d6000602084013e610376565b606091505b5091509150816103bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103b2906109d8565b60405180910390fd5b6000818060200190518101906103d19190610877565b905080945050505050919050565b6103e7610591565b60006108039050600061080373ffffffffffffffffffffffffffffffffffffffff1663b38e0bbe60e01b8585604051602401610424929190610a13565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161048e919061095a565b6000604051808303816000865af19150503d80600081146104cb576040519150601f19603f3d011682016040523d82523d6000602084013e6104d0565b606091505b5050905080610514576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161050b906109d8565b60405180910390fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054b610591565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561058557600080fd5b61058e816105d2565b50565b3373ffffffffffffffffffffffffffffffffffffffff166105b061051a565b73ffffffffffffffffffffffffffffffffffffffff16146105d057600080fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60006106a96106a484610a7c565b610a57565b9050828152602081018484840111156106c157600080fd5b6106cc848285610b39565b509392505050565b6000813590506106e381610c15565b92915050565b600082601f8301126106fa57600080fd5b813561070a848260208601610696565b91505092915050565b60008135905061072281610c2c565b92915050565b60008135905061073781610c43565b92915050565b60008151905061074c81610c43565b92915050565b60006020828403121561076457600080fd5b6000610772848285016106d4565b91505092915050565b60008060006060848603121561079057600080fd5b600084013567ffffffffffffffff8111156107aa57600080fd5b6107b6868287016106e9565b935050602084013567ffffffffffffffff8111156107d357600080fd5b6107df868287016106e9565b925050604084013567ffffffffffffffff8111156107fc57600080fd5b610808868287016106e9565b9150509250925092565b60006020828403121561082457600080fd5b600061083284828501610713565b91505092915050565b6000806040838503121561084e57600080fd5b600061085c85828601610713565b925050602061086d85828601610728565b9150509250929050565b60006020828403121561088957600080fd5b60006108978482850161073d565b91505092915050565b6108a981610ae5565b82525050565b60006108ba82610aad565b6108c48185610ab8565b93506108d4818560208601610b48565b6108dd81610bdb565b840191505092915050565b60006108f382610aad565b6108fd8185610ac9565b935061090d818560208601610b48565b80840191505092915050565b6000610926601283610ad4565b915061093182610bec565b602082019050919050565b61094581610af7565b82525050565b61095481610b25565b82525050565b600061096682846108e8565b915081905092915050565b600060208201905061098660008301846108a0565b92915050565b600060608201905081810360008301526109a681866108af565b905081810360208301526109ba81856108af565b905081810360408301526109ce81846108af565b9050949350505050565b600060208201905081810360008301526109f181610919565b9050919050565b6000602082019050610a0d600083018461093c565b92915050565b6000604082019050610a28600083018561093c565b610a35602083018461094b565b9392505050565b6000602082019050610a51600083018461094b565b92915050565b6000610a61610a72565b9050610a6d8282610b7b565b919050565b6000604051905090565b600067ffffffffffffffff821115610a9757610a96610bac565b5b610aa082610bdb565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000610af082610b05565b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600067ffffffffffffffff82169050919050565b82818337600083830152505050565b60005b83811015610b66578082015181840152602081019050610b4b565b83811115610b75576000848401525b50505050565b610b8482610bdb565b810181811067ffffffffffffffff82111715610ba357610ba2610bac565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f5375626e65742063616c6c206661696c65640000000000000000000000000000600082015250565b610c1e81610ae5565b8114610c2957600080fd5b50565b610c3581610af7565b8114610c4057600080fd5b50565b610c4c81610b25565b8114610c5757600080fd5b5056fea26469706673582212200e657685be0d4a155c28ec7471273753d1c625c562f268b2efdf0a8b2c7e4dbe64736f6c63430008030033"; + "0x608060405234801561001057600080fd5b50604051610e6d380380610e6d8339818101604052810190610032919061015c565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561006d57600080fd5b61007c8161008360201b60201c565b50506101ce565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050610156816101b7565b92915050565b60006020828403121561016e57600080fd5b600061017c84828501610147565b91505092915050565b600061019082610197565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6101c081610185565b81146101cb57600080fd5b50565b610c90806101dd6000396000f3fe6080604052600436106100555760003560e01c8063290212c11461005a578063715018a614610076578063786fede51461008d57806378b63cb6146100ca5780638da5cb5b146100e6578063f2fde38b14610111575b600080fd5b610074600480360381019061006f919061077b565b61013a565b005b34801561008257600080fd5b5061008b610279565b005b34801561009957600080fd5b506100b460048036038101906100af9190610812565b61028d565b6040516100c19190610a3c565b60405180910390f35b6100e460048036038101906100df919061083b565b6103df565b005b3480156100f257600080fd5b506100fb61051a565b6040516101089190610971565b60405180910390f35b34801561011d57600080fd5b5061013860048036038101906101339190610752565b610543565b005b610142610591565b60006108039050600061080373ffffffffffffffffffffffffffffffffffffffff163463290212c160e01b8787876040516024016101829392919061098c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101ec919061095a565b60006040518083038185875af1925050503d8060008114610229576040519150601f19603f3d011682016040523d82523d6000602084013e61022e565b606091505b5050905080610272576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610269906109d8565b60405180910390fd5b5050505050565b610281610591565b61028b60006105d2565b565b600080610803905060008061080373ffffffffffffffffffffffffffffffffffffffff16637444dadc60e01b866040516024016102ca91906109f8565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610334919061095a565b6000604051808303816000865af19150503d8060008114610371576040519150601f19603f3d011682016040523d82523d6000602084013e610376565b606091505b5091509150816103bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103b2906109d8565b60405180910390fd5b6000818060200190518101906103d19190610877565b9050809450505050919050565b6103e7610591565b60006108039050600061080373ffffffffffffffffffffffffffffffffffffffff1663b38e0bbe60e01b8585604051602401610424929190610a13565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161048e919061095a565b6000604051808303816000865af19150503d80600081146104cb576040519150601f19603f3d011682016040523d82523d6000602084013e6104d0565b606091505b5050905080610514576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161050b906109d8565b60405180910390fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054b610591565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561058557600080fd5b61058e816105d2565b50565b3373ffffffffffffffffffffffffffffffffffffffff166105b061051a56b73ffffffffffffffffffffffffffffffffffffffff16146105d057600080fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60006106a96106a484610a7c565b610a57565b9050828152602081018484840111156106c157600080fd5b6106cc848285610b39565b509392505050565b6000813590506106e381610c15565b92915050565b600082601f8301126106fa57600080fd5b813561070a848260208601610696565b91505092915050565b60008135905061072281610c2c565b92915050565b60008135905061073781610c43565b92915050565b60008151905061074c81610c43565b92915050565b60006020828403121561076457600080fd5b6000610772848285016106d4565b91505092915050565b60008060006060848603121561079057600080fd5b600084013567ffffffffffffffff8111156107aa57600080fd5b6107b6868287016106e9565b935050602084013567ffffffffffffffff8111156107d357600080fd5b6107df868287016106e9565b925050604084013567ffffffffffffffff8111156107fc57600080fd5b610808868287016106e9565b9150509250925092565b60006020828403121561082457600080fd5b600061083284828501610713565b91505092915050565b6000806040838503121561084e57600080fd5b600061085c85828601610713565b925050602061086d85828601610728565b9150509250929050565b60006020828403121561088957600080fd5b60006108978482850161073d565b91505092915050565b6108a981610ae5565b82525050565b60006108ba82610aad565b6108c48185610ab8565b93506108d4818560208601610b48565b6108dd81610bdb565b840191505092915050565b60006108f382610aad565b6108fd8185610ac9565b935061090d818560208601610b48565b80840191505092915050565b6000610926601283610ad4565b915061093182610bec565b602082019050919050565b61094581610af7565b82525050565b61095481610b25565b82525050565b600061096682846108e8565b915081905092915050565b600060208201905061098660008301846108a0565b92915050565b600060608201905081810360008301526109a681866108af565b905081810360208301526109ba81856108af565b905081810360408301526109ce81846108af565b9050949350505050565b60006020820190506109f181610919565b9050919050565b6000602082019050610a0d600083018461093c565b92915050565b6000604082019050610a28600083018561093c565b610a35602083018461094b565b9392505050565b6000602082019050610a51600083018461094b565b92915050565b6000610a61610a72565b9050610a6d8282610b7b565b919050565b6000604051905090565b600067ffffffffffffffff821115610a9757610a96610bac565b5b610aa082610bdb565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000610af082610b05565b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600067ffffffffffffffff82169050919050565b82818337600083830152505050565b60005b83811015610b66578082015181840152602081019050610b4b565b83811115610b75576000848401525b50505050565b610b8482610bdb565b810181811067ffffffffffffffff82111715610ba357610ba2610bac565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f5375626e65742063616c6c206661696c65640000000000000000000000000000600082015250565b610c1e81610ae5565b8114610c2957600080fd5b50565b610c3581610af7565b8114610c4057600080fd5b50565b610c4c81610b25565b8114610c5757600080fd5b5056fea26469706673582212200e657685be0d4a155c28ec7471273753d1c625c562f268b2efdf0a8b2c7e4dbe64736f6c63430008030033"; // Create a signer const privateKey = ethPrivateKey; // DO NOT HARDCODE YOUR PRIVATE KEY IN PRODUCTION @@ -278,6 +812,8 @@ async function createSubnetGetSetParameter() { ).toHuman(); console.log("networkOwner is ", networkOwner); + // Note: This example uses setHyperParameter which calls setServingRateLimit + // Some other functions like setMinBurn, setMaxBurn, setWeightsSetRateLimit are deprecated tx = await subnet_contract.setHyperParameter(netuid, 255); await tx.wait(); @@ -305,7 +841,7 @@ async function createSubnetGetSetParameter() { } async function main() { - await createSubnetCheckEmission(); + await createSubnetGetSetParameter(); } main().catch(console.error); diff --git a/docs/learn/anatomy-of-incentive-mechanism.md b/docs/learn/anatomy-of-incentive-mechanism.md index 039d3a83e..70e3e3ff1 100644 --- a/docs/learn/anatomy-of-incentive-mechanism.md +++ b/docs/learn/anatomy-of-incentive-mechanism.md @@ -6,7 +6,7 @@ title: "Understanding Incentive Mechanisms" This page explores the concept and usage of incentive mechanisms in Bittensor. -See [Components of the Bittensor platform](../learn/bittensor-building-blocks) for an explanation of the basics, such as subnets, miners, validators, and the role of the blockchain. +See [Components of the Bittensor platform](../learn/neurons) for an explanation of the basics, such as subnets, miners, validators, and the role of the blockchain. Each subnet has its own *incentive mechanism*, a scoring model that drives the behavior of its participants, and the production of the subnet's digital commodity, by defining **how validators are to evaluate miners’ work**. Miners are incentivized to optimize for this model so validators will score (or 'weight') their work highly, resulting in higher emissions. Validators are incentivized to accurately score miners' work according to the model because the algorithm penalizes departure from consensus in miner scores with lower emissions. @@ -63,7 +63,7 @@ A subnet incentive mechanism must provide the following: A subnet creator must define a protocol for how validators are to query miners, and how miners should respond. Protocols are built using the Axon-Dendrite client-server model and Synapse data objects. -See [Neuron to neuron communication](./bittensor-building-blocks.md#neuron-to-neuron-communication). +See [Neuron to neuron communication](./neurons.md#neuron-to-neuron-communication). ### Subnet task diff --git a/docs/learn/bittensor-building-blocks.md b/docs/learn/neurons.md similarity index 100% rename from docs/learn/bittensor-building-blocks.md rename to docs/learn/neurons.md diff --git a/docs/subnets/walkthrough-prompting.md b/docs/subnets/walkthrough-prompting.md index c0e7ff8b2..da6d2cd26 100644 --- a/docs/subnets/walkthrough-prompting.md +++ b/docs/subnets/walkthrough-prompting.md @@ -25,7 +25,7 @@ You can see the prompting subnet in action on the [TAO.app explorer (select Subn If you are new to Bittensor subnets and building blocks, read the following sections before you proceed further: -- [Bittensor Building Blocks](../learn/bittensor-building-blocks). +- [Bittensor Building Blocks](../learn/neurons). - [Anatomy of Incentive Mechanism](../learn/anatomy-of-incentive-mechanism). The below diagram shows a typical subnet with many subnet miners and subnet validators together executing the subnet incentive mechanism code. On the [TAO.app explorer (select Subnet 01: Text Prompting from the top menu)](https://tao.app) the **Metagraph** view for this Subnet 1: Prompting shows the performance details for each subnet miner and validator. diff --git a/docs/tutorials/ocr-subnet-tutorial.md b/docs/tutorials/ocr-subnet-tutorial.md index 5402367b9..f946955eb 100644 --- a/docs/tutorials/ocr-subnet-tutorial.md +++ b/docs/tutorials/ocr-subnet-tutorial.md @@ -53,7 +53,7 @@ For the rest of this tutorial we will proceed by demonstrating which blocks of P If you are new to Bittensor, read the following sections before you proceed: 1. [Introduction](../learn/introduction.md) that describes how subnets form the heartbeat of the Bittensor network. -2. [Bittensor Building Blocks](../learn/bittensor-building-blocks.md) that presents the basic building blocks you use to develop your subnet incentive mechanism. +2. [Bittensor Building Blocks](../learn/neurons.md) that presents the basic building blocks you use to develop your subnet incentive mechanism. 3. [Anatomy of Incentive Mechanism](../learn/anatomy-of-incentive-mechanism.md) that introduces the general concept of a subnet incentive mechanism. ## OCR subnet summary @@ -218,7 +218,7 @@ See the `OCRSynapse` class definition in [**ocr_subnet/protocol.py**](https://gi ``` :::tip Study tip -See [Neuron-to-neuron communication](../learn/bittensor-building-blocks.md#neuron-to-neuron-communication). +See [Neuron-to-neuron communication](../learn/neurons.md#neuron-to-neuron-communication). ::: #### Send OCRSynapse to miners diff --git a/sidebars.js b/sidebars.js index dc4c24ac0..c85c41161 100644 --- a/sidebars.js +++ b/sidebars.js @@ -37,7 +37,7 @@ const sidebars = { "learn/introduction", "questions-and-answers", "subnets/understanding-subnets", - "learn/bittensor-building-blocks", + "learn/neurons", "learn/anatomy-of-incentive-mechanism", "emissions", "yuma-consensus", From 625fc89c7175090197813e899cc48d552ebde26f Mon Sep 17 00:00:00 2001 From: michael trestman Date: Fri, 30 May 2025 08:00:19 -0700 Subject: [PATCH 19/27] wip --- docs/evm-tutorials/_create-mm-wallet.mdx | 2 +- docs/evm-tutorials/_install.mdx | 6 +---- docs/evm-tutorials/convert-h160-to-ss58.md | 26 +++++++--------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/docs/evm-tutorials/_create-mm-wallet.mdx b/docs/evm-tutorials/_create-mm-wallet.mdx index 155859bb5..ff9d13a92 100644 --- a/docs/evm-tutorials/_create-mm-wallet.mdx +++ b/docs/evm-tutorials/_create-mm-wallet.mdx @@ -2,7 +2,7 @@ import React from 'react'; export const CreatePartial = () => ( <> -

Create Wallet with MetaMask

+

Create Wallet with MetaMask

  1. Install MetaMask browser extension if you haven't already.
  2. diff --git a/docs/evm-tutorials/_install.mdx b/docs/evm-tutorials/_install.mdx index 2a39b3092..e8dbe0d8d 100644 --- a/docs/evm-tutorials/_install.mdx +++ b/docs/evm-tutorials/_install.mdx @@ -1,10 +1,6 @@ export const InstallPartial = () => ( <> -

    Install the EVM Examples repo

    -

    - Before you can run any EVM tutorials, you must install the dependencies. Follow the below steps: -

    - +

    Install the EVM Examples repo

    1. Clone the Opentensor EVM-Bittensor GitHub repo: diff --git a/docs/evm-tutorials/convert-h160-to-ss58.md b/docs/evm-tutorials/convert-h160-to-ss58.md index e7cf51d02..2e3f151e9 100644 --- a/docs/evm-tutorials/convert-h160-to-ss58.md +++ b/docs/evm-tutorials/convert-h160-to-ss58.md @@ -4,48 +4,38 @@ title: "Convert Ethereum (H160) Address to Substrate (SS58)" import { InstallPartial } from "./_install.mdx"; import { CreatePartial } from "./_create-mm-wallet.mdx"; - # Convert Ethereum (H160) Address to Substrate (SS58) This tutorial demonstrates how to convert between Ethereum (H160) and Substrate (SS58) addresses in the Bittensor EVM environment. When working with Bittensor's EVM implementation, you may need to convert between Ethereum-style addresses (H160) and Substrate-style addresses (SS58). This is particularly useful when interacting with both EVM and native Substrate functionality. -This conversion is particularly useful when: -- Interacting with both EVM and native Substrate contracts -- Managing accounts that need to work across both environments -- Verifying addresses across different address formats -- Integrating EVM-based applications with native Bittensor functionality - ## Procedure - ## Set your config - ### Convert Address for Bittensor + +Run the conversion script, replacing `ethereumAddress` with your address: -Run the conversion script with your MetaMask address: ```bash node convert-address.js ``` -Note down the SS58 address output by the script - this is your Bittensor address +Note down the SS58 address output by the script - this is your wallet's coldkey public key, your address on any Bittensor network. -### 3. Transfer TAO to EVM Wallet +### Transfer TAO to EVM Wallet + +Use `btcli` to transfer TAO to your SS58 address. Here we will use test network. -1. Use `btcli` to transfer TAO to your SS58 address: ```bash - btcli root transfer --amount 1.0 --dest + btcli wallet transfer --destination --network test ``` - -2. Wait for the transfer to complete (usually takes a few blocks) - -### 4. Verify Balance in MetaMask +### Verify Balance in MetaMask 1. Open MetaMask 2. Ensure you're connected to the Bittensor EVM network From e8b7722992f70f3f5d90512799f74053b5f71cf7 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Fri, 30 May 2025 08:05:48 -0700 Subject: [PATCH 20/27] wip --- docs/evm-tutorials/subnet-precompile.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md index 14ca336d3..90df123f4 100644 --- a/docs/evm-tutorials/subnet-precompile.md +++ b/docs/evm-tutorials/subnet-precompile.md @@ -7,7 +7,11 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Subnet Precompile -The subnet precompile allows you to interact with subnet operations on the Bittensor network through smart contracts. This precompile provides functionality for registering networks, managing network parameters, and querying network state. +The subnet precompile allows you to interact with subnet operations on the Bittensor network through smart contracts, including functionality for registering networks, managing network parameters, and querying network state. + +This page: +- described the precompile's [available functions](#available-functions) on the precompile +- demonstrates the precompile's usage with [example scripts](#example-script). ## Precompile Address From 85513d0fdc7685f4ad44e4f36aa84c4468238934 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Fri, 30 May 2025 12:08:04 -0700 Subject: [PATCH 21/27] wip --- docs/evm-tutorials/subnet-precompile.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md index 90df123f4..d98f06430 100644 --- a/docs/evm-tutorials/subnet-precompile.md +++ b/docs/evm-tutorials/subnet-precompile.md @@ -7,16 +7,33 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; # Subnet Precompile -The subnet precompile allows you to interact with subnet operations on the Bittensor network through smart contracts, including functionality for registering networks, managing network parameters, and querying network state. +This precompile allows you to interact with Bittensor subnets through EVM smart contracts, affording functionality for registering networks, viewing and setting network parameters, and querying network state. This page: - described the precompile's [available functions](#available-functions) on the precompile - demonstrates the precompile's usage with [example scripts](#example-script). -## Precompile Address + The subnet precompile is available at address `0x803` (2051 in decimal). +View the [source on GitHub](https://github.com/opentensor/subtensor/blob/main/precompiles/src/subnet.rs) + + + + +:::info permissions +Subnet operations have distinct requirements! + +- Creating a subnet, i.e. [`registerNetwork`,](#registernetwork) requires a coldkey with sufficient TAO to cover the current burn cost. + + See [burn cost for subnet creation](./docs/local-build/create-subnet#burn-cost). + +- Setting subnet hyperparameters requires the private key for the coldkey that owns the subnet (the one that created it, unless this has been transferred). + +::: + + ## Available Functions The subnet precompile provides comprehensive functionality for subnet management and configuration. All functions are categorized below: @@ -24,7 +41,8 @@ The subnet precompile provides comprehensive functionality for subnet management ### Network Registration #### `registerNetwork` -Registers a new subnet without additional identity information. + +Create/register a new subnet, without setting identity information. **Parameters:** - `hotkey` (bytes32): The hotkey (32 bytes) that will own the network From 53fcd0fd1b34b3cbfc541ce90cc7ebed0f2a76e5 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Fri, 30 May 2025 12:21:36 -0700 Subject: [PATCH 22/27] wip --- docs/evm-tutorials/metagraph-precompile.md | 89 ---------------------- 1 file changed, 89 deletions(-) diff --git a/docs/evm-tutorials/metagraph-precompile.md b/docs/evm-tutorials/metagraph-precompile.md index e77dd5f64..a405df5f0 100644 --- a/docs/evm-tutorials/metagraph-precompile.md +++ b/docs/evm-tutorials/metagraph-precompile.md @@ -29,11 +29,6 @@ Returns the total number of UIDs (neurons) in a specific subnetwork. **Returns:** - `uint16`: Total count of neurons in the subnetwork -**Example:** -```solidity -// Get the number of neurons in subnetwork 1 -uint16 neuronCount = IMetagraph(METAGRAPH_PRECOMPILE).getUidCount(1); -``` ### Token and Consensus Metrics @@ -309,54 +304,7 @@ Returns the coldkey (owner key) associated with a neuron's hotkey. bytes32 coldkey = IMetagraph(METAGRAPH_PRECOMPILE).getColdkey(1, 13); ``` -## Interface Definition -Here's the complete Solidity interface for the Metagraph Precompile: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IMetagraph { - struct AxonInfo { - uint64 block; - uint32 version; - uint128 ip; - uint16 port; - uint8 ip_type; - uint8 protocol; - } - - // Network information - function getUidCount(uint16 netuid) external view returns (uint16); - - // Financial metrics - function getStake(uint16 netuid, uint16 uid) external view returns (uint64); - function getEmission(uint16 netuid, uint16 uid) external view returns (uint64); - - // Performance metrics - function getRank(uint16 netuid, uint16 uid) external view returns (uint16); - function getTrust(uint16 netuid, uint16 uid) external view returns (uint16); - function getConsensus(uint16 netuid, uint16 uid) external view returns (uint16); - function getIncentive(uint16 netuid, uint16 uid) external view returns (uint16); - function getDividends(uint16 netuid, uint16 uid) external view returns (uint16); - - // Validator functions - function getVtrust(uint16 netuid, uint16 uid) external view returns (uint16); - function getValidatorStatus(uint16 netuid, uint16 uid) external view returns (bool); - - // State information - function getLastUpdate(uint16 netuid, uint16 uid) external view returns (uint64); - function getIsActive(uint16 netuid, uint16 uid) external view returns (bool); - - // Network connection - function getAxon(uint16 netuid, uint16 uid) external view returns (AxonInfo memory); - - // Key management - function getHotkey(uint16 netuid, uint16 uid) external view returns (bytes32); - function getColdkey(uint16 netuid, uint16 uid) external view returns (bytes32); -} -``` ## Usage Examples @@ -439,40 +387,3 @@ The metagraph precompile can throw the following errors: - **InvalidRange**: Thrown when querying a UID that doesn't exist in the specified network - **"hotkey not found"**: Thrown when trying to get axon information for a non-existent neuron - -Always handle these errors appropriately in your smart contracts: - -```solidity -contract SafeMetagraphQuery { - IMetagraph constant METAGRAPH = IMetagraph(0x0000000000000000000000000000000000000802); - - function safeGetStake(uint16 netuid, uint16 uid) external view returns (uint64, bool) { - try METAGRAPH.getStake(netuid, uid) returns (uint64 stake) { - return (stake, true); - } catch { - return (0, false); - } - } -} -``` - -## Gas Considerations - -All metagraph precompile functions are view functions that don't modify state. They have very low gas costs, typically: - -- Simple queries (rank, trust, etc.): ~2,100 gas -- Complex queries (axon info): ~3,000 gas -- Key lookups: ~2,500 gas - -This makes them suitable for frequent queries and batch operations within smart contracts. - -## Best Practices - -1. **Batch Queries**: When querying multiple neurons, consider batching operations to reduce transaction costs -2. **Cache Results**: If querying the same data multiple times, consider caching results within your contract -3. **Error Handling**: Always implement proper error handling for edge cases -4. **Network Validation**: Validate that the netuid exists before querying UIDs -5. **UID Bounds Checking**: Ensure UIDs are within the valid range (0 to getUidCount - 1) - - - From 72ebb216615f293d0d58f1c26fce6fa645839445 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Fri, 30 May 2025 13:49:27 -0700 Subject: [PATCH 23/27] wip --- docs/evm-tutorials/subnet-precompile.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/evm-tutorials/subnet-precompile.md b/docs/evm-tutorials/subnet-precompile.md index d98f06430..d28802dc1 100644 --- a/docs/evm-tutorials/subnet-precompile.md +++ b/docs/evm-tutorials/subnet-precompile.md @@ -27,7 +27,7 @@ Subnet operations have distinct requirements! - Creating a subnet, i.e. [`registerNetwork`,](#registernetwork) requires a coldkey with sufficient TAO to cover the current burn cost. - See [burn cost for subnet creation](./docs/local-build/create-subnet#burn-cost). + See [burn cost for subnet creation](../local-build/create-subnet#burn-cost). - Setting subnet hyperparameters requires the private key for the coldkey that owns the subnet (the one that created it, unless this has been transferred). From 9b765ac4b34ba02c2792f11c48d1c85d36bb8ded Mon Sep 17 00:00:00 2001 From: michael trestman Date: Sun, 1 Jun 2025 19:36:45 -0700 Subject: [PATCH 24/27] wip --- docs/evm-tutorials/_create-mm-wallet.mdx | 8 +++++--- docs/evm-tutorials/convert-h160-to-ss58.md | 17 +++-------------- docs/evm-tutorials/index.md | 22 ++++++++++++++++++++-- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/docs/evm-tutorials/_create-mm-wallet.mdx b/docs/evm-tutorials/_create-mm-wallet.mdx index ff9d13a92..e563f245d 100644 --- a/docs/evm-tutorials/_create-mm-wallet.mdx +++ b/docs/evm-tutorials/_create-mm-wallet.mdx @@ -5,7 +5,7 @@ export const CreatePartial = () => (

      Create Wallet with MetaMask

        -
      1. Install MetaMask browser extension if you haven't already.
      2. +
      3. Install [Metamask wallet](https://metamask.io/download/) browser extension, if you haven't already.
      4. Create a new account or import an existing one.
      5. Add the Bittensor EVM network to MetaMask:
          @@ -13,9 +13,11 @@ export const CreatePartial = () => (
        • RPC URL: https://test.chain.opentensor.ai
        • Chain ID: 945
        • Currency Symbol: TAO
        • -
        • Block Explorer URL: https://evm.bittensor.com
        • -
        +
      6. Block Explorer URL: test.chain.opentensor.ai
      7. + +
      8. Click Save.
      9. +
      10. Click Switch network.
      ); \ No newline at end of file diff --git a/docs/evm-tutorials/convert-h160-to-ss58.md b/docs/evm-tutorials/convert-h160-to-ss58.md index 2e3f151e9..ebb80014e 100644 --- a/docs/evm-tutorials/convert-h160-to-ss58.md +++ b/docs/evm-tutorials/convert-h160-to-ss58.md @@ -6,9 +6,9 @@ import { CreatePartial } from "./_create-mm-wallet.mdx"; # Convert Ethereum (H160) Address to Substrate (SS58) -This tutorial demonstrates how to convert between Ethereum (H160) and Substrate (SS58) addresses in the Bittensor EVM environment. +This tutorial demonstrates how to convert between Ethereum (H160) and Substrate (SS58) addresses. This is useful for moving across the boundary between a) EVM smart contracts and b) core Subtensor functionality based on Polkadot. -When working with Bittensor's EVM implementation, you may need to convert between Ethereum-style addresses (H160) and Substrate-style addresses (SS58). This is particularly useful when interacting with both EVM and native Substrate functionality. +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 @@ -85,15 +85,4 @@ function convertH160ToSS58(ethAddress) { const ss58Address = encodeAddress(hash, 42); // Network ID 42 for Bittensor return ss58Address; } -``` - -### Step-by-Step Explanation - -1. **Prefix Addition**: The function adds an 'evm:' prefix to distinguish EVM addresses -2. **Byte Conversion**: - - Converts the prefix to bytes using TextEncoder - - Converts the Ethereum address to bytes using hexToU8a -3. **Combination**: Creates a new Uint8Array containing both the prefix and address bytes -4. **Hashing**: Uses Blake2b (via blake2AsU8a) to create a deterministic hash of the combined bytes -5. **SS58 Encoding**: Finally encodes the hash as an SS58 address using network ID 42 (Bittensor's network ID) - +``` \ No newline at end of file diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index ec1727217..f51f215c5 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -25,7 +25,10 @@ import { GrStakeholder } from "react-icons/gr"; # Bittensor EVM Smart Contracts -Full Ethereum virtual machine (EVM) compatibility is now available on subtensor (the blockchain in Bittensor). This allows users to deploy most EVM smart contracts on subtensor without changing the code, interact with deployed smart contracts on the subtensor blockchain, and access standard Ethereum JSON-RPC methods. +A full ethereum virtual machine (EVM) runtime operates as an application layer on top of the Bittensor blockchain (Subtensor). This allows users to: +- deploy most EVM smart contracts on subtensor without changing the code, +- interact with deployed smart contracts on the subtensor blockchain, and +- access standard Ethereum JSON-RPC methods. Bittensor EVM smart contracts are executed solely on the **Bittensor blockchain, *not* on the Ethereum blockchain.** @@ -36,7 +39,22 @@ See: - [EVM on Mainnet](./evm-mainnet-with-metamask-wallet) - [OTF Blogpost: EVM on Bittensor](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) -## Ethereum vs Bittensor EVM Smart Contracts +## Ethereum-style and Bittensor-style wallets on the Bittensor blockchian + +Bittensor wallets are based on Polkadot-style ss58 addresses, whereas Ethereum uses h160 addresses. + +The holder of a private key for an ss58 address based on the corresponding public key can sign transactions on any Bittensor chain for thataddress. Anyone who creates key-pairs using `btcli wallet`, for example, holds the private key and the corresponding seed phrase, and hence can sign Bittensor transactions for that wallet. + +Similarly, creating an Ethereum wallet gives you control of the h160 private key for the corresponding public key. + +It is a simple matter to convert an h160 address to an ss58 address, or vice versa, but this does *not* yield the corresponding private key. This means that if you create a wallet in Bittensor, you will not be able to sign Ethereum contracts with it, nor versa. + +Hence, in the context of Bittensor EVM we can distinguish between: +- 'Bittensor wallets': created using the Bittensor tool chain and therefore able to sign transactions using Bittensor transaction clients (BTCLI and the Bittensor SDK), but not EVM smart contracts, on the Bittensor blockchain. +- 'EVM wallets': created using an EVM client such as MetaMask and therefore able to sign EVM smart contracts, but not Subtensor extrinsics, on the Bittensor blockchain. + + +## Ethereum vs Bittensor EVM smart contract runtime On the Ethereum network, nodes such as full nodes, validator nodes and archive nodes run the Ethereum Virtual Environment (EVM) run-time environment. Smart contracts operate under this EVM. See the below high-level diagram. From 7068f2e2b60c1ded65ba5bd4e437271dd481ab17 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Sun, 1 Jun 2025 19:42:06 -0700 Subject: [PATCH 25/27] wip --- docs/evm-tutorials/convert-h160-to-ss58.md | 2 +- docs/evm-tutorials/convert-ss58-to-h160.md | 7 ++++++- docs/evm-tutorials/index.md | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/evm-tutorials/convert-h160-to-ss58.md b/docs/evm-tutorials/convert-h160-to-ss58.md index ebb80014e..65b20defa 100644 --- a/docs/evm-tutorials/convert-h160-to-ss58.md +++ b/docs/evm-tutorials/convert-h160-to-ss58.md @@ -6,7 +6,7 @@ import { CreatePartial } from "./_create-mm-wallet.mdx"; # 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 a) EVM smart contracts and b) core Subtensor functionality based on Polkadot. +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](./#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. diff --git a/docs/evm-tutorials/convert-ss58-to-h160.md b/docs/evm-tutorials/convert-ss58-to-h160.md index ccc63a51c..72ce044e8 100644 --- a/docs/evm-tutorials/convert-ss58-to-h160.md +++ b/docs/evm-tutorials/convert-ss58-to-h160.md @@ -4,9 +4,14 @@ title: "Convert Substrate (SS58) Address to Ethereum (H160)" # Convert Substrate (SS58) Address to Ethereum (H160) - ## Procedure +### Create a wallet with BTCLI + +### Convert the address + +### Transfer TAO to it with an EVM smart contract + ## Conversion Script Below is the code used above for the conversion. diff --git a/docs/evm-tutorials/index.md b/docs/evm-tutorials/index.md index f51f215c5..2ec78378b 100644 --- a/docs/evm-tutorials/index.md +++ b/docs/evm-tutorials/index.md @@ -39,7 +39,7 @@ See: - [EVM on Mainnet](./evm-mainnet-with-metamask-wallet) - [OTF Blogpost: EVM on Bittensor](https://blog.bittensor.com/evm-on-bittensor-draft-6f323e69aff7) -## Ethereum-style and Bittensor-style wallets on the Bittensor blockchian +## EVM and Subtensor wallets on the Bittensor blockchian Bittensor wallets are based on Polkadot-style ss58 addresses, whereas Ethereum uses h160 addresses. @@ -47,7 +47,7 @@ The holder of a private key for an ss58 address based on the corresponding publi Similarly, creating an Ethereum wallet gives you control of the h160 private key for the corresponding public key. -It is a simple matter to convert an h160 address to an ss58 address, or vice versa, but this does *not* yield the corresponding private key. This means that if you create a wallet in Bittensor, you will not be able to sign Ethereum contracts with it, nor versa. +It is a simple matter to [convert an h160 address to an ss58 address](./convert-h160-to-ss58), or vice versa, but this does *not* yield the corresponding private key. This means that if you create a wallet in Bittensor, you will not be able to sign Ethereum contracts with it, nor versa. Hence, in the context of Bittensor EVM we can distinguish between: - 'Bittensor wallets': created using the Bittensor tool chain and therefore able to sign transactions using Bittensor transaction clients (BTCLI and the Bittensor SDK), but not EVM smart contracts, on the Bittensor blockchain. From 8b74eb8bc12e2fcfcd1d4d24f682c2c6e0da503b Mon Sep 17 00:00:00 2001 From: michael trestman Date: Sun, 1 Jun 2025 19:49:24 -0700 Subject: [PATCH 26/27] wip --- docs/evm-tutorials/convert-ss58-to-h160.md | 72 +++++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/docs/evm-tutorials/convert-ss58-to-h160.md b/docs/evm-tutorials/convert-ss58-to-h160.md index 72ce044e8..aeba2d9da 100644 --- a/docs/evm-tutorials/convert-ss58-to-h160.md +++ b/docs/evm-tutorials/convert-ss58-to-h160.md @@ -2,15 +2,51 @@ title: "Convert Substrate (SS58) Address to Ethereum (H160)" --- +import { InstallPartial } from "./_install.mdx"; +import { CreateBtcliPartial } from "./_create-btcli-wallet.mdx"; + # Convert Substrate (SS58) Address to Ethereum (H160) +This tutorial demonstrates how to convert between Substrate (SS58) and Ethereum (H160) addresses. This is useful for moving across the boundary between a) core Subtensor functionality based on Polkadot and b) EVM smart contracts. + +In what follows, we'll create a wallet in BTCLI and convert its SS58 address to H160 format in order to use it with EVM smart contracts and MetaMask. + ## Procedure -### Create a wallet with BTCLI + + + + +## Set your config + +### Convert Address for EVM + +Run the conversion script, replacing `ss58Address` with your address: + +```bash +node convert-ss58-address.js +``` + +Note down the H160 address output by the script - this is your wallet's mirror address in EVM format that can be used with MetaMask and EVM smart contracts. + +### Transfer TAO from BTCLI to EVM Mirror + +Use `btcli` to transfer TAO to the H160 mirror address. Here we will use test network. + +```bash +btcli wallet transfer --destination --network test +``` -### Convert the address +:::info +When transferring to an H160 address from BTCLI, the funds will be available on the EVM side and can be accessed through MetaMask or EVM smart contracts. +::: -### Transfer TAO to it with an EVM smart contract +### Verify Balance in MetaMask + +1. [Set up MetaMask for Bittensor EVM](./evm-testnet-with-metamask-wallet) +2. Import your H160 address into MetaMask using the private key (if available) or add it as a watch-only address +3. Your TAO balance should now be visible in MetaMask +4. You can now use this address for EVM transactions on Bittensor ## Conversion Script @@ -18,4 +54,34 @@ Below is the code used above for the conversion. **Source code**: - [EVM examples repo](https://github.com/opentensor/evm-bittensor) +- [Address mapping](https://github.com/opentensor/evm-bittensor/blob/main/examples/address-mapping.js) +- [Convert SS58 address](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw-address.js) + +```javascript +//convert-ss58-address.js + +function ss58ToH160(ss58Address) { + // Decode the SS58 address to a Uint8Array public key + const publicKey = decodeAddress(ss58Address); + + // Take the first 20 bytes of the hashed public key for the Ethereum address + const ethereumAddressBytes = publicKey.slice(0, 20); + + // Convert the 20 bytes into an Ethereum H160 address format (Hex string) + const ethereumAddress = '0x' + Buffer.from(ethereumAddressBytes).toString('hex'); + + return ethereumAddress; +} + +async function main() { + const ss58Address = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"; + + const h160Address = ss58ToH160(ss58Address); + console.log(`H160 mirror: ${h160Address}`); +} + +main().catch(console.error); +``` + + From 9eb4f6455b6dd67ac9bea573c2dfb05aabbbdfa2 Mon Sep 17 00:00:00 2001 From: michael trestman Date: Sun, 1 Jun 2025 20:10:47 -0700 Subject: [PATCH 27/27] wip --- docs/evm-tutorials/_create-btcli-wallet.mdx | 32 +++++++ docs/evm-tutorials/_create-mm-wallet.mdx | 2 +- docs/evm-tutorials/convert-h160-to-ss58.md | 2 +- docs/evm-tutorials/convert-ss58-to-h160.md | 87 ------------------- .../evm-testnet-with-metamask-wallet.md | 10 +-- sidebars.js | 1 - 6 files changed, 38 insertions(+), 96 deletions(-) create mode 100644 docs/evm-tutorials/_create-btcli-wallet.mdx delete mode 100644 docs/evm-tutorials/convert-ss58-to-h160.md diff --git a/docs/evm-tutorials/_create-btcli-wallet.mdx b/docs/evm-tutorials/_create-btcli-wallet.mdx new file mode 100644 index 000000000..22300a5e4 --- /dev/null +++ b/docs/evm-tutorials/_create-btcli-wallet.mdx @@ -0,0 +1,32 @@ +import React from 'react'; + +export const CreateBtcliPartial = () => ( + <> +

      Create Wallet with BTCLI

      + +
        +
      1. Install BTCLI if you haven't already: +

        + + pip install bittensor + +

        +
      2. +
      3. Create a new wallet: +

        + + btcli wallet new_coldkey --wallet.name my_wallet + +

        +
      4. +
      5. Note down your wallet's SS58 address, which you can get with: +

        + + btcli wallet overview --wallet.name my_wallet + +

        +
      6. +
      7. Your coldkey address will start with "5" and is in SS58 format (for example: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty).
      8. +
      + +); \ No newline at end of file diff --git a/docs/evm-tutorials/_create-mm-wallet.mdx b/docs/evm-tutorials/_create-mm-wallet.mdx index e563f245d..60c061a79 100644 --- a/docs/evm-tutorials/_create-mm-wallet.mdx +++ b/docs/evm-tutorials/_create-mm-wallet.mdx @@ -5,7 +5,7 @@ export const CreatePartial = () => (

      Create Wallet with MetaMask

        -
      1. Install [Metamask wallet](https://metamask.io/download/) browser extension, if you haven't already.
      2. +
      3. Install Metamask wallet browser extension, if you haven't already.
      4. Create a new account or import an existing one.
      5. Add the Bittensor EVM network to MetaMask:
          diff --git a/docs/evm-tutorials/convert-h160-to-ss58.md b/docs/evm-tutorials/convert-h160-to-ss58.md index 65b20defa..dda6e81ec 100644 --- a/docs/evm-tutorials/convert-h160-to-ss58.md +++ b/docs/evm-tutorials/convert-h160-to-ss58.md @@ -26,7 +26,7 @@ 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 coldkey public key, your address on any Bittensor network. +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 diff --git a/docs/evm-tutorials/convert-ss58-to-h160.md b/docs/evm-tutorials/convert-ss58-to-h160.md deleted file mode 100644 index aeba2d9da..000000000 --- a/docs/evm-tutorials/convert-ss58-to-h160.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: "Convert Substrate (SS58) Address to Ethereum (H160)" ---- - -import { InstallPartial } from "./_install.mdx"; -import { CreateBtcliPartial } from "./_create-btcli-wallet.mdx"; - -# Convert Substrate (SS58) Address to Ethereum (H160) - -This tutorial demonstrates how to convert between Substrate (SS58) and Ethereum (H160) addresses. This is useful for moving across the boundary between a) core Subtensor functionality based on Polkadot and b) EVM smart contracts. - -In what follows, we'll create a wallet in BTCLI and convert its SS58 address to H160 format in order to use it with EVM smart contracts and MetaMask. - -## Procedure - - - - - -## Set your config - -### Convert Address for EVM - -Run the conversion script, replacing `ss58Address` with your address: - -```bash -node convert-ss58-address.js -``` - -Note down the H160 address output by the script - this is your wallet's mirror address in EVM format that can be used with MetaMask and EVM smart contracts. - -### Transfer TAO from BTCLI to EVM Mirror - -Use `btcli` to transfer TAO to the H160 mirror address. Here we will use test network. - -```bash -btcli wallet transfer --destination --network test -``` - -:::info -When transferring to an H160 address from BTCLI, the funds will be available on the EVM side and can be accessed through MetaMask or EVM smart contracts. -::: - -### Verify Balance in MetaMask - -1. [Set up MetaMask for Bittensor EVM](./evm-testnet-with-metamask-wallet) -2. Import your H160 address into MetaMask using the private key (if available) or add it as a watch-only address -3. Your TAO balance should now be visible in MetaMask -4. You can now use this address for EVM transactions on Bittensor - -## Conversion Script - -Below is the code used above for the conversion. - -**Source code**: -- [EVM examples repo](https://github.com/opentensor/evm-bittensor) -- [Address mapping](https://github.com/opentensor/evm-bittensor/blob/main/examples/address-mapping.js) -- [Convert SS58 address](https://github.com/opentensor/evm-bittensor/blob/main/examples/withdraw-address.js) - -```javascript -//convert-ss58-address.js - -function ss58ToH160(ss58Address) { - // Decode the SS58 address to a Uint8Array public key - const publicKey = decodeAddress(ss58Address); - - // Take the first 20 bytes of the hashed public key for the Ethereum address - const ethereumAddressBytes = publicKey.slice(0, 20); - - // Convert the 20 bytes into an Ethereum H160 address format (Hex string) - const ethereumAddress = '0x' + Buffer.from(ethereumAddressBytes).toString('hex'); - - return ethereumAddress; -} - -async function main() { - const ss58Address = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"; - - const h160Address = ss58ToH160(ss58Address); - console.log(`H160 mirror: ${h160Address}`); -} - -main().catch(console.error); -``` - - - diff --git a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md index 25b69909b..69ef27f08 100644 --- a/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md +++ b/docs/evm-tutorials/evm-testnet-with-metamask-wallet.md @@ -3,6 +3,7 @@ title: "EVM on Testnet" --- import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; +import { CreatePartial } from "./_create-mm-wallet.mdx"; # EVM on Testnet @@ -12,7 +13,9 @@ Key values: - The **Bittensor Testnet URL:** `https://test.chain.opentensor.ai` - **EVM Subtensor Chain ID:** `945` (UTF-8 encoded alpha character) - **Opentensor EVM-Bittensor GitHub repo:** `https://github.com/opentensor/evm-bittensor/tree/main` - + + + ## Connect to EVM Testnet Confirm the EVM node is online and accessible. You can check the node status independently using `curl` or similar tools: @@ -26,11 +29,6 @@ curl -X POST \ ```console {"jsonrpc":"2.0","id":1,"result":"0x460943"} ``` -## Create a Metamask wallet - -1. If you don't already have it, [install Metamask wallet](https://metamask.io/download/) browser extension. -2. Create a new account. - ### Add testnet to Metamask Add the testnet to Metamask from within the Metamask wallet. Follow the below steps: diff --git a/sidebars.js b/sidebars.js index c85c41161..fa458500e 100644 --- a/sidebars.js +++ b/sidebars.js @@ -209,7 +209,6 @@ const sidebars = { items:[ "evm-tutorials/examples", "evm-tutorials/convert-h160-to-ss58", - "evm-tutorials/convert-ss58-to-h160", "evm-tutorials/ed25519-verify-precompile", "evm-tutorials/transfer-from-metamask-to-ss58", "evm-tutorials/transfer-between-two-h160-accounts",