Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] add authorised accounts to manage vesting contracts #214

Merged
merged 1 commit into from
Mar 15, 2023
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
1 change: 1 addition & 0 deletions pallets/carbon-credits-pool/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl pallet_carbon_credits::Config for Test {
type MaxIpfsReferenceLength = ConstU32<20>;
type MaxLongStringLength = ConstU32<100>;
type MaxRoyaltyRecipients = ConstU32<5>;
type MaxCoordinatesLength = ConstU32<100>;
type MaxShortStringLength = ConstU32<20>;
type MinProjectId = ConstU32<1000>;
type NFTHandler = Uniques;
Expand Down
97 changes: 92 additions & 5 deletions pallets/vesting-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ pub mod pallet {
pub type BulkContractRemove<T> =
BoundedVec<<T as frame_system::Config>::AccountId, <T as Config>::MaxContractInputLength>;

/// AuthorizedAccounts type of pallet
pub type AuthorizedAccountsListOf<T> = BoundedVec<
<T as frame_system::Config>::AccountId,
<T as pallet::Config>::MaxAuthorizedAccountCount,
>;

/// Pallet version of balance
pub type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
Expand All @@ -142,6 +148,9 @@ pub mod pallet {
#[pallet::constant]
type PalletId: Get<PalletId>;

/// Maximum amount of authorised accounts permitted
type MaxAuthorizedAccountCount: Get<u32>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}
Expand All @@ -162,6 +171,12 @@ pub mod pallet {
// Ideally this should be equal to the pallet account balance.
pub type VestingBalance<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn authorized_accounts)]
// List of AuthorizedAccounts for the pallet
pub type AuthorizedAccounts<T: Config> =
StorageValue<_, AuthorizedAccountsListOf<T>, ValueQuery>;

// Pallets use events to inform users when important changes are made.
// https://docs.substrate.io/v3/runtime/events-and-errors
#[pallet::event]
Expand All @@ -173,6 +188,10 @@ pub mod pallet {
ContractRemoved { recipient: T::AccountId },
/// An existing contract has been completed/withdrawn
ContractWithdrawn { recipient: T::AccountId, expiry: T::BlockNumber, amount: BalanceOf<T> },
/// A new authorized account has been added to storage
AuthorizedAccountAdded { account_id: T::AccountId },
/// An authorized account has been removed from storage
AuthorizedAccountRemoved { account_id: T::AccountId },
}

// Errors inform users that something went wrong.
Expand All @@ -190,6 +209,12 @@ pub mod pallet {
ContractNotExpired,
/// Contract already exists, remove old contract before adding new
ContractAlreadyExists,
/// Not authorized to perform this operation
NotAuthorised,
/// Authorized account already exists
AuthorizedAccountAlreadyExists,
/// Too many authorized accounts
TooManyAuthorizedAccounts,
}

#[pallet::call]
Expand All @@ -208,7 +233,8 @@ pub mod pallet {
amount: BalanceOf<T>,
) -> DispatchResultWithPostInfo {
// ensure caller is allowed to add new recipient
T::ForceOrigin::ensure_origin(origin)?;
let sender = ensure_signed(origin)?;
Self::check_authorized_account(&sender)?;
Self::do_add_new_contract(recipient, expiry, amount)?;
Ok(().into())
}
Expand All @@ -221,7 +247,8 @@ pub mod pallet {
recipient: T::AccountId,
) -> DispatchResultWithPostInfo {
// ensure caller is allowed to remove recipient
T::ForceOrigin::ensure_origin(origin)?;
let sender = ensure_signed(origin)?;
Self::check_authorized_account(&sender)?;
Self::do_remove_contract(recipient)?;
Ok(().into())
}
Expand All @@ -235,7 +262,8 @@ pub mod pallet {
recipients: BulkContractInputs<T>,
) -> DispatchResultWithPostInfo {
// ensure caller is allowed to add new recipient
T::ForceOrigin::ensure_origin(origin)?;
let sender = ensure_signed(origin)?;
Self::check_authorized_account(&sender)?;
for input in recipients {
Self::do_add_new_contract(input.recipient, input.expiry, input.amount)?;
}
Expand All @@ -251,7 +279,8 @@ pub mod pallet {
recipients: BulkContractRemove<T>,
) -> DispatchResultWithPostInfo {
// ensure caller is allowed to remove recipients
T::ForceOrigin::ensure_origin(origin)?;
let sender = ensure_signed(origin)?;
Self::check_authorized_account(&sender)?;
for recipient in recipients {
Self::do_remove_contract(recipient)?;
}
Expand Down Expand Up @@ -286,9 +315,67 @@ pub mod pallet {
recipient: T::AccountId,
) -> DispatchResultWithPostInfo {
// ensure caller is allowed to force withdraw
T::ForceOrigin::ensure_origin(origin)?;
let sender = ensure_signed(origin)?;
Self::check_authorized_account(&sender)?;
Self::do_withdraw_vested(recipient)?;
Ok(().into())
}

/// Add a new account to the list of authorised Accounts
/// The caller must be from a permitted origin
#[transactional]
#[pallet::weight(T::WeightInfo::force_withdraw_vested())]
pub fn force_add_authorized_account(
origin: OriginFor<T>,
account_id: T::AccountId,
) -> DispatchResult {
T::ForceOrigin::ensure_origin(origin)?;
// add the account_id to the list of authorized accounts
AuthorizedAccounts::<T>::try_mutate(|account_list| -> DispatchResult {
ensure!(
!account_list.contains(&account_id),
Error::<T>::AuthorizedAccountAlreadyExists
);

account_list
.try_push(account_id.clone())
.map_err(|_| Error::<T>::TooManyAuthorizedAccounts)?;
Ok(())
})?;

Self::deposit_event(Event::AuthorizedAccountAdded { account_id });
Ok(())
}

/// Remove an account from the list of authorised accounts
#[transactional]
#[pallet::weight(T::WeightInfo::force_withdraw_vested())]
pub fn force_remove_authorized_account(
origin: OriginFor<T>,
account_id: T::AccountId,
) -> DispatchResult {
T::ForceOrigin::ensure_origin(origin)?;
// remove the account_id from the list of authorized accounts if already exists
AuthorizedAccounts::<T>::try_mutate(|account_list| -> DispatchResult {
if let Ok(index) = account_list.binary_search(&account_id) {
account_list.swap_remove(index);
Self::deposit_event(Event::AuthorizedAccountRemoved { account_id });
}

Ok(())
})
}
}
}

impl<T: Config> Pallet<T> {
/// Checks if the given account_id is part of authorized account list
pub fn check_authorized_account(account_id: &T::AccountId) -> DispatchResult {
let authorized_accounts = AuthorizedAccounts::<T>::get();
if !authorized_accounts.contains(account_id) {
Err(Error::<T>::NotAuthorised.into())
} else {
Ok(())
}
}
}
2 changes: 2 additions & 0 deletions pallets/vesting-contract/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ impl pallet_balances::Config for Test {

parameter_types! {
pub const MaxContractInputLength : u32 = 10;
pub const MaxAuthorizedAccountCount : u32 = 2;
pub const VestingContractPalletId: PalletId = PalletId(*b"bitg/vcp");
}

Expand All @@ -88,6 +89,7 @@ impl vesting_contract::Config for Test {
type ForceOrigin = frame_system::EnsureRoot<u64>;
type MaxContractInputLength = MaxContractInputLength;
type PalletId = VestingContractPalletId;
type MaxAuthorizedAccountCount = MaxAuthorizedAccountCount;
type WeightInfo = ();
}

Expand Down
Loading