Skip to content

Commit 3386b10

Browse files
committed
Merge branch 'devnet-ready' into fix-doc-for-storage
2 parents b7f776b + 99a542b commit 3386b10

File tree

13 files changed

+813
-100
lines changed

13 files changed

+813
-100
lines changed

evm-tests/src/contracts/staking.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const IStakingABI = [
1212
],
1313
name: "addProxy",
1414
outputs: [],
15-
stateMutability: "nonpayable",
15+
stateMutability: "payable",
1616
type: "function",
1717
},
1818
{
@@ -43,7 +43,7 @@ export const IStakingABI = [
4343
],
4444
name: "removeProxy",
4545
outputs: [],
46-
stateMutability: "nonpayable",
46+
stateMutability: "payable",
4747
type: "function",
4848
},
4949
{
@@ -95,7 +95,7 @@ export const IStakingABI = [
9595
],
9696
name: "removeStake",
9797
outputs: [],
98-
stateMutability: "nonpayable",
98+
stateMutability: "payable",
9999
type: "function",
100100
},
101101
];
@@ -111,7 +111,7 @@ export const IStakingV2ABI = [
111111
],
112112
"name": "addProxy",
113113
"outputs": [],
114-
"stateMutability": "nonpayable",
114+
"stateMutability": "payable",
115115
"type": "function"
116116
},
117117
{
@@ -275,7 +275,7 @@ export const IStakingV2ABI = [
275275
],
276276
"name": "removeProxy",
277277
"outputs": [],
278-
"stateMutability": "nonpayable",
278+
"stateMutability": "payable",
279279
"type": "function"
280280
},
281281
{
@@ -298,7 +298,7 @@ export const IStakingV2ABI = [
298298
],
299299
"name": "removeStake",
300300
"outputs": [],
301-
"stateMutability": "nonpayable",
301+
"stateMutability": "payable",
302302
"type": "function"
303303
},
304304
{
@@ -331,7 +331,7 @@ export const IStakingV2ABI = [
331331
],
332332
"name": "addStakeLimit",
333333
"outputs": [],
334-
"stateMutability": "nonpayable",
334+
"stateMutability": "payable",
335335
"type": "function"
336336
},
337337
{
@@ -364,7 +364,7 @@ export const IStakingV2ABI = [
364364
],
365365
"name": "removeStakeLimit",
366366
"outputs": [],
367-
"stateMutability": "nonpayable",
367+
"stateMutability": "payable",
368368
"type": "function"
369369
},
370370
{
@@ -382,7 +382,7 @@ export const IStakingV2ABI = [
382382
],
383383
"name": "removeStakeFull",
384384
"outputs": [],
385-
"stateMutability": "nonpayable",
385+
"stateMutability": "payable",
386386
"type": "function"
387387
},
388388
{
@@ -405,7 +405,30 @@ export const IStakingV2ABI = [
405405
],
406406
"name": "removeStakeFullLimit",
407407
"outputs": [],
408-
"stateMutability": "nonpayable",
408+
"stateMutability": "payable",
409+
"type": "function"
410+
},
411+
{
412+
"inputs": [
413+
{
414+
"internalType": "bytes32",
415+
"name": "hotkey",
416+
"type": "bytes32"
417+
},
418+
{
419+
"internalType": "uint256",
420+
"name": "amount",
421+
"type": "uint256"
422+
},
423+
{
424+
"internalType": "uint256",
425+
"name": "netuid",
426+
"type": "uint256"
427+
}
428+
],
429+
"name": "burnAlpha",
430+
"outputs": [],
431+
"stateMutability": "payable",
409432
"type": "function"
410433
}
411434
];
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import * as assert from "assert";
2+
import { getDevnetApi, getRandomSubstrateKeypair } from "../src/substrate"
3+
import { devnet } from "@polkadot-api/descriptors"
4+
import { TypedApi } from "polkadot-api";
5+
import { convertPublicKeyToSs58, convertH160ToSS58 } from "../src/address-utils"
6+
import { tao } from "../src/balance-math"
7+
import { ethers } from "ethers"
8+
import { generateRandomEthersWallet } from "../src/utils"
9+
import { convertH160ToPublicKey } from "../src/address-utils"
10+
import {
11+
forceSetBalanceToEthAddress, forceSetBalanceToSs58Address, addNewSubnetwork, burnedRegister,
12+
startCall,
13+
} from "../src/subtensor"
14+
import { ISTAKING_V2_ADDRESS, IStakingV2ABI } from "../src/contracts/staking"
15+
16+
describe("Test staking precompile burn alpha", () => {
17+
// init eth part
18+
const wallet1 = generateRandomEthersWallet();
19+
// init substrate part
20+
const hotkey = getRandomSubstrateKeypair();
21+
const coldkey = getRandomSubstrateKeypair();
22+
23+
let api: TypedApi<typeof devnet>
24+
25+
before(async () => {
26+
// init variables got from await and async
27+
api = await getDevnetApi()
28+
29+
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey.publicKey))
30+
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(coldkey.publicKey))
31+
await forceSetBalanceToEthAddress(api, wallet1.address)
32+
33+
let netuid = await addNewSubnetwork(api, hotkey, coldkey)
34+
await startCall(api, netuid, coldkey)
35+
36+
console.log("test the case on subnet ", netuid)
37+
38+
await burnedRegister(api, netuid, convertH160ToSS58(wallet1.address), coldkey)
39+
})
40+
41+
it("Can burn alpha after adding stake", async () => {
42+
let netuid = (await api.query.SubtensorModule.TotalNetworks.getValue()) - 1
43+
44+
// First add some stake
45+
let stakeBalance = tao(50)
46+
const contract = new ethers.Contract(ISTAKING_V2_ADDRESS, IStakingV2ABI, wallet1);
47+
const addStakeTx = await contract.addStake(hotkey.publicKey, stakeBalance.toString(), netuid)
48+
await addStakeTx.wait()
49+
50+
// Get stake before burning
51+
const stakeBefore = BigInt(await contract.getStake(hotkey.publicKey, convertH160ToPublicKey(wallet1.address), netuid))
52+
53+
console.log("Stake before burn:", stakeBefore)
54+
assert.ok(stakeBefore > BigInt(0), "Should have stake before burning")
55+
56+
// Burn some alpha (burn 20 TAO worth)
57+
let burnAmount = tao(20)
58+
const burnTx = await contract.burnAlpha(hotkey.publicKey, burnAmount.toString(), netuid)
59+
await burnTx.wait()
60+
61+
// Get stake after burning
62+
const stakeAfter = BigInt(await contract.getStake(hotkey.publicKey, convertH160ToPublicKey(wallet1.address), netuid))
63+
64+
console.log("Stake after burn:", stakeAfter)
65+
66+
// Verify that stake decreased by burn amount
67+
assert.ok(stakeAfter < stakeBefore, "Stake should decrease after burning")
68+
// assert.strictEqual(stakeBefore - stakeAfter, burnAmount, "Stake should decrease by exactly burn amount")
69+
})
70+
71+
it("Cannot burn more alpha than staked", async () => {
72+
let netuid = (await api.query.SubtensorModule.TotalNetworks.getValue()) - 1
73+
74+
// Get current stake
75+
const currentStake = await api.query.SubtensorModule.Alpha.getValue(
76+
convertPublicKeyToSs58(hotkey.publicKey),
77+
convertH160ToSS58(wallet1.address),
78+
netuid
79+
)
80+
81+
// Try to burn more than staked
82+
let burnAmount = currentStake + tao(10000)
83+
const contract = new ethers.Contract(ISTAKING_V2_ADDRESS, IStakingV2ABI, wallet1);
84+
85+
try {
86+
const burnTx = await contract.burnAlpha(hotkey.publicKey, burnAmount.toString(), netuid)
87+
await burnTx.wait()
88+
assert.fail("Transaction should have failed - cannot burn more than staked");
89+
} catch (error) {
90+
// Transaction failed as expected
91+
console.log("Correctly failed to burn more than staked amount")
92+
assert.ok(true, "Burning more than staked should fail");
93+
}
94+
})
95+
96+
it("Cannot burn alpha from non-existent subnet", async () => {
97+
// wrong netuid
98+
let netuid = 12345;
99+
let burnAmount = tao(10)
100+
const contract = new ethers.Contract(ISTAKING_V2_ADDRESS, IStakingV2ABI, wallet1);
101+
102+
try {
103+
const burnTx = await contract.burnAlpha(hotkey.publicKey, burnAmount.toString(), netuid)
104+
await burnTx.wait()
105+
assert.fail("Transaction should have failed - subnet doesn't exist");
106+
} catch (error) {
107+
// Transaction failed as expected
108+
console.log("Correctly failed to burn from non-existent subnet")
109+
assert.ok(true, "Burning from non-existent subnet should fail");
110+
}
111+
})
112+
113+
it("Cannot burn zero alpha", async () => {
114+
let netuid = (await api.query.SubtensorModule.TotalNetworks.getValue()) - 1
115+
116+
// First add some stake for this test
117+
let stakeBalance = tao(10)
118+
const contract = new ethers.Contract(ISTAKING_V2_ADDRESS, IStakingV2ABI, wallet1);
119+
const addStakeTx = await contract.addStake(hotkey.publicKey, stakeBalance.toString(), netuid)
120+
await addStakeTx.wait()
121+
122+
// Try to burn zero amount
123+
let burnAmount = BigInt(0)
124+
125+
try {
126+
const burnTx = await contract.burnAlpha(hotkey.publicKey, burnAmount.toString(), netuid)
127+
await burnTx.wait()
128+
assert.fail("Transaction should have failed - cannot burn zero amount");
129+
} catch (error) {
130+
// Transaction failed as expected
131+
console.log("Correctly failed to burn zero amount")
132+
assert.ok(true, "Burning zero amount should fail");
133+
}
134+
})
135+
})
136+

pallets/admin-utils/src/lib.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -543,27 +543,17 @@ pub mod pallet {
543543
/// It is only callable by the root account or subnet owner.
544544
/// The extrinsic will call the Subtensor pallet to set the kappa.
545545
#[pallet::call_index(16)]
546-
#[pallet::weight(Weight::from_parts(26_210_000, 0)
547-
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(3_u64))
546+
#[pallet::weight(Weight::from_parts(15_390_000, 0)
547+
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(1_u64))
548548
.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1_u64)))]
549549
pub fn sudo_set_kappa(origin: OriginFor<T>, netuid: NetUid, kappa: u16) -> DispatchResult {
550-
let maybe_owner = pallet_subtensor::Pallet::<T>::ensure_sn_owner_or_root_with_limits(
551-
origin,
552-
netuid,
553-
&[Hyperparameter::Kappa.into()],
554-
)?;
555-
550+
ensure_root(origin)?;
556551
ensure!(
557552
pallet_subtensor::Pallet::<T>::if_subnet_exist(netuid),
558553
Error::<T>::SubnetDoesNotExist
559554
);
560555
pallet_subtensor::Pallet::<T>::set_kappa(netuid, kappa);
561556
log::debug!("KappaSet( netuid: {netuid:?} kappa: {kappa:?} ) ");
562-
pallet_subtensor::Pallet::<T>::record_owner_rl(
563-
maybe_owner,
564-
netuid,
565-
&[Hyperparameter::Kappa.into()],
566-
);
567557
Ok(())
568558
}
569559

@@ -1218,7 +1208,7 @@ pub mod pallet {
12181208
/// The extrinsic will call the Subtensor pallet to set the minimum delegate take.
12191209
#[pallet::call_index(46)]
12201210
#[pallet::weight((
1221-
Weight::from_parts(7_885_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)),
1211+
Weight::from_parts(7_214_000, 0).saturating_add(T::DbWeight::get().writes(1_u64)),
12221212
DispatchClass::Operational,
12231213
Pays::Yes
12241214
))]
@@ -1655,11 +1645,7 @@ pub mod pallet {
16551645
netuid: NetUid,
16561646
hotkey: <T as frame_system::Config>::AccountId,
16571647
) -> DispatchResult {
1658-
pallet_subtensor::Pallet::<T>::ensure_subnet_owner(origin.clone(), netuid)?;
1659-
pallet_subtensor::Pallet::<T>::set_subnet_owner_hotkey(netuid, &hotkey);
1660-
1661-
log::debug!("SubnetOwnerHotkeySet( netuid: {netuid:?}, hotkey: {hotkey:?} )");
1662-
Ok(())
1648+
pallet_subtensor::Pallet::<T>::do_set_sn_owner_hotkey(origin, netuid, &hotkey)
16631649
}
16641650

16651651
///

0 commit comments

Comments
 (0)