diff --git a/src/connector.rs b/src/connector.rs index 1be52fd8d..25b86a902 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -1,14 +1,15 @@ use crate::fungible_token::*; use crate::parameters::*; use crate::sdk; -use crate::types::{AccountId, Balance, EthAddress, Gas, PromiseResult, Proof, ERR_FAILED_PARSE}; +use crate::types::{ + AccountId, Balance, EthAddress, Gas, PromiseResult, Proof, SdkUnwrap, ERR_FAILED_PARSE, +}; use crate::admin_controlled::{AdminControlled, PausedMask}; use crate::deposit_event::*; use crate::engine::Engine; use crate::json::parse_json; use crate::prelude::*; -use crate::prover::validate_eth_address; use crate::storage::{self, EthConnectorStorageId, KeyPrefix}; #[cfg(feature = "log")] use alloc::format; @@ -110,7 +111,8 @@ impl EthConnectorContract { // Get initial contract arguments let contract_data = EthConnector { prover_account: args.prover_account, - eth_custodian_address: validate_eth_address(args.eth_custodian_address), + eth_custodian_address: crate::types::validate_eth_address(args.eth_custodian_address) + .sdk_unwrap(), }; // Save eth-connector specific data sdk::save_contract( diff --git a/src/lib.rs b/src/lib.rs index 803b94b6d..b50b81bba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,6 @@ mod fungible_token; mod json; mod log_entry; mod precompiles; -mod prover; pub mod sdk; #[cfg(test)] diff --git a/src/prover.rs b/src/prover.rs deleted file mode 100644 index e62941b94..000000000 --- a/src/prover.rs +++ /dev/null @@ -1,225 +0,0 @@ -use super::prelude::*; -use super::sdk; -use crate::engine::Engine; -use crate::precompiles::ecrecover; -use crate::prelude::Vec; -use crate::types::{AccountId, EthAddress, Proof}; -#[cfg(feature = "log")] -use alloc::format; -use borsh::BorshSerialize; -use ethabi::{Bytes, Token}; - -/// Validate Etherium address from string and return EthAddress -#[allow(dead_code)] -pub fn validate_eth_address(address: String) -> EthAddress { - let data = hex::decode(address).expect("ETH_ADDRESS_FAILED"); - assert_eq!(data.len(), 20, "ETH_WRONG_ADDRESS_LENGTH"); - let mut result = [0u8; 20]; - result.copy_from_slice(&data); - result -} - -/// Encodes vector of tokens using non-standard Packed mode into ABI.encodePacked() compliant vector of bytes. -pub fn encode_packed(tokens: &[Token]) -> Bytes { - tokens.iter().flat_map(encode_token_packed).collect() -} - -fn encode_token_packed(token: &Token) -> Vec { - match *token { - Token::Address(ref address) => { - let mut padded = [0u8; 32]; - padded[12..].copy_from_slice(address.as_ref()); - padded[..].to_vec() - } - Token::Bytes(ref bytes) => bytes.to_vec(), - Token::String(ref s) => s.as_bytes().to_vec(), - Token::FixedBytes(ref bytes) => bytes.to_vec(), - Token::Int(int) => { - let data: [u8; 32] = int.into(); - data[..].to_vec() - } - Token::Uint(uint) => { - let data: [u8; 32] = uint.into(); - data[..].to_vec() - } - Token::Bool(b) => { - vec![b.into()] - } - Token::Array(_) | Token::FixedArray(_) | Token::Tuple(_) => { - panic!("These token types are not supported in packed mode"); - } - } -} - -#[allow(dead_code)] -impl Proof { - pub fn get_key(&self) -> String { - let mut data = self.log_index.try_to_vec().unwrap(); - data.extend(self.receipt_index.try_to_vec().unwrap()); - data.extend(self.header_data.clone()); - sdk::sha256(&data[..]) - .0 - .iter() - .map(|n| n.to_string()) - .collect() - } -} - -const EIP_712_MSG_PREFIX: &[u8] = &[0x19, 0x01]; -const EIP_712_DOMAIN_TYPEHASH: &str = - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; -const AURORA_DOMAIN_NAME: &str = "Aurora-Engine domain"; -const AURORA_DOMAIN_VERSION: &str = "1.0"; -const WITHDRAW_FROM_EVM_TYPEHASH: &str = - "WithdrawFromEVMRequest(address ethRecipient,uint256 amount,address verifyingContract)"; -const TRANSFER_FROM_EVM_TO_NEAR_TYPEHASH: &str = - "TransferFromEVMtoNearRequest(string nearRecipient,uint256 amount,uint256 fee)"; - -enum EIP712Recipient { - Eth(EthAddress), - Near(AccountId), -} - -/// Encode EIP712 withdraw message data -fn encode_eip712( - eth_recipient: EIP712Recipient, - amount: U256, - custodian_address: EthAddress, - type_hash: &str, -) -> H256 { - let chain_id = U256::from(Engine::get_state().unwrap().chain_id); - - let domain_separator_encoded = encode_packed(&[ - Token::FixedBytes( - sdk::keccak(&encode_packed(&[Token::Bytes( - EIP_712_DOMAIN_TYPEHASH.as_bytes().to_vec(), - )])) - .as_bytes() - .to_vec(), - ), - Token::FixedBytes(encode_packed(&[ - // Domain - Token::Bytes( - sdk::keccak(AURORA_DOMAIN_NAME.as_bytes()) - .as_bytes() - .to_vec(), - ), - // Version - Token::Bytes( - sdk::keccak(AURORA_DOMAIN_VERSION.as_bytes()) - .as_bytes() - .to_vec(), - ), - // ChainID - Token::Uint(chain_id), - // Custodian address - Token::Address(H160::from(custodian_address)), - ])), - ]); - crate::log!(&format!( - "Domain_separator encoded: {}", - hex::encode(domain_separator_encoded.clone()) - )); - - let domain_separator = sdk::keccak(&domain_separator_encoded); - crate::log!(&format!( - "Domain_separator hash: {}", - hex::encode(domain_separator) - )); - - let token_address = match eth_recipient { - EIP712Recipient::Eth(eth_recipient) => Token::Address(H160::from(eth_recipient)), - EIP712Recipient::Near(account_id) => Token::String(account_id), - }; - let withdraw_from_evm_struct_encoded = encode_packed(&[ - Token::FixedBytes( - sdk::keccak(&encode_packed(&[Token::Bytes( - type_hash.as_bytes().to_vec(), - )])) - .as_bytes() - .to_vec(), - ), - Token::FixedBytes(encode_packed(&[ - token_address, - Token::Uint(amount), - Token::Address(H160::from(custodian_address)), - ])), - ]); - crate::log!(&format!( - "WithdrawFromEVM struct encoded: {}", - hex::encode(withdraw_from_evm_struct_encoded.clone()), - )); - - let withdraw_from_evm_struct_hash = sdk::keccak(&withdraw_from_evm_struct_encoded); - crate::log!(&format!( - "WithdrawFromEVM struct hash: {}", - hex::encode(withdraw_from_evm_struct_hash) - )); - - let digest_encoded = encode_packed(&[ - Token::Bytes(EIP_712_MSG_PREFIX.to_vec()), - Token::FixedBytes(domain_separator.as_bytes().to_vec()), - Token::FixedBytes(withdraw_from_evm_struct_hash.as_bytes().to_vec()), - ]); - crate::log!(&format!( - "digest_encoded: {}", - hex::encode(digest_encoded.clone()) - )); - - // clippy doesn't like this `let` binding if the logging feature is disabled - // because the log line is not really there in that case - #[allow(clippy::let_and_return)] - let digest = sdk::keccak(&digest_encoded); - crate::log!(&format!("digest: {}", hex::encode(&digest))); - digest -} - -#[allow(dead_code)] -pub fn verify_withdraw_eip712( - sender: EthAddress, - eth_recipient: EthAddress, - custodian_address: EthAddress, - amount: U256, - eip712_signature: Vec, -) -> bool { - let res = encode_eip712( - EIP712Recipient::Eth(eth_recipient), - amount, - custodian_address, - WITHDRAW_FROM_EVM_TYPEHASH, - ); - let withdraw_msg_signer = ecrecover(res, &eip712_signature[..]).unwrap(); - crate::log!(&format!("sender: {}", hex::encode(sender))); - crate::log!(&format!("ecrecover: {}", hex::encode(withdraw_msg_signer))); - crate::log!(&format!( - "ecrecover: {}", - H160::from(sender) == withdraw_msg_signer - )); - - H160::from(sender) == withdraw_msg_signer -} - -#[allow(dead_code)] -pub fn verify_transfer_eip712( - sender: EthAddress, - near_recipient: AccountId, - custodian_address: EthAddress, - amount: U256, - eip712_signature: Vec, -) -> bool { - let res = encode_eip712( - EIP712Recipient::Near(near_recipient), - amount, - custodian_address, - TRANSFER_FROM_EVM_TO_NEAR_TYPEHASH, - ); - let withdraw_msg_signer = ecrecover(res, &eip712_signature[..]).unwrap(); - crate::log!(&format!("sender: {}", hex::encode(sender))); - crate::log!(&format!("ecrecover: {}", hex::encode(withdraw_msg_signer))); - crate::log!(&format!( - "ecrecover: {}", - H160::from(sender) == withdraw_msg_signer - )); - - H160::from(sender) == withdraw_msg_signer -} diff --git a/src/types.rs b/src/types.rs index 06d883ff5..03168b82a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -117,6 +117,33 @@ fn long_signature(name: &str, params: &[ParamType]) -> Hash { H256::from(result) } +#[derive(Debug)] +pub enum ValidationError { + EthAddressFailedDecode, + WrongEthAddress, +} + +impl AsRef<[u8]> for ValidationError { + fn as_ref(&self) -> &[u8] { + match self { + Self::EthAddressFailedDecode => b"FAILED_DECODE_ETH_ADDRESS", + Self::WrongEthAddress => b"WRONG_ETH_ADDRESS", + } + } +} + +/// Validate Etherium address from string and return EthAddress +pub fn validate_eth_address(address: String) -> Result { + let data = hex::decode(address).map_err(|_| ValidationError::EthAddressFailedDecode)?; + if data.len() != 20 { + return Err(ValidationError::WrongEthAddress); + } + assert_eq!(data.len(), 20, "ETH_WRONG_ADDRESS_LENGTH"); + let mut result = [0u8; 20]; + result.copy_from_slice(&data); + Ok(result) +} + #[derive(Default, BorshDeserialize, BorshSerialize, Clone)] #[cfg_attr(test, derive(serde::Deserialize, serde::Serialize))] pub struct Proof { @@ -128,6 +155,19 @@ pub struct Proof { pub proof: Vec>, } +impl Proof { + pub fn get_key(&self) -> String { + let mut data = self.log_index.try_to_vec().unwrap(); + data.extend(self.receipt_index.try_to_vec().unwrap()); + data.extend(self.header_data.clone()); + sdk::sha256(&data[..]) + .0 + .iter() + .map(|n| n.to_string()) + .collect() + } +} + /// Newtype to distinguish balances (denominated in Wei) from other U256 types. #[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] pub struct Wei(U256); @@ -226,8 +266,6 @@ pub enum ErrorKind { InvalidEcRecoverSignature, } -pub type Result = core::result::Result; - #[allow(dead_code)] pub fn u256_to_arr(value: &U256) -> [u8; 32] { let mut result = [0u8; 32];