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

Commit

Permalink
Support to reward activity
Browse files Browse the repository at this point in the history
  • Loading branch information
kikakkz committed Dec 7, 2023
1 parent 92a9f39 commit a85d030
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 10 deletions.
8 changes: 7 additions & 1 deletion activity/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl Contract for Activity {
Ok(result)
}
Message::Finalize { activity_id } => {
self.finalize(activity_id).await?;
self._finalize(activity_id).await?;
let dest =
Destination::Subscribers(ChannelName::from(SUBSCRIPTION_CHANNEL.to_vec()));
Ok(ExecutionResult::default()
Expand Down Expand Up @@ -266,6 +266,7 @@ impl Activity {
let activity_id = self.create_activity(owner, params.clone()).await?;
let call = review::ApplicationCall::SubmitActivity {
activity_id,
activity_host: owner,
budget_amount: params.budget_amount,
};
self.call_application(true, Self::review_app_id()?, &call, vec![])
Expand All @@ -280,4 +281,9 @@ impl Activity {
.await?;
Ok(approved)
}

async fn _finalize(&mut self, activity_id: u64) -> Result<(), ActivityError> {
self.finalize(activity_id).await?;
Ok(())
}
}
74 changes: 73 additions & 1 deletion foundation/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use self::state::Foundation;
use async_trait::async_trait;
use foundation::{ApplicationCall, Message, Operation, RewardType};
use linera_sdk::{
base::{ChannelName, Destination, SessionId, WithContractAbi},
base::{Amount, ChannelName, Destination, Owner, SessionId, WithContractAbi},
contract::system_api,
ApplicationCallResult, CalleeContext, Contract, ExecutionResult, MessageContext,
OperationContext, SessionCallResult, ViewStateStorage,
Expand Down Expand Up @@ -148,6 +148,34 @@ impl Contract for Foundation {
Ok(ExecutionResult::default()
.with_authenticated_message(dest, Message::Transfer { from, to, amount }))
}
Message::ActivityRewards {
activity_id,
winner_user,
voter_users,
reward_amount,
voter_reward_percent,
} => {
self._activity_rewards(
activity_id,
winner_user,
voter_users.clone(),
reward_amount,
voter_reward_percent,
)
.await?;
let dest =
Destination::Subscribers(ChannelName::from(SUBSCRIPTION_CHANNEL.to_vec()));
Ok(ExecutionResult::default().with_authenticated_message(
dest,
Message::ActivityRewards {
activity_id,
winner_user,
voter_users,
reward_amount,
voter_reward_percent,
},
))
}
}
}

Expand Down Expand Up @@ -199,6 +227,22 @@ impl Contract for Foundation {
result.value = balance;
return Ok(result);
}
ApplicationCall::ActivityRewards {
activity_id,
winner_user,
voter_users,
reward_amount,
voter_reward_percent,
} => ExecutionResult::default().with_authenticated_message(
system_api::current_application_id().creation.chain_id,
Message::ActivityRewards {
activity_id,
winner_user,
voter_users,
reward_amount,
voter_reward_percent,
},
),
};
let mut result = ApplicationCallResult::default();
result.execution_result = execution_result;
Expand All @@ -217,6 +261,28 @@ impl Contract for Foundation {
}
}

impl Foundation {
async fn _activity_rewards(
&mut self,
activity_id: u64,
winner_user: Owner,
voter_users: Vec<Owner>,
reward_amount: Amount,
voter_reward_percent: u8,
) -> Result<(), ContractError> {
self.spend_activity_funds(activity_id, reward_amount)
.await?;
self.distribute_activity_rewards(
winner_user,
voter_users,
reward_amount,
voter_reward_percent,
)
.await?;
Ok(())
}
}

/// An error that can occur during the contract execution.
#[derive(Debug, Error)]
pub enum ContractError {
Expand All @@ -228,6 +294,9 @@ pub enum ContractError {
#[error("Failed to deserialize JSON string")]
JsonError(#[from] serde_json::Error),

#[error("View error")]
ViewError(#[from] linera_views::views::ViewError),

// Add more error variants here.
#[error(transparent)]
StateError(#[from] state::StateError),
Expand All @@ -237,4 +306,7 @@ pub enum ContractError {

#[error("Cross-application sessions not supported")]
SessionsNotSupported,

#[error("Insufficient funds")]
InsufficientFunds,
}
26 changes: 20 additions & 6 deletions foundation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,22 @@ pub enum ApplicationCall {
amount: Amount,
},
Reward {
// Review: sender is the reward user
// Author: sender is not the reward user
// Activity: sender is not the reward user
// Review: sender is the reward user (the reviewer)
// Author: sender is not the reward user but the reviewer
// Activity: sender must be the activity host
reward_user: Option<Owner>,
reward_type: RewardType,
// For activity we have amount, for other type amount is determined by foundation
amount: Option<Amount>,
activity_id: Option<u64>,
},
ActivityRewards {
activity_id: u64,
winner_user: Owner,
voter_users: Vec<Owner>,
reward_amount: Amount,
voter_reward_percent: u8,
},
Lock {
activity_id: u64,
amount: Amount,
Expand Down Expand Up @@ -92,15 +99,22 @@ pub enum Message {
amount: Amount,
},
Reward {
// Review: sender is the reward user
// Author: sender is not the reward user
// Activity: sender is not the reward user
// Review: sender is the reward user (the reviewer)
// Author: sender is not the reward user but the reviewer
// Activity: sender must be the activity host
reward_user: Option<Owner>,
reward_type: RewardType,
// For activity we have amount, for other type amount is determined by foundation
amount: Option<Amount>,
activity_id: Option<u64>,
},
ActivityRewards {
activity_id: u64,
winner_user: Owner,
voter_users: Vec<Owner>,
reward_amount: Amount,
voter_reward_percent: u8,
},
Lock {
activity_id: u64,
amount: Amount,
Expand Down
76 changes: 76 additions & 0 deletions foundation/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,79 @@ impl Foundation {
.unwrap()
.unwrap_or_default())
}

pub(crate) async fn spend_activity_funds(
&mut self,
activity_id: u64,
reward_amount: Amount,
) -> Result<(), StateError> {
match self.activity_lock_funds.get(&activity_id).await {
Ok(Some(funds)) => {
if funds < reward_amount {
return Err(StateError::InsufficientBalance);
} else {
self.activity_lock_funds
.insert(&activity_id, funds.saturating_sub(reward_amount))?;
Ok(())
}
}
Ok(None) => return Err(StateError::InvalidActivityFunds),
Err(err) => return Err(StateError::ViewError(err)),
}
}

pub(crate) async fn distribute_activity_rewards(
&mut self,
winner_user: Owner,
voter_users: Vec<Owner>,
reward_amount: Amount,
voter_reward_percent: u8,
) -> Result<(), StateError> {
if voter_reward_percent > 100 {
return Err(StateError::InvalidPercent);
}
let balance = match self.user_balances.get(&winner_user).await {
Ok(Some(balance)) => balance,
_ => Amount::ZERO,
};
let winner_amount = Amount::from_tokens(
reward_amount
.saturating_mul(100 - voter_reward_percent as u128)
.saturating_div(Amount::from_atto(100)),
);
let balance = balance.saturating_add(winner_amount);
self.user_balances.insert(&winner_user, balance)?;

let mut user_balance_total = Amount::ZERO;
for user in voter_users.clone().into_iter() {
let balance = match self.user_balances.get(&user).await {
Ok(Some(balance)) => balance,
_ => Amount::ZERO,
};
user_balance_total = user_balance_total.saturating_add(balance);
}

let voter_amount = reward_amount.saturating_sub(winner_amount);
for user in voter_users.into_iter() {
let balance = match self.user_balances.get(&user).await {
Ok(Some(balance)) => balance,
_ => Amount::ZERO,
};
if balance == Amount::ZERO {
continue;
}
let percent = balance
.saturating_mul(100 as u128)
.saturating_div(user_balance_total);
let balance = balance.saturating_add(Amount::from_tokens(
voter_amount
.saturating_div(Amount::from_atto(100))
.saturating_mul(percent),
));
self.user_balances.insert(&user, balance)?;
}
Ok(())
}
}

#[derive(Debug, Error)]
Expand All @@ -260,4 +333,7 @@ pub enum StateError {

#[error("Invalid account")]
InvalidAccount,

#[error("Invalid activity funds")]
InvalidActivityFunds,
}
11 changes: 9 additions & 2 deletions review/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,18 @@ impl Contract for Review {
}
Message::SubmitActivity {
activity_id,
activity_host,
budget_amount,
} => {
self._submit_activity(activity_id, budget_amount).await?;
self._submit_activity(activity_id, activity_host, budget_amount)
.await?;
let dest =
Destination::Subscribers(ChannelName::from(SUBSCRIPTION_CHANNEL.to_vec()));
Ok(ExecutionResult::default().with_authenticated_message(
dest,
Message::SubmitActivity {
activity_id,
activity_host,
budget_amount,
},
))
Expand Down Expand Up @@ -531,13 +534,15 @@ impl Contract for Review {
}
ApplicationCall::SubmitActivity {
activity_id,
activity_host,
budget_amount,
} => {
let mut result = ApplicationCallResult::default();
result.execution_result = ExecutionResult::default().with_authenticated_message(
system_api::current_application_id().creation.chain_id,
Message::SubmitActivity {
activity_id,
activity_host,
budget_amount,
},
);
Expand Down Expand Up @@ -994,9 +999,11 @@ impl Review {
async fn _submit_activity(
&mut self,
activity_id: u64,
activity_host: Owner,
budget_amount: Amount,
) -> Result<(), ContractError> {
self.submit_activity(activity_id, budget_amount).await?;
self.submit_activity(activity_id, activity_host, budget_amount)
.await?;
Ok(())
}

Expand Down
3 changes: 3 additions & 0 deletions review/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub struct Asset {
#[derive(Debug, Deserialize, Serialize, Clone, SimpleObject, Eq, PartialEq)]
pub struct Activity {
pub activity_id: u64,
pub activity_host: Owner,
pub budget_amount: Amount,
pub approved: u16,
pub rejected: u16,
Expand Down Expand Up @@ -221,6 +222,7 @@ pub enum Message {
},
SubmitActivity {
activity_id: u64,
activity_host: Owner,
budget_amount: Amount,
},
ApproveActivity {
Expand All @@ -242,6 +244,7 @@ pub enum ApplicationCall {
},
SubmitActivity {
activity_id: u64,
activity_host: Owner,
budget_amount: Amount,
},
ActivityApproved {
Expand Down
2 changes: 2 additions & 0 deletions review/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ impl Review {
pub(crate) async fn submit_activity(
&mut self,
activity_id: u64,
activity_host: Owner,
budget_amount: Amount,
) -> Result<(), StateError> {
match self.activity_applications.get(&activity_id).await {
Expand All @@ -473,6 +474,7 @@ impl Review {
&activity_id,
Activity {
activity_id,
activity_host,
budget_amount,
approved: 0,
rejected: 0,
Expand Down

0 comments on commit a85d030

Please sign in to comment.