Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7a4d699
Cleanup blocksSinceLastTransfer
gztensor Jun 22, 2025
4684f4b
Merge pull request #2 from gztensor/patch-1
distributedstatemachine Jun 27, 2025
e023f38
first test case ok
Jun 28, 2025
b4ab44f
remove forge std
Jun 28, 2025
3d778f9
add coldkey swap
Jul 1, 2025
5a30239
add set ss58 method
Jul 7, 2025
e142129
clean code and all tests done
Jul 7, 2025
19d64cd
add test cases done
Jul 10, 2025
2c5a31f
add aggregate method
Jul 13, 2025
38d3b09
Use highest yield validator for selection, misc changes/fixes.
jondurbin Jul 15, 2025
5dab745
Merge pull request #1 from jondurbin/fixes
open-junius Jul 15, 2025
655f4a9
fixed all
Jul 16, 2025
4d32d3d
clean logs
Jul 16, 2025
fd4249d
make the gap bigger
Jul 16, 2025
6d44c7a
Simplify validator switch (always execute, if called by authorized us…
jondurbin Jul 16, 2025
51113b1
Merge pull request #2 from jondurbin/test-updates
open-junius Jul 16, 2025
c7e2fa5
rebase upstream main
Jul 17, 2025
be2f616
add modifier for setSs58PublicKey
Jul 21, 2025
c19a3e6
new solution
Aug 3, 2025
8fffeef
fix more tests
Aug 4, 2025
8bee234
add blake2 hash map
Aug 4, 2025
d8dfdfd
fix test
Aug 5, 2025
35a4e4d
fix construtor in deploy
Aug 5, 2025
b741918
update test script
Aug 5, 2025
d940c56
most of test ok
Aug 5, 2025
79a2550
add integration test done
Aug 6, 2025
0c189e5
update constructor
Aug 6, 2025
fca4793
fix all unit tests
Aug 7, 2025
e69104b
fix more unit tests
Aug 7, 2025
461ee9c
fix unit tests
Aug 7, 2025
c31f9cb
minor fix according to ai
Aug 7, 2025
c29cb1a
changes according to audit
Aug 12, 2025
137b575
remove unused function
Aug 14, 2025
ccc1228
combine executeTransfer and setTotalStake
Aug 19, 2025
a2255be
remove getNextTransferAmount method
Aug 19, 2025
f0e7096
add new deployment guidance
Aug 31, 2025
6254f36
add note about duration
Aug 31, 2025
74c7516
update manual transaction trigger
Sep 1, 2025
2aedc68
use btcli for coldkey swap
Sep 9, 2025
0140ff2
refactor two convert scripts
Sep 10, 2025
3c44fa6
add separate deploy script
Oct 1, 2025
4003aea
add emergency drain part
Oct 7, 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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "subtensor_chain"]
path = subtensor_chain
url = https://github.com/opentensor/subtensor.git
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
155 changes: 155 additions & 0 deletions DEPLOYMENT2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# SaintDurbin Deployment Guide

This guide explains how to deploy the SaintDurbin contract with the correct SS58 public key configuration.

## Pre-Deployment Steps

### 1. Prepare coldkey and hotkey

Install the btcli, to create both coldkey and hotkey.

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/opentensor/bittensor/master/scripts/install.sh)"
btcli wallet new-coldkey
btcli wallet new-hotkey
```

Register neuron, creating the coldkey and hotkey relation

```bash
btcli subnets register --netuid 1
```

### 2. Set Environment Variables

Create a `.env` file or export the following environment variables:

```bash
# Contract configuration
export CONTRACT_SS58_KEY="0x..." # From step 1
export EMERGENCY_OPERATOR="0x..." # EVM address of emergency operator
export DRAIN_SS58_ADDRESS="0x..." # SS58 public key for emergency drain
export VALIDATOR_HOTKEY="0x..." # Initial validator's SS58 hotkey
export VALIDATOR_UID=123 # Initial validator's UID
export NETUID=1 # Subnet ID

