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
4 changes: 2 additions & 2 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions frame/evm/precompile/shielded-pool/src/calls/shield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ where
let asset_id = abi::decode_u32(&params[0..32])?;

// Reject zero-value calls at the precompile boundary (defense-in-depth;
// the pallet also rejects via MinShieldAmount, but this produces a cleaner
// error before reaching the dispatch layer).
// the pallet also rejects them, but this produces a cleaner error before
// reaching the dispatch layer).
let apparent_value = handle.context().apparent_value;
if apparent_value.is_zero() {
return Err(err("shield: amount must be non-zero"));
Expand Down
2 changes: 0 additions & 2 deletions frame/evm/precompile/shielded-pool/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ parameter_types! {
pub const MaxHistoricRoots: u32 = 100;
pub const RootRetentionBlocks: u64 = 128;
pub const MaxLeavesPerTree: u32 = 8;
pub const MinShieldAmount: u128 = 100;
}

pub struct MockZkVerifier;
Expand Down Expand Up @@ -248,7 +247,6 @@ impl pallet_shielded_pool::Config for Test {
type MaxHistoricRoots = MaxHistoricRoots;
type RootRetentionBlocks = RootRetentionBlocks;
type MaxLeavesPerTree = MaxLeavesPerTree;
type MinShieldAmount = MinShieldAmount;
type WeightInfo = ();
type Relayer = MockRelayer;
}
Expand Down
6 changes: 3 additions & 3 deletions frame/evm/precompile/shielded-pool/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,12 @@ fn shield_rejects_truncated_input() {
}

#[test]
fn shield_rejects_below_min_amount() {
// MinShieldAmount = 100; sending value = 1 should be rejected by the pallet.
fn shield_accepts_smallest_non_zero_amount() {
// There is no minimum shield amount: msg.value = 1 must go through.
new_test_ext().execute_with(|| {
let input = encode_shield(0, [0x11; 32], &[0xAB; 180]);
let mut h = MockHandle::with_value(input, 1);
expect_error(ShieldedPoolPrecompile::<Test>::execute(&mut h));
assert_success(ShieldedPoolPrecompile::<Test>::execute(&mut h));
});
}

Expand Down
10 changes: 5 additions & 5 deletions frame/shielded-pool/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ mod benchmarks {
}

// 2. Fund caller
let amount: BalanceOf<T> = T::MinShieldAmount::get() * 1000u32.into();
let amount: BalanceOf<T> = 1_000_000u32.into();
let _ = <T::Currency as Currency<T::AccountId>>::make_free_balance_be(&caller, amount);

(caller, asset_id)
Expand All @@ -67,7 +67,7 @@ mod benchmarks {
#[benchmark]
fn shield() {
let (caller, asset_id) = setup_benchmark_env::<T>();
let amount: BalanceOf<T> = T::MinShieldAmount::get() * 10u32.into();
let amount: BalanceOf<T> = 10_000u32.into();
let commitment = Commitment([1u8; 32]);
// Memo must be exactly 180 bytes (MAX_ENCRYPTED_MEMO_SIZE): nonce(12) + data(120) + MAC(16) + ephPk(32)
let memo_bytes = vec![0u8; MAX_ENCRYPTED_MEMO_SIZE as usize];
Expand All @@ -86,7 +86,7 @@ mod benchmarks {
#[benchmark]
fn shield_batch(n: Linear<1, 20>) {
let (caller, asset_id) = setup_benchmark_env::<T>();
let amount: BalanceOf<T> = T::MinShieldAmount::get() * 10u32.into();
let amount: BalanceOf<T> = 10_000u32.into();

let mut operations = Vec::new();
for i in 0..n {
Expand Down Expand Up @@ -151,7 +151,7 @@ mod benchmarks {
let (_caller, asset_id) = setup_benchmark_env::<T>();
let recipient: T::AccountId = account("recipient", 0, 0);
let merkle_root = [1u8; 32];
let amount: BalanceOf<T> = T::MinShieldAmount::get() * 10u32.into();
let amount: BalanceOf<T> = 10_000u32.into();

// Setup valid state: root and pool balance
crate::storage::MerkleRepository::add_historic_poseidon_root::<T>(merkle_root);
Expand Down Expand Up @@ -222,7 +222,7 @@ mod benchmarks {
#[benchmark]
fn claim_shielded_fees() {
let (caller, asset_id) = setup_benchmark_env::<T>();
let amount: BalanceOf<T> = T::MinShieldAmount::get() * 10u32.into();
let amount: BalanceOf<T> = 10_000u32.into();
let amount_u128: u128 = amount.saturated_into();

// Accumulate relay fees for the validator.
Expand Down
7 changes: 1 addition & 6 deletions frame/shielded-pool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,6 @@ pub mod pallet {
#[pallet::constant]
type RootRetentionBlocks: Get<BlockNumberFor<Self>>;

/// Minimum amount that can be shielded
#[pallet::constant]
type MinShieldAmount: Get<BalanceOf<Self>>;
/// Weight information for extrinsics in this pallet
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -584,8 +581,6 @@ pub mod pallet {
InvalidProof,
/// Insufficient balance in the pool
InsufficientPoolBalance,
/// The amount is below the minimum
AmountTooSmall,
/// The amount is invalid (zero or overflow)
InvalidAmount,
/// Too many inputs or outputs
Expand Down Expand Up @@ -640,7 +635,7 @@ pub mod pallet {
/// * `encrypted_memo` - Encrypted metadata for note recovery and audit
///
/// # Errors
/// * `AmountTooSmall` - Amount is below minimum
/// * `InvalidAmount` - Amount is zero
/// * `MerkleTreeFull` - No more space in the tree
/// * `CommitmentAlreadyExists` - Duplicate commitment
/// * `InvalidMemoSize` - Encrypted memo is not exactly 180 bytes
Expand Down
2 changes: 0 additions & 2 deletions frame/shielded-pool/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ parameter_types! {
/// a test can advance past it to exercise expiry.
pub const RootRetentionBlocks: u64 = 128;
pub const MaxLeavesPerTree: u32 = 8;
pub const MinShieldAmount: u128 = 100;
pub const MaxProofSize: u32 = 256;
pub const MaxPublicInputs: u32 = 10;
}
Expand Down Expand Up @@ -160,7 +159,6 @@ impl pallet_shielded_pool::Config for Test {
type MaxHistoricRoots = MaxHistoricRoots;
type RootRetentionBlocks = RootRetentionBlocks;
type MaxLeavesPerTree = MaxLeavesPerTree;
type MinShieldAmount = MinShieldAmount;
type WeightInfo = ();
type Relayer = pallet_relayer::Pallet<Test>;
}
Expand Down
28 changes: 20 additions & 8 deletions frame/shielded-pool/src/operations/shield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use frame_support::{
pallet_prelude::*,
traits::{Currency, ExistenceRequirement},
};
use sp_runtime::traits::Zero;

use crate::{
merkle::MerkleTreeService,
Expand All @@ -22,10 +23,7 @@ impl ShieldOperation {
) -> DispatchResult {
let asset = AssetRepository::get_asset::<T>(asset_id).ok_or(Error::<T>::InvalidAssetId)?;
ensure!(asset.is_verified, Error::<T>::AssetNotVerified);
ensure!(
amount >= T::MinShieldAmount::get(),
Error::<T>::AmountTooSmall
);
ensure!(!amount.is_zero(), Error::<T>::InvalidAmount);
ensure!(
encrypted_memo.0.len() == MAX_ENCRYPTED_MEMO_SIZE as usize,
Error::<T>::InvalidMemoSize
Expand Down Expand Up @@ -160,23 +158,37 @@ mod tests {
}

#[test]
fn execute_amount_too_small_fails() {
fn execute_zero_amount_fails() {
new_test_ext().execute_with(|| {
let asset_id = setup_asset();
// MinShieldAmount = 100; amount = 50 < 100
assert_noop!(
ShieldOperation::execute::<Test>(
acc(1),
asset_id,
50u128,
0u128,
commitment(1),
memo_valid()
),
crate::pallet::Error::<Test>::AmountTooSmall
crate::pallet::Error::<Test>::InvalidAmount
);
});
}

/// There is no minimum: a 1-unit shield is accepted.
#[test]
fn execute_accepts_smallest_non_zero_amount() {
new_test_ext().execute_with(|| {
let asset_id = setup_asset();
assert_ok!(ShieldOperation::execute::<Test>(
acc(1),
asset_id,
1u128,
commitment(1),
memo_valid(),
));
});
}

#[test]
fn execute_invalid_memo_size_fails() {
new_test_ext().execute_with(|| {
Expand Down
38 changes: 38 additions & 0 deletions frame/validator-set/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,44 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

---

## [0.2.0] — 2026-08-06

### Removed

#### Validator bond
The 1 000 ORB bond required by `register_validator` is gone, along with the
`ValidatorBond` and `Currency` Config items, the `ValidatorBondOf` storage map,
the `ValidatorBondReserved` / `ValidatorBondReleased` events, and the
`InsufficientBond` error.

Registration is now free. What still gates it is unchanged: the account needs
session keys and a registered EVM relayer, the pending queue is bounded by
`MaxPendingValidators`, and — the part that actually matters — no account enters
the active set without an explicit `approve_validator` from sudo. A bond deters
spam that governance approval already blocks, and on a testnet where operators
are onboarded by hand it only added a funding step.

Consensus is expected to change before mainnet; a staking-based scheme will
bring its own economic gate.

**Breaking:** `register_validator` no longer reserves funds and no longer fails
with `InsufficientBond`. Callers that pre-funded 1 001 ORB to register can stop.

### Notes
- No migration ships with this change: `ValidatorBondOf` was verified empty on
testnet (0 entries, empty pending queue) before removing it, so there are no
reserves left stranded. A chain that *had* live bonds would need one.

### Verification
50 pallet tests; runtime, `try-runtime` and `runtime-benchmarks` all compile. A
dev-node E2E (`ts-tests/no-bond-no-min-shield.test.cjs`, 11/11) checks that the
constant, the storage map, the events and `InsufficientBond` are all absent from
metadata, and that an account holding 1 ORB — a thousandth of the old bond —
reaches the prerequisite gate instead of failing on funds, reserving nothing on
the way.

---

## [0.1.0] — 2026-06-03

### Added
Expand Down
2 changes: 1 addition & 1 deletion frame/validator-set/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-validator-set"
version = "0.1.0"
version = "0.2.0"
description = "Sudo-controlled validator set for Orbinum. Validators can only join via governance."
authors = { workspace = true }
license = "GPL-3.0-or-later"
Expand Down
Loading
Loading