Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

feat(fee): Support fee management on acurast pallet #21

Merged
merged 1 commit into from
Oct 27, 2022
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
94 changes: 53 additions & 41 deletions pallets/acurast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ edition = "2021"
targets = ["x86_64-unknown-linux-gnu"]

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

# Substrate
frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.29" }
Expand All @@ -28,17 +32,24 @@ pallet-assets = { git = "https://github.com/paritytech/substrate", default-featu
parachains-common = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.29", default-features = false }

# Polkadot
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.29"}
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.29"}
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.29"}
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.29" }
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.29" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.29" }

# Attestation
asn1 = { version = "0.11.0", default-features = false, features = ["derive"] }
p256 = { git = "https://github.com/Acurast/elliptic-curves", default-features = false, branch = "p256/v0.10.1", features = ["ecdsa", "sha256"] }
p384 = { package = "p384_vendored", path = "p384", default-features = false, features = ["ecdsa", "arithmetic", "expose-field"] }
p256 = { git = "https://github.com/Acurast/elliptic-curves", default-features = false, branch = "p256/v0.10.1", features = [
"ecdsa",
"sha256",
] }
p384 = { package = "p384_vendored", path = "p384", default-features = false, features = [
"ecdsa",
"arithmetic",
"expose-field",
] }
sha2 = { version = "0.10", default-features = false }
num-bigint = { version = "0.4.3", default-features = false }
ecdsa-vendored = { package = "ecdsa_vendored", path = "p384/ecdsa", default-features = false}
ecdsa-vendored = { package = "ecdsa_vendored", path = "p384/ecdsa", default-features = false }

# benchmarks
hex-literal = { version = "0.3", optional = true }
Expand All @@ -57,46 +68,47 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkad
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.29" }
parachain-info = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.29" }

# Acurast
acurast-p256-crypto = { path = "../../p256-crypto" }

[features]
default = ["std"]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"hex-literal",
"sp-runtime",
"parachain-info",
"pallet-balances",
"sp-core"
"frame-benchmarking/runtime-benchmarks",
"hex-literal",
"sp-runtime",
"parachain-info",
"pallet-balances",
"sp-core",
]


std = [
"acurast-p256-crypto/std",
"asn1/std",
"base64/std",
"codec/std",
"ecdsa-vendored/std",
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
"num-bigint/std",
"p256/std",
"p384/std",
"pallet-assets/std",
"pallet-balances/std",
"pallet-timestamp/std",
"parachain-info/std",
"parachains-common/std",
"scale-info/std",
"sha2/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"sp-version/std",
"xcm-builder/std",
"xcm-executor/std",
"xcm/std",
"acurast-p256-crypto/std",
"asn1/std",
"base64/std",
"codec/std",
"ecdsa-vendored/std",
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
"num-bigint/std",
"p256/std",
"p384/std",
"pallet-assets/std",
"pallet-balances/std",
"pallet-timestamp/std",
"parachain-info/std",
"parachains-common/std",
"scale-info/std",
"sha2/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"sp-version/std",
"xcm-builder/std",
"xcm-executor/std",
"xcm/std",
]
try-runtime = [ "frame-support/try-runtime" ]
try-runtime = ["frame-support/try-runtime"]
60 changes: 6 additions & 54 deletions pallets/acurast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ mod attestation;
pub mod payments;
mod types;
mod utils;
mod traits;
pub mod weights;
pub mod xcm_adapters;

pub use pallet::*;
pub use payments::*;
pub use types::*;
pub use traits::*;

