Skip to content

Commit

Permalink
Implement add, delete and rotate address of the beneficiaries
Browse files Browse the repository at this point in the history
  • Loading branch information
CaptainVincent authored and dm4 committed Jun 25, 2021
1 parent 4476faa commit c26d90a
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 10 deletions.
10 changes: 10 additions & 0 deletions docs/licensing-revenue-model/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# License Fee

Currently we charge the gas-fee as our license-fee when user executes evm/ssvm action, but when the system has no any beneficiary we still burn it.

## Sudo Permission
We need root permission to update the beneficiaries. Here we use `pallet-sudo` to help us get root permission. Below figure shows us how the evm's extrinsics add and delete beneficiary is work.

![](./updateBeneficiary.png)

You could also set up default beneficiaries by customizing chain spec ([Create a Custom Chain Spec](https://substrate.dev/docs/en/tutorials/start-a-private-network/customspec)).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 59 additions & 9 deletions frame/vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,34 @@ pub mod pallet {

/// Set the benefit address for charge licence fee
#[pallet::weight(0)]
pub fn set_beneficiacry(
pub fn add_beneficiary(
origin: OriginFor<T>,
address: H160,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
<BenefitAddr<T>>::mutate(|beneficiacry| *beneficiacry = address);
Self::deposit_event(Event::BenefitAddrSet(address));
<BenefitAddreses<T>>::insert(<BenefitCount<T>>::get(), address);
<BenefitCount<T>>::mutate(|count| *count += 1);
Self::deposit_event(Event::BenefitAddrAdded(address));
Ok(().into())
}

/// Delete the benefit address by index
#[pallet::weight(0)]
pub fn delete_beneficiary(
origin: OriginFor<T>,
index: u32,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
if <BenefitCount<T>>::get() <= index {
Self::deposit_event(Event::BenefitAddrDeleteFailed(index));
}
else {
<BenefitCount<T>>::mutate(|count| *count -= 1);
<BenefitAddreses<T>>::swap(index, <BenefitCount<T>>::get());
let address = <BenefitAddreses<T>>::get(<BenefitCount<T>>::get());
<BenefitAddreses<T>>::remove(<BenefitCount<T>>::get());
Self::deposit_event(Event::BenefitAddrDeleted(index, address));
}
Ok(().into())
}

Expand Down Expand Up @@ -350,8 +371,12 @@ pub mod pallet {
EthAddrSet((T::AccountId, H160)),
/// Ethereum Reward to miner fail
EthRewardFailed(H160),
/// Setup the etherem address for gas fee beneficiacry
BenefitAddrSet(H160),
/// Add the etherem address for charge license fee
BenefitAddrAdded(H160),
/// Delete beneficiary by index
BenefitAddrDeleted(u32, H160),
/// Delete beneficiary fail with wrong index
BenefitAddrDeleteFailed(u32),
/// Ethereum events from contracts.
Log(Log),
/// A contract has been created at given \[address\].
Expand Down Expand Up @@ -392,13 +417,15 @@ pub mod pallet {
#[pallet::genesis_config]
pub struct GenesisConfig {
pub accounts: std::collections::BTreeMap<H160, GenesisAccount>,
pub beneficiaries: Vec<H160>,
}

#[cfg(feature = "std")]
impl Default for GenesisConfig {
fn default() -> Self {
Self {
accounts: Default::default(),
beneficiaries: Default::default(),
}
}
}
Expand Down Expand Up @@ -426,16 +453,29 @@ pub mod pallet {
<AccountStorages<T>>::insert(address, index, value);
}
}
for address in &self.beneficiaries {
<BenefitAddreses<T>>::insert(<BenefitCount<T>>::get(), address);
<BenefitCount<T>>::mutate(|count| *count += 1);
}
<NextBenefitIndex<T>>::mutate(|next| *next = 0);
}
}

#[pallet::storage]
#[pallet::getter(fn eth_addr)]
pub type EthAddrOf<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, H160>;

#[pallet::storage]
#[pallet::getter(fn benefit_count)]
pub type BenefitCount<T: Config> = StorageValue<_, u32, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn next_benefit)]
pub type NextBenefitIndex<T: Config> = StorageValue<_, u32, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn benefit_addr)]
pub type BenefitAddr<T: Config> = StorageValue<_, H160, ValueQuery>;
pub type BenefitAddreses<T: Config> = StorageMap<_, Twox64Concat, u32, H160, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn account_codes)]
Expand Down Expand Up @@ -747,10 +787,20 @@ where
// that case we don't refund anything.
let refund_imbalance = C::deposit_into_existing(&account_id, refund_amount)
.unwrap_or_else(|_| C::PositiveImbalance::zero());
// merge the imbalance caused by paying the fees and refunding parts of it again.