# Recipients (SS58 public keys)
export RECIPIENT_SAM="0x..."
export RECIPIENT_WSL="0x..."
export RECIPIENT_PAPER="0x..."
export RECIPIENT_FLORIAN="0x..."
export RECIPIENT_4="0x..."
# ... continue for all 16 recipients
export RECIPIENT_15="0x..."
```

Notes:
Sine the precompile can't get the original caller. The SS58 public key will be used a coldkey for following contract operations like moveStake. But as a new deployed contract, there is no fund, no connected hotkey. The initial value of thisSs58PublicKey can be set as the coldkey's public key. Later, we will use the coldkey to send coldkey_swap extrinsic to change it as deployed contract's public key.

### 3. Deploy the Contract

```bash
# Deploy using Foundry
forge script script/DeploySaintDurbin.s.sol:DeploySaintDurbin \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast \
--verify
```

### 4. Send coldkey_swap extrinsic

Get the SS58 address of contract, then use it as new coldkey

```bash
cd scripts
npm install # Install dependencies if not already done
node convert-h160-to-ss58.js $DEPLOYER_ADDRESS
# output like,
Contract Address: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
SS58 Address is: 5FBpj1M73tNRZ8qWW5nGFYnUQgZ5SdrBPw5j2VUebmL6UsZ7
```

Btcli command to send swap-coldkey extrinsic.

```bash
btcli wallet swap-coldkey --new-coldkey 5FBpj1M73tNRZ8qWW5nGFYnUQgZ5SdrBPw5j2VUebmL6UsZ7
```

Duration defined in the rust code.

```bash

pub const InitialColdkeySwapScheduleDuration: BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days
pub fn schedule_swap_coldkey(
origin: OriginFor<T>,
new_coldkey: T::AccountId,
) -> DispatchResultWithPostInfo {

```

After 5 days, the coldkey swap will be executed. All funds will be transferred to contract, also the coldkey/hotkey relations.
Note: the duration could be updated on chain. need to check before sending the extrinsic.

### 5. set the Contract's SS58 Public Key

get the SS58 public key from contract address

```bash
cd scripts
npm install # Install dependencies if not already done
node convert-h160-to-public-key.js $DEPLOYER_ADDRESS
# output like, a 32 bytes hex string
SS58 Public Key (bytes32): 0xdbb1da614802ea83f7b0fd97279204316cdc1fb62386d44c4fb0b3489a7657c9
```

call setThisSs58PublicKey with correct SS58_PUBLIC_KEY

```bash
export SS58_PUBLIC_KEY=""
cast send $CONTRACT "setThisSs58PublicKey(bytes32)" \
$SS58_PUBLIC_KEY \
--private-key $EMERGENCY_KEY
```

### 6 Run the regular task like executeTransfer, aggregateStake according difference frequency. It is also important to query the data stakedBalance, principleLocked, we can know the status of contract.

For executeTransfer, we need to know the totalHotkeyAlpha before calling it. the value is from storage

```bash
# parameters are current hotkey and netuid
api.query.SubtensorModule.TotalHotkeyAlpha.getValue
```

For aggregateStake, we need to iterate all uids in subnet and get how many stake from current contract address. Based on the data, we can decide if to run aggregateStake.

### 7 Emergency drain

Emergency drain is used to handle some emergency situations. An account with permission needs to apply first, and then send a transaction to transfer the current staked token to the drain address after the timelock.
The drain address is EVM account, you can call precompile to transfer token from EVM to Substrate address if needed. Check the following code as reference.

[EVM to Substrate](https://github.com/opentensor/subtensor/blob/main/evm-tests/test/eth.substrate-transfer.test.ts#L78)

## Important Notes

1. **SS58 Key Generation**: The `CONTRACT_SS58_KEY` MUST be generated from the contract's deployment address using the Blake2b-256 hash of `"evm:" + contract_address`. This is how the Bittensor precompiles identify the contract.

2. **Address Types**:

- `EMERGENCY_OPERATOR`: Standard EVM address (20 bytes)
- All other addresses: SS58 public keys (32 bytes)

3. **Immutability**: Once deployed, the contract configuration cannot be changed. Double-check all values before deployment.

## Verification

After deployment, verify:

1. The contract's `thisSs58PublicKey` matches your pre-calculated value
2. The contract can successfully call `getStakedBalance()`
3. All recipients are correctly configured

## Troubleshooting

- **"Precompile call failed: getStake"**: Likely means the SS58 key is incorrect. Verify you calculated it from the correct contract address.
- **Invalid recipient addresses**: Ensure all recipient coldkeys are 32-byte SS58 public keys, not EVM addresses.
Loading