From 1e64a5b0300cbd1cd8ab1999b483d0a0d6834c16 Mon Sep 17 00:00:00 2001 From: Watchmaker Date: Wed, 16 Oct 2024 15:16:04 -0700 Subject: [PATCH] Removed docs directory, moved all JS into examples directory and edited README --- README.md | 74 +++------------- docs/ed25519verify-precompile.md | 24 ----- docs/hardhat-config.md | 28 ------ docs/plain-vanilla-balance-transfer.md | 32 ------- docs/qna.md | 83 ----------------- docs/running-locally.md | 50 ----------- docs/running-on-testnet.md | 39 -------- docs/staking-precompile.md | 88 ------------------- .../address-mapping.js | 0 .../config-example.js | 0 .../convert-address.js | 0 .../ed25519-verify.js | 0 examples/eth-addr-format-to-ss58.js | 7 +- transfer.js => examples/transfer.js | 0 .../withdraw-address.js | 0 withdraw.js => examples/withdraw.js | 0 16 files changed, 17 insertions(+), 408 deletions(-) delete mode 100644 docs/ed25519verify-precompile.md delete mode 100644 docs/hardhat-config.md delete mode 100644 docs/plain-vanilla-balance-transfer.md delete mode 100644 docs/qna.md delete mode 100644 docs/running-locally.md delete mode 100644 docs/running-on-testnet.md delete mode 100644 docs/staking-precompile.md rename address-mapping.js => examples/address-mapping.js (100%) rename config-example.js => examples/config-example.js (100%) rename convert-address.js => examples/convert-address.js (100%) rename ed25519-verify.js => examples/ed25519-verify.js (100%) rename transfer.js => examples/transfer.js (100%) rename withdraw-address.js => examples/withdraw-address.js (100%) rename withdraw.js => examples/withdraw.js (100%) diff --git a/README.md b/README.md index b606934..3639cdd 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,23 @@ -# Subtensor EVM Integration Kit +
+# **EVM on Subtensor** +[![Discord Chat](https://img.shields.io/discord/308323056592486420.svg)](https://discord.gg/bittensor) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -## Setting up network +--- -The developer setup can be done in two ways. It includes settings up network URLs, account private keys, and initial balances needed for this guide (and further development). +## Internet-scale Neural Networks -1. [Using EVM Subtensor TestNet](docs/running-on-testnet.md) -2. [Local setup](docs/running-locally.md) (requires Rust and tools to be installed) +[Discord](https://discord.gg/qasY3HA9F9) • [Subtensor](https://github.com/opentensor/subtensor) • [Research](https://bittensor.com/whitepaper) -[Testnet Faucet](https://evm-testnet.dev.opentensor.ai/faucet) +
-## Balance transfer from Substrate (ss58) to EVM (H160) address +This repo contains tutorials and scripts for working with EVM on subtensor. Using this EVM feature you can: -This step is not required if you're working with Subtensor Testnet. It is only essential for starting development with local setup because it transfers some initial TAO balance from the Substrate side to EVM side. +- 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. -Execute: +**NOTE**: The EVM on subtensor 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. -```bash -yarn install -node transfer.js -``` +**Full documenatation**: See [EVM Tutorials](http://docs.bittensor.com/evm-tutorials/) section on the Bittensor developer documentation site. -## Balance transfer from EVM address back to Substrate balances - method 1: Using evm::withdraw - -1. Copy your ss58 address (Example: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty). You need to have the private key for this address setup in Polkadot JS extension. -2. Paste it into `ss58Address` in main function in withdraw-address.js script -3. Execute: - -```bash -node withdraw-address.js -``` - -4. Copy the "Ethereum mirror:" output address -5. 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) -6. Make sure your destination address is funded to run a transaction -7. Open Extrisics tab in Apps UI: https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9946#/extrinsics -8. Select `evm` pallet and `withdraw` extrinsic -9. Paste the "Ethereum mirror" output address into address field -10. 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. -11. Submit transaction - -## Balance transfer from EVM address back to Substrate balances - method 2: Using a SubtensorBalanceTransfer precompile - -This step will transfer 1 TAO to your ss58 address configured with seed phrase in config.js as `subSeed`. - -Execute: - -```bash -node withdraw.js -``` - -Nonetheless, the destination address can be changed to any ss58 address (the private key/seed is not required for it in this step). Look for these lines in `withdraw.js` file: - -```javascript -// Destination address can be replaced with any ss58 address here: -const destinationAddress = account.address; -// const destinationAddress = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"; -``` - -## Further examples - -- [Hardhat configuration](docs/hardhat-config.md) -- [Plain vanilla balance transfer (in JS)](docs/plain-vanilla-balance-transfer.md) -- [Deploying and interacting with ERC-20 token](https://github.com/gztensor/subtensor-erc20) -- [Interaction with staking precompile](docs/staking-precompile.md) -- [Verification of Ed25519 signature with a precompile](docs/ed25519verify-precompile.md) - -## Q&A - -[Q&A](docs/qna.md) diff --git a/docs/ed25519verify-precompile.md b/docs/ed25519verify-precompile.md deleted file mode 100644 index 9017303..0000000 --- a/docs/ed25519verify-precompile.md +++ /dev/null @@ -1,24 +0,0 @@ -# Ed25519 Verify Precompile - -This precompile is deployed at address `0x0000000000000000000000000000000000000402` and allows to verify an ed25519 signature. This can useful for verifying proof of ss58 account ownership on EVM side. One of the use cases for such verification is 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 (e.g. a signed message, uniquely specific for a given airdrop). - -For a complete example see [ed25519-verify.js](../ed25519-verify.js) - -## Usage - -To run an example, execute: -```bash -node ed25519-verify.js -``` - -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, nonetheless, the arbitrary message can be converted into 32-byte message by calculating the message hash (like it is done in this 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 \ No newline at end of file diff --git a/docs/hardhat-config.md b/docs/hardhat-config.md deleted file mode 100644 index bc8bfa5..0000000 --- a/docs/hardhat-config.md +++ /dev/null @@ -1,28 +0,0 @@ -# Hardhat Configuration for Subtensor EVM - -The HardHat networks can be configures as follows. The code below configures two networks: - -1. Local network with URL: http://127.0.0.1:9946 -2. EVM Testnet network with URL: https://evm-testnet.dev.opentensor.ai - -```js -const hardhatConfig: HardhatUserConfig = { - solidity: "0.8.24", - defaultNetwork: "subevm", - networks: { - subevm: { - url: "https://evm-testnet.dev.opentensor.ai", - accounts: [config.ethPrivateKey] - }, - local: { - url: "http://127.0.0.1:9946", - accounts: [config.ethPrivateKey] - } - }, - mocha: { - timeout: 300000 - }, -}; -``` - -See [ERC-20 Example Token repository](https://github.com/gztensor/subtensor-erc20) for complete example. \ No newline at end of file diff --git a/docs/plain-vanilla-balance-transfer.md b/docs/plain-vanilla-balance-transfer.md deleted file mode 100644 index 36b10ff..0000000 --- a/docs/plain-vanilla-balance-transfer.md +++ /dev/null @@ -1,32 +0,0 @@ -# Example: Balance Transfer between two H160 (Ethereum) accounts - -The complete code for this example is located in file [examples/transfer-h160-to-h160.js](examples/transfer-h160-to-h160.js). - -1. Create additional address in Metamask - -You can just create a new account or add exising one using a private key. Copy the address (Example: 0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF) - -2. Paste the address in `destinationEthereumAddress`: - -```js -// Enter your destination address here: -const destinationEthereumAddress = '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF'; -``` - -3. Configure the amount to be sent. In this example we are using large numbers so that the result is visible in Metamask: Because Metamask doesn't respect decimals of 9 and always defaults to 18 decimals. In production environment 0.1 TAO will match to "100000000000" (10^8), while for this demonstration we have to use "100000000000000000" (10^17), which will appear as "0.1 TAO" in Metamask, but will actually be equal to 100000000 TAO (10^8 TAO). - -```js - // Create a transfer transaction to send TAO - const tx = { - to: destinationEthereumAddress, - value: "100000000000000000", - }; -``` - -4. Run - -```bash -node examples/transfer-h160-to-h160.js -``` - -5. Observe the transaction receipt and the change of the recipient balance in logs. You can also look how the recipient balance changed in Metamask. \ No newline at end of file diff --git a/docs/qna.md b/docs/qna.md deleted file mode 100644 index e1e2186..0000000 --- a/docs/qna.md +++ /dev/null @@ -1,83 +0,0 @@ -# Subtensor EVM Q&A - -This upgrade expands the possible ways to interact with the Bittensor network, making it possible for users to be able to use EVM-focused applications like MetaMask and Trust Wallet (among many others) as well as ones specific to substrate. It does not change the core mission of Bittensor, which is to supercharge the development of first-class AI models through incentivized competition. The intent is not to make Bittensor a general-purpose blockchain, but rather to allow options to use EVM tools to accomplish what is only possible with substrate right now. - -## Is Subtensor EVM different from any other EVM chains? - -The EVM side of Subtensor is built with Frontier and EVM pallets. It has most of the EVM functionality in place, but some new EIPs that are recently deployed to Ethereum network may be yet be available. - -## How can smart contracts or EVM-based dApps interact with Subtensor? - -The initial release will provide a few precompile contracts that allow such interaction: - -1. Balance transfers between EVM addresses operating on the Bittensor network, and native Subtensor addresses. - -This is not a transfer of non-native TAO tokens on an EVM network to native TAO tokens on the Bittensor network. This is a transfer of native TAO tokens from an EVM-style account that's interacting with the Bittensor network (the kind that starts with `0x`) to another account on the Bittensor network (either another EVM-style account or a regular substrate account (the kind that starts with `5`). - -2. Smart contracts and/or user addresses can act like coldkeys to stake and unstake to delegate hotkeys. -3. Verification of ed25519 signatures (e.g. to allow airdrop or claiming functionality). - -Later we will make more features available such as: - -1. Miscellaneous state variables such as stake, bonds, validator trust, etc. will be accessible from smart contracts (and via EVM RPC interface) -2. More extrinsics will be available on the EVM side as well. Examples of such may include creating subnets, registrations, settings weights, etc. - -## How will a regular user interact with Subtensor EVM? - -A regular user (with no engineering background) familiar with Metamask or other EVM crypto wallets will initially be able to participate in staking, as soon as web3 applications that provide a UI for such functionality become available. They will be able to nominate stake to one of the hotkeys that allow delegation. These applications will also be capable of providing DEX functionality, liquid staking, and staking pools to leverage Subtensor staking further. - -Later, as more Subtensor features become available to EVM space, users will see more flexible dApps with advanced functionality. - -## How to transfer balance from Substrate to Metamask address and back? - -The readme in [Subtensor EVM Integration Kit](https://github.com/gztensor/evm-demo) explains how to do it programmatically. -There are no UI tools for this yet that are ready to be used by non-engineers. - -## Are there any active bridges that allow transferring value between Subtensor EVM and other chains? - -Not at the moment, but a few integrations are in progress. - -## I am confused: Does having EVM functionality on Subtensor mean that I can transfer my Ethereum assets to it or that Ethereum smart contracts can interact with BitTensor? - -Not exactly. The EVM functionality means that BitTensor mimics the programming interface provided by Ethereum or similar networks. The analogy here is Polygon and Ethereum. While Eth can be transferred to Polygon via a bridge, it does not necessarily mean that an Ethereum smart contract can call Polygon smart contract directly because they are two different networks. - -Similarly, BitTensor will have its own address space, block numbers, native currency (TAO), etc. The only thing in common between Ethereum and BitTensor EVM is their programming interface. - -## What is the gas price in Subtensor EVM? - -Default base fee is 10 GWei per gas unit. - -## What are network parameters to access the Subtensor EVM network? - -### Dedicated EVM Testnet - -``` -RPC Endpoint: https://evm-testnet.dev.opentensor.ai -Chain ID: 945 -``` - -### Subtensor Testnet - -Currently (as of beginning of October 2024) EVM functionality is not yet available on the Testnet, but when we deploy EVM functionality to our Testnet, it will be available with the following parameters: - -``` -RPC Endpoint: https://test.finney.opentensor.ai -Chain ID: 946 -``` - -## How can I deploy smart contracts on Bittensor? - -TBD - -## How can I mint NFTs on Bittensor? - -TBD - -## How can I deploy a token (ERC-20) on Bittensor? - -TBD - -## What are the list of ERCs that Bittensor supports (I guarantee you that they are looking for ERC-20, and some flavor of ERC-721/-1155 etc). - -TBD - diff --git a/docs/running-locally.md b/docs/running-locally.md deleted file mode 100644 index 3731235..0000000 --- a/docs/running-locally.md +++ /dev/null @@ -1,50 +0,0 @@ -# Testing with a local Subtensor devnet - -## 1. Run EVM-enabled localnet - -```bash -git clone https://github.com/opentensor/subtensor -git checkout feat/evm-devnet-ready -./scripts/localnet.sh -``` - -## 2. Setup Metamask - -1. You should have Metamask installed -2. Create a new account -3. Setup the network: - - Open Metamask settings - - Click on "Add a network manually" - - Enter - - Network name: "Subtensor" - - New RPC URL: http://localhost:9946 - - Chain ID: "945" (This is UTF-8 encoding for Alpha character) - - Currency symbol: "TAO" - - Click Save - -## 3. Configure secrets, addresses, and RPC endpoint - -1. Make sure you have at least one address configured in Metamask. If you don't have Metamask installed, you need to install it first. -2. Create config.js file by copying the config-example.js file: - -```bash -cp config-example.js config.js -``` - -3. Locate your H160 account address in Metamask (Example: 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf) and its private key (Example: 0000000000000000000000000000000000000000000000000000000000000001) -4. Copy the private key into `ethPrivateKey` string in your config.js file like that: - -```javascript -const ethPrivateKey = "0000000000000000000000000000000000000000000000000000000000000001"; -``` - -5. Specify local endpoint for RPC and WS URLs in your config.js file: - -```javascript -module.exports = { - ethPrivateKey, - subSeed, - rpcUrl: rpcUrlLocal, - wsUrl: wsUrlLocal, -} -``` diff --git a/docs/running-on-testnet.md b/docs/running-on-testnet.md deleted file mode 100644 index 81829ef..0000000 --- a/docs/running-on-testnet.md +++ /dev/null @@ -1,39 +0,0 @@ -# Testing with a local Subtensor devnet - -## 1. Setup Metamask and get Test TAO - -1. You should have Metamask installed -2. Create a new account -3. Open the [Faucet page](https://evm-testnet.dev.opentensor.ai/faucet) -4. Click "Add Chain to Metamask" button - -The network may also be added manually: - - Open Metamask settings - - Click on "Add a network manually" - - Enter - - Network name: "Subtensor" - - New RPC URL: https://evm-testnet.dev.opentensor.ai - - Chain ID: "945" (This is UTF-8 encoding for Alpha character) - - Currency symbol: "TAO" - - Block explorer URL: https://evm-testscan.dev.opentensor.ai/ - - Click Save - -5. Click connect icon in the address field or paste your address and click REQUEST 1 TAO button - -## 2. Configure your address private key - -1. Make sure you have at least one address configured in Metamask. If you don't have Metamask installed, you need to install it first. -2. Create config.js file by copying the config-example.js file: - -```bash -cp config-example.js config.js -``` - -3. Locate your H160 account address in Metamask (Example: 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf) and its private key (Example: 0000000000000000000000000000000000000000000000000000000000000001) -4. Copy the private key into `ethPrivateKey` string in your config.js file like that: - -```javascript -const ethPrivateKey = "0000000000000000000000000000000000000000000000000000000000000001"; -``` - - diff --git a/docs/staking-precompile.md b/docs/staking-precompile.md deleted file mode 100644 index eb42526..0000000 --- a/docs/staking-precompile.md +++ /dev/null @@ -1,88 +0,0 @@ -# Interacting with Staking Precompile - -Staking precompile allows EVM user space code to interact with staking feature of Subtensor. For example, `add_stake` or `remove_stake` methods can be called in order to delegate or undelegate stake to/from a hotkey. Below steps describe how to interact with staking precompile via a smart contract or a Metamask wallet with a local testnet and Remix IDE. - -## Prerequisites - -1 You should be familiar with Bittensor and usage of `btcli` tool in order to understand staking process of Bittensor. If you are new to Bittensor ecosystem, please read [Bittensor Docs](https://docs.bittensor.com/) first and setup btcli locally. - -2 You should also be comfortable using [Remix IDE](https://remix.ethereum.org/). - -## Calling Staking Precompile - -1. [Launch local testnet](./running-locally.md). Also, follow the instructions of running local chain all the way so that you have a Metamask address with some TAO balance. - -2. Setup a local testnet so that it contains one subnet and a delegate hotkey. The commands below may change with a different version of btcli: - -```bash -btcli subnet create --subtensor.network localhost:9946 -btcli subnet register --subtensor.network localhost:9946 -btcli root nominate --subtensor.network localhost:9946 -``` - -Save the hotkey address that becomes the delegate. In this example, we are going to use Alice key for simplicity: `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY` and the public key that matches to this address: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d. You can convert ss58 address into a public key using [ss58.org](https://ss58.org/). - -### Interaction via a smart contract (Staking Pool use case) - -If you would like to ineract with staking precompile using just the Metamask wallet as a user, skip to step 6 - -3. Copy the text of stake.sol contract to Remix IDE and compile it. Replace `HOTKEY` constant with your hotkey public key. - -4. Connect Remix IDE to Injected Provider - Metamask and your Metamask address that has TAO balance. - -5. Execute Stake contract method `stake_from_this_contract_to_alice` and pass 1^9 Wei to it (1 TAO). - -### Interaction via a user account (Staking as an individual use case) - -6. Copy this ABI of staking precompile contract into Remix IDE as a new file: - -``` -[ - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hotkey", - "type": "bytes32" - } - ], - "name": "addStake", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hotkey", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "amount", - "type": "uint64" - } - ], - "name": "removeStake", - "outputs": [], - "stateMutability": "payable", - "type": "function" - } -] -``` - -7. Copy staking precompile address `0x0000000000000000000000000000000000000801` to the "At Address" field in Remix IDE, and click "At Address" button. - -8. Remix IDE will find the precompile 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 mine. - -### Proof of result - -9. Observe that stake map is updated in [Apps UI](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9946#/chainstate): - -9.1 Select subtensorModule + stake in the drop-down lists -9.2 Paste the delegate hotkey account ID in the first parameter -9.3 Toggle "include option" off for the second parameter -9.4 Click "+" button and find the new stake records - - diff --git a/address-mapping.js b/examples/address-mapping.js similarity index 100% rename from address-mapping.js rename to examples/address-mapping.js diff --git a/config-example.js b/examples/config-example.js similarity index 100% rename from config-example.js rename to examples/config-example.js diff --git a/convert-address.js b/examples/convert-address.js similarity index 100% rename from convert-address.js rename to examples/convert-address.js diff --git a/ed25519-verify.js b/examples/ed25519-verify.js similarity index 100% rename from ed25519-verify.js rename to examples/ed25519-verify.js diff --git a/examples/eth-addr-format-to-ss58.js b/examples/eth-addr-format-to-ss58.js index 9289f3e..7d98ed2 100644 --- a/examples/eth-addr-format-to-ss58.js +++ b/examples/eth-addr-format-to-ss58.js @@ -6,10 +6,11 @@ const { convertH160ToSS58 } = require('./address-mapping.js'); const { ethPrivateKey, subSeed, rpcUrl, wsUrl } = require('./config.js'); async function main() { - // Get ethereum address that matches the private key from the secrets file - // const recipientEthereumAddress = "put your destination address here"; + // Paste your Metamask wallet account address (Ethereum H160 address) into recipientEthereumAddress. For example: // const recipientEthereumAddress = "0x709615c655B24919F48B365D292521EFcC74467B"; - const recipientEthereumAddress = "0xd685a847471F7f07Ce36f89F99C198B098B13817"; + // Run "yarn install" followed by "node eth-addr-format-to-ss58.js". + // The script will display the output, for example: "The SS58 address of your Ethereum H160 address is: 5HMd2QQ2XKaQ5gF5wQvKautTvTU21bDMFWVhv2YJ84SQMi6Z" + const recipientEthereumAddress = "0x709615c655B24919F48B365D292521EFcC74467B"; const ss58Address = convertH160ToSS58(recipientEthereumAddress); console.log(`For your Ethereum H160 address: ${recipientEthereumAddress}, the SS58 address is: ${ss58Address}`); process.exit(0); diff --git a/transfer.js b/examples/transfer.js similarity index 100% rename from transfer.js rename to examples/transfer.js diff --git a/withdraw-address.js b/examples/withdraw-address.js similarity index 100% rename from withdraw-address.js rename to examples/withdraw-address.js diff --git a/withdraw.js b/examples/withdraw.js similarity index 100% rename from withdraw.js rename to examples/withdraw.js