Skip to content

Commit 76236c6

Browse files
Merge pull request #1242 from galacticcouncil/fix/evm-set-currency-erc20
fix: evm set currency for erc20
2 parents 1803bdf + b548435 commit 76236c6

9 files changed

Lines changed: 214 additions & 41 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration-tests/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "runtime-integration-tests"
3-
version = "1.55.0"
3+
version = "1.56.0"
44
description = "Integration tests"
55
authors = ["GalacticCouncil"]
66
edition = "2021"

integration-tests/src/evm_permit.rs

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -738,8 +738,6 @@ fn evm_permit_set_currency_dispatch_should_pay_evm_fee_in_chosen_erc20_currency(
738738
));
739739
let fee_currency = asset;
740740

741-
//let fee_currency = DAI;
742-
743741
init_omnipool_with_oracle_for_block_10();
744742
//Add new erc20 token to omnipool and populate oracle
745743
assert_ok!(hydradx_runtime::Omnipool::add_token(
@@ -864,6 +862,177 @@ fn evm_permit_set_currency_dispatch_should_pay_evm_fee_in_chosen_erc20_currency(
864862
})
865863
}
866864

865+
#[test]
866+
fn evm_permit_set_currency_dispatch_should_work_when_wrapped_in_dispatch_with_extra_gas_by_frontend() {
867+
TestNet::reset();
868+
869+
let user_evm_address = alith_evm_address();
870+
let user_secret_key = alith_secret_key();
871+
let user_acc = MockAccount::new(alith_truncated_account());
872+
let treasury_acc = MockAccount::new(Treasury::account_id());
873+
874+
Hydra::execute_with(|| {
875+
//Create new erc20, fund user with it and set it as fee payment currency
876+
let contract = crate::erc20::deploy_token_contract();
877+
let asset = crate::erc20::bind_erc20(contract);
878+
let balance = Currencies::free_balance(asset, &ALICE.into());
879+
let initial_treasury_fee_balance = treasury_acc.balance(asset);
880+
let erc20_balance = 2000000000000000;
881+
assert_eq!(erc20_balance, 2000000000000000);
882+
assert_ok!(<Erc20Currency<Runtime> as ERC20>::transfer(
883+
CallContext {
884+
contract: contract,
885+
sender: crate::erc20::deployer(),
886+
origin: crate::erc20::deployer()
887+
},
888+
user_evm_address,
889+
erc20_balance
890+
));
891+
892+
assert_ok!(Currencies::transfer(
893+
hydradx_runtime::RuntimeOrigin::signed(alith_evm_account()),
894+
hydradx_runtime::Omnipool::protocol_account(),
895+
asset,
896+
erc20_balance / 2
897+
));
898+
899+
let alith_balance = Currencies::free_balance(asset, &alith_evm_account().into());
900+
assert_eq!(alith_balance, erc20_balance / 2);
901+
902+
assert_ok!(MultiTransactionPayment::add_currency(
903+
hydradx_runtime::RuntimeOrigin::root(),
904+
asset,
905+
FixedU128::from_rational(1, 2)
906+
));
907+
assert_ok!(MultiTransactionPayment::set_currency(
908+
hydradx_runtime::RuntimeOrigin::signed(alith_evm_account()),
909+
DAI,
910+
));
911+
let fee_currency = asset;
912+
913+
init_omnipool_with_oracle_for_block_10();
914+
//Add new erc20 token to omnipool and populate oracle
915+
assert_ok!(hydradx_runtime::Omnipool::add_token(
916+
hydradx_runtime::RuntimeOrigin::root(),
917+
asset,
918+
FixedU128::from_rational(1, 2),
919+
Permill::from_percent(100),
920+
AccountId::from(alith_evm_account()),
921+
));
922+
assert_ok!(Omnipool::sell(
923+
RuntimeOrigin::signed(alith_evm_account()),
924+
asset,
925+
0,
926+
erc20_balance / 10,
927+
Balance::MIN
928+
));
929+
hydradx_run_to_next_block();
930+
931+
pallet_transaction_payment::pallet::NextFeeMultiplier::<hydradx_runtime::Runtime>::put(
932+
hydradx_runtime::MinimumMultiplier::get(),
933+
);
934+
935+
let initial_user_fee_currency_balance = user_acc.balance(fee_currency);
936+
let initial_user_weth_balance = user_acc.balance(WETH);
937+
938+
let initial_fee_currency_issuance = Currencies::total_issuance(fee_currency);
939+
940+
// just reset the weth balance to 0 - to make sure we don't have enough WETH
941+
assert_ok!(hydradx_runtime::Currencies::update_balance(
942+
hydradx_runtime::RuntimeOrigin::root(),
943+
user_acc.address(),
944+
WETH,
945+
-(initial_user_weth_balance as i128),
946+
));
947+
948+
let initial_user_weth_balance = user_acc.balance(WETH);
949+
assert_eq!(initial_user_weth_balance, 0);
950+
951+
let set_currency_call = hydradx_runtime::RuntimeCall::MultiTransactionPayment(
952+
pallet_transaction_multi_payment::Call::set_currency { currency: fee_currency },
953+
);
954+
let dispatch_set_currency_call =
955+
hydradx_runtime::RuntimeCall::Dispatcher(pallet_dispatcher::Call::dispatch_with_extra_gas {
956+
call: Box::new(set_currency_call.clone()),
957+
extra_gas: 100_000,
958+
});
959+
960+
let gas_limit = 1000000;
961+
let deadline = U256::from(1000000000000u128);
962+
963+
let permit =
964+
pallet_evm_precompile_call_permit::CallPermitPrecompile::<hydradx_runtime::Runtime>::generate_permit(
965+
CALLPERMIT,
966+
user_evm_address,
967+
DISPATCH_ADDR,
968+
U256::from(0),
969+
dispatch_set_currency_call.encode(),
970+
gas_limit,
971+
U256::zero(),
972+
deadline,
973+
);
974+
let secret_key = SecretKey::parse(&user_secret_key).unwrap();
975+
let message = Message::parse(&permit);
976+
let (rs, v) = sign(&message, &secret_key);
977+
978+
// Validate unsigned first
979+
let call: pallet_transaction_multi_payment::Call<hydradx_runtime::Runtime> =
980+
pallet_transaction_multi_payment::Call::dispatch_permit {
981+
from: user_evm_address,
982+
to: DISPATCH_ADDR,
983+
value: U256::from(0),
984+
data: dispatch_set_currency_call.encode(),
985+
gas_limit,
986+
deadline,
987+
v: v.serialize(),
988+
r: H256::from(rs.r.b32()),
989+
s: H256::from(rs.s.b32()),
990+
};
991+
992+
let tag: Vec<u8> = ("EVMPermit", (U256::zero(), user_evm_address)).encode();
993+
assert_eq!(
994+
MultiTransactionPayment::validate_unsigned(TransactionSource::External, &call),
995+
Ok(ValidTransaction {
996+
priority: 0,
997+
requires: vec![],
998+
provides: vec![tag],
999+
longevity: 64,
1000+
propagate: true,
1001+
})
1002+
);
1003+
1004+
// And Dispatch
1005+
assert_ok!(MultiTransactionPayment::dispatch_permit(
1006+
hydradx_runtime::RuntimeOrigin::none(),
1007+
user_evm_address,
1008+
DISPATCH_ADDR,
1009+
U256::from(0),
1010+
dispatch_set_currency_call.encode(),
1011+
gas_limit,
1012+
deadline,
1013+
v.serialize(),
1014+
H256::from(rs.r.b32()),
1015+
H256::from(rs.s.b32()),
1016+
));
1017+
1018+
let currency =
1019+
pallet_transaction_multi_payment::Pallet::<hydradx_runtime::Runtime>::account_currency(&user_acc.address());
1020+
assert_eq!(currency, fee_currency);
1021+
1022+
let fee_currency_issuance = Currencies::total_issuance(fee_currency);
1023+
assert_eq!(initial_fee_currency_issuance, fee_currency_issuance);
1024+
1025+
let user_fee_currency_balance = user_acc.balance(fee_currency);
1026+
assert!(user_fee_currency_balance < initial_user_fee_currency_balance);
1027+
let final_treasury_fee_balance = treasury_acc.balance(asset);
1028+
1029+
assert!(final_treasury_fee_balance > initial_treasury_fee_balance);
1030+
let fee_amount = initial_user_fee_currency_balance - user_fee_currency_balance;
1031+
let treasury_received = final_treasury_fee_balance - initial_treasury_fee_balance;
1032+
assert_eq!(fee_amount, treasury_received);
1033+
})
1034+
}
1035+
8671036
#[test]
8681037
fn evm_permit_set_currency_dispatch_should_pay_evm_fee_in_insufficient_asset() {
8691038
TestNet::reset();

pallets/transaction-multi-payment/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-transaction-multi-payment"
3-
version = "10.1.8"
3+
version = "10.2.0"
44
description = "Transaction multi currency payment support module"
55
authors = ["GalacticCoucil"]
66
edition = "2021"

pallets/transaction-multi-payment/src/lib.rs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -843,36 +843,6 @@ impl<T: Config> AccountFeeCurrency<T::AccountId> for Pallet<T> {
843843
}
844844
}
845845

846-
pub struct TryCallCurrency<T>(PhantomData<T>);
847-
impl<T> TryConvert<&<T as frame_system::Config>::RuntimeCall, AssetIdOf<T>> for TryCallCurrency<T>
848-
where
849-
T: Config + pallet_utility::Config,
850-
<T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>> + IsSubType<pallet_utility::pallet::Call<T>>,
851-
<T as pallet_utility::Config>::RuntimeCall: IsSubType<Call<T>>,
852-
{
853-
fn try_convert(
854-
call: &<T as frame_system::Config>::RuntimeCall,
855-
) -> Result<AssetIdOf<T>, &<T as frame_system::Config>::RuntimeCall> {
856-
if let Some(crate::pallet::Call::set_currency { currency }) = call.is_sub_type() {
857-
Ok(*currency)
858-
} else if let Some(pallet_utility::pallet::Call::batch { calls })
859-
| Some(pallet_utility::pallet::Call::batch_all { calls })
860-
| Some(pallet_utility::pallet::Call::force_batch { calls }) = call.is_sub_type()
861-
{
862-
// `calls` can be empty Vec
863-
match calls.first() {
864-
Some(first_call) => match first_call.is_sub_type() {
865-
Some(crate::pallet::Call::set_currency { currency }) => Ok(*currency),
866-
_ => Err(call),
867-
},
868-
_ => Err(call),
869-
}
870-
} else {
871-
Err(call)
872-
}
873-
}
874-
}
875-
876846
pub struct NoCallCurrency<T>(PhantomData<T>);
877847
impl<T: Config> TryConvert<&<T as frame_system::Config>::RuntimeCall, AssetIdOf<T>> for NoCallCurrency<T> {
878848
fn try_convert(

runtime/hydradx/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "hydradx-runtime"
3-
version = "356.0.0"
3+
version = "357.0.0"
44
authors = ["GalacticCouncil"]
55
edition = "2021"
66
license = "Apache 2.0"

runtime/hydradx/src/assets.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ use pallet_staking::{
7373
types::{Action, Point},
7474
SigmoidPercentage,
7575
};
76-
use pallet_transaction_multi_payment::{AddTxAssetOnAccount, RemoveTxAssetOnKilled};
76+
use pallet_transaction_multi_payment::{AddTxAssetOnAccount, AssetIdOf, Call, Config, RemoveTxAssetOnKilled};
7777
use pallet_xyk::weights::WeightInfo as XykWeights;
7878
use primitives::constants::{
7979
chain::{CORE_ASSET_ID, OMNIPOOL_SOURCE, XYK_SOURCE},
@@ -1402,6 +1402,7 @@ use hydradx_adapters::price::OraclePriceProviderUsingRoute;
14021402

14031403
#[cfg(feature = "runtime-benchmarks")]
14041404
use frame_support::storage::with_transaction;
1405+
use frame_support::traits::IsSubType;
14051406
use hydradx_traits::evm::{Erc20Inspect, Erc20OnDust};
14061407
#[cfg(feature = "runtime-benchmarks")]
14071408
use hydradx_traits::price::PriceProvider;
@@ -1421,6 +1422,7 @@ use pallet_referrals::{FeeDistribution, Level};
14211422
use pallet_stableswap::types::PegType;
14221423
#[cfg(feature = "runtime-benchmarks")]
14231424
use pallet_stableswap::BenchmarkHelper;
1425+
use sp_runtime::traits::TryConvert;
14241426
use sp_runtime::TokenError;
14251427
#[cfg(feature = "runtime-benchmarks")]
14261428
use sp_runtime::TransactionOutcome;
@@ -2111,3 +2113,35 @@ impl Erc20OnDust<AccountId, AssetId> for ATokenAccountDuster {
21112113
Ok(())
21122114
}
21132115
}
2116+
2117+
pub struct TryCallCurrency;
2118+
impl TryConvert<&<Runtime as frame_system::Config>::RuntimeCall, AssetIdOf<Runtime>> for TryCallCurrency {
2119+
fn try_convert(
2120+
call: &<Runtime as frame_system::Config>::RuntimeCall,
2121+
) -> Result<AssetIdOf<Runtime>, &<Runtime as frame_system::Config>::RuntimeCall> {
2122+
if let Some(pallet_transaction_multi_payment::pallet::Call::set_currency { currency }) = call.is_sub_type() {
2123+
Ok(*currency)
2124+
} else if let Some(pallet_utility::pallet::Call::batch { calls })
2125+
| Some(pallet_utility::pallet::Call::batch_all { calls })
2126+
| Some(pallet_utility::pallet::Call::force_batch { calls }) = call.is_sub_type()
2127+
{
2128+
// `calls` can be empty Vec
2129+
match calls.first() {
2130+
Some(first_call) => match first_call.is_sub_type() {
2131+
Some(pallet_transaction_multi_payment::pallet::Call::set_currency { currency }) => Ok(*currency),
2132+
_ => Err(call),
2133+
},
2134+
_ => Err(call),
2135+
}
2136+
} else if let Some(pallet_dispatcher::pallet::Call::dispatch_with_extra_gas { call: inner_call, .. }) =
2137+
call.is_sub_type()
2138+
{
2139+
match inner_call.is_sub_type() {
2140+
Some(pallet_transaction_multi_payment::pallet::Call::set_currency { currency }) => Ok(*currency),
2141+
_ => Err(call),
2142+
}
2143+
} else {
2144+
Err(call)
2145+
}
2146+
}
2147+
}

runtime/hydradx/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
122122
spec_name: create_runtime_str!("hydradx"),
123123
impl_name: create_runtime_str!("hydradx"),
124124
authoring_version: 1,
125-
spec_version: 356,
125+
spec_version: 357,
126126
impl_version: 0,
127127
apis: RUNTIME_API_VERSIONS,
128128
transaction_version: 1,

runtime/hydradx/src/system.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ impl pallet_transaction_multi_payment::Config for Runtime {
620620
type InspectEvmAccounts = EVMAccounts;
621621
type WeightToFee = WeightToFee;
622622
type EvmPermit = evm::permit::EvmPermitHandler<Runtime>;
623-
type TryCallCurrency<'a> = pallet_transaction_multi_payment::TryCallCurrency<Runtime>;
623+
type TryCallCurrency<'a> = TryCallCurrency;
624624
type SwappablePaymentAssetSupport = assets::XykPaymentAssetSupport;
625625
}
626626

0 commit comments

Comments
 (0)