Skip to content
Open
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
17 changes: 17 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ members = [
"pallets/ddc-clusters-gov",
"pallets/fee-handler",
"pallets/origins",
"pallets/withdrawal-fix",
"runtime/cere",
"runtime/cere-dev",
"contracts/customer-deposit",
Expand Down Expand Up @@ -194,6 +195,7 @@ pallet-erc20 = { path = "pallets/erc20", default-features = false }
pallet-erc721 = { path = "pallets/erc721", default-features = false }
pallet-origins = { path = "pallets/origins", default-features = false }
pallet-fee-handler = { path = "pallets/fee-handler", default-features = false }
pallet-withdrawal-fix = { path = "pallets/withdrawal-fix", default-features = false }

# Cere External Dependencies
ddc-primitives = { git = "https://github.com/Cerebellum-Network/ddc-primitives.git", branch = "staging", default-features = false }
Expand Down
52 changes: 52 additions & 0 deletions pallets/withdrawal-fix/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[package]
name = "pallet-withdrawal-fix"
version.workspace = true
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
# 3rd-party dependencies
codec = { workspace = true }
scale-info = { workspace = true }

# Substrate dependencies
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-balances = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }

# Cere dependencies
ddc-primitives = { workspace = true }

[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"frame-support/std",
"frame-system/std",
"pallet-balances/std",
"sp-io/std",
"ddc-primitives/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
]
try-runtime = []
191 changes: 191 additions & 0 deletions pallets/withdrawal-fix/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//! # Withdrawal Fix Pallet
//!
//! This pallet is responsible for handling withdrawal fixes in a Substrate-based blockchain.
//! It provides functionality to fix withdrawal issues and manage withdrawal states.
//!
//! ## Overview
//!
//! - Allows governance to fix withdrawal issues.
//! - Manages withdrawal states and transitions.
//! - Emits events for key actions such as withdrawal fixes and state changes.
//!
//! ## Dispatchable Functions
//!
//! - `fix_withdrawal`: Allows governance to fix a withdrawal issue.
//! - `update_withdrawal_state`: Allows governance to update withdrawal state.

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
pub mod weights;

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

use frame_support::{
traits::{
fungible::{Inspect, Mutate},
},
};
use codec::{Encode, Decode, DecodeWithMemTracking, MaxEncodedLen};
use scale_info::TypeInfo;
pub use pallet::*;

#[allow(deprecated)]
#[allow(clippy::let_unit_value)]
#[allow(clippy::manual_inspect)]
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use crate::weights::WeightInfo;

use super::*;

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching runtime event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Native Currency Support.
type Currency: Mutate<Self::AccountId> + Inspect<Self::AccountId>;
/// Governance origin for privileged calls.
type GovernanceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: crate::weights::WeightInfo;
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// Withdrawal fix applied successfully.
WithdrawalFixed { account: T::AccountId, amount: u128 },
/// Withdrawal state updated.
WithdrawalStateUpdated { account: T::AccountId, state: WithdrawalState },
}

#[pallet::error]
pub enum Error<T> {
/// Withdrawal not found.
WithdrawalNotFound,
/// Invalid withdrawal state transition.
InvalidStateTransition,
/// Insufficient balance for withdrawal fix.
InsufficientBalance,
/// Withdrawal already processed.
WithdrawalAlreadyProcessed,
}

#[pallet::storage]
#[pallet::getter(fn withdrawal_states)]
pub type WithdrawalStates<T: Config> = StorageMap<
_,
Blake2_128Concat,
T::AccountId,
WithdrawalState,
OptionQuery,
>;

#[pallet::storage]
#[pallet::getter(fn pending_withdrawals)]
pub type PendingWithdrawals<T: Config> = StorageMap<
_,
Blake2_128Concat,
T::AccountId,
u128,
OptionQuery,
>;

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Fix a withdrawal issue for a specific account.
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::fix_withdrawal())]
pub fn fix_withdrawal(
origin: OriginFor<T>,
account: T::AccountId,
amount: u128,
) -> DispatchResult {
T::GovernanceOrigin::ensure_origin(origin)?;

// Check if withdrawal exists
ensure!(
PendingWithdrawals::<T>::contains_key(&account),
Error::<T>::WithdrawalNotFound
);

// Check if withdrawal is already processed
let current_state = WithdrawalStates::<T>::get(&account);
ensure!(
current_state != Some(WithdrawalState::Processed),
Error::<T>::WithdrawalAlreadyProcessed
);

// Update withdrawal state to processed
WithdrawalStates::<T>::insert(&account, WithdrawalState::Processed);

// Remove from pending withdrawals
PendingWithdrawals::<T>::remove(&account);

Self::deposit_event(Event::WithdrawalFixed { account, amount });
Ok(())
}

/// Update withdrawal state for a specific account.
#[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::update_withdrawal_state())]
pub fn update_withdrawal_state(
origin: OriginFor<T>,
account: T::AccountId,
state: WithdrawalState,
) -> DispatchResult {
T::GovernanceOrigin::ensure_origin(origin)?;

// Validate state transition
let current_state = WithdrawalStates::<T>::get(&account);
Self::validate_state_transition(current_state, &state)?;

// Update state
WithdrawalStates::<T>::insert(&account, state.clone());

Self::deposit_event(Event::WithdrawalStateUpdated { account, state });
Ok(())
}
}

impl<T: Config> Pallet<T> {
/// Validate state transition
fn validate_state_transition(
current_state: Option<WithdrawalState>,
new_state: &WithdrawalState,
) -> Result<(), Error<T>> {
match (current_state, new_state) {
(None, WithdrawalState::Pending) => Ok(()),
(Some(WithdrawalState::Pending), WithdrawalState::Processing) => Ok(()),
(Some(WithdrawalState::Processing), WithdrawalState::Processed) => Ok(()),
(Some(WithdrawalState::Processing), WithdrawalState::Failed) => Ok(()),
(Some(WithdrawalState::Failed), WithdrawalState::Pending) => Ok(()),
_ => Err(Error::<T>::InvalidStateTransition),
}
}
}
}

/// Withdrawal state enumeration
#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen)]
pub enum WithdrawalState {
/// Withdrawal is pending
Pending,
/// Withdrawal is being processed
Processing,
/// Withdrawal has been processed successfully
Processed,
/// Withdrawal failed
Failed,
}
Loading
Loading