difftreelog
style reformat code
in: master
3 files changed
pallets/nft/Cargo.tomldiffbeforeafterboth--- a/pallets/nft/Cargo.toml
+++ b/pallets/nft/Cargo.toml
@@ -42,7 +42,7 @@
rlp = { default-features = false, version = "0.5.0" }
evm-coder = { default-features = false, path = "../../crates/evm-coder" }
-primitive-types = { version = "0.9.0", default-features = false }
+primitive-types = { version = "0.9.0", default-features = false, features = ["serde_no_std"] }
hex-literal = "0.3.1"
pallets/nft/src/eth/account.rsdiffbeforeafterboth--- a/pallets/nft/src/eth/account.rs
+++ b/pallets/nft/src/eth/account.rs
@@ -1,6 +1,7 @@
use crate::Config;
use codec::{Encode, EncodeLike, Decode};
-use sp_core::{H160, H256, crypto::AccountId32};
+use sp_core::crypto::AccountId32;
+use primitive_types::H160;
use core::cmp::Ordering;
use serde::{Serialize, Deserialize};
use pallet_evm::AddressMapping;
pallets/nft/src/eth/mod.rsdiffbeforeafterboth1pub mod account;2use account::CrossAccountId;3pub mod abi;4use abi::{AbiReader, AbiWriter};5pub mod log;67use sp_std::borrow::ToOwned;8use sp_std::vec::Vec;9use sp_std::convert::TryInto;1011use codec::{Decode, Encode};12use pallet_evm::{AddressMapping, PrecompileLog, PrecompileOutput, ExitReason, ExitRevert, ExitSucceed};13use sp_core::{H160, H256};14use frame_support::storage::{StorageMap, StorageDoubleMap};1516use crate::{Allowances, NftItemList, Module, Balance, Config, CollectionById, CollectionHandle, CollectionId, CollectionMode};1718pub struct NftErcSupport<T: Config>(core::marker::PhantomData<T>);1920// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection21// TODO: Unhardcode prefix22const ETH_ACCOUNT_PREFIX: [u8; 16] = [0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e];2324fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {25 if ð[0..16] != ETH_ACCOUNT_PREFIX {26 return None;27 }28 let mut id_bytes = [0; 4];29 id_bytes.copy_from_slice(ð[16..20]);30 Some(u32::from_be_bytes(id_bytes))31}32pub fn collection_id_to_address(id: u32) -> H160 {33 let mut out = [0; 20];34 out[0..16].copy_from_slice(Ð_ACCOUNT_PREFIX);35 out[16..20].copy_from_slice(&u32::to_be_bytes(id));36 H160(out)37}3839fn call_internal<T: Config>(40 collection: &mut CollectionHandle<T>,41 caller: caller,42 method_id: u32,43 mut input: AbiReader,44 value: U256,45) -> Result<Option<AbiWriter>, evm_coder::abi::StringError> {46 match collection.mode.clone() {47 CollectionMode::Fungible(_) => {48 #[cfg(feature = "std")]49 {50 println!("Parse fungible call {:x}", method_id);51 }52 let call = match UniqueFungibleCall::parse(method_id, &mut input)? {53 Some(v) => v,54 None => {55 #[cfg(feature = "std")]56 {57 println!("Method not found");58 }59 return Ok(None);60 }61 };62 #[cfg(feature = "std")]63 {64 dbg!(&call);65 }66 Ok(Some(<CollectionHandle<T> as UniqueFungible>::call(67 collection,68 Msg {69 call,70 caller,71 value,72 },73 )?))74 }75 CollectionMode::NFT => {76 let call = match UniqueNFTCall::parse(method_id, &mut input)? {77 Some(v) => v,78 None => return Ok(None),79 };80 Ok(Some(<CollectionHandle<T> as UniqueNFT>::call(81 collection,82 Msg {83 call,84 caller,85 value,86 },87 )?))88 }89 _ => {90 return Err(StringError::from(91 "erc calls only supported to fungible and nft collections for now",92 )93 .into())94 }95 }96}9798impl<T: Config> pallet_evm::OnMethodCall<T> for NftErcSupport<T> {99 fn is_reserved(target: &H160) -> bool {100 map_eth_to_id(target).is_some()101 }102 fn is_used(target: &H160) -> bool {103 map_eth_to_id(target)104 .map(<CollectionById<T>>::contains_key)105 .unwrap_or(false)106 }107 fn get_code(target: &H160) -> Option<Vec<u8>> {108 map_eth_to_id(&target)109 .and_then(<CollectionById<T>>::get)110 .map(|collection| {111 match collection.mode {112 CollectionMode::NFT => include_bytes!("stubs/ERC721.bin") as &[u8],113 CollectionMode::Fungible(_) => include_bytes!("stubs/ERC20.bin") as &[u8],114 CollectionMode::ReFungible => include_bytes!("stubs/ERC1633.bin") as &[u8],115 CollectionMode::Invalid => include_bytes!("stubs/Invalid.bin") as &[u8],116 }.to_owned()117 })118 }119 fn call(120 source: &H160,121 target: &H160,122 gas_limit: u64,123 input: &[u8],124 value: U256,125 ) -> Option<PrecompileOutput> {126 let mut collection = map_eth_to_id(&target)127 .and_then(|id| <CollectionHandle<T>>::get_with_gas_limit(id, gas_limit))?;128 let (method_id, input) = AbiReader::new_call(input).unwrap();129 let result = call_internal(&mut collection, *source, method_id, input, value);130 let cost = gas_limit - collection.gas_left();131 let logs = collection.logs.retrieve_logs();132 match result {133 Ok(Some(v)) => Some(PrecompileOutput {134 exit_status: ExitReason::Succeed(ExitSucceed::Returned),135 cost,136 logs,137 output: v.finish(),138 }),139 Ok(None) => None,140 Err(e) => Some(PrecompileOutput {141 exit_status: ExitReason::Revert(ExitRevert::Reverted),142 cost: 0,143 logs: Default::default(),144 output: AbiWriter::from(e).finish(),145 }),146 }147 }148}149150// TODO: This function is slow, and output can be memoized151pub fn generate_transaction(collection_id: u32, chain_id: u64) -> ethereum::Transaction {152 let contract = collection_id_to_address(collection_id);153154 // FIXME: Can be done on wasm runtime with https://github.com/paritytech/substrate/pull/8728155 #[cfg(feature = "std")]156 {157 let signed = ethereum_tx_sign::RawTransaction {158 nonce: 0.into(),159 to: Some(contract.0.into()),160 value: 0.into(),161 gas_price: 0.into(),162 gas: 0.into(),163 // zero selector, this transaction always have same sender, so all data should be acquired from logs164 data: Vec::from([0, 0, 0, 0]),165 }.sign(166 // TODO: move to pallet config167 // 0xF70631E55faff9f3FD3681545aa6c724226a3853168 // 9dbaef9b3ebc00e53f67c6a77bcfbf2c4f2aebe4d70d94af4f2df01744b7a91a169 &hex_literal::hex!("9dbaef9b3ebc00e53f67c6a77bcfbf2c4f2aebe4d70d94af4f2df01744b7a91a").into(),170 &chain_id171 );172 rlp::decode::<ethereum::Transaction>(&signed).expect("transaction is just created, it can't be broken")173 }174 #[cfg(not(feature = "std"))]175 {176 panic!("transaction generation not yet supported by wasm runtime")177 }178}1pub mod account;2pub mod erc;3mod erc_impl;4pub mod log;5pub mod sponsoring;67use evm_coder::abi::AbiWriter;8use evm_coder::abi::StringError;9use sp_std::prelude::*;10use sp_std::borrow::ToOwned;11use sp_std::vec::Vec;1213use pallet_evm::{PrecompileOutput, ExitReason, ExitRevert, ExitSucceed};14use sp_core::{H160, U256};15use frame_support::storage::StorageMap;1617use crate::{Config, CollectionById, CollectionHandle, CollectionId, CollectionMode};1819use erc::{UniqueFungible, UniqueFungibleCall, UniqueNFT, UniqueNFTCall};20use evm_coder::{types::*, abi::AbiReader};2122pub struct NftErcSupport<T: Config>(core::marker::PhantomData<T>);2324// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection25// TODO: Unhardcode prefix26const ETH_ACCOUNT_PREFIX: [u8; 16] = [27 0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,28];2930fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {31 if ð[0..16] != ETH_ACCOUNT_PREFIX {32 return None;33 }34 let mut id_bytes = [0; 4];35 id_bytes.copy_from_slice(ð[16..20]);36 Some(u32::from_be_bytes(id_bytes))37}38pub fn collection_id_to_address(id: u32) -> H160 {39 let mut out = [0; 20];40 out[0..16].copy_from_slice(Ð_ACCOUNT_PREFIX);41 out[16..20].copy_from_slice(&u32::to_be_bytes(id));42 H160(out)43}4445fn call_internal<T: Config>(46 collection: &mut CollectionHandle<T>,47 caller: caller,48 method_id: u32,49 mut input: AbiReader,50 value: U256,51) -> Result<Option<AbiWriter>, evm_coder::abi::StringError> {52 match collection.mode.clone() {53 CollectionMode::Fungible(_) => {54 #[cfg(feature = "std")]55 {56 println!("Parse fungible call {:x}", method_id);57 }58 let call = match UniqueFungibleCall::parse(method_id, &mut input)? {59 Some(v) => v,60 None => {61 #[cfg(feature = "std")]62 {63 println!("Method not found");64 }65 return Ok(None);66 }67 };68 #[cfg(feature = "std")]69 {70 dbg!(&call);71 }72 Ok(Some(<CollectionHandle<T> as UniqueFungible>::call(73 collection,74 Msg {75 call,76 caller,77 value,78 },79 )?))80 }81 CollectionMode::NFT => {82 let call = match UniqueNFTCall::parse(method_id, &mut input)? {83 Some(v) => v,84 None => return Ok(None),85 };86 Ok(Some(<CollectionHandle<T> as UniqueNFT>::call(87 collection,88 Msg {89 call,90 caller,91 value,92 },93 )?))94 }95 _ => {96 return Err(StringError::from(97 "erc calls only supported to fungible and nft collections for now",98 )99 .into())100 }101 }102}103104impl<T: Config> pallet_evm::OnMethodCall<T> for NftErcSupport<T> {105 fn is_reserved(target: &H160) -> bool {106 map_eth_to_id(target).is_some()107 }108 fn is_used(target: &H160) -> bool {109 map_eth_to_id(target)110 .map(<CollectionById<T>>::contains_key)111 .unwrap_or(false)112 }113 fn get_code(target: &H160) -> Option<Vec<u8>> {114 map_eth_to_id(&target)115 .and_then(<CollectionById<T>>::get)116 .map(|collection| {117 match collection.mode {118 CollectionMode::NFT => include_bytes!("stubs/ERC721.bin") as &[u8],119 CollectionMode::Fungible(_) => include_bytes!("stubs/ERC20.bin") as &[u8],120 CollectionMode::ReFungible => include_bytes!("stubs/ERC1633.bin") as &[u8],121 CollectionMode::Invalid => include_bytes!("stubs/Invalid.bin") as &[u8],122 }123 .to_owned()124 })125 }126 fn call(127 source: &H160,128 target: &H160,129 gas_limit: u64,130 input: &[u8],131 value: U256,132 ) -> Option<PrecompileOutput> {133 let mut collection = map_eth_to_id(&target)134 .and_then(|id| <CollectionHandle<T>>::get_with_gas_limit(id, gas_limit))?;135 let (method_id, input) = AbiReader::new_call(input).unwrap();136 let result = call_internal(&mut collection, *source, method_id, input, value);137 let cost = gas_limit - collection.gas_left();138 let logs = collection.logs.retrieve_logs();139 match result {140 Ok(Some(v)) => Some(PrecompileOutput {141 exit_status: ExitReason::Succeed(ExitSucceed::Returned),142 cost,143 logs,144 output: v.finish(),145 }),146 Ok(None) => None,147 Err(e) => Some(PrecompileOutput {148 exit_status: ExitReason::Revert(ExitRevert::Reverted),149 cost: 0,150 logs: Default::default(),151 output: AbiWriter::from(e).finish(),152 }),153 }154 }155}156157// TODO: This function is slow, and output can be memoized158pub fn generate_transaction(collection_id: u32, chain_id: u64) -> ethereum::Transaction {159 let contract = collection_id_to_address(collection_id);160161 // FIXME: Can be done on wasm runtime with https://github.com/paritytech/substrate/pull/8728162 #[cfg(feature = "std")]163 {164 let signed = ethereum_tx_sign::RawTransaction {165 nonce: 0.into(),166 to: Some(contract.0.into()),167 value: 0.into(),168 gas_price: 0.into(),169 gas: 0.into(),170 // zero selector, this transaction always have same sender, so all data should be acquired from logs171 data: Vec::from([0, 0, 0, 0]),172 }173 .sign(174 // TODO: move to pallet config175 // 0xF70631E55faff9f3FD3681545aa6c724226a3853176 // 9dbaef9b3ebc00e53f67c6a77bcfbf2c4f2aebe4d70d94af4f2df01744b7a91a177 &hex_literal::hex!("9dbaef9b3ebc00e53f67c6a77bcfbf2c4f2aebe4d70d94af4f2df01744b7a91a")178 .into(),179 &chain_id,180 );181 rlp::decode::<ethereum::Transaction>(&signed)182 .expect("transaction is just created, it can't be broken")183 }184 #[cfg(not(feature = "std"))]185 {186 panic!("transaction generation not yet supported by wasm runtime")187 }188}