Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
19f09f1
Add pallet-contracts dependency
silva-fj Aug 27, 2025
7d65d8f
Integrate contracts pallet into runtime
silva-fj Aug 27, 2025
d241271
Add contracts genesis config to localnet
silva-fj Aug 27, 2025
27c2510
fix(chain-spec): remove empty contracts from localnet config
silva-fj Aug 28, 2025
ac2089a
Configure contracts pallet with call filter and custom schedule
silva-fj Sep 2, 2025
594c930
feat(runtime): add Subtensor chain extension for contracts
silva-fj Sep 11, 2025
f13e1a0
docs(runtime): clarify comment for smart contracts support
silva-fj Sep 15, 2025
ceca15e
refactor(runtime): rename ContractSchedule to ContractsSchedule
silva-fj Sep 15, 2025
587ee48
docs: add smart contracts documentation
silva-fj Sep 15, 2025
1b6aec5
fix docs
silva-fj Sep 15, 2025
c8ca999
feat(runtime): update code hash lockup deposit percent to 30
silva-fj Sep 18, 2025
af86928
feat(runtime): customize contract storage deposit calculation
silva-fj Sep 18, 2025
c569dac
feat(runtime): expand contract call whitelist for staking operations
silva-fj Sep 18, 2025
ef563d3
docs: document expanded contract call whitelist
silva-fj Sep 18, 2025
12788fc
fix(runtime): remove create_pure from proxy call filter
silva-fj Sep 24, 2025
395d6a1
Merge upstream/devnet-ready into feature/add-pallet-contracts
silva-fj Sep 29, 2025
8693c7c
Merge remote-tracking branch 'upstream/devnet-ready' into feature/add…
silva-fj Oct 8, 2025
33b0083
Add DoNotBreakSmartContracts trait for contract API stability
silva-fj Oct 13, 2025
4c0109b
Merge remote-tracking branch 'upstream/devnet-ready' into feature/add…
silva-fj Oct 13, 2025
2610ac1
docs(contracts): remove Proxy::create_pure from allowed calls
silva-fj Oct 13, 2025
a490159
refactor(runtime): rename DoNotBreakSmartContracts trait
silva-fj Oct 13, 2025
cf70929
refactor(runtime): remove DoNotBreakSmartContractsV1 trait
silva-fj Oct 15, 2025
cf30094
build: add chain-extensions workspace member
silva-fj Oct 15, 2025
da84eed
feat(chain-extensions): add chain extensions crate
silva-fj Oct 15, 2025
7e7c364
feat(chain-extensions): add FunctionId and Outcome types
silva-fj Oct 15, 2025
bab0039
feat(chain-extensions): implement staking chain extensions
silva-fj Oct 15, 2025
3724e33
refactor(chain-ext): rename Outcome to Output
silva-fj Oct 15, 2025
c6547fd
build(chain-ext): add test dependencies
silva-fj Oct 16, 2025
2279c43
refactor(chain-ext): introduce testable extension environment trait
silva-fj Oct 16, 2025
dab4c46
test(chain-ext): add test infrastructure and test suite
silva-fj Oct 16, 2025
8e55f84
refactor(runtime): replace chain extension with subtensor-chain-exten…
silva-fj Oct 16, 2025
8dd3c5c
refactor(contracts): remove SubtensorModule calls from whitelist
silva-fj Oct 16, 2025
4e7e913
docs(contracts): document all chain extension functions and error codes
silva-fj Oct 16, 2025
20cfeb3
Merge upstream/devnet-ready into feature/add-pallet-contracts
silva-fj Oct 16, 2025
68b89f8
fix(chain-extensions): make types module public
silva-fj Oct 17, 2025
61219e7
fix(chain-extensions): return correct success code
silva-fj Oct 17, 2025
673d8c4
refactor(mock): clean up unused imports
silva-fj Oct 17, 2025
e542ed5
chore(chain-extensions): add no_std support
silva-fj Oct 17, 2025
0fd04bf
refactor(chain-extensions): remove unused mock utilities
silva-fj Oct 17, 2025
6a60750
feat(chain-extensions): add AddProxyV1 function ID and error codes
silva-fj Oct 18, 2025
2d975b7
build(chain-extensions): add pallet-subtensor-proxy dependency
silva-fj Oct 18, 2025
ea31d42
feat(chain-extensions): implement AddProxyV1 chain extension
silva-fj Oct 18, 2025
7e89630
test(chain-extensions): add proxy pallet to test runtime
silva-fj Oct 18, 2025
0724349
test(chain-extensions): add test for AddProxyV1
silva-fj Oct 18, 2025
00dc850
docs: add AddProxyV1 to chain extension documentation
silva-fj Oct 18, 2025
61b5541
refactor(runtime): remove add_proxy from contract call filter
silva-fj Oct 18, 2025
24e87c6
chore: update Cargo.lock
silva-fj Oct 18, 2025
73e9387
feat(chain-extensions): add RemoveProxyV1 function ID and error code
silva-fj Oct 18, 2025
f919287
feat(chain-extensions): implement RemoveProxyV1 chain extension
silva-fj Oct 18, 2025
0a362f2
test(chain-extensions): add test for RemoveProxyV1
silva-fj Oct 18, 2025
49b07bd
docs: add RemoveProxyV1 to chain extension documentation
silva-fj Oct 18, 2025
05550de
fix: add num_enum/std feature propagation
silva-fj Oct 20, 2025
fc7eeff
Merge remote-tracking branch 'upstream/devnet-ready' into feature/add…
silva-fj Oct 20, 2025
142842d
fix: remove InitialMaxWeightsLimit from chain-extensions mock
silva-fj Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/polkadot-sdk
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false }
pallet-root-testing = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false }
pallet-contracts = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false }

