1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use crate::{BalanceOf, Config, Error};
use frame_support::{dispatch::DispatchResult, sp_runtime::traits::Zero};
use t3rn_primitives::{
    account_manager::{AccountManager, Outcome, RequestCharge},
    claimable::{BenefitSource, CircuitRole},
    contracts_registry::{AuthorInfo, KindValidator},
    threevm::{ModuleOperations, Remunerated},
};

const LOG_TARGET: &str = "3vm::remuneration";

pub(crate) fn try_remunerate<T: Config, Module: ModuleOperations<T, BalanceOf<T>>>(
    payee: &T::AccountId,
    module: &Module,
) -> Result<Remunerated<T::Hash>, sp_runtime::DispatchError> {
    if let Some(author) = module.get_author() {
        let amount = author.fees_per_single_use.unwrap_or_default();
        handle_remuneration(payee, module, author, amount)
    } else {
        Ok(Remunerated::default())
    }
}

pub(crate) fn try_remunerate_exact<T: Config, Module: ModuleOperations<T, BalanceOf<T>>>(
    payee: &T::AccountId,
    amount: BalanceOf<T>,
    module: &Module,
) -> Result<Remunerated<T::Hash>, sp_runtime::DispatchError> {
    if let Some(author) = module.get_author() {
        handle_remuneration(payee, module, author, amount)
    } else {
        Ok(Remunerated::default())
    }
}

pub(crate) fn try_finalize<T: Config>(ledger_id: T::Hash, outcome: Outcome) -> DispatchResult {
    T::AccountManager::finalize(ledger_id, outcome, None, Option::<BalanceOf<T>>::None)
}

fn handle_remuneration<T: Config, Module: ModuleOperations<T, BalanceOf<T>>>(
    payee: &T::AccountId,
    module: &Module,
    author: &AuthorInfo<T::AccountId, BalanceOf<T>>,
    amount: BalanceOf<T>,
) -> Result<Remunerated<T::Hash>, sp_runtime::DispatchError> {
    if amount > BalanceOf::<T>::zero() {
        let kind = module.get_type();
        log::trace!(
            target: LOG_TARGET,
            "Checking module {:?}, can remunerate to author: {:?}",
            kind,
            author.clone()
        );
        if kind.can_remunerate() {
            let next_charge_id = T::AccountManager::bump_contracts_registry_nonce()?;
            T::AccountManager::deposit(
                next_charge_id,
                RequestCharge {
                    payee: payee.clone(),
                    offered_reward: amount,
                    charge_fee: Zero::zero(),
                    source: BenefitSource::TrafficRewards,
                    role: CircuitRole::ContractAuthor,
                    recipient: Some(author.account.clone()),
                    maybe_asset_id: None,
                },
            )?;

            Ok(Remunerated::<T::Hash>::new(Some(next_charge_id)))
        } else {
            Err(Error::<T>::ContractCannotRemunerate.into())
        }
    } else {
        Ok(Remunerated::<T::Hash>::default())
    }
}