lib.rs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Ensure we're `no_std` when compiling for Wasm.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. #[cfg(feature = "std")]
  4. use rstd::prelude::*;
  5. use codec::{Codec, Decode, Encode};
  6. use runtime_primitives::traits::{MaybeSerialize, Member, One, SimpleArithmetic, Zero};
  7. use srml_support::traits::Currency;
  8. use srml_support::{decl_module, decl_storage, ensure, Parameter};
  9. mod mint;
  10. mod mock;
  11. mod tests;
  12. pub use mint::*;
  13. use system;
  14. pub trait Trait: system::Trait {
  15. /// The currency to mint.
  16. type Currency: Currency<Self::AccountId>;
  17. /// The type used as a mint identifier.
  18. type MintId: Parameter
  19. + Member
  20. + SimpleArithmetic
  21. + Codec
  22. + Default
  23. + Copy
  24. + MaybeSerialize
  25. + PartialEq;
  26. }
  27. pub type BalanceOf<T> =
  28. <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
  29. #[derive(PartialEq, Eq, Debug)]
  30. pub enum GeneralError {
  31. MintNotFound,
  32. NextAdjustmentInPast,
  33. }
  34. /// Errors that can arise from attempt to mint and transfer tokens from a mint to
  35. /// an account.
  36. #[derive(PartialEq, Eq, Debug)]
  37. pub enum TransferError {
  38. MintNotFound,
  39. NotEnoughCapacity,
  40. }
  41. /// Errors that can arise from attempt to transfer capacity between mints.
  42. #[derive(PartialEq, Eq, Debug)]
  43. pub enum CapacityTransferError {
  44. SourceMintNotFound,
  45. DestinationMintNotFound,
  46. NotEnoughCapacity,
  47. }
  48. impl From<MintingError> for CapacityTransferError {
  49. fn from(err: MintingError) -> CapacityTransferError {
  50. match err {
  51. MintingError::NotEnoughCapacity => CapacityTransferError::NotEnoughCapacity,
  52. }
  53. }
  54. }
  55. impl From<MintingError> for TransferError {
  56. fn from(err: MintingError) -> TransferError {
  57. match err {
  58. MintingError::NotEnoughCapacity => TransferError::NotEnoughCapacity,
  59. }
  60. }
  61. }
  62. #[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)]
  63. pub enum Adjustment<Balance: Zero, BlockNumber> {
  64. // First adjustment will be after AdjustOnInterval.block_interval
  65. Interval(AdjustOnInterval<Balance, BlockNumber>),
  66. // First Adjustment will be at absolute blocknumber
  67. IntervalAfterFirstAdjustmentAbsolute(AdjustOnInterval<Balance, BlockNumber>, BlockNumber),
  68. // First Adjustment will be after a specified number of blocks
  69. IntervalAfterFirstAdjustmentRelative(AdjustOnInterval<Balance, BlockNumber>, BlockNumber),
  70. }
  71. decl_storage! {
  72. trait Store for Module<T: Trait> as TokenMint {
  73. /// Mints
  74. pub Mints get(mints) : linked_map T::MintId => Mint<BalanceOf<T>, T::BlockNumber>;
  75. /// The number of mints created.
  76. pub MintsCreated get(mints_created): T::MintId;
  77. }
  78. }
  79. decl_module! {
  80. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  81. fn on_finalize(now: T::BlockNumber) {
  82. Self::update_mints(now);
  83. }
  84. }
  85. }
  86. impl<T: Trait> Module<T> {
  87. fn update_mints(now: T::BlockNumber) {
  88. // Are we reading value from storage twice?
  89. for (mint_id, ref mut mint) in <Mints<T>>::enumerate() {
  90. if mint.maybe_do_capacity_adjustment(now) {
  91. <Mints<T>>::insert(&mint_id, mint);
  92. }
  93. }
  94. }
  95. /// Adds a new mint with given settings to mints, and returns new MintId.
  96. pub fn add_mint(
  97. initial_capacity: BalanceOf<T>,
  98. adjustment: Option<Adjustment<BalanceOf<T>, T::BlockNumber>>,
  99. ) -> Result<T::MintId, GeneralError> {
  100. let now = <system::Module<T>>::block_number();
  101. // Ensure the next adjustment if set, is in the future
  102. if let Some(adjustment) = adjustment {
  103. match adjustment {
  104. Adjustment::IntervalAfterFirstAdjustmentAbsolute(_, first_adjustment_in) => {
  105. ensure!(
  106. first_adjustment_in > now,
  107. GeneralError::NextAdjustmentInPast
  108. );
  109. }
  110. _ => (),
  111. }
  112. }
  113. // Determine next adjutment
  114. let next_adjustment = adjustment.map(|adjustment| match adjustment {
  115. Adjustment::Interval(adjust_on_interval) => NextAdjustment {
  116. at_block: now + adjust_on_interval.block_interval,
  117. adjustment: adjust_on_interval,
  118. },
  119. Adjustment::IntervalAfterFirstAdjustmentAbsolute(
  120. adjust_on_interval,
  121. first_adjustment_at,
  122. ) => NextAdjustment {
  123. adjustment: adjust_on_interval,
  124. at_block: first_adjustment_at,
  125. },
  126. Adjustment::IntervalAfterFirstAdjustmentRelative(
  127. adjust_on_interval,
  128. first_adjustment_after,
  129. ) => NextAdjustment {
  130. adjustment: adjust_on_interval,
  131. at_block: now + first_adjustment_after,
  132. },
  133. });
  134. // get next mint_id and increment total number of mints created
  135. let mint_id = Self::mints_created();
  136. <MintsCreated<T>>::put(mint_id + One::one());
  137. <Mints<T>>::insert(mint_id, Mint::new(initial_capacity, next_adjustment, now));
  138. Ok(mint_id)
  139. }
  140. /// Removes a mint. Passing a non existent mint has no side effects.
  141. pub fn remove_mint(mint_id: T::MintId) {
  142. <Mints<T>>::remove(&mint_id);
  143. }
  144. /// Tries to transfer exact requested amount from mint to a recipient account id.
  145. /// Returns error if amount exceeds mint capacity or the specified mint doesn't exist.
  146. /// Transfering amount of zero has no side effects. Return nothing on success.
  147. pub fn transfer_tokens(
  148. mint_id: T::MintId,
  149. requested_amount: BalanceOf<T>,
  150. recipient: &T::AccountId,
  151. ) -> Result<(), TransferError> {
  152. if requested_amount == Zero::zero() {
  153. return Ok(());
  154. }
  155. ensure!(<Mints<T>>::exists(&mint_id), TransferError::MintNotFound);
  156. let mut mint = Self::mints(&mint_id);
  157. // Try minting
  158. mint.mint_tokens(requested_amount)?;
  159. <Mints<T>>::insert(&mint_id, mint);
  160. // Deposit into recipient account
  161. T::Currency::deposit_creating(recipient, requested_amount);
  162. Ok(())
  163. }
  164. /// Provided mint exists, sets its capacity to specied value, return error otherwise.
  165. pub fn set_mint_capacity(
  166. mint_id: T::MintId,
  167. capacity: BalanceOf<T>,
  168. ) -> Result<(), GeneralError> {
  169. ensure!(<Mints<T>>::exists(&mint_id), GeneralError::MintNotFound);
  170. <Mints<T>>::mutate(&mint_id, |mint| {
  171. mint.set_capacity(capacity);
  172. });
  173. Ok(())
  174. }
  175. /// Provided source and destination mints exist, will attempt to transfer capacity from the source mint
  176. /// to the destination mint. Will return errors on non-existence of
  177. /// mints or capacity_to_transfer exceeds the source mint's capacity.
  178. pub fn transfer_capacity(
  179. source: T::MintId,
  180. destination: T::MintId,
  181. capacity_to_transfer: BalanceOf<T>,
  182. ) -> Result<(), CapacityTransferError> {
  183. ensure!(
  184. <Mints<T>>::exists(&source),
  185. CapacityTransferError::SourceMintNotFound
  186. );
  187. ensure!(
  188. <Mints<T>>::exists(&destination),
  189. CapacityTransferError::DestinationMintNotFound
  190. );
  191. <Mints<T>>::mutate(&source, |source_mint| {
  192. <Mints<T>>::mutate(&destination, |destination_mint| {
  193. source_mint.transfer_capacity_to(destination_mint, capacity_to_transfer)
  194. })
  195. })?;
  196. Ok(())
  197. }
  198. /// Returns a mint's capacity if it exists, error otherwise.
  199. pub fn get_mint_capacity(mint_id: T::MintId) -> Result<BalanceOf<T>, GeneralError> {
  200. ensure!(<Mints<T>>::exists(&mint_id), GeneralError::MintNotFound);
  201. let mint = Self::mints(&mint_id);
  202. Ok(mint.capacity())
  203. }
  204. /// Returns a mint's adjustment policy if it exists, error otherwise.
  205. pub fn get_mint_next_adjustment(
  206. mint_id: T::MintId,
  207. ) -> Result<Option<NextAdjustment<BalanceOf<T>, T::BlockNumber>>, GeneralError> {
  208. ensure!(<Mints<T>>::exists(&mint_id), GeneralError::MintNotFound);
  209. let mint = Self::mints(&mint_id);
  210. Ok(mint.next_adjustment())
  211. }
  212. /// Returns true if a mint exists.
  213. pub fn mint_exists(mint_id: T::MintId) -> bool {
  214. <Mints<T>>::exists(&mint_id)
  215. }
  216. }