Skip to content

Commit

Permalink
feat: implement pallet
Browse files Browse the repository at this point in the history
  • Loading branch information
devwckd committed Dec 18, 2024
1 parent feafbaa commit 10941fa
Show file tree
Hide file tree
Showing 11 changed files with 563 additions and 89 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pallet-evm-precompile-modexp = { git = "https://github.com/paritytech/frontier.g
pallet-evm-precompile-sha3fips = { git = "https://github.com/paritytech/frontier.git", rev = "b9b1c620c8b418bdeeadc79725f9cfa4703c0333", default-features = false }
pallet-evm-precompile-simple = { git = "https://github.com/paritytech/frontier.git", rev = "b9b1c620c8b418bdeeadc79725f9cfa4703c0333", default-features = false }

substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", default-features = false }

# CLI-specific dependencies
clap = { version = "4.5.22", features = ["derive"] }
serde_json = { version = "1.0", default-features = false }
Expand Down
3 changes: 2 additions & 1 deletion pallets/torus0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ edition.workspace = true

[features]
default = ["std"]
std = ["codec/std", "polkadot-sdk/std", "scale-info/std"]
std = ["codec/std", "polkadot-sdk/std", "scale-info/std", "substrate-fixed/std"]
runtime-benchmarks = ["polkadot-sdk/runtime-benchmarks"]
try-runtime = ["polkadot-sdk/try-runtime"]

[dependencies]
codec = { workspace = true, features = ["derive"] }
scale-info = { workspace = true, features = ["derive"] }
substrate-fixed = { workspace = true }
polkadot-sdk = { workspace = true, features = ["experimental", "runtime"] }

[dev-dependencies]
Expand Down
205 changes: 187 additions & 18 deletions pallets/torus0/src/agent.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::AccountIdOf;
use codec::{Decode, Encode, MaxEncodedLen};
use polkadot_sdk::frame_election_provider_support::Get;
use polkadot_sdk::sp_runtime::DispatchError;
use polkadot_sdk::{
frame_support::{dispatch::DispatchResult, CloneNoBound},
polkadot_sdk_frame::prelude::OriginFor,
frame_support::{dispatch::DispatchResult, ensure, CloneNoBound},
sp_runtime::{BoundedVec, Percent},
};
use scale_info::prelude::vec::Vec;
Expand All @@ -13,31 +14,199 @@ use scale_info::TypeInfo;
pub struct Agent<T: crate::Config> {
pub key: AccountIdOf<T>,
pub name: BoundedVec<u8, T::MaxAgentNameLengthConstraint>,
pub address: BoundedVec<u8, T::MaxAgentAddressLengthConstraint>,
pub url: BoundedVec<u8, T::MaxAgentUrlLengthConstraint>,
pub metadata: BoundedVec<u8, T::MaxAgentMetadataLengthConstraint>,
pub weight_factor: Percent,
}

pub fn register<T: crate::Config>(
_origin: OriginFor<T>,
_name: Vec<u8>,
_address: Vec<u8>,
_agent_key: AccountIdOf<T>,
_metadata: Option<Vec<u8>>,
agent_key: AccountIdOf<T>,
name: Vec<u8>,
url: Vec<u8>,
metadata: Vec<u8>,
) -> DispatchResult {
todo!()
ensure!(
!exists::<T>(&agent_key),
crate::Error::<T>::AgentAlreadyRegistered
);

ensure!(
crate::RegistrationsThisBlock::<T>::get() < crate::MaxRegistrationsPerBlock::<T>::get(),
crate::Error::<T>::TooManyAgentRegistrationsThisBlock
);

let burn_config = crate::BurnConfig::<T>::get();
ensure!(
crate::RegistrationsThisInterval::<T>::get() < burn_config.max_registrations_per_interval,
crate::Error::<T>::TooManyAgentRegistrationsThisBlock
);

validate_agent_name::<T>(&name[..])?;
validate_agent_url::<T>(&url[..])?;
validate_agent_metadata::<T>(&metadata[..])?;

// TODO: check if agent is on whitelist

crate::Agents::<T>::insert(
agent_key.clone(),
Agent {
key: agent_key.clone(),
name: BoundedVec::truncate_from(name),
url: BoundedVec::truncate_from(url),
metadata: BoundedVec::truncate_from(metadata),
weight_factor: Percent::from_percent(100),
},
);

crate::Pallet::<T>::deposit_event(crate::Event::<T>::AgentRegistered(agent_key));

Ok(())
}

pub fn deregister<T: crate::Config>(_origin: OriginFor<T>) -> DispatchResult {
todo!()
pub fn unregister<T: crate::Config>(agent_key: AccountIdOf<T>) -> DispatchResult {
ensure!(
exists::<T>(&agent_key),
crate::Error::<T>::AgentDoesNotExist
);

crate::Agents::<T>::remove(&agent_key);

crate::Pallet::<T>::deposit_event(crate::Event::<T>::AgentUnregistered(agent_key));

Ok(())
}

pub fn update<T: crate::Config>(
_origin: OriginFor<T>,
_name: Vec<u8>,
_address: Vec<u8>,
_metadata: Option<Vec<u8>>,
_staking_fee: Option<Percent>,
_weight_control_fee: Option<Percent>,
agent_key: AccountIdOf<T>,
name: Vec<u8>,
url: Vec<u8>,
metadata: Option<Vec<u8>>,
staking_fee: Option<Percent>,
weight_control_fee: Option<Percent>,
) -> DispatchResult {
todo!()
ensure!(
exists::<T>(&agent_key),
crate::Error::<T>::AgentDoesNotExist
);

crate::Agents::<T>::try_mutate(&agent_key, |agent| {
let Some(agent) = agent else {
return Err(crate::Error::<T>::AgentDoesNotExist.into());
};

validate_agent_name::<T>(&name[..])?;
agent.name = BoundedVec::truncate_from(name);

validate_agent_url::<T>(&url[..])?;
agent.url = BoundedVec::truncate_from(url);

if let Some(metadata) = metadata {
validate_agent_metadata::<T>(&metadata[..])?;
agent.metadata = BoundedVec::truncate_from(metadata);
}

Ok::<(), DispatchError>(())
})?;

if staking_fee.is_none() && weight_control_fee.is_none() {
return Ok(());
}

crate::Fee::<T>::try_mutate(&agent_key, |fee| {
let constraints = crate::FeeConstraints::<T>::get();

if let Some(staking_fee) = staking_fee {
ensure!(
staking_fee >= constraints.min_staking_fee,
crate::Error::<T>::InvalidStakingFee
);

fee.staking_fee = staking_fee;
}

if let Some(weight_control_fee) = weight_control_fee {
ensure!(
weight_control_fee >= constraints.min_weight_control_fee,
crate::Error::<T>::InvalidWeightControlFee
);

fee.weight_control_fee = weight_control_fee;
}

Ok::<(), DispatchError>(())
})?;

Ok(())
}

pub fn exists<T: crate::Config>(key: &AccountIdOf<T>) -> bool {
crate::Agents::<T>::contains_key(key)
}

fn validate_agent_name<T: crate::Config>(bytes: &[u8]) -> DispatchResult {
let len: u32 = bytes
.len()
.try_into()
.map_err(|_| crate::Error::<T>::AgentNameTooLong)?;

ensure!(
len >= crate::MinNameLength::<T>::get() as u32,
crate::Error::<T>::AgentNameTooShort
);

ensure!(
len <= (crate::MaxNameLength::<T>::get() as u32)
.min(T::MaxAgentNameLengthConstraint::get()),
crate::Error::<T>::AgentNameTooShort
);

ensure!(
core::str::from_utf8(bytes).is_ok(),
crate::Error::<T>::InvalidAgentName
);

Ok(())
}

fn validate_agent_url<T: crate::Config>(bytes: &[u8]) -> DispatchResult {
let len: u32 = bytes
.len()
.try_into()
.map_err(|_| crate::Error::<T>::AgentUrlTooLong)?;

ensure!(len > 0, crate::Error::<T>::AgentNameTooShort);

ensure!(
len <= (crate::MaxNameLength::<T>::get() as u32)
.min(T::MaxAgentNameLengthConstraint::get()),
crate::Error::<T>::AgentUrlTooShort
);

ensure!(
core::str::from_utf8(bytes).is_ok(),
crate::Error::<T>::InvalidAgentUrl
);

Ok(())
}

fn validate_agent_metadata<T: crate::Config>(bytes: &[u8]) -> DispatchResult {
let len: u32 = bytes
.len()
.try_into()
.map_err(|_| crate::Error::<T>::AgentMetadataTooLong)?;

ensure!(len > 0, crate::Error::<T>::AgentMetadataTooShort);

ensure!(
len <= T::MaxAgentMetadataLengthConstraint::get(),
crate::Error::<T>::AgentMetadataTooLong
);

ensure!(
core::str::from_utf8(bytes).is_ok(),
crate::Error::<T>::InvalidAgentMetadata
);

Ok(())
}
26 changes: 17 additions & 9 deletions pallets/torus0/src/balance.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
use polkadot_sdk::{
frame_support::dispatch::DispatchResult, polkadot_sdk_frame::prelude::OriginFor,
};

use crate::{AccountIdOf, BalanceOf};
use polkadot_sdk::frame_support::traits::{Currency, ExistenceRequirement};
use polkadot_sdk::frame_support::{dispatch::DispatchResult, ensure};

pub fn transfer_balance_multiple<T: crate::Config>(
_origin: OriginFor<T>,
_destination: AccountIdOf<T>,
_amount: BalanceOf<T>,
pub fn transfer_balance<T: crate::Config>(
key: AccountIdOf<T>,
destination: AccountIdOf<T>,
amount: BalanceOf<T>,
) -> DispatchResult {
todo!()
ensure!(amount > 0, crate::Error::<T>::InvalidAmount);

<T as crate::Config>::Currency::transfer(
&key,
&destination,
amount,
ExistenceRequirement::KeepAlive,
)
.map_err(|_| crate::Error::<T>::NotEnoughBalanceToTransfer)?;

Ok(())
}
Loading

0 comments on commit 10941fa

Please sign in to comment.