Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 67 additions & 1 deletion evm-tests/src/contracts/staking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,71 @@ export const IStakingV2ABI = [
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "hotkey",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit_price",
"type": "uint256"
},
{
"internalType": "bool",
"name": "allow_partial",
"type": "bool"
},
{
"internalType": "uint256",
"name": "netuid",
"type": "uint256"
}
],
"name": "addStakeLimit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "hotkey",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit_price",
"type": "uint256"
},
{
"internalType": "bool",
"name": "allow_partial",
"type": "bool"
},
{
"internalType": "uint256",
"name": "netuid",
"type": "uint256"
}
],
"name": "removeStakeLimit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
];
113 changes: 113 additions & 0 deletions evm-tests/test/staking.precompile.limit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import * as assert from "assert";
import { getDevnetApi, getRandomSubstrateKeypair } from "../src/substrate";
import { devnet } from "@polkadot-api/descriptors";
import { TypedApi } from "polkadot-api";
import {
convertH160ToSS58,
convertPublicKeyToSs58,
} from "../src/address-utils";
import { tao, raoToEth } from "../src/balance-math";
import {
addNewSubnetwork,
addStake,
forceSetBalanceToEthAddress,
forceSetBalanceToSs58Address,
startCall,
} from "../src/subtensor";
import { ethers } from "ethers";
import { generateRandomEthersWallet } from "../src/utils";
import { ISTAKING_V2_ADDRESS, IStakingV2ABI } from "../src/contracts/staking";
import { log } from "console";

describe("Test staking precompile add remove limit methods", () => {
const hotkey = getRandomSubstrateKeypair();
const coldkey = getRandomSubstrateKeypair();
const wallet1 = generateRandomEthersWallet();

let api: TypedApi<typeof devnet>;

before(async () => {
api = await getDevnetApi();
await forceSetBalanceToSs58Address(
api,
convertPublicKeyToSs58(hotkey.publicKey),
);
await forceSetBalanceToSs58Address(
api,
convertPublicKeyToSs58(coldkey.publicKey),
);
await forceSetBalanceToEthAddress(api, wallet1.address);
await addNewSubnetwork(api, hotkey, coldkey);
let netuid = (await api.query.SubtensorModule.TotalNetworks.getValue()) - 1;
await startCall(api, netuid, coldkey);
console.log("will test in subnet: ", netuid);
});

it("Staker add limit", async () => {
let netuid = (await api.query.SubtensorModule.TotalNetworks.getValue()) - 1;
let ss58Address = convertH160ToSS58(wallet1.address);

const alpha = await api.query.SubtensorModule.Alpha.getValue(
convertPublicKeyToSs58(hotkey.publicKey),
ss58Address,
netuid,
);

const contract = new ethers.Contract(
ISTAKING_V2_ADDRESS,
IStakingV2ABI,
wallet1,
);

const tx = await contract.addStakeLimit(
hotkey.publicKey,
tao(2000),
tao(1000),
true,
netuid,
);
await tx.wait();

const alphaAfterAddStake = await api.query.SubtensorModule.Alpha.getValue(
convertPublicKeyToSs58(hotkey.publicKey),
ss58Address,
netuid,
);

assert.ok(alphaAfterAddStake > alpha);
});

it("Staker remove limit", async () => {
let netuid = (await api.query.SubtensorModule.TotalNetworks.getValue()) - 1;
let ss58Address = convertH160ToSS58(wallet1.address);

const alpha = await api.query.SubtensorModule.Alpha.getValue(
convertPublicKeyToSs58(hotkey.publicKey),
ss58Address,
netuid,
);

const contract = new ethers.Contract(
ISTAKING_V2_ADDRESS,
IStakingV2ABI,
wallet1,
);

const tx = await contract.removeStakeLimit(
hotkey.publicKey,
tao(100),
tao(1),
true,
netuid,
);
await tx.wait();

const alphaAfterRemoveStake = await api.query.SubtensorModule.Alpha.getValue(
convertPublicKeyToSs58(hotkey.publicKey),
ss58Address,
netuid,
);

assert.ok(alphaAfterRemoveStake < alpha);
});
});
68 changes: 67 additions & 1 deletion precompiles/src/solidity/stakingV2.abi
Original file line number Diff line number Diff line change
Expand Up @@ -251,5 +251,71 @@
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "hotkey",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit_price",
"type": "uint256"
},
{
"internalType": "bool",
"name": "allow_partial",
"type": "bool"
},
{
"internalType": "uint256",
"name": "netuid",
"type": "uint256"
}
],
"name": "addStakeLimit",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "hotkey",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit_price",
"type": "uint256"
},
{
"internalType": "bool",
"name": "allow_partial",
"type": "bool"
},
{
"internalType": "uint256",
"name": "netuid",
"type": "uint256"
}
],
"name": "removeStakeLimit",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
]
71 changes: 63 additions & 8 deletions precompiles/src/solidity/stakingV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ interface IStaking {
) external;