let benefit_account = T::AddressMapping::into_account_id(<BenefitAddr<T>>::get());
C::deposit_creating(&benefit_account, corrected_fee.low_u128().unique_saturated_into());
if <BenefitCount<T>>::get() == 0 {
// merge the imbalance caused by paying the fees and refunding parts of it again.
let adjusted_paid = paid
.offset(refund_imbalance)
.map_err(|_| Error::<T>::BalanceLow)?;
OU::on_unbalanced(adjusted_paid);
}
else {
let address = <BenefitAddreses<T>>::get(<NextBenefitIndex<T>>::get() % <BenefitCount<T>>::get());
let benefit_account = T::AddressMapping::into_account_id(address);
<NextBenefitIndex<T>>::mutate(|next| *next = (*next + 1) % <BenefitCount<T>>::get());
C::deposit_creating(&benefit_account, corrected_fee.low_u128().unique_saturated_into());
}
}
Ok(())
}
Expand Down
72 changes: 71 additions & 1 deletion frame/vm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,10 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
],
}
);
let beneficiaries: Vec<H160> = vec![];

pallet_balances::GenesisConfig::<Test>::default().assimilate_storage(&mut t).unwrap();
<GenesisConfig as GenesisBuild<Test>>::assimilate_storage(&GenesisConfig { accounts }, &mut t).unwrap();
<GenesisConfig as GenesisBuild<Test>>::assimilate_storage(&GenesisConfig { accounts, beneficiaries }, &mut t).unwrap();
t.into()
}

Expand Down Expand Up @@ -247,6 +248,75 @@ fn fee_deduction() {
});
}

fn ten_units_imbalance(evm_addr: &H160) -> <<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::LiquidityInfo {
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::withdraw_fee(&evm_addr, U256::from(10)).unwrap()
}

#[test]
fn rotate_license_fee_beneficiaries() {
new_test_ext().execute_with(|| {
// Create an EVM address and the corresponding Substrate address that will be charged fees and refunded
let evm_addr = H160::from_str("1000000000000000000000000000000000000004").unwrap();
let substrate_addr = <Test as Config>::AddressMapping::into_account_id(evm_addr);

// Seed account
let _ = <Test as Config>::Currency::deposit_creating(&substrate_addr, 100);
assert_eq!(Balances::free_balance(&substrate_addr), 100);

// Burn 5 units as gas-fees
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), ten_units_imbalance(&evm_addr));
assert_eq!(Balances::free_balance(&substrate_addr), 95);

// Add 3 beneficiaries
let evm_addr_beneficiary_1 = H160::from_str("2000000000000000000000000000000000000001").unwrap();
let substrate_addr_beneficiary_1 = <Test as Config>::AddressMapping::into_account_id(evm_addr_beneficiary_1);
EVM::add_beneficiary(
Origin::root(),
evm_addr_beneficiary_1,
);
let evm_addr_beneficiary_2 = H160::from_str("2000000000000000000000000000000000000002").unwrap();
let substrate_addr_beneficiary_2 = <Test as Config>::AddressMapping::into_account_id(evm_addr_beneficiary_2);
EVM::add_beneficiary(
Origin::root(),
evm_addr_beneficiary_2,
);
let evm_addr_beneficiary_3 = H160::from_str("2000000000000000000000000000000000000003").unwrap();
let substrate_addr_beneficiary_3 = <Test as Config>::AddressMapping::into_account_id(evm_addr_beneficiary_3);
EVM::add_beneficiary(
Origin::root(),
evm_addr_beneficiary_3,
);
assert_eq!(<BenefitCount<Test>>::get(), 3);

// Charge 5 units to beneficiary_1 as license-fee
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), ten_units_imbalance(&evm_addr));
assert_eq!(Balances::free_balance(&substrate_addr), 90);
assert_eq!(Balances::free_balance(&substrate_addr_beneficiary_1), 5);

// Charge 5 units to beneficiary_2 as license-fee
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), ten_units_imbalance(&evm_addr));
assert_eq!(Balances::free_balance(&substrate_addr), 85);
assert_eq!(Balances::free_balance(&substrate_addr_beneficiary_2), 5);

// Charge 5 units to beneficiary_3 as license-fee
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), ten_units_imbalance(&evm_addr));
assert_eq!(Balances::free_balance(&substrate_addr), 80);
assert_eq!(Balances::free_balance(&substrate_addr_beneficiary_3), 5);

// Charge 5 units to beneficiary_1 as license-fee
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), ten_units_imbalance(&evm_addr));
assert_eq!(Balances::free_balance(&substrate_addr), 75);
assert_eq!(Balances::free_balance(&substrate_addr_beneficiary_1), 10);

// Delete one beneficiary with index 2
EVM::delete_beneficiary(
Origin::root(),
2,
);
assert_eq!(<BenefitCount<Test>>::get(), 2);
});
}

#[test]
fn set_eth_addr() {
new_test_ext().execute_with(|| {
Expand Down
2 changes: 2 additions & 0 deletions template/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ fn testnet_genesis(
storage: Default::default(),
}
);

GenesisConfig {
frame_system: SystemConfig {
// Add Wasm runtime to storage.
Expand Down Expand Up @@ -185,6 +186,7 @@ fn testnet_genesis(
},
pallet_vm: EVMConfig {
accounts: vm_genesis,
beneficiaries: vec![],
},
pallet_ethereum: EthereumConfig {},
pallet_dynamic_fee: Default::default(),
Expand Down

0 comments on commit c26d90a

Please sign in to comment.