Skip to content
Snippets Groups Projects

Oneshot accounts

Merged Pascal Engélibert requested to merge poc-oneshot-accounts into master
Compare and Show latest version
1 file
+ 74
118
Compare changes
  • Side-by-side
  • Inline
@@ -148,15 +148,8 @@ pub mod pallet {
},
OneshotAccountConsumed {
account: T::AccountId,
balance: T::Balance,
dest: T::AccountId,
},
OneshotAccountConsumedTwoDests {
account: T::AccountId,
balance1: T::Balance,
balance2: T::Balance,
dest1: T::AccountId,
dest2: T::AccountId,
dest1: (T::AccountId, T::Balance),
dest2: Option<(T::AccountId, T::Balance)>,
},
/// Random id assigned
/// [account_id, random_id]
@@ -167,17 +160,19 @@ pub mod pallet {
#[pallet::error]
pub enum Error<T> {
/// DestAccountNotExist
/// Block height is in the future
BlockHeightInFuture,
/// Block height is too old
BlockHeightTooOld,
/// Destination account does not exist
DestAccountNotExist,
/// ExistentialDeposit
/// Destination account has balance less than existential deposit
ExistentialDeposit,
/// InsufficientBalance
/// Source account has insufficient balance
InsufficientBalance,
/// Block height is either too old or future
InvalidBlockHeight,
/// OneshotAccouncAlreadyCreated
/// Destination oneshot account already exists
OneshotAccountAlreadyCreated,
/// OneshotAccountNotExist
/// Source oneshot account does not exist
OneshotAccountNotExist,
}
@@ -264,6 +259,9 @@ pub mod pallet {
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Create an account that can only be consumed once
///
/// - `dest`: The oneshot account to be created.
/// - `balance`: The balance to be transfered to this oneshot account.
#[pallet::weight(500_000_000)]
pub fn create_oneshot_account(
origin: OriginFor<T>,
@@ -304,7 +302,8 @@ pub mod pallet {
}
/// Consume a oneshot account and transfer its balance to an account
///
/// `block_height` must be a recent block number. (this is to prevent replay attacks)
/// - `block_height`: must be a recent block number. The limit is `BlockHashCount` in the past. (this is to prevent replay attacks)
/// - `dest`: `dest.1` is the destination account. If `dest.0` is `true`, then a oneshot account is created at `dest.1`. Else, `dest.1` has to be an existing account.
#[pallet::weight(500_000_000)]
pub fn consume_oneshot_account(
origin: OriginFor<T>,
@@ -318,46 +317,45 @@ pub mod pallet {
let value = OneshotAccounts::<T>::take(&transactor)
.ok_or(Error::<T>::OneshotAccountNotExist)?;
ensure!(
block_height <= frame_system::Pallet::<T>::block_number(),
Error::<T>::BlockHeightInFuture
);
ensure!(
frame_system::pallet::BlockHash::<T>::contains_key(block_height),
Error::<T>::InvalidBlockHeight
Error::<T>::BlockHeightTooOld
);
if dest_is_oneshot {
ensure!(
OneshotAccounts::<T>::get(&dest).is_none(),
Error::<T>::OneshotAccountAlreadyCreated
);
OneshotAccounts::<T>::remove(&transactor);
OneshotAccounts::<T>::insert(&dest, value);
Self::deposit_event(Event::OneshotAccountConsumed {
account: transactor.clone(),
balance: value,
dest: dest.clone(),
});
Self::deposit_event(Event::OneshotAccountCreated {
account: dest,
account: dest.clone(),
balance: value,
creator: transactor,
creator: transactor.clone(),
});
} else {
let dest_data = frame_system::Account::<T>::get(&dest).data;
ensure!(dest_data.was_providing(), Error::<T>::DestAccountNotExist);
frame_system::Account::<T>::mutate(&dest, |a| a.data.add_free(value));
OneshotAccounts::<T>::remove(&transactor);
Self::deposit_event(Event::OneshotAccountConsumed {
account: transactor,
balance: value,
dest,
});
}
OneshotAccounts::<T>::remove(&transactor);
Self::deposit_event(Event::OneshotAccountConsumed {
account: transactor,
dest1: (dest, value),
dest2: None,
});
Ok(())
}
/// Consume a oneshot account and transfer its balance to two accounts
///
/// `block_height` must be a recent block number. (this is to prevent replay attacks)
///
/// `balance1` is transfered to `dest1`, and the leftover is transfered to `dest2`.
/// - `block_height`: must be a recent block number. The limit is `BlockHashCount` in the past. (this is to prevent replay attacks)
/// - `dest1`: `dest1.1` is the destination account. If `dest1.0` is `true`, then a oneshot account is created at `dest1.1`. Else, `dest1.1` has to be an existing account.
/// - `dest2`: Idem.
/// - `balance1`: The amount transfered to `dest1`, the leftover being transfered to `dest2`.
#[pallet::weight(500_000_000)]
pub fn consume_oneshot_account_two_dests(
origin: OriginFor<T>,
@@ -377,9 +375,13 @@ pub mod pallet {
ensure!(value > balance1, Error::<T>::InsufficientBalance);
let balance2 = value.saturating_sub(balance1);
ensure!(
block_height <= frame_system::Pallet::<T>::block_number(),
Error::<T>::BlockHeightInFuture
);
ensure!(
frame_system::pallet::BlockHash::<T>::contains_key(block_height),
Error::<T>::InvalidBlockHeight
Error::<T>::BlockHeightTooOld
);
if dest1_is_oneshot {
ensure!(
@@ -390,92 +392,46 @@ pub mod pallet {
balance1 >= T::ExistentialDeposit::get(),
Error::<T>::ExistentialDeposit
);
if dest2_is_oneshot {
ensure!(
OneshotAccounts::<T>::get(&dest2).is_none(),
Error::<T>::OneshotAccountAlreadyCreated
);
ensure!(
balance2 >= T::ExistentialDeposit::get(),
Error::<T>::ExistentialDeposit
);
OneshotAccounts::<T>::remove(&transactor);
OneshotAccounts::<T>::insert(&dest1, balance1);
OneshotAccounts::<T>::insert(&dest2, balance2);
Self::deposit_event(Event::OneshotAccountConsumedTwoDests {
account: transactor.clone(),
balance1,
balance2,
dest1: dest1.clone(),
dest2: dest2.clone(),
});
Self::deposit_event(Event::OneshotAccountCreated {
account: dest1,
balance: balance1,
creator: transactor.clone(),
});
Self::deposit_event(Event::OneshotAccountCreated {
account: dest2,
balance: balance2,
creator: transactor,
});
} else {
OneshotAccounts::<T>::remove(&transactor);
OneshotAccounts::<T>::insert(&dest1, balance1);
frame_system::Account::<T>::mutate(&dest2, |a| a.data.add_free(balance2));
Self::deposit_event(Event::OneshotAccountConsumedTwoDests {
account: transactor.clone(),
balance1,
balance2,
dest1: dest1.clone(),
dest2,
});
Self::deposit_event(Event::OneshotAccountCreated {
account: dest1,
balance: balance1,
creator: transactor,
});
}
} else {
let dest1_data = frame_system::Account::<T>::get(&dest1).data;
ensure!(dest1_data.was_providing(), Error::<T>::DestAccountNotExist);
if dest2_is_oneshot {
ensure!(
OneshotAccounts::<T>::get(&dest2).is_none(),
Error::<T>::OneshotAccountAlreadyCreated
);
ensure!(
balance2 >= T::ExistentialDeposit::get(),
Error::<T>::ExistentialDeposit
);
OneshotAccounts::<T>::remove(&transactor);
frame_system::Account::<T>::mutate(&dest1, |a| a.data.add_free(balance1));
OneshotAccounts::<T>::insert(&dest2, balance2);
Self::deposit_event(Event::OneshotAccountConsumedTwoDests {
account: transactor.clone(),
balance1,
balance2,
dest1,
dest2: dest2.clone(),
});
Self::deposit_event(Event::OneshotAccountCreated {
account: dest2,
balance: balance2,
creator: transactor,
});
} else {
OneshotAccounts::<T>::remove(&transactor);
frame_system::Account::<T>::mutate(&dest1, |a| a.data.add_free(balance1));
frame_system::Account::<T>::mutate(&dest2, |a| a.data.add_free(balance2));
Self::deposit_event(Event::OneshotAccountConsumedTwoDests {
account: transactor,
balance1,
balance2,
dest1,
dest2,
});
}
}
if dest2_is_oneshot {
ensure!(
OneshotAccounts::<T>::get(&dest2).is_none(),
Error::<T>::OneshotAccountAlreadyCreated
);
ensure!(
balance2 >= T::ExistentialDeposit::get(),
Error::<T>::ExistentialDeposit
);
OneshotAccounts::<T>::insert(&dest2, balance2);
Self::deposit_event(Event::OneshotAccountCreated {
account: dest2.clone(),
balance: balance2,
creator: transactor.clone(),
});
} else {
let dest2_data = frame_system::Account::<T>::get(&dest2).data;
ensure!(dest2_data.was_providing(), Error::<T>::DestAccountNotExist);
frame_system::Account::<T>::mutate(&dest2, |a| a.data.add_free(balance2));
}
if dest1_is_oneshot {
OneshotAccounts::<T>::insert(&dest1, balance1);
Self::deposit_event(Event::OneshotAccountCreated {
account: dest1.clone(),
balance: balance1,
creator: transactor.clone(),
});
} else {
frame_system::Account::<T>::mutate(&dest1, |a| a.data.add_free(balance1));
}
OneshotAccounts::<T>::remove(&transactor);
Self::deposit_event(Event::OneshotAccountConsumed {
account: transactor,
dest1: (dest1, balance1),
dest2: Some((dest2, balance2)),
});
Ok(())
}
Loading