use frame_support::pallet_prelude::RuntimeDebug;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::{crypto::AccountId32, H160};
use sp_runtime::{traits::AccountIdConversion, TypeId};
use crate::EVMChainId;
const MAX_ADDRESS_SIZE: usize = 32;
pub fn account_to_eth_address(address: AccountId32) -> H160 {
let bytes: [u8; 32] = address.into();
H160::from(
*(bytes)
.split_first_chunk::<20>()
.expect("always fit, qed")
.0,
)
}
pub fn eth_address_to_account(chain_id: u64, address: H160) -> AccountId32 {
let tag = b"EVM";
let mut bytes = [0; 32];
bytes[0..20].copy_from_slice(&address.0);
bytes[20..28].copy_from_slice(&chain_id.to_be_bytes());
bytes[28..31].copy_from_slice(tag);
AccountId32::new(bytes)
}
#[derive(Encode, Decode, Clone, Copy, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub enum Domain {
Centrifuge,
Evm(EVMChainId),
}
impl TypeId for Domain {
const TYPE_ID: [u8; 4] = crate::ids::DOMAIN_ID;
}
impl Domain {
pub fn into_account<AccountId: Encode + Decode>(&self) -> AccountId {
self.into_account_truncating()
}
pub fn get_evm_chain_id(&self) -> Option<EVMChainId> {
match self {
Domain::Centrifuge => None,
Domain::Evm(id) => Some(*id),
}
}
}
#[derive(Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub enum DomainAddress {
Centrifuge(AccountId32),
Evm(EVMChainId, H160),
}
impl TypeId for DomainAddress {
const TYPE_ID: [u8; 4] = crate::ids::DOMAIN_ADDRESS_ID;
}
impl From<DomainAddress> for Domain {
fn from(x: DomainAddress) -> Self {
match x {
DomainAddress::Centrifuge(_) => Domain::Centrifuge,
DomainAddress::Evm(chain_id, _) => Domain::Evm(chain_id),
}
}
}
impl DomainAddress {
pub fn new(domain: Domain, address: [u8; MAX_ADDRESS_SIZE]) -> Self {
match domain {
Domain::Centrifuge => DomainAddress::Centrifuge(address.into()),
Domain::Evm(chain_id) => {
DomainAddress::Evm(chain_id, account_to_eth_address(address.into()))
}
}
}
pub fn domain(&self) -> Domain {
self.clone().into()
}
}
impl DomainAddress {
pub fn account(&self) -> AccountId32 {
match self.clone() {
Self::Centrifuge(x) => x,
Self::Evm(chain_id, x) => eth_address_to_account(chain_id, x),
}
}
pub fn h160(&self) -> H160 {
match self.clone() {
Self::Centrifuge(x) => account_to_eth_address(x),
Self::Evm(_, x) => x,
}
}
pub fn bytes(&self) -> [u8; MAX_ADDRESS_SIZE] {
self.account().into()
}
}