/**
* @dev Moves a subtensor stake `amount` associated with the `hotkey` to a different hotkey
* @dev Moves a subtensor stake `amount` associated with the `hotkey` to a different hotkey
* `destination_hotkey`.
*
* This function allows external accounts and contracts to move staked TAO from one hotkey to another,
* which effectively calls `move_stake` on the subtensor pallet with specified origin and destination
* hotkeys as parameters being the hashed address mappings of H160 sender address to Substrate ss58
* which effectively calls `move_stake` on the subtensor pallet with specified origin and destination
* hotkeys as parameters being the hashed address mappings of H160 sender address to Substrate ss58
* address as implemented in Frontier HashedAddressMapping:
* https://github.com/polkadot-evm/frontier/blob/2e219e17a526125da003e64ef22ec037917083fa/frame/evm/src/lib.rs#L739
*
Expand All @@ -67,7 +67,7 @@ interface IStaking {
* @param amount The amount to move in rao.
*
* Requirements:
* - `origin_hotkey` and `destination_hotkey` must be valid hotkeys registered on the network, ensuring
* - `origin_hotkey` and `destination_hotkey` must be valid hotkeys registered on the network, ensuring
* that the stake is correctly attributed.
*/
function moveStake(
Expand All @@ -79,12 +79,12 @@ interface IStaking {
) external;

/**
* @dev Transfer a subtensor stake `amount` associated with the transaction signer to a different coldkey
* @dev Transfer a subtensor stake `amount` associated with the transaction signer to a different coldkey
* `destination_coldkey`.
*
* This function allows external accounts and contracts to transfer staked TAO to another coldkey,
* which effectively calls `transfer_stake` on the subtensor pallet with specified destination
* coldkey as a parameter being the hashed address mapping of H160 sender address to Substrate ss58
* which effectively calls `transfer_stake` on the subtensor pallet with specified destination
* coldkey as a parameter being the hashed address mapping of H160 sender address to Substrate ss58
* address as implemented in Frontier HashedAddressMapping:
* https://github.com/polkadot-evm/frontier/blob/2e219e17a526125da003e64ef22ec037917083fa/frame/evm/src/lib.rs#L739
*
Expand All @@ -95,7 +95,7 @@ interface IStaking {
* @param amount The amount to move in rao.
*
* Requirements:
* - `origin_hotkey` and `destination_hotkey` must be valid hotkeys registered on the network, ensuring
* - `origin_hotkey` and `destination_hotkey` must be valid hotkeys registered on the network, ensuring
* that the stake is correctly attributed.
*/
function transferStake(
Expand Down Expand Up @@ -194,4 +194,59 @@ interface IStaking {
bytes32 hotkey,
uint256 netuid
) external view returns (uint256);

/**
* @dev Adds a subtensor stake `amount` associated with the `hotkey` within a price limit.
*
* This function allows external accounts and contracts to stake TAO into the subtensor pallet,
* which effectively calls `add_stake_limit` on the subtensor pallet with specified hotkey as a parameter
* and coldkey being the hashed address mapping of H160 sender address to Substrate ss58 address as
* implemented in Frontier HashedAddressMapping:
* https://github.com/polkadot-evm/frontier/blob/2e219e17a526125da003e64ef22ec037917083fa/frame/evm/src/lib.rs#L739
*
* @param hotkey The hotkey public key (32 bytes).
* @param amount The amount to stake in rao.
* @param limit_price The price limit to stake at in rao. Number of rao per alpha.
* @param allow_partial Whether to allow partial stake.
* @param netuid The subnet to stake to (uint256).
*
* Requirements:
* - `hotkey` must be a valid hotkey registered on the network, ensuring that the stake is
* correctly attributed.
*/
function addStakeLimit(
bytes32 hotkey,
uint256 amount,
uint256 limit_price,
bool allow_partial,
uint256 netuid
) external payable;

/**
* @dev Removes a subtensor stake `amount` from the specified `hotkey` within a price limit.
*
* This function allows external accounts and contracts to unstake TAO from the subtensor pallet,
* which effectively calls `remove_stake_limit` on the subtensor pallet with specified hotkey as a parameter
* and coldkey being the hashed address mapping of H160 sender address to Substrate ss58 address as
* implemented in Frontier HashedAddressMapping:
* https://github.com/polkadot-evm/frontier/blob/2e219e17a526125da003e64ef22ec037917083fa/frame/evm/src/lib.rs#L739
*
* @param hotkey The hotkey public key (32 bytes).
* @param amount The amount to unstake in alpha.
* @param limit_price The price limit to unstake at in rao. Number of rao per alpha.
* @param allow_partial Whether to allow partial unstake.
* @param netuid The subnet to stake to (uint256).
*
* Requirements:
* - `hotkey` must be a valid hotkey registered on the network, ensuring that the stake is
* correctly attributed.
* - The existing stake amount must be not lower than specified amount
*/
function removeStakeLimit(
bytes32 hotkey,
uint256 amount,
uint256 limit_price,
bool allow_partial,
uint256 netuid
) external;
}
Loading
Loading