#[frame_support::pallet]
pub mod pallet {
Expand All @@ -31,59 +33,7 @@ pub mod pallet {
use crate::payments::*;
use crate::types::*;
use crate::utils::*;

/// This trait provides the interface for a fulfillment router.
pub trait FulfillmentRouter<T: Config> {
fn received_fulfillment(
origin: OriginFor<T>,
from: T::AccountId,
fulfillment: Fulfillment,
registration: JobRegistration<T::AccountId, T::RegistrationExtra>,
requester: <T::Lookup as StaticLookup>::Target,
) -> DispatchResultWithPostInfo;
}

pub trait RevocationListUpdateBarrier<T: Config> {
fn can_update_revocation_list(
origin: &T::AccountId,
updates: &Vec<CertificateRevocationListUpdate>,
) -> bool;
}

impl<T: Config> RevocationListUpdateBarrier<T> for () {
fn can_update_revocation_list(
_origin: &T::AccountId,
_updates: &Vec<CertificateRevocationListUpdate>,
) -> bool {
false
}
}

pub trait JobAssignmentUpdateBarrier<T: Config> {
fn can_update_assigned_jobs(
origin: &T::AccountId,
updates: &Vec<JobAssignmentUpdate<T::AccountId>>,
) -> bool;
}

impl<T: Config> JobAssignmentUpdateBarrier<T> for () {
fn can_update_assigned_jobs(
_origin: &T::AccountId,
_updates: &Vec<JobAssignmentUpdate<T::AccountId>>,
) -> bool {
false
}
}

pub trait WeightInfo {
fn register() -> Weight;
fn deregister() -> Weight;
fn update_allowed_sources() -> Weight;
fn update_job_assignments() -> Weight;
fn fulfill() -> Weight;
fn submit_attestation() -> Weight;
fn update_certificate_revocation_list() -> Weight;
}
use crate::traits::*;

#[pallet::config]
pub trait Config:
Expand All @@ -106,7 +56,9 @@ pub mod pallet {
type RevocationListUpdateBarrier: RevocationListUpdateBarrier<Self>;
/// Barrier for update_job_assignments extrinsic call.
type JobAssignmentUpdateBarrier: JobAssignmentUpdateBarrier<Self>;

// Fee Logic
type FeeManager: FeeManager;
// Weight Logic
type WeightInfo: WeightInfo;
}

Expand Down
28 changes: 22 additions & 6 deletions pallets/acurast/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use frame_support::{pallet_prelude::GenesisBuild, PalletId};
use hex_literal::hex;
use sp_io;
use sp_runtime::traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, ConstU128, ConstU32};
use sp_runtime::{generic, parameter_types, AccountId32};
use sp_runtime::{generic, parameter_types, AccountId32, DispatchError, Percent};
use xcm::prelude::*;

use crate::{
payments, AttestationChain, Fulfillment, JobAssignmentUpdate, JobAssignmentUpdateBarrier,
JobRegistration, LockAndPayAsset, RevocationListUpdateBarrier, Script, SerialNumber,
JobRegistration, LockAndPayAsset, RevocationListUpdateBarrier, Script, SerialNumber, FeeManager,
};

type AccountId = AccountId32;
Expand Down Expand Up @@ -67,18 +67,29 @@ impl LockAndPayAsset<Test> for TestTransactor {
fn lock_asset(
_asset: MultiAsset,
_owner: <<Test as frame_system::Config>::Lookup as sp_runtime::traits::StaticLookup>::Source,
) -> Result<(), ()> {
) -> Result<(), DispatchError> {
Ok(())
}

fn pay_asset(
_asset: MultiAsset,
_target: <<Test as frame_system::Config>::Lookup as sp_runtime::traits::StaticLookup>::Source,
) -> Result<(), ()> {
) -> Result<(), DispatchError> {
Ok(())
}
}

pub struct FeeManagerImpl;
impl FeeManager for FeeManagerImpl {
fn get_fee_percentage() -> Percent {
Percent::from_percent(30)
}

fn pallet_id() -> PalletId {
PalletId(*b"acurfees")
}
}

pub struct ExtBuilder;
impl ExtBuilder {
pub fn build(self) -> sp_io::TestExternalities {
Expand All @@ -100,6 +111,7 @@ impl ExtBuilder {
balances: vec![
(alice_account_id(), INITIAL_BALANCE),
(pallet_assets_account(), INITIAL_BALANCE),
(pallet_fees_account(), INITIAL_BALANCE),
(bob_account_id(), INITIAL_BALANCE),
(processor_account_id(), INITIAL_BALANCE),
],
Expand Down Expand Up @@ -154,7 +166,7 @@ frame_support::construct_runtime!(
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
Assets: pallet_assets::{Pallet, Config<T>, Event<T>, Storage},
ParachainInfo: parachain_info::{Pallet, Storage, Config},
Acurast: crate::{Pallet, Call, Storage, Event<T>},
Acurast: crate::{Pallet, Call, Storage, Event<T>}
}
);

Expand All @@ -167,7 +179,6 @@ parameter_types! {
pub AllowedRevocationListUpdate: Vec<AccountId> = vec![alice_account_id(), <Test as crate::Config>::PalletId::get().into_account_truncating()];
pub AllowedJobAssignmentUpdate: Vec<AccountId> = vec![bob_account_id()];
pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
pub const TestPalletId: PalletId = PalletId(*b"testpid1");
}
parameter_types! {
pub const MaxReserves: u32 = 50;
Expand Down Expand Up @@ -253,6 +264,7 @@ impl crate::Config for Test {
type PalletId = AcurastPalletId;
type RevocationListUpdateBarrier = Barrier;
type JobAssignmentUpdateBarrier = JobBarrier;
type FeeManager = FeeManagerImpl;
type WeightInfo = crate::weights::WeightInfo<Test>;
}

Expand Down Expand Up @@ -392,6 +404,10 @@ pub fn pallet_assets_account() -> <Test as frame_system::Config>::AccountId {
<Test as crate::Config>::PalletId::get().into_account_truncating()
}

pub fn pallet_fees_account() -> <Test as frame_system::Config>::AccountId {
<Test as crate::Config>::FeeManager::pallet_id().into_account_truncating()
}

pub fn alice_account_id() -> AccountId {
[0; 32].into()
}
Expand Down
49 changes: 27 additions & 22 deletions pallets/acurast/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ use frame_support::{
dispatch::RawOrigin,
sp_runtime::traits::{AccountIdConversion, Get, StaticLookup},
};
use sp_runtime::DispatchError;
use xcm::latest::prelude::*;
use crate::traits::FeeManager;

pub trait LockAndPayAsset<T: Config> {
fn lock_asset(asset: MultiAsset, owner: <T::Lookup as StaticLookup>::Source) -> Result<(), ()>;
fn lock_asset(asset: MultiAsset, owner: <T::Lookup as StaticLookup>::Source) -> Result<(), DispatchError>;

fn pay_asset(asset: MultiAsset, target: <T::Lookup as StaticLookup>::Source) -> Result<(), ()>;
fn pay_asset(asset: MultiAsset, target: <T::Lookup as StaticLookup>::Source) -> Result<(), DispatchError>;
}

pub struct StatemintAssetTransactor;
Expand All @@ -18,52 +20,55 @@ where
T::AssetId: TryFrom<u128>,
T::Balance: TryFrom<u128>,
{
fn lock_asset(asset: MultiAsset, owner: <T::Lookup as StaticLookup>::Source) -> Result<(), ()> {
fn lock_asset(asset: MultiAsset, owner: <T::Lookup as StaticLookup>::Source) -> Result<(), DispatchError> {
let pallet_account: T::AccountId = T::PalletId::get().into_account_truncating();
let raw_origin = RawOrigin::<T::AccountId>::Signed(pallet_account.clone());
let pallet_origin: T::Origin = raw_origin.into();

let (id, amount) = get_statemint_asset(&asset).map_err(|_| ())?;
let (id, amount) = get_statemint_asset(&asset).or(Err(DispatchError::Other("Asset not found.")))?;
let (id, amount): (T::AssetId, T::Balance) = match (id.try_into(), amount.try_into()) {
(Ok(id), Ok(amount)) => (id, amount),
_ => return Err(()),
(Err(_err), _) => return Err(DispatchError::Other("Invalid asset id.")),
(_, Err(_err)) => return Err(DispatchError::Other("Invalid asset balance."))
};

// transfer funds from caller to pallet account for holding until fulfill is called
// this is a privileged operation, hence the force_transfer call.
// we could do an approve_transfer first, but this would require the assets pallet being
// public which we can't do at the moment due to our statemint assets 1 to 1 integration
let extrinsic_call = pallet_assets::Pallet::<T>::force_transfer(
pallet_assets::Pallet::<T>::force_transfer(
pallet_origin,
id,
owner,
T::Lookup::unlookup(pallet_account),
amount,
);

match extrinsic_call {
Ok(_) => Ok(()),
Err(_e) => Err(()),
}
)
}

fn pay_asset(asset: MultiAsset, target: <T::Lookup as StaticLookup>::Source) -> Result<(), ()> {
fn pay_asset(asset: MultiAsset, target: <T::Lookup as StaticLookup>::Source) -> Result<(), DispatchError> {
let pallet_account: T::AccountId = T::PalletId::get().into_account_truncating();
let raw_origin = RawOrigin::<T::AccountId>::Signed(pallet_account);
let raw_origin = RawOrigin::<T::AccountId>::Signed(pallet_account.clone());
let pallet_origin: T::Origin = raw_origin.into();

let (id, amount) = get_statemint_asset(&asset).map_err(|_| ())?;
let (id, amount) = get_statemint_asset(&asset).or(Err(DispatchError::Other("Asset not found.")))?;
let (id, amount): (T::AssetId, T::Balance) = match (id.try_into(), amount.try_into()) {
(Ok(id), Ok(amount)) => (id, amount),
_ => return Err(()),
(Err(_err), _) => return Err(DispatchError::Other("Invalid asset id.")),
(_, Err(_err)) => return Err(DispatchError::Other("Invalid asset balance."))
};

let extrinsic_call =
pallet_assets::Pallet::<T>::transfer(pallet_origin, id, target, amount);
// Extract fee from the processor reward
let fee_percentage = T::FeeManager::get_fee_percentage(); // TODO: fee will be indexed by version in the future
let fee = fee_percentage.mul_floor(amount);

// Subtract the fee from the reward
let reward_after_fee = amount - fee;

// Transfer fees to Acurast fees manager account
let fee_pallet_account: T::AccountId = T::FeeManager::pallet_id().into_account_truncating();
pallet_assets::Pallet::<T>::transfer(pallet_origin.clone(), id, T::Lookup::unlookup(fee_pallet_account), fee)?;

match extrinsic_call {
Ok(_) => Ok(()),
Err(_) => Err(()),
}
// Transfer reward to the processor
pallet_assets::Pallet::<T>::transfer(pallet_origin, id, target, reward_after_fee)
}
}
Loading