transporter_precompile/
lib.rs

1//! Transporter precompile
2#![cfg_attr(not(feature = "std"), no_std)]
3#![forbid(unsafe_code)]
4#![warn(rust_2018_idioms)]
5
6use core::marker::PhantomData;
7use domain_runtime_primitives::MultiAccountId;
8use fp_evm::Log;
9use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo};
10use frame_support::traits::OriginTrait;
11use pallet_evm::AddressMapping;
12use pallet_transporter::{BalanceOf, Location};
13use parity_scale_codec::Decode;
14use precompile_utils::prelude::*;
15use precompile_utils::solidity;
16use sp_core::crypto::AccountId32;
17use sp_core::{Get, H160, H256, U256};
18use sp_messenger::messages::ChainId;
19use sp_runtime::traits::Dispatchable;
20
21pub struct TransporterPrecompile<Runtime>(PhantomData<Runtime>);
22
23/// Solidity selector of the Transfer to Consensus log.
24pub const SELECTOR_LOG_TRANSFER_TO_CONSENSUS: [u8; 32] =
25    keccak256!("TransferToConsensus(address,bytes32,uint256)");
26
27pub fn log_transfer_to_consensus(address: H160, who: H160, receiver: H256, amount: U256) -> Log {
28    log3(
29        address,
30        SELECTOR_LOG_TRANSFER_TO_CONSENSUS,
31        who,
32        receiver,
33        solidity::encode_event_data(amount),
34    )
35}
36
37#[precompile]
38impl<Runtime> TransporterPrecompile<Runtime>
39where
40    Runtime: pallet_evm::Config + pallet_transporter::Config,
41    Runtime::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo + Decode,
42    <Runtime as pallet_evm::Config>::AddressMapping: AddressMapping<Runtime::AccountId>,
43    Runtime::RuntimeCall: From<pallet_transporter::Call<Runtime>>,
44    BalanceOf<Runtime>: From<u128> + Into<u128>,
45{
46    #[precompile::public("transfer_to_consensus_v1(bytes32,uint256)")]
47    fn transfer_to_consensus_v1(
48        handle: &mut impl PrecompileHandle,
49        receiver: H256,
50        amount: Convert<U256, u128>,
51    ) -> EvmResult {
52        let amount = amount.converted();
53
54        let event = log_transfer_to_consensus(
55            handle.context().address,
56            handle.context().caller,
57            receiver,
58            amount.into(),
59        );
60        handle.record_log_costs(&[&event])?;
61
62        let receiver = AccountId32::new(receiver.0);
63        let amount: BalanceOf<Runtime> = amount.into();
64
65        let origin = Runtime::RuntimeOrigin::signed(Runtime::AddressMapping::into_account_id(
66            handle.context().caller,
67        ));
68
69        RuntimeHelper::<Runtime>::try_dispatch(
70            handle,
71            origin,
72            pallet_transporter::Call::<Runtime>::transfer {
73                dst_location: Location {
74                    chain_id: ChainId::Consensus,
75                    account_id: MultiAccountId::AccountId32(receiver.into()),
76                },
77                amount,
78            },
79            // we do not need to account for additional storage growth
80            0,
81        )?;
82
83        event.record(handle)?;
84
85        Ok(())
86    }
87
88    #[precompile::public("minimum_transfer_amount()")]
89    #[precompile::view]
90    fn minimum_transfer_amount(_handle: &mut impl PrecompileHandle) -> EvmResult<U256> {
91        let min_transfer = <Runtime as pallet_transporter::Config>::MinimumTransfer::get();
92        Ok(U256::from(min_transfer.into()))
93    }
94}