-
Notifications
You must be signed in to change notification settings - Fork 583
/
Copy pathevm.rs
205 lines (184 loc) · 8.21 KB
/
evm.rs
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// This file is part of Acala.
// Copyright (C) 2020-2021 Acala Foundation.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program 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.
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{
currency::{CurrencyId, CurrencyIdType, DexShareType},
Balance, BlockNumber, Nonce,
};
use codec::{Decode, Encode};
use core::ops::Range;
use module_evm_utiltity::{
ethereum::{Log, TransactionAction},
evm::ExitReason,
};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_core::{H160, H256, U256};
use sp_runtime::RuntimeDebug;
use sp_std::vec::Vec;
/// Evm Address.
pub type EvmAddress = sp_core::H160;
#[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
/// External input from the transaction.
pub struct Vicinity {
/// Current transaction gas price.
pub gas_price: U256,
/// Origin of the transaction.
pub origin: EvmAddress,
}
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ExecutionInfo<T> {
pub exit_reason: ExitReason,
pub value: T,
pub used_gas: U256,
pub used_storage: i32,
pub logs: Vec<Log>,
}
pub type CallInfo = ExecutionInfo<Vec<u8>>;
pub type CreateInfo = ExecutionInfo<H160>;
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Erc20Info {
pub address: EvmAddress,
pub name: Vec<u8>,
pub symbol: Vec<u8>,
pub decimals: u8,
}
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct EstimateResourcesRequest {
/// From
pub from: Option<H160>,
/// To
pub to: Option<H160>,
/// Gas Limit
pub gas_limit: Option<u64>,
/// Storage Limit
pub storage_limit: Option<u32>,
/// Value
pub value: Option<Balance>,
/// Data
pub data: Option<Vec<u8>>,
}
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct EthereumTransactionMessage {
pub nonce: Nonce,
pub tip: Balance,
pub gas_limit: u64,
pub storage_limit: u32,
pub action: TransactionAction,
pub value: Balance,
pub input: Vec<u8>,
pub chain_id: u64,
pub genesis: H256,
pub valid_until: BlockNumber,
}
/// Ethereum precompiles
/// 0 - 0x0000000000000000000000000000000000000400
/// Acala precompiles
/// 0x0000000000000000000000000000000000000400 - 0x0000000000000000000000000000000000000800
pub const PRECOMPILE_ADDRESS_START: EvmAddress = H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]);
/// Predeployed system contracts (except Mirrored ERC20)
/// 0x0000000000000000000000000000000000000800 - 0x0000000000000000000000000000000000001000
pub const PREDEPLOY_ADDRESS_START: EvmAddress = H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0]);
pub const MIRRORED_TOKENS_ADDRESS_START: EvmAddress =
H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
pub const MIRRORED_NFT_ADDRESS_START: u64 = 0x2000000;
/// System contract address prefix
pub const SYSTEM_CONTRACT_ADDRESS_PREFIX: [u8; 9] = [0u8; 9];
#[rustfmt::skip]
/// CurrencyId to H160([u8; 20]) bit encoding rule.
///
/// Type occupies 1 byte, and data occupies 4 bytes(less than 4 bytes, right justified).
///
/// 0x0000000000000000000000000000000000000000
/// 0 1 2 3 4 5 6 7 8 910111213141516171819 index
/// ^^^^^^^^^^^^^^^^^^ System contract address prefix
/// ^^ CurrencyId Type: 1-Token 2-DexShare 3-StableAsset
/// 4-LiquidCroadloan
/// 5-ForeignAsset(ignore Erc20, without the prefix of system contracts)
/// ^^ CurrencyId Type is 1-Token, Token
/// ^^ CurrencyId Type is 2-DexShare, DexShare Left Type:
/// 0-Token 1-Erc20 2-LiquidCroadloan 3-ForeignAsset
/// ^^^^^^^^ CurrencyId Type is 2-DexShare, DexShare left field
/// ^^ CurrencyId Type is 2-DexShare, DexShare Right Type:
/// the same as DexShare Left Type
/// ^^^^^^^^ CurrencyId Type is 2-DexShare, DexShare right field
/// ^^^^^^^^ CurrencyId Type is 3-StableAsset, StableAssetPoolId
/// ^^^^^^^^ CurrencyId Type is 4-LiquidCroadloan, Lease
/// ^^^^ CurrencyId Type is 5-ForeignAsset, ForeignAssetId
/// Check if the given `address` is a system contract.
///
/// It's system contract if the address starts with SYSTEM_CONTRACT_ADDRESS_PREFIX.
pub fn is_system_contract(address: EvmAddress) -> bool {
address.as_bytes().starts_with(&SYSTEM_CONTRACT_ADDRESS_PREFIX)
}
pub fn is_acala_precompile(address: EvmAddress) -> bool {
address >= PRECOMPILE_ADDRESS_START && address < PREDEPLOY_ADDRESS_START
}
pub fn is_mirrored_tokens_address_prefix(address: EvmAddress) -> bool {
is_system_contract(address) && CurrencyIdType::try_from(address.as_bytes()[H160_POSITION_CURRENCY_ID_TYPE]).is_ok()
}
pub const H160_POSITION_CURRENCY_ID_TYPE: usize = 9;
pub const H160_POSITION_TOKEN: usize = 19;
pub const H160_POSITION_TOKEN_TYPE: usize = 10;
pub const H160_POSITION_DEXSHARE_LEFT_TYPE: usize = 10;
pub const H160_POSITION_DEXSHARE_LEFT_FIELD: Range<usize> = 11..15;
pub const H160_POSITION_DEXSHARE_RIGHT_TYPE: usize = 15;
pub const H160_POSITION_DEXSHARE_RIGHT_FIELD: Range<usize> = 16..20;
pub const H160_POSITION_STABLE_ASSET: Range<usize> = 16..20;
pub const H160_POSITION_LIQUID_CROADLOAN: Range<usize> = 16..20;
pub const H160_POSITION_FOREIGN_ASSET: Range<usize> = 18..20;
/// Generate the EvmAddress from CurrencyId so that evm contracts can call the erc20 contract.
/// NOTE: Can not be used directly, need to check the erc20 is mapped.
impl TryFrom<CurrencyId> for EvmAddress {
type Error = ();
fn try_from(val: CurrencyId) -> Result<Self, Self::Error> {
let mut address = [0u8; 20];
match val {
CurrencyId::Token(token) => {
address[H160_POSITION_CURRENCY_ID_TYPE] = CurrencyIdType::Token.into();
address[H160_POSITION_TOKEN] = token.into();
}
CurrencyId::DexShare(left, right) => {
let left_field: u32 = left.into();
let right_field: u32 = right.into();
address[H160_POSITION_CURRENCY_ID_TYPE] = CurrencyIdType::DexShare.into();
address[H160_POSITION_DEXSHARE_LEFT_TYPE] = Into::<DexShareType>::into(left).into();
address[H160_POSITION_DEXSHARE_LEFT_FIELD].copy_from_slice(&left_field.to_be_bytes());
address[H160_POSITION_DEXSHARE_RIGHT_TYPE] = Into::<DexShareType>::into(right).into();
address[H160_POSITION_DEXSHARE_RIGHT_FIELD].copy_from_slice(&right_field.to_be_bytes());
}
CurrencyId::Erc20(erc20) => {
address[..].copy_from_slice(erc20.as_bytes());
}
CurrencyId::StableAssetPoolToken(_) => {
// Unsupported
return Err(());
}
CurrencyId::LiquidCroadloan(lease) => {
address[H160_POSITION_CURRENCY_ID_TYPE] = CurrencyIdType::LiquidCroadloan.into();
address[H160_POSITION_LIQUID_CROADLOAN].copy_from_slice(&lease.to_be_bytes());
}
CurrencyId::ForeignAsset(foreign_asset_id) => {
address[H160_POSITION_CURRENCY_ID_TYPE] = CurrencyIdType::ForeignAsset.into();
address[H160_POSITION_FOREIGN_ASSET].copy_from_slice(&foreign_asset_id.to_be_bytes());
}
};
Ok(EvmAddress::from_slice(&address))
}
}