-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add basic implementation for total_supply and balance_of calls * Integrate initial precompile-evm-balances-erc20 implementation into humanode-runtime * Add metadata erc20 methods * Add approvals related logic * Add transfer related method * Add transferFrom related method * Add event logs * Add docs to interface actions * Fix some clippy * Add docs for approves logic * Fix typos * Remove unnecesary docs * Introduce helper functions to simplify code * Some refactoring * Update features snapshot * Fix docs * Add ERC20 solidity interface * Rename erc20 metadata at frontier precompiles * Add mocked environment * Add metadata related tests * Add balance_of_works and total_supply_works tests * Add approve_works test * Rename some tests * Add transfer_works test * Add transfer_from_works test * Rename symbol Co-authored-by: MOZGIII <[email protected]> * Edit name erc20 metadata Co-authored-by: MOZGIII <[email protected]> * Introduce pallet-erc20 to store approvals data * Use approvals logic from pallet-erc20 at precompile * Use currency config instead of pallet-evm-balances config * Add erc20 related logic into pallet-erc20 * Add utility aliases * Integrate pallet-erc20 logic into precompile * Fix mock at pallet-erc20 * Fix mock at precompile * Remove redundant dependency * Rename pallet-erc20 to pallet-token-wrapper * Rename precompile-evm-balances-erc20 into precompile-token-wrapper * Integrate introduced changes into humanode-runtime * Use wrapped-token instead for token-wrapper * Rename EvmBalancesErc20 into WrappedEvmBalances * Add total_supply_works test to pallet-wrapped-token * Improve approvals related test at pallet-wrapped-token * Add transfer_works test * Add transfer_from_works test * Add fails tests for transfer from logic * Add with_storage_layer usage at pallet-wrapped-token * Fix features * Use approvals aliases * Rename pallet-wrapped-token into pallet-erc20-support * Some renaming and docs improvements * Update features snapshot * Add comments for tests at pallet-erc20-support * Improve dispatch error handling * Add more tests at precompile-erc20-support * Rename precompile-erc20-support into precompile-native-currency * Rename Erc20EvmBalancesMetadata into EvmBalancesErc20Metadata * Rename Erc20EvmBalances into EvmBalancesErc20Support * Revert "Use approvals aliases" This reverts commit 654dc65. * Properly handle transferFrom logic * Improve dispatch error handling * Add approve_overwrite_works test * Fix transfer * Add tests to check approve logic with sending full approved balance * Add approve_approval_value_more_than_balance_works test --------- Co-authored-by: MOZGIII <[email protected]>
- Loading branch information
1 parent
81af4ca
commit c58d5a3
Showing
14 changed files
with
1,859 additions
and
5 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "pallet-erc20-support" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[dependencies] | ||
codec = { workspace = true, package = "parity-scale-codec", features = ["derive"] } | ||
frame-support = { workspace = true } | ||
frame-system = { workspace = true } | ||
scale-info = { workspace = true, features = ["derive"] } | ||
|
||
[dev-dependencies] | ||
pallet-balances = { workspace = true } | ||
sp-core = { workspace = true } | ||
|
||
[features] | ||
default = ["std"] | ||
std = ["codec/std", "frame-support/std", "frame-system/std", "pallet-balances/std", "scale-info/std", "sp-core/std"] | ||
try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
//! A substrate pallet that exposes currency instance using the ERC20 interface standard.. | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
use frame_support::{ | ||
sp_runtime::{traits::CheckedSub, DispatchResult}, | ||
storage::with_storage_layer, | ||
traits::{Currency, StorageVersion}, | ||
}; | ||
pub use pallet::*; | ||
|
||
#[cfg(test)] | ||
mod mock; | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
/// Metadata of an ERC20 token. | ||
pub trait Metadata { | ||
/// Returns the name of the token. | ||
fn name() -> &'static str; | ||
|
||
/// Returns the symbol of the token. | ||
fn symbol() -> &'static str; | ||
|
||
/// Returns the decimals places of the token. | ||
fn decimals() -> u8; | ||
} | ||
|
||
/// The current storage version. | ||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); | ||
|
||
/// Utility alias for easy access to the [`Config::AccountId`]. | ||
type AccountIdOf<T, I> = <T as Config<I>>::AccountId; | ||
|
||
/// Utility alias for easy access to the [`Currency::Balance`] of the [`Config::Currency`] type. | ||
type BalanceOf<T, I> = <<T as Config<I>>::Currency as Currency<AccountIdOf<T, I>>>::Balance; | ||
|
||
// We have to temporarily allow some clippy lints. Later on we'll send patches to substrate to | ||
// fix them at their end. | ||
#[allow(clippy::missing_docs_in_private_items)] | ||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use frame_support::{pallet_prelude::*, sp_runtime::traits::MaybeDisplay, sp_std::fmt::Debug}; | ||
|
||
use super::*; | ||
|
||
#[pallet::pallet] | ||
#[pallet::storage_version(STORAGE_VERSION)] | ||
#[pallet::generate_store(pub(super) trait Store)] | ||
pub struct Pallet<T, I = ()>(_); | ||
|
||
/// Configuration trait of this pallet. | ||
#[pallet::config] | ||
pub trait Config<I: 'static = ()>: frame_system::Config { | ||
/// The user account identifier type. | ||
type AccountId: Parameter | ||
+ Member | ||
+ MaybeSerializeDeserialize | ||
+ Debug | ||
+ MaybeDisplay | ||
+ Ord | ||
+ MaxEncodedLen; | ||
|
||
/// The currency to be exposed as ERC20 token. | ||
type Currency: Currency<AccountIdOf<Self, I>>; | ||
|
||
/// Interface into ERC20 metadata implementation. | ||
type Metadata: Metadata; | ||
} | ||
|
||
/// ERC20-style approvals data. | ||
/// (Owner => Allowed => Amount). | ||
#[pallet::storage] | ||
#[pallet::getter(fn approvals)] | ||
pub type Approvals<T: Config<I>, I: 'static = ()> = StorageDoubleMap< | ||
_, | ||
Blake2_128Concat, | ||
AccountIdOf<T, I>, | ||
Blake2_128Concat, | ||
AccountIdOf<T, I>, | ||
BalanceOf<T, I>, | ||
ValueQuery, | ||
>; | ||
|
||
/// Possible errors. | ||
#[pallet::error] | ||
pub enum Error<T, I = ()> { | ||
/// Spender can't transfer tokens more than allowed. | ||
SpendMoreThanAllowed, | ||
} | ||
} | ||
|
||
impl<T: Config<I>, I: 'static> Pallet<T, I> { | ||
/// Returns the amount of tokens in existence. | ||
pub fn total_supply() -> BalanceOf<T, I> { | ||
T::Currency::total_issuance() | ||
} | ||
|
||
/// Returns the amount of tokens owned by provided account. | ||
pub fn balance_of(owner: &AccountIdOf<T, I>) -> BalanceOf<T, I> { | ||
T::Currency::total_balance(owner) | ||
} | ||
|
||
/// Returns the remaining number of tokens that spender will be allowed to spend on behalf of | ||
/// owner. This is zero by default. | ||
pub fn allowance(owner: &AccountIdOf<T, I>, spender: &AccountIdOf<T, I>) -> BalanceOf<T, I> { | ||
<Approvals<T, I>>::get(owner, spender) | ||
} | ||
|
||
/// Sets amount as the allowance of spender over the caller’s tokens. | ||
pub fn approve(owner: AccountIdOf<T, I>, spender: AccountIdOf<T, I>, amount: BalanceOf<T, I>) { | ||
<Approvals<T, I>>::insert(owner, spender, amount); | ||
} | ||
|
||
/// Moves amount tokens from the caller’s account to recipient. | ||
pub fn transfer( | ||
caller: AccountIdOf<T, I>, | ||
recipient: AccountIdOf<T, I>, | ||
amount: BalanceOf<T, I>, | ||
) -> DispatchResult { | ||
with_storage_layer(move || { | ||
T::Currency::transfer( | ||
&caller, | ||
&recipient, | ||
amount, | ||
frame_support::traits::ExistenceRequirement::AllowDeath, | ||
)?; | ||
|
||
Ok(()) | ||
}) | ||
} | ||
|
||
/// Moves amount tokens from sender to recipient using the allowance mechanism, | ||
/// amount is then deducted from the caller’s allowance. | ||
pub fn transfer_from( | ||
caller: AccountIdOf<T, I>, | ||
sender: AccountIdOf<T, I>, | ||
recipient: AccountIdOf<T, I>, | ||
amount: BalanceOf<T, I>, | ||
) -> DispatchResult { | ||
with_storage_layer(move || { | ||
<Approvals<T, I>>::mutate(sender.clone(), caller, |entry| { | ||
// Remove "value" from allowed, exit if underflow. | ||
let allowed = entry | ||
.checked_sub(&amount) | ||
.ok_or(Error::<T, I>::SpendMoreThanAllowed)?; | ||
|
||
// Update allowed value. | ||
*entry = allowed; | ||
|
||
Ok::<(), Error<T, I>>(()) | ||
})?; | ||
|
||
T::Currency::transfer( | ||
&sender, | ||
&recipient, | ||
amount, | ||
frame_support::traits::ExistenceRequirement::AllowDeath, | ||
)?; | ||
|
||
Ok(()) | ||
}) | ||
} | ||
} |
Oops, something went wrong.