diff --git a/res/mock_evm/src/ft.rs b/res/mock_evm/src/ft.rs index 8c4497f..bfcfd12 100644 --- a/res/mock_evm/src/ft.rs +++ b/res/mock_evm/src/ft.rs @@ -13,4 +13,8 @@ impl MockEvmContract { pub fn ft_on_transfer(&mut self, sender_id: AccountId, amount: u128, msg: String) -> String { serde_json::to_string(&0).expect("Failed to serialize message") } + + pub fn ft_total_eth_supply_on_aurora(&self) -> String { + "0".into() + } } diff --git a/res/mock_evm/src/lib.rs b/res/mock_evm/src/lib.rs index 99b5499..a66a253 100644 --- a/res/mock_evm/src/lib.rs +++ b/res/mock_evm/src/lib.rs @@ -1,5 +1,5 @@ use crate::out::SubmitResult; -use aurora_workspace_types::input::{CallInput, DeployErc20Input, SetEthConnectorInput}; +use aurora_workspace_types::input::{CallInput, DeployErc20Input, NewInput, SetEthConnectorInput}; use aurora_workspace_types::output::{Log, TransactionStatus}; use aurora_workspace_types::{AccountId, Address, Raw, H256}; use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; @@ -8,6 +8,7 @@ use near_sdk::{near_bindgen, PanicOnDefault}; pub mod ft; mod metadata; mod out; +mod selfcall; mod storage; fn dummy_submit_result() -> SubmitResult { @@ -32,25 +33,16 @@ pub struct MockEvmContract { #[near_bindgen] impl MockEvmContract { #[init] - pub fn new( - chain_id: [u8; 32], - owner_id: AccountId, - bridge_prover_id: AccountId, - upgrade_delay_blocks: u64, - ) -> MockEvmContract { + pub fn new(#[serializer(borsh)] input: NewInput) -> MockEvmContract { MockEvmContract { - chain_id, - owner_id, - bridge_prover_id, - upgrade_delay_blocks, + chain_id: input.chain_id, + owner_id: input.owner_id, + bridge_prover_id: input.bridge_prover_id, + upgrade_delay_blocks: input.upgrade_delay_blocks, eth_connector: None, } } - pub fn new_eth_connector(&mut self, #[serializer(borsh)] input: SetEthConnectorInput) { - self.eth_connector = Some(input); - } - #[result_serializer(borsh)] pub fn deploy_code(&mut self, #[serializer(borsh)] _input: Raw) -> SubmitResult { dummy_submit_result() diff --git a/res/mock_evm/src/metadata.rs b/res/mock_evm/src/metadata.rs index d575c60..49f0aaf 100644 --- a/res/mock_evm/src/metadata.rs +++ b/res/mock_evm/src/metadata.rs @@ -1,5 +1,3 @@ -use std::ascii; - use aurora_workspace_types::{output::TransactionStatus, AccountId, Raw}; use near_sdk::{borsh, near_bindgen}; @@ -11,10 +9,6 @@ impl MockEvmContract { "v1".to_string() } - pub fn ft_total_eth_supply_on_aurora(&self) -> String { - "0".into() - } - #[result_serializer(borsh)] pub fn get_view(&self, #[serializer(borsh)] _input: Raw) -> TransactionStatus { TransactionStatus::Succeed(vec![]) diff --git a/res/mock_evm/src/selfcall.rs b/res/mock_evm/src/selfcall.rs new file mode 100644 index 0000000..3b51844 --- /dev/null +++ b/res/mock_evm/src/selfcall.rs @@ -0,0 +1,38 @@ +use aurora_workspace_types::input::SetEthConnectorInput; +use aurora_workspace_types::Raw; +use near_sdk::{borsh, near_bindgen}; +use near_sdk::{json_types::U128, serde_json}; + +use crate::{MockEvmContract, MockEvmContractExt}; + +#[near_bindgen] +impl MockEvmContract { + pub fn new_eth_connector(&mut self, #[serializer(borsh)] input: SetEthConnectorInput) { + self.eth_connector = Some(input); + } + + pub fn ft_resolve_transfer(&mut self, #[serializer(borsh)] _input: Raw) -> String { + serde_json::to_string(&U128::from(0)).expect("Failed to serialize message") + } + + pub fn set_eth_connector_contract_data(&mut self, #[serializer(borsh)] _input: Raw) {} + + pub fn set_paused_flags(&mut self, #[serializer(borsh)] _input: Raw) {} + + // Callbacks: + + #[result_serializer(borsh)] + pub fn finish_deposit(&self, #[serializer(borsh)] _input: Raw) -> u8 { + 0 + } + + #[result_serializer(borsh)] + pub fn factory_update_address_version(&mut self, #[serializer(borsh)] _input: Raw) -> u8 { + 0 + } + + #[result_serializer(borsh)] + pub fn refund_on_error(&mut self, #[serializer(borsh)] _input: Raw) -> u8 { + 0 + } +} diff --git a/workspace/src/contract.rs b/workspace/src/contract.rs index e270797..8275103 100644 --- a/workspace/src/contract.rs +++ b/workspace/src/contract.rs @@ -1,17 +1,24 @@ use crate::operation::{ - Call, CallDeployCode, CallDeployErc20, CallEvm, CallFtOnTransfer, CallFtTransfer, - CallFtTransferCall, CallRegisterRelayer, CallStorageDeposit, CallStorageUnregister, - CallStorageWithdraw, CallSubmit, View, ViewResultDetails, + Call, CallDeployCode, CallDeployErc20, CallEvm, CallFactoryUpdateAddressVersion, + CallFinishDeposit, CallFtOnTransfer, CallFtResolveTransfer, CallFtTransfer, CallFtTransferCall, + CallRefundOnError, CallRegisterRelayer, CallSetEthConnectorContractData, CallSetPausedFlags, + CallStorageDeposit, CallStorageUnregister, CallStorageWithdraw, CallSubmit, SelfCall, View, + ViewResultDetails, }; #[cfg(feature = "deposit-withdraw")] use crate::operation::{CallDeposit, CallWithdraw}; use crate::{EvmCallTransaction, Result}; -use aurora_engine::parameters::{ - GetStorageAtArgs, InitCallArgs, IsUsedProofCallArgs, StorageBalance, StorageDepositCallArgs, - StorageWithdrawCallArgs, TransactionStatus, TransferCallArgs, TransferCallCallArgs, +use aurora_engine::{ + admin_controlled::PausedMask, + parameters::{ + FinishDepositCallArgs, GetStorageAtArgs, InitCallArgs, IsUsedProofCallArgs, + ResolveTransferCallArgs, SetContractDataCallArgs, StorageBalance, StorageDepositCallArgs, + StorageWithdrawCallArgs, TransactionStatus, TransferCallArgs, TransferCallCallArgs, + }, + xcc::AddressVersionUpdateArgs, }; -use aurora_engine::proof::Proof; use aurora_engine::{fungible_token::FungibleTokenMetadata, parameters::ViewCallArgs}; +use aurora_engine::{parameters::PauseEthConnectorCallArgs, proof::Proof}; use aurora_workspace_types::input::{CallInput, DeployErc20Input, FtOnTransferInput}; #[cfg(feature = "deposit-withdraw")] use aurora_workspace_types::input::{ProofInput, WithdrawInput}; @@ -183,6 +190,114 @@ impl EvmAccount { self.account.id() } + pub async fn new_eth_connector( + &self, + prover_account: impl AsRef, + eth_custodian_address: impl Into, + metadata: FungibleTokenMetadata, + ) -> Result<()> { + let args = InitCallArgs { + prover_account: aurora_engine_types::account_id::AccountId::from_str( + prover_account.as_ref(), + ) + .unwrap(), + eth_custodian_address: eth_custodian_address.into(), + metadata, + }; + self.near_call(&SelfCall::NewEthConnector) + .args_borsh(args) + .transact() + .await? + .into_result()?; + Ok(()) + } + + pub fn set_eth_connector_contract_data( + &self, + prover_account: impl AsRef, + eth_custodian_address: impl Into, + metadata: FungibleTokenMetadata, + ) -> CallSetEthConnectorContractData<'_> { + let args = SetContractDataCallArgs { + prover_account: aurora_engine_types::account_id::AccountId::new( + prover_account.as_ref(), + ) + .unwrap(), + eth_custodian_address: eth_custodian_address.into(), + metadata, + }; + CallSetEthConnectorContractData( + self.near_call(&SelfCall::SetEthConnectorContractData) + .args_borsh(args), + ) + } + + pub fn set_paused_flags( + &self, + // TODO: maybe use u8 instead of pausedmask or an impl conversion + paused_mask: PausedMask, + ) -> CallSetPausedFlags<'_> { + let args = PauseEthConnectorCallArgs { paused_mask }; + CallSetPausedFlags(self.near_call(&SelfCall::SetPausedFlags).args_borsh(args)) + } + + pub fn finish_deposit( + &self, + new_owner_id: impl AsRef, + amount: u128, + proof_key: impl Into, + relayer_id: impl AsRef, + fee: u128, + msg: Option>, + ) -> CallFinishDeposit<'_> { + let args = FinishDepositCallArgs { + // TODO: handle errors. maybe we should just accept AccountId and let the user deal with + // error handling? seems to make more sense + new_owner_id: aurora_engine_types::account_id::AccountId::new(new_owner_id.as_ref()) + .unwrap(), + amount: aurora_engine_types::types::NEP141Wei::new(amount), + proof_key: proof_key.into(), + relayer_id: aurora_engine_types::account_id::AccountId::new(relayer_id.as_ref()) + .unwrap(), + fee: fee.into(), + msg, + }; + CallFinishDeposit(self.near_call(&SelfCall::FinishDeposit).args_borsh(args)) + } + + pub fn factory_update_address_version( + &self, + address: impl Into
, + version: u32, + ) -> CallFactoryUpdateAddressVersion<'_> { + let args = AddressVersionUpdateArgs { + address: aurora_engine_types::types::Address::new(address.into()), + version: aurora_engine::xcc::CodeVersion(version), + }; + CallFactoryUpdateAddressVersion( + self.near_call(&SelfCall::FactoryUpdateAddressVersion) + .args_borsh(args), + ) + } + + pub fn refund_on_error>( + &self, + recipient_address: A, + erc20_address: Option, + amount: U256, + ) -> CallRefundOnError<'_> { + let mut raw_amount: aurora_engine_types::types::RawU256 = Default::default(); + amount.to_big_endian(&mut raw_amount); + let args = aurora_engine_types::parameters::RefundCallArgs { + recipient_address: aurora_engine_types::types::Address::new(recipient_address.into()), + erc20_address: erc20_address + .map(Into::into) + .map(aurora_engine_types::types::Address::new), + amount: raw_amount, + }; + CallRefundOnError(self.near_call(&SelfCall::RefundOnError).args_borsh(args)) + } + /// Deploys contract code using the caller's NEAR account ID as an Ethereum address. /// /// The logic which creates the ETH address is as follows: @@ -292,6 +407,25 @@ impl EvmAccount { CallFtTransferCall(self.near_call(&Call::FtTransferCall).args_json(args)) } + pub fn ft_resolve_transfer( + &self, + sender_id: impl AsRef, + amount: u128, + receiver_id: impl AsRef, + ) -> CallFtResolveTransfer<'_> { + let args = ResolveTransferCallArgs { + // TODO: impl error + sender_id: aurora_engine_types::account_id::AccountId::new(sender_id.as_ref()).unwrap(), + amount: aurora_engine_types::types::NEP141Wei::new(amount), + receiver_id: aurora_engine_types::account_id::AccountId::new(receiver_id.as_ref()) + .unwrap(), + }; + CallFtResolveTransfer( + self.near_call(&SelfCall::FtResolveTransfer) + .args_borsh(args), + ) + } + // TODO we are not NEP-145 compliant pub fn storage_deposit>( &self, @@ -684,20 +818,13 @@ impl EvmContract { .into_result()?; if let Some(eth_prover_config) = init_config.eth_prover_config { - let new_eth_connector_args = InitCallArgs { - prover_account: aurora_engine_types::account_id::AccountId::from_str( + self.contract + .new_eth_connector( eth_prover_config.account_id.as_str(), + eth_prover_config.evm_custodian_address, + FungibleTokenMetadata::default(), ) - .unwrap(), - eth_custodian_address: eth_prover_config.evm_custodian_address, - metadata: FungibleTokenMetadata::default(), - }; - self.contract - .near_call("new_eth_connector") - .args_borsh(new_eth_connector_args) - .transact() - .await? - .into_result()?; + .await?; } Ok(()) diff --git a/workspace/src/operation.rs b/workspace/src/operation.rs index 1b04337..9202605 100644 --- a/workspace/src/operation.rs +++ b/workspace/src/operation.rs @@ -3,8 +3,8 @@ use crate::error::Error; use crate::result::ExecutionSuccess; use crate::types::output::SubmitResult; use crate::Result; +use aurora_engine::fungible_token::FungibleTokenMetadata; use aurora_engine::parameters::{StorageBalance, TransactionStatus}; -use aurora_engine::{fungible_token::FungibleTokenMetadata, parameters::WithdrawResult}; use aurora_engine_sdk::promise::PromiseId; use aurora_engine_types::types::Wei; use aurora_workspace_types::AccountId; @@ -16,7 +16,7 @@ use workspaces::operations::CallTransaction; use workspaces::result::ExecutionFinalResult; macro_rules! impl_call_return { - ($(($name:ident, $return:ty, $fun:ident)),*) => { + ( $( ($name:ident, $return:ty, $deser_fn:ident)),* $(,)? ) => { $(pub struct $name<'a>(pub(crate) EvmCallTransaction<'a>); impl<'a> $name<'a> { @@ -31,7 +31,7 @@ macro_rules! impl_call_return { } pub async fn transact(self) -> Result<$return> { - ExecutionSuccess::$fun(self.0.transact().await?) + ExecutionSuccess::$deser_fn(self.0.transact().await?) } })* } @@ -49,10 +49,29 @@ impl_call_return![ (CallRegisterRelayer, ExecutionSuccess<()>, try_from), (CallFtOnTransfer, ExecutionSuccess, try_from_json), (CallFtTransfer, ExecutionSuccess<()>, try_from), + // TODO: ser? res type? + ( + CallFtResolveTransfer, + ExecutionSuccess, + try_from_json + ), (CallFtTransferCall, ExecutionSuccess, try_from), (CallStorageDeposit, ExecutionSuccess<()>, try_from), (CallStorageUnregister, ExecutionSuccess<()>, try_from), - (CallStorageWithdraw, ExecutionSuccess<()>, try_from) + (CallStorageWithdraw, ExecutionSuccess<()>, try_from), + ( + CallSetEthConnectorContractData, + ExecutionSuccess<()>, + try_from_borsh + ), + (CallSetPausedFlags, ExecutionSuccess<()>, try_from_borsh), + (CallFinishDeposit, ExecutionSuccess, try_from_borsh), + ( + CallFactoryUpdateAddressVersion, + ExecutionSuccess, + try_from_borsh + ), + (CallRefundOnError, ExecutionSuccess, try_from_borsh), ]; #[cfg(feature = "deposit-withdraw")] @@ -405,7 +424,7 @@ impl AsRef for SelfCall { FactoryUpdateAddressVersion => "factory_update_address_version", RefundOnError => "refund_on_error", FinishDeposit => "finish_deposit", - FtResolveTransfer => "resolve_transfer", + FtResolveTransfer => "ft_resolve_transfer", SetPausedFlags => "set_paused_flags", } } diff --git a/workspace/tests/ft_tests.rs b/workspace/tests/ft_tests.rs index 63c34a3..e0f5c38 100644 --- a/workspace/tests/ft_tests.rs +++ b/workspace/tests/ft_tests.rs @@ -1,3 +1,4 @@ +use aurora_engine::parameters::TransferCallArgs; use aurora_workspace_types::AccountId; use std::str::FromStr; diff --git a/workspace/tests/self_call_tests.rs b/workspace/tests/self_call_tests.rs new file mode 100644 index 0000000..051b409 --- /dev/null +++ b/workspace/tests/self_call_tests.rs @@ -0,0 +1,108 @@ +use aurora_engine::{fungible_token::FungibleTokenMetadata, parameters::TransactionStatus}; +use aurora_engine_types::U256; +use aurora_workspace::ViewResultDetails; +use aurora_workspace_types::{Address, H256}; + +mod common; + +#[tokio::test] +async fn test_new_eth_connector() { + let contract = common::init_and_deploy_contract().await.unwrap(); + + contract + .as_account() + .new_eth_connector( + "prover.test.near", + "eth_connector.test.near", + Default::default(), + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn test_ft_resolve_transfer() { + let contract = common::init_and_deploy_contract().await.unwrap(); + + let res = contract + .as_account() + .ft_resolve_transfer("sender.test.near", 0, "receiver.test.near") + .transact() + .await + .unwrap() + .into_value(); + + let expected = r#""0""#; + assert_eq!(expected, res); +} + +#[tokio::test] +async fn test_set_eth_connector_contract_data() { + let contract = common::init_and_deploy_contract().await.unwrap(); + + contract + .as_account() + .set_eth_connector_contract_data( + "prover.test.near", + "custodian.test.near", + FungibleTokenMetadata::default(), + ) + .transact() + .await + .unwrap(); +} + +#[tokio::test] +async fn test_finish_deposit() { + let contract = common::init_and_deploy_contract().await.unwrap(); + + let res = contract + .as_account() + .finish_deposit( + "new_owner.test.near", + 0, + "proof_key", + "relayer.test.near", + 0, + None, + ) + .transact() + .await + .unwrap() + .into_value(); + + let expected = 0; + assert_eq!(expected, res); +} + +#[tokio::test] +async fn test_factory_update_address_version() { + let contract = common::init_and_deploy_contract().await.unwrap(); + + let res = contract + .as_account() + .factory_update_address_version(Address::default(), 0) + .transact() + .await + .unwrap() + .into_value(); + + let expected = 0; + assert_eq!(expected, res); +} + +#[tokio::test] +async fn test_refund_on_error() { + let contract = common::init_and_deploy_contract().await.unwrap(); + + let res = contract + .as_account() + .refund_on_error(Address::default(), Some(Address::default()), 0.into()) + .transact() + .await + .unwrap() + .into_value(); + + let expected = 0; + assert_eq!(expected, res); +}