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

liquid-crowdloan #2503

Merged
merged 21 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from 8 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
21 changes: 21 additions & 0 deletions Cargo.lock

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

41 changes: 41 additions & 0 deletions modules/liquid-crowdloan/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "module-liquid-crowdloan"
version = "2.16.0"
authors = ["Acala Developers"]
edition = "2021"

[dependencies]
scale-info = { version = "2.2.0", default-features = false, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }

sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false }

orml-traits = { path = "../../orml/traits", default-features = false }
primitives = { package = "acala-primitives", path = "../../primitives", default-features = false }
support = { package = "module-support", path = "../support", default-features = false }

[dev-dependencies]
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" }
module-currencies = { path = "../currencies" }
orml-tokens = { path = "../../orml/tokens" }

[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"sp-runtime/std",
"frame-support/std",
"frame-system/std",
"orml-traits/std",
"primitives/std",
"support/std",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
]
130 changes: 130 additions & 0 deletions modules/liquid-crowdloan/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// This file is part of Acala.

// Copyright (C) 2020-2023 Acala Foundation.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! # Liquid Crowdloan Module
//!
//! Allow people to redeem lcDOT for DOT.

#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::unused_unit)]

use frame_support::{pallet_prelude::*, traits::EnsureOrigin, PalletId};
use frame_system::pallet_prelude::*;
use orml_traits::MultiCurrency;
use primitives::{Balance, CurrencyId};
use sp_runtime::traits::AccountIdConversion;

use support::CrowdloanVaultXcm;

mod mock;
mod tests;

pub use module::*;

#[frame_support::pallet]
pub mod module {
use super::*;

#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

type Currency: MultiCurrency<Self::AccountId, CurrencyId = CurrencyId, Balance = Balance>;

/// Liquid crowdloan currency Id, i.e. LDOT for Polkadot.
xlc marked this conversation as resolved.
Show resolved Hide resolved
#[pallet::constant]
type LiquidCrowdloanCurrencyId: Get<CurrencyId>;

/// Relay chain currency Id, i.e. DOT for Polkadot.
#[pallet::constant]
type RelayChainCurrencyId: Get<CurrencyId>;

/// Pallet Id for liquid crowdloan module.
#[pallet::constant]
type PalletId: Get<PalletId>;

/// The governance origin for liquid crowdloan module. For instance for DOT cross-chain
/// transfer DOT from relay chain crowdloan vault to liquid crowdloan module account.
type GovernanceOrigin: EnsureOrigin<Self::RuntimeOrigin>;

/// The crowdloan vault account on relay chain.
#[pallet::constant]
type CrowdloanVault: Get<Self::AccountId>;

/// XCM transfer impl.
type XcmTransfer: CrowdloanVaultXcm<Self::AccountId, Balance>;
}

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
/// Liquid Crowdloan asset was redeemed.
Redeemed { amount: Balance },
/// The transfer from relay chain crowdloan vault was requested.
TransferFromCrowdloanVaultRequested { amount: Balance },
}

#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Redeem liquid crowdloan currency for relay chain currency.
#[pallet::call_index(0)]
#[pallet::weight(0)]
pub fn redeem(origin: OriginFor<T>, #[pallet::compact] amount: Balance) -> DispatchResult {
let who = ensure_signed(origin)?;

T::Currency::withdraw(T::LiquidCrowdloanCurrencyId::get(), &who, amount)?;

T::Currency::transfer(T::RelayChainCurrencyId::get(), &Self::account_id(), &who, amount)?;

Self::deposit_event(Event::Redeemed { amount });

Ok(())
}

/// Send an XCM message to cross-chain transfer DOT from relay chain crowdloan vault to
/// liquid crowdloan module account.
shaunxw marked this conversation as resolved.
Show resolved Hide resolved
///
/// This call requires `GovernanceOrigin`.
#[pallet::call_index(1)]
#[pallet::weight(0)]
pub fn transfer_from_crowdloan_vault(
origin: OriginFor<T>,
#[pallet::compact] amount: Balance,
) -> DispatchResult {
T::GovernanceOrigin::ensure_origin(origin)?;

T::XcmTransfer::transfer_to_liquid_crowdloan_module_account(
T::CrowdloanVault::get(),
Self::account_id(),
amount,
)?;

Self::deposit_event(Event::TransferFromCrowdloanVaultRequested { amount });

Ok(())
}
}
}

impl<T: Config> Pallet<T> {
pub fn account_id() -> T::AccountId {
T::PalletId::get().into_account_truncating()
}
}
Loading