Skip to content

Commit b1775b7

Browse files
ensure none
1 parent 52f3204 commit b1775b7

3 files changed

Lines changed: 38 additions & 8 deletions

File tree

integration-tests/src/pepl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,7 @@ fn liquidate_with_pool_should_liquidate_when_pool_matches_deployed_pool() {
14111411
let decision = v2_decision(caller, borrower_evm);
14121412

14131413
assert_ok!(Liquidation::liquidate_with_pool(
1414-
RuntimeOrigin::signed(BOB.into()),
1414+
RuntimeOrigin::none(),
14151415
pool_contract,
14161416
decision.collateral_asset,
14171417
decision.debt_asset,
@@ -1438,7 +1438,7 @@ fn liquidate_with_pool_should_fail_when_pool_is_wrong() {
14381438

14391439
frame_support::assert_noop!(
14401440
Liquidation::liquidate_with_pool(
1441-
RuntimeOrigin::signed(BOB.into()),
1441+
RuntimeOrigin::none(),
14421442
EvmAddress::from_slice(&[0x42; 20]),
14431443
decision.collateral_asset,
14441444
decision.debt_asset,

pallets/liquidation/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use frame_support::{
4040
},
4141
PalletId,
4242
};
43-
use frame_system::{pallet_prelude::OriginFor, RawOrigin};
43+
use frame_system::{ensure_none, pallet_prelude::OriginFor, RawOrigin};
4444
use hydradx_traits::evm::CallResult;
4545
use hydradx_traits::evm::Erc20Mapping;
4646
use hydradx_traits::gigahdx::Seize;
@@ -369,8 +369,13 @@ pub mod pallet {
369369
/// This lets a multi-money-market worker state which market a decision was made
370370
/// against and guarantees the liquidation can never execute against a different one.
371371
///
372+
/// Unlike `liquidate`, this call is not publicly dispatchable: the origin must be
373+
/// none, and `ValidateUnsigned` rejects externally received transactions, so only
374+
/// a collator's own liquidation worker can submit it. The public permissionless
375+
/// path remains `liquidate`.
376+
///
372377
/// Parameters:
373-
/// - `origin`: Signed origin.
378+
/// - `origin`: Must be none (unsigned transaction).
374379
/// - `pool`: EVM address of the money-market pool this liquidation targets.
375380
/// - `collateral_asset`: Asset ID used as collateral in the MM position.
376381
/// - `debt_asset`: Asset ID used as debt in the MM position.
@@ -402,7 +407,7 @@ pub mod pallet {
402407
)]
403408
#[allow(clippy::too_many_arguments)]
404409
pub fn liquidate_with_pool(
405-
_origin: OriginFor<T>,
410+
origin: OriginFor<T>,
406411
pool: EvmAddress,
407412
collateral_asset: AssetId,
408413
debt_asset: AssetId,
@@ -411,6 +416,8 @@ pub mod pallet {
411416
route: Route<AssetId>,
412417
_unsigned_priority: Option<Priority>,
413418
) -> DispatchResult {
419+
ensure_none(origin)?;
420+
414421
let expected = if collateral_asset == T::GigaHdx::gigahdx_asset_id() {
415422
T::GigaHdx::pool_contract().ok_or(Error::<T>::GigaHdxPoolNotSet)?
416423
} else {

pallets/liquidation/src/tests/liquidation.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ fn liquidate_with_pool_should_liquidate_when_pool_matches_borrowing_contract() {
389389

390390
// Act
391391
assert_ok!(Liquidation::liquidate_with_pool(
392-
RuntimeOrigin::signed(ALICE),
392+
RuntimeOrigin::none(),
393393
pool,
394394
HDX, // collateral
395395
DOT, // debt
@@ -433,7 +433,7 @@ fn liquidate_with_pool_should_fail_when_pool_does_not_match_borrowing_contract()
433433

434434
assert_noop!(
435435
Liquidation::liquidate_with_pool(
436-
RuntimeOrigin::signed(ALICE),
436+
RuntimeOrigin::none(),
437437
EvmAddress::from_slice(&[8; 20]), // not the borrowing contract
438438
HDX,
439439
DOT,
@@ -457,7 +457,7 @@ fn liquidate_with_pool_should_fail_when_gigahdx_pool_is_not_set() {
457457

458458
assert_noop!(
459459
Liquidation::liquidate_with_pool(
460-
RuntimeOrigin::signed(ALICE),
460+
RuntimeOrigin::none(),
461461
EvmAddress::from_slice(&[9; 20]),
462462
67, // GIGAHDX collateral routes the pool check to `pool_contract()`
463463
222, // HOLLAR
@@ -471,6 +471,29 @@ fn liquidate_with_pool_should_fail_when_gigahdx_pool_is_not_set() {
471471
});
472472
}
473473

474+
// `liquidate_with_pool` is the worker-only channel — the public permissionless path is
475+
// `liquidate`. Signed submissions must be rejected before any liquidation logic runs.
476+
#[test]
477+
fn liquidate_with_pool_should_fail_when_origin_is_signed() {
478+
ExtBuilder::default().build().execute_with(|| {
479+
let bob_evm_address = EvmAccounts::evm_address(&BOB);
480+
481+
assert_noop!(
482+
Liquidation::liquidate_with_pool(
483+
RuntimeOrigin::signed(ALICE),
484+
EvmAddress::from_slice(&[9; 20]),
485+
HDX,
486+
DOT,
487+
bob_evm_address,
488+
1_000 * ONE,
489+
BoundedVec::new(),
490+
None,
491+
),
492+
sp_runtime::traits::BadOrigin
493+
);
494+
});
495+
}
496+
474497
#[test]
475498
fn validate_unsigned_should_provide_user_and_pool_when_call_is_liquidate_with_pool() {
476499
ExtBuilder::default().build().execute_with(|| {

0 commit comments

Comments
 (0)