difftreelog
added erc20 api for refungible tokens
in: master
7 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6322,11 +6322,14 @@
name = "pallet-refungible"
version = "0.1.1"
dependencies = [
+ "ethereum",
+ "evm-coder",
"frame-benchmarking",
"frame-support",
"frame-system",
"pallet-common",
"pallet-evm",
+ "pallet-evm-coder-substrate",
"pallet-structure",
"parity-scale-codec 3.1.5",
"scale-info",
pallets/refungible/Cargo.tomldiffbeforeafterboth1[package]2name = "pallet-refungible"3version = "0.1.1"4license = "GPLv3"5edition = "2021"67[dependencies.codec]8default-features = false9features = ['derive']10package = 'parity-scale-codec'11version = '3.1.2'1213[dependencies]14frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }15frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }16sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }17sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }18sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }19pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }20pallet-common = { default-features = false, path = '../common' }21pallet-structure = { default-features = false, path = '../structure' }22up-data-structs = { default-features = false, path = '../../primitives/data-structs' }23frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }24scale-info = { version = "2.0.1", default-features = false, features = [25 "derive",26] }27struct-versioning = { path = "../../crates/struct-versioning" }2829[features]30default = ["std"]31std = [32 "frame-support/std",33 "frame-system/std",34 "sp-runtime/std",35 "sp-std/std",36 "up-data-structs/std",37 "pallet-common/std",38 "pallet-structure/std",39 'frame-benchmarking/std',40 "pallet-evm/std",41]42runtime-benchmarks = [43 'frame-benchmarking',44 'frame-support/runtime-benchmarks',45 'frame-system/runtime-benchmarks',46]1[package]2name = "pallet-refungible"3version = "0.1.1"4license = "GPLv3"5edition = "2021"67[dependencies.codec]8default-features = false9features = ['derive']10package = 'parity-scale-codec'11version = '3.1.2'1213[dependencies]14evm-coder = { default-features = false, path = '../../crates/evm-coder' }15pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }16pallet-common = { default-features = false, path = '../common' }17pallet-structure = { default-features = false, path = '../structure' }18struct-versioning = { path = "../../crates/struct-versioning" }19up-data-structs = { default-features = false, path = '../../primitives/data-structs' }2021ethereum = { version = "0.12.0", default-features = false }22scale-info = { version = "2.0.1", default-features = false, features = ["derive",] }2324frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }25frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }26frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }27pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }28sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }29sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }30sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }3132[features]33default = ["std"]34std = [35 "ethereum/std",36 "evm-coder/std",37 'frame-benchmarking/std',38 "frame-support/std",39 "frame-system/std",40 "pallet-common/std",41 "pallet-evm/std",42 "pallet-evm-coder-substrate/std",43 "pallet-structure/std",44 "sp-runtime/std",45 "sp-std/std",46 "up-data-structs/std",47]48runtime-benchmarks = [49 'frame-benchmarking',50 'frame-support/runtime-benchmarks',51 'frame-system/runtime-benchmarks',52 'up-data-structs/runtime-benchmarks',53]pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use up_data_structs::TokenId;
-use pallet_common::erc::CommonEvmHandler;
-use pallet_evm::PrecompileHandle;
-
-use crate::{Config, RefungibleHandle};
-
-impl<T: Config> CommonEvmHandler for RefungibleHandle<T> {
- const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw");
-
- fn call(
- self,
- _handle: &mut impl PrecompileHandle,
- ) -> Option<pallet_common::erc::PrecompileResult> {
- // TODO: Implement RFT variant of ERC721
- None
- }
-}
-
-pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
-
-impl<T: Config> CommonEvmHandler for RefungibleTokenHandle<T> {
- const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungibleToken.raw");
-
- fn call(
- self,
- _handle: &mut impl PrecompileHandle,
- ) -> Option<pallet_common::erc::PrecompileResult> {
- // TODO: Implement RFT variant of ERC20
- None
- }
-}
pallets/refungible/src/erc20.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/refungible/src/erc20.rs
@@ -0,0 +1,204 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+extern crate alloc;
+use core::{
+ char::{REPLACEMENT_CHARACTER, decode_utf16},
+ convert::TryInto,
+ ops::Deref,
+};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
+use pallet_common::{
+ CommonWeightInfo,
+ erc::{CommonEvmHandler, PrecompileResult},
+};
+use pallet_evm::{account::CrossAccountId, PrecompileHandle};
+use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};
+use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
+use sp_std::vec::Vec;
+use up_data_structs::{CollectionMode, TokenId};
+
+use crate::{
+ Allowance, Balance, common::CommonWeights, Config, erc721::UniqueRFTCall, Pallet,
+ RefungibleHandle, SelfWeightOf, weights::WeightInfo, TotalSupply,
+};
+
+pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
+
+#[derive(ToLog)]
+pub enum ERC20Events {
+ Transfer {
+ #[indexed]
+ from: address,
+ #[indexed]
+ to: address,
+ value: uint256,
+ },
+ Approval {
+ #[indexed]
+ owner: address,
+ #[indexed]
+ spender: address,
+ value: uint256,
+ },
+}
+
+#[solidity_interface(name = "ERC20", events(ERC20Events))]
+impl<T: Config> RefungibleTokenHandle<T> {
+ fn name(&self) -> Result<string> {
+ Ok(decode_utf16(self.name.iter().copied())
+ .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
+ .collect::<string>())
+ }
+ fn symbol(&self) -> Result<string> {
+ Ok(string::from_utf8_lossy(&self.token_prefix).into())
+ }
+ fn total_supply(&self) -> Result<uint256> {
+ self.consume_store_reads(1)?;
+ Ok(<TotalSupply<T>>::get((self.id, self.1)).into())
+ }
+
+ fn decimals(&self) -> Result<uint8> {
+ Ok(if let CollectionMode::Fungible(decimals) = &self.mode {
+ *decimals
+ } else {
+ unreachable!()
+ })
+ }
+ fn balance_of(&self, owner: address) -> Result<uint256> {
+ self.consume_store_reads(1)?;
+ let owner = T::CrossAccountId::from_eth(owner);
+ let balance = <Balance<T>>::get((self.id, self.1, owner));
+ Ok(balance.into())
+ }
+ #[weight(<CommonWeights<T>>::transfer())]
+ fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let amount = amount.try_into().map_err(|_| "amount overflow")?;
+ let budget = self
+ .recorder
+ .weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+ <Pallet<T>>::transfer(self, &caller, &to, self.1, amount, &budget)
+ .map_err(|_| "transfer error")?;
+ Ok(true)
+ }
+ #[weight(<CommonWeights<T>>::transfer_from())]
+ fn transfer_from(
+ &mut self,
+ caller: caller,
+ from: address,
+ to: address,
+ amount: uint256,
+ ) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let from = T::CrossAccountId::from_eth(from);
+ let to = T::CrossAccountId::from_eth(to);
+ let amount = amount.try_into().map_err(|_| "amount overflow")?;
+ let budget = self
+ .recorder
+ .weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+ <Pallet<T>>::transfer_from(self, &caller, &from, &to, self.1, amount, &budget)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+ #[weight(<SelfWeightOf<T>>::approve())]
+ fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let spender = T::CrossAccountId::from_eth(spender);
+ let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+ <Pallet<T>>::set_allowance(self, &caller, &spender, self.1, amount)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+ fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+ self.consume_store_reads(1)?;
+ let owner = T::CrossAccountId::from_eth(owner);
+ let spender = T::CrossAccountId::from_eth(spender);
+
+ Ok(<Allowance<T>>::get((self.id, self.1, owner, spender)).into())
+ }
+}
+
+#[solidity_interface(name = "ERC20UniqueExtensions")]
+impl<T: Config> RefungibleTokenHandle<T> {
+ #[weight(<SelfWeightOf<T>>::burn_from())]
+ fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let from = T::CrossAccountId::from_eth(from);
+ let amount = amount.try_into().map_err(|_| "amount overflow")?;
+ let budget = self
+ .recorder
+ .weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+ <Pallet<T>>::burn_from(self, &caller, &from, self.1, amount, &budget)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+}
+
+impl<T: Config> RefungibleTokenHandle<T> {
+ pub fn into_inner(self) -> RefungibleHandle<T> {
+ self.0
+ }
+ pub fn common_mut(&mut self) -> &mut RefungibleHandle<T> {
+ &mut self.0
+ }
+}
+
+impl<T: Config> WithRecorder<T> for RefungibleTokenHandle<T> {
+ fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
+ self.0.recorder()
+ }
+ fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
+ self.0.into_recorder()
+ }
+}
+
+impl<T: Config> Deref for RefungibleTokenHandle<T> {
+ type Target = RefungibleHandle<T>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+#[solidity_interface(
+ name = "UniqueRefungibleToken",
+ is(
+ ERC20,
+ ERC20UniqueExtensions,
+ via("RefungibleHandle<T>", common_mut, UniqueRFT)
+ )
+)]
+impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}
+
+generate_stubgen!(gen_impl, UniqueRefungibleTokenCall<()>, true);
+generate_stubgen!(gen_iface, UniqueRefungibleTokenCall<()>, false);
+
+impl<T: Config> CommonEvmHandler for RefungibleTokenHandle<T>
+where
+ T::AccountId: From<[u8; 32]>,
+{
+ const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungibleToken.raw");
+
+ fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
+ call::<T, UniqueRefungibleTokenCall<T>, _, _>(handle, self)
+ }
+}
pallets/refungible/src/erc721.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/refungible/src/erc721.rs
@@ -0,0 +1,32 @@
+extern crate alloc;
+use evm_coder::{generate_stubgen, solidity_interface, types::*};
+
+use pallet_common::{CollectionHandle, erc::CollectionCall, erc::CommonEvmHandler};
+
+use pallet_evm::PrecompileHandle;
+use pallet_evm_coder_substrate::call;
+
+use crate::{Config, RefungibleHandle};
+
+#[solidity_interface(
+ name = "UniqueRFT",
+ is(via("CollectionHandle<T>", common_mut, Collection),)
+)]
+impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> {}
+
+// Not a tests, but code generators
+generate_stubgen!(gen_impl, UniqueRFTCall<()>, true);
+generate_stubgen!(gen_iface, UniqueRFTCall<()>, false);
+
+impl<T: Config> CommonEvmHandler for RefungibleHandle<T>
+where
+ T::AccountId: From<[u8; 32]>,
+{
+ const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw");
+ fn call(
+ self,
+ handle: &mut impl PrecompileHandle,
+ ) -> Option<pallet_common::erc::PrecompileResult> {
+ call::<T, UniqueRFTCall<T>, _, _>(handle, self)
+ }
+}
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -87,30 +87,31 @@
#![cfg_attr(not(feature = "std"), no_std)]
-use frame_support::{ensure, fail, BoundedVec, transactional, storage::with_transaction};
-use up_data_structs::{
- AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,
- CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,
- Property, PropertyScope, TrySetProperty, PropertyKey, PropertyValue, PropertyPermission,
- PropertyKeyPermission,
-};
-use pallet_evm::account::CrossAccountId;
-use pallet_common::{
- Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,
- CommonCollectionOperations as _,
-};
+use crate::erc20::ERC20Events;
+
+use codec::{Encode, Decode, MaxEncodedLen};
+use core::ops::Deref;
+use evm_coder::ToLog;
+use frame_support::{BoundedVec, ensure, fail, storage::with_transaction, transactional};
+use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
+use pallet_evm_coder_substrate::WithRecorder;
+use pallet_common::{CommonCollectionOperations, Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};
use pallet_structure::Pallet as PalletStructure;
+use scale_info::TypeInfo;
+use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
-use core::ops::Deref;
-use codec::{Encode, Decode, MaxEncodedLen};
-use scale_info::TypeInfo;
+use up_data_structs::{
+ AccessMode, budget::Budget, CollectionId, CreateCollectionData, CreateRefungibleExData, CustomDataLimit, mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, TokenId,
+ Property, PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TrySetProperty
+};
pub use pallet::*;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
pub mod common;
-pub mod erc;
+pub mod erc20;
+pub mod erc721;
pub mod weights;
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
@@ -271,7 +272,11 @@
pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {
self.0
}
+ pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {
+ &mut self.0
+ }
}
+
impl<T: Config> Deref for RefungibleHandle<T> {
type Target = pallet_common::CollectionHandle<T>;
@@ -280,6 +285,15 @@
}
}
+impl<T: Config> WithRecorder<T> for RefungibleHandle<T> {
+ fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
+ self.0.recorder()
+ }
+ fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
+ self.0.into_recorder()
+ }
+}
+
impl<T: Config> Pallet<T> {
/// Get number of RFT tokens in collection
pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {
@@ -460,7 +474,18 @@
<Balance<T>>::insert((collection.id, token, owner), balance);
}
<TotalSupply<T>>::insert((collection.id, token), total_supply);
- // TODO: ERC20 transfer event
+
+ <PalletEvm<T>>::deposit_log(
+ ERC20Events::Transfer {
+ from: *owner.as_eth(),
+ to: H160::default(),
+ value: amount.into(),
+ }
+ .to_log(T::EvmTokenAddressMapping::token_to_address(
+ collection.id,
+ token,
+ )),
+ );
<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
collection.id,
token,
@@ -736,7 +761,17 @@
}
}
- // TODO: ERC20 transfer event
+ <PalletEvm<T>>::deposit_log(
+ ERC20Events::Transfer {
+ from: *from.as_eth(),
+ to: *to.as_eth(),
+ value: amount.into(),
+ }
+ .to_log(T::EvmTokenAddressMapping::token_to_address(
+ collection.id,
+ token,
+ )),
+ );
<PalletCommon<T>>::deposit_event(CommonEvent::Transfer(
collection.id,
token,
@@ -889,7 +924,17 @@
continue;
}
- // TODO: ERC20 transfer event
+ <PalletEvm<T>>::deposit_log(
+ ERC20Events::Transfer {
+ from: H160::default(),
+ to: *user.as_eth(),
+ value: amount.into(),
+ }
+ .to_log(T::EvmTokenAddressMapping::token_to_address(
+ collection.id,
+ TokenId(token_id),
+ )),
+ );
<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
collection.id,
TokenId(token_id),
@@ -913,7 +958,18 @@
} else {
<Allowance<T>>::insert((collection.id, token, sender, spender), amount);
}
- // TODO: ERC20 approval event
+
+ <PalletEvm<T>>::deposit_log(
+ ERC20Events::Approval {
+ owner: *sender.as_eth(),
+ spender: *spender.as_eth(),
+ value: amount.into(),
+ }
+ .to_log(T::EvmTokenAddressMapping::token_to_address(
+ collection.id,
+ token,
+ )),
+ );
<PalletCommon<T>>::deposit_event(CommonEvent::Approved(
collection.id,
token,
runtime/common/src/dispatch.rsdiffbeforeafterboth--- a/runtime/common/src/dispatch.rs
+++ b/runtime/common/src/dispatch.rs
@@ -25,7 +25,7 @@
pub use pallet_common::dispatch::CollectionDispatch;
use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
-use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc::RefungibleTokenHandle};
+use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc20::RefungibleTokenHandle};
use up_data_structs::{
CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
};