# NPoS
frame-election-provider-support = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This repository contains Bittensor's substrate-chain. Subtensor contains the tru
1. Runs Bittensor's [consensus mechanism](./docs/consensus.md);
2. Advertises neuron information, IPs, etc., and
3. Facilitates value transfer via TAO.
4. Supports wasm smart contract functionality via `pallet-contracts` (see [contracts documentation](./docs/contracts.md)).

## System Requirements

Expand Down
66 changes: 66 additions & 0 deletions docs/contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Smart Contracts on Subtensor

## Overview

Subtensor now supports smart contract functionality through the integration of `pallet-contracts`, enabling developers to deploy and execute WebAssembly (WASM) smart contracts on the network. Contracts are written in [ink!](https://use.ink/), a Rust-based embedded domain-specific language (eDSL) for writing smart contracts on Substrate-based chains.

## Getting Started

For general smart contract development on Subtensor, please refer to the official ink! documentation:
- [ink! Documentation](https://use.ink/docs/v5/)
- [ink! Getting Started Guide](https://use.ink/docs/v5/getting-started/setup)
- [ink! Examples](https://github.com/use-ink/ink-examples/tree/v5.x.x)

## Subtensor-Specific Features

### Chain Extension

Subtensor provides a custom chain extension that allows smart contracts to interact with Subtensor-specific functionality:

#### Available Functions

| Function ID | Name | Description | Parameters | Returns |
|------------|------|-------------|------------|---------|
| 1001 | `get_stake_info_for_hotkey_coldkey_netuid` | Query stake information | `(AccountId32, AccountId32, NetUid)` | Stake information |

Example usage in your ink! contract:
```rust
#[ink::chain_extension(extension = 0)]
pub trait SubtensorExtension {
type ErrorCode = SubtensorError;

#[ink(function = 1001)]
fn get_stake_info(
hotkey: AccountId,
coldkey: AccountId,
netuid: u16,
) -> Result<Option<StakeInfo>, SubtensorError>;
}
```

### Call Filter

For security, contracts can only dispatch a limited set of runtime calls:

**Whitelisted Calls:**
- `SubtensorModule::move_stake` - Move stake between hotkeys
- `SubtensorModule::transfer_stake` - Transfer stake between accounts
- `Proxy::proxy` - Execute proxy calls

All other runtime calls are restricted and cannot be dispatched from contracts.

### Configuration Parameters

| Parameter | Value | Description |
|-----------|-------|-------------|
| Maximum code size | 128 KB | Maximum size of contract WASM code |
| Call stack depth | 5 frames | Maximum nested contract call depth |
| Runtime memory | 1 GB | Memory available during contract execution |
| Validator runtime memory | 2 GB | Memory available for validators |
| Transient storage | 1 MB | Maximum transient storage size |


## Additional Resources

- [cargo-contract CLI Tool](https://github.com/paritytech/cargo-contract)
- [Contracts UI](https://contracts-ui.substrate.io/)
7 changes: 7 additions & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ pallet-commitments.workspace = true

# for prod_or_fast! macro
runtime-common.workspace = true

# Wasm smart contracts support
pallet-contracts.workspace = true

# NPoS
frame-election-provider-support = { workspace = true }
pallet-authority-discovery = { workspace = true }
Expand Down Expand Up @@ -267,6 +271,7 @@ std = [
"pallet-subtensor-swap/std",
"pallet-subtensor-swap-runtime-api/std",
"subtensor-swap-interface/std",
"pallet-contracts/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
Expand Down Expand Up @@ -301,6 +306,7 @@ runtime-benchmarks = [
"pallet-nomination-pools/runtime-benchmarks",
"pallet-offences/runtime-benchmarks",
"sp-staking/runtime-benchmarks",
"pallet-contracts/runtime-benchmarks",

# EVM + Frontier
"pallet-ethereum/runtime-benchmarks",
Expand Down Expand Up @@ -342,6 +348,7 @@ try-runtime = [
"pallet-babe/try-runtime",
"pallet-session/try-runtime",
"pallet-staking/try-runtime",
"pallet-contracts/try-runtime",
"pallet-election-provider-multi-phase/try-runtime",
"frame-election-provider-support/try-runtime",
"pallet-authority-discovery/try-runtime",
Expand Down
52 changes: 52 additions & 0 deletions runtime/src/chain_extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use codec::Encode;
use pallet_contracts::chain_extension::{
ChainExtension, Environment, Ext, InitState, RetVal, SysConfig,
};
use sp_runtime::{AccountId32, DispatchError};
use subtensor_runtime_common::NetUid;

use crate::{Runtime, SubtensorModule};

#[derive(Default)]
pub struct SubtensorChainExtension;

impl ChainExtension<Runtime> for SubtensorChainExtension {
fn call<E: Ext>(&mut self, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>
where
E::T: SysConfig,
{
let func_id = env.func_id();

match func_id {
// Function ID 1001: get_stake_info_for_hotkey_coldkey_netuid
1001 => {
let mut env = env.buf_in_buf_out();

let input: (AccountId32, AccountId32, NetUid) = env
.read_as()
.map_err(|_| DispatchError::Other("Failed to decode input parameters"))?;

let (hotkey, coldkey, netuid) = input;

let stake_info = SubtensorModule::get_stake_info_for_hotkey_coldkey_netuid(
hotkey, coldkey, netuid,
);

let encoded_result = stake_info.encode();

env.write(&encoded_result, false, None)
.map_err(|_| DispatchError::Other("Failed to write output"))?;

Ok(RetVal::Converging(0))
}
_ => {
log::error!("Called an unregistered chain extension function: {func_id}",);
Err(DispatchError::Other("Unimplemented function ID"))
}
}
}

fn enabled() -> bool {
true
}
}
Loading
Loading