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
pub use pallet_bridge_dispatch::Instance1 as WithPangolinDispatch;
use frame_support::{
ensure,
traits::{OriginTrait, WithdrawReasons},
};
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError};
use crate::*;
use bp_message_dispatch::{CallValidate, IntoDispatchOrigin as IntoDispatchOriginT};
use bp_messages::{LaneId, MessageNonce};
use darwinia_ethereum::{RawOrigin, Transaction};
use darwinia_evm::CurrencyAdapt;
use darwinia_support::evm::{DeriveEthereumAddress, DeriveSubstrateAddress};
use pallet_bridge_dispatch::Config;
pub struct CallValidator;
impl CallValidate<bp_pangoro::AccountId, Origin, Call> for CallValidator {
fn check_receiving_before_dispatch(
relayer_account: &bp_pangoro::AccountId,
call: &Call,
) -> Result<(), &'static str> {
match call {
Call::Ethereum(darwinia_ethereum::Call::message_transact {
transaction: Transaction::Legacy(t),
}) => {
ensure!(t.value.is_zero(), "Only non-payable transaction supported.");
ensure!(
t.gas_limit <= <Runtime as darwinia_evm::Config>::BlockGasLimit::get(),
"Tx gas limit over block limit"
);
let gas_price = <Runtime as darwinia_evm::Config>::FeeCalculator::min_gas_price();
let fee = t.gas_limit.saturating_mul(gas_price);
Ok(<Runtime as darwinia_evm::Config>::RingBalanceAdapter::ensure_can_withdraw(
relayer_account,
fee,
WithdrawReasons::all(),
)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?)
},
_ => Ok(()),
}
}
fn call_validate(
relayer_account: &bp_pangoro::AccountId,
origin: &Origin,
call: &Call,
) -> Result<(), TransactionValidityError> {
match call {
Call::Ethereum(darwinia_ethereum::Call::message_transact { transaction: tx }) => {
match origin.caller() {
OriginCaller::Ethereum(RawOrigin::EthereumTransaction(id)) => match tx {
Transaction::Legacy(t) => {
let gas_price =
<Runtime as darwinia_evm::Config>::FeeCalculator::min_gas_price();
let fee = t.gas_limit.saturating_mul(gas_price);
let derived_substrate_address =
<Runtime as darwinia_evm::Config>::IntoAccountId::derive_substrate_address(id);
<Runtime as darwinia_evm::Config>::RingBalanceAdapter::evm_transfer(
relayer_account,
&derived_substrate_address,
fee,
)
.map_err(|_| {
TransactionValidityError::Invalid(InvalidTransaction::Custom(3))
})
},
_ => Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1))),
},
_ => Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))),
}
},
_ => Ok(()),
}
}
}
pub struct IntoDispatchOrigin;
impl IntoDispatchOriginT<bp_pangoro::AccountId, Call, Origin> for IntoDispatchOrigin {
fn into_dispatch_origin(id: &bp_pangoro::AccountId, call: &Call) -> Origin {
match call {
Call::Ethereum(darwinia_ethereum::Call::message_transact { .. }) => {
let derive_eth_address = id.derive_ethereum_address();
darwinia_ethereum::RawOrigin::EthereumTransaction(derive_eth_address).into()
},
_ => frame_system::RawOrigin::Signed(id.clone()).into(),
}
}
}
impl Config<WithPangolinDispatch> for Runtime {
type AccountIdConverter = bp_pangoro::AccountIdConverter;
type BridgeMessageId = (LaneId, MessageNonce);
type Call = Call;
type CallValidator = CallValidator;
type EncodedCall = bm_pangolin::FromPangolinEncodedCall;
type Event = Event;
type IntoDispatchOrigin = IntoDispatchOrigin;
type SourceChainAccountId = bp_pangolin::AccountId;
type TargetChainAccountPublic = bp_pangoro::AccountPublic;
type TargetChainSignature = bp_pangoro::Signature;
}