Skip to content

Commit f1163a9

Browse files
Merge pull request #1179 from galacticcouncil/feat/hsm-improve
feat: hsm - account whitelisting, arb profit receiver
2 parents ddbaeb0 + 3f8a514 commit f1163a9

File tree

10 files changed

+51
-33
lines changed

10 files changed

+51
-33
lines changed

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.52.2"
3+
version = "1.52.3"
44
description = "Integration tests"
55
authors = ["GalacticCouncil"]
66
edition = "2021"

integration-tests/src/hsm.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use hydradx_runtime::{
1111
precompiles::{handle::EvmDataWriter, Bytes},
1212
Executor,
1313
},
14-
AccountId, Currencies, EVMAccounts, FixedU128, Liquidation, Router, Runtime, Tokens, Treasury, HSM,
14+
AccountId, Currencies, EVMAccounts, FixedU128, Liquidation, Router, Runtime, Tokens, Treasury, TreasuryAccount,
15+
HSM,
1516
};
1617
use hydradx_runtime::{OriginCaller, RuntimeCall, RuntimeEvent, RuntimeOrigin, Stableswap};
1718
use hydradx_traits::evm::{CallContext, EvmAddress, InspectEvmAccounts, EVM};
@@ -120,21 +121,6 @@ fn check_flash_borrower(borrower: EvmAddress) -> bool {
120121
!value.is_empty() && value.iter().any(|&x| x != 0)
121122
}
122123

123-
fn get_max_flash_loan(minter: EvmAddress) -> U256 {
124-
//let acl_manager = hex!["c54dcFaEB75F56907E8B1De931dB4E37Bd0Afbb4"].into();
125-
let data = EvmDataWriter::new_with_selector(Function::MaxFlashLoan)
126-
.write(hollar_contract_address())
127-
.build();
128-
let context = CallContext::new_view(minter);
129-
let (res, value) = Executor::<hydradx_runtime::Runtime>::view(context, data, 100_000);
130-
std::assert_eq!(res, Succeed(Returned), "{:?}", hex::encode(value));
131-
if value.is_empty() {
132-
return U256::zero();
133-
} else {
134-
return U256::from_big_endian(&value[..]);
135-
}
136-
}
137-
138124
fn mint(facilitator: EvmAddress, to: EvmAddress, amount: u128) {
139125
let context = CallContext::new_call(hollar_contract_address(), facilitator);
140126
let data = EvmDataWriter::new_with_selector(Function::Mint)
@@ -1642,11 +1628,14 @@ fn arbitrage_should_work_when_hollar_amount_is_less_in_the_pool() {
16421628
flash_minter,
16431629
));
16441630

1631+
let treasury_balance_initial = Tokens::free_balance(2, &TreasuryAccount::get());
16451632
let hsm_dai_balance = Tokens::free_balance(2, &hsm_address);
16461633
assert_ok!(HSM::execute_arbitrage(hydradx_runtime::RuntimeOrigin::none(), 2, None));
16471634
let final_hsm_dai_balance = Tokens::free_balance(2, &hsm_address);
16481635
let received = final_hsm_dai_balance - hsm_dai_balance;
1649-
assert_eq!(received, 65746999678827350701713);
1636+
let treasury_balance_final = Tokens::free_balance(2, &TreasuryAccount::get());
1637+
let profit = treasury_balance_final - treasury_balance_initial;
1638+
assert_eq!(received + profit, 65746999678827350701713);
16501639
});
16511640
}
16521641

pallets/hsm/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-hsm"
3-
version = "1.2.3"
3+
version = "1.3.0"
44
edition = "2021"
55
description = "Hollar stability module"
66
authors = ["GalacticCouncil"]

pallets/hsm/src/lib.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ pub mod pallet {
145145
/// GHO contract address - EVM address of GHO token contract
146146
type GhoContractAddress: BoundErc20<AssetId = Self::AssetId>;
147147

148+
/// Arbitrage profit receiver
149+
type ArbitrageProfitReceiver: Get<Self::AccountId>;
150+
148151
/// Currency - fungible tokens trait to access token transfers
149152
type Currency: Mutate<Self::AccountId, Balance = Balance, AssetId = Self::AssetId>;
150153

@@ -243,8 +246,10 @@ pub mod pallet {
243246
/// - `asset_id`: The collateral asset used in the arbitrage
244247
/// - `hollar_amount`: Amount of Hollar that was included in the arbitrage operation
245248
ArbitrageExecuted {
249+
arbitrage: u8,
246250
asset_id: T::AssetId,
247251
hollar_amount: Balance,
252+
profit: Balance,
248253
},
249254

250255
/// Flash minter address set
@@ -860,14 +865,25 @@ pub mod pallet {
860865

861866
let (exit_reason, value) = T::Evm::call(context, data, U256::zero(), T::GasLimit::get());
862867

868+
let receiver_balance_initial = <T as crate::pallet::Config>::Currency::total_balance(
869+
collateral_asset_id,
870+
&T::ArbitrageProfitReceiver::get(),
871+
);
863872
if exit_reason != ExitReason::Succeed(ExitSucceed::Returned) {
864873
log::error!(target: "hsm", "Flash loan Hollar EVM execution failed - {:?}. Reason: {:?}", exit_reason, value);
865874
return Err(Error::<T>::InvalidEVMInteraction.into());
866875
}
876+
let receiver_balance_final = <T as crate::pallet::Config>::Currency::total_balance(
877+
collateral_asset_id,
878+
&T::ArbitrageProfitReceiver::get(),
879+
);
880+
let profit = receiver_balance_final.saturating_sub(receiver_balance_initial);
867881

868882
Self::deposit_event(Event::<T>::ArbitrageExecuted {
883+
arbitrage: arb_direction,
869884
asset_id: collateral_asset_id,
870885
hollar_amount: flash_loan_amount,
886+
profit,
871887
});
872888

873889
Ok(())
@@ -1642,11 +1658,10 @@ where
16421658
log::trace!(target: "hsm", "Collateral remaining : {:?}", remaining);
16431659
// In case there is some collateral left after the buy,
16441660
// we transfer it to the HSM account
1645-
let hsm_account = Self::account_id();
16461661
<T as Config>::Currency::transfer(
16471662
collateral_asset_id,
16481663
&flash_loan_account,
1649-
&hsm_account,
1664+
&T::ArbitrageProfitReceiver::get(),
16501665
remaining,
16511666
Preservation::Expendable,
16521667
)?;
@@ -1681,11 +1696,10 @@ where
16811696

16821697
if remaining > 0 {
16831698
log::trace!(target: "hsm", "Collateral remaining : {:?}", remaining);
1684-
let hsm_account = Self::account_id();
16851699
<T as Config>::Currency::transfer(
16861700
collateral_asset_id,
16871701
&flash_loan_account,
1688-
&hsm_account,
1702+
&T::ArbitrageProfitReceiver::get(),
16891703
remaining,
16901704
Preservation::Expendable,
16911705
)?;
@@ -1753,6 +1767,12 @@ where
17531767
capacity.saturating_sub(level)
17541768
}
17551769
}
1770+
1771+
pub fn is_flash_loan_account(account: &T::AccountId) -> bool {
1772+
GetFlashMinterSupport::<T>::get().map_or(false, |(_, loan_receiver)| {
1773+
T::EvmAccounts::account_id(loan_receiver) == *account
1774+
})
1775+
}
17561776
}
17571777

17581778
pub struct GetFlashMinterSupport<T>(sp_std::marker::PhantomData<T>);

pallets/hsm/src/tests/arb.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ fn arbitrage_should_work_when_less_hollar_in_the_pool_and_arb_amount_given() {
123123
assert_eq!(arb_amount, 500_005_437_502_633_106_476);
124124

125125
let hsm_balance_dai_after = Tokens::free_balance(DAI, &HSM::account_id());
126-
assert_eq!(hsm_balance_dai_after - hsm_balance_dai_before, arb_amount);
127-
assert_eq!(hsm_balance_dai_after, arb_amount);
126+
let profit = Tokens::free_balance(DAI, &HsmArbProfitReceiver::get());
127+
assert_eq!(profit, 10_875_005_266_593_893);
128+
assert_eq!(hsm_balance_dai_after - hsm_balance_dai_before + profit, arb_amount);
128129
});
129130
}
130131

@@ -181,8 +182,9 @@ fn arbitrage_should_work_when_less_hollar_in_the_pool() {
181182
assert_eq!(arb_amount, 500_005_437_502_633_106_476);
182183

183184
let hsm_balance_dai_after = Tokens::free_balance(DAI, &HSM::account_id());
184-
assert_eq!(hsm_balance_dai_after - hsm_balance_dai_before, arb_amount);
185-
assert_eq!(hsm_balance_dai_after, arb_amount);
185+
let profit = Tokens::free_balance(DAI, &HsmArbProfitReceiver::get());
186+
assert_eq!(profit, 10_875_005_266_593_893);
187+
assert_eq!(hsm_balance_dai_after - hsm_balance_dai_before + profit, arb_amount);
186188
});
187189
}
188190

pallets/hsm/src/tests/mock.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub const CHARLIE: AccountId = AccountId::new([3; 32]);
7272
pub const PROVIDER: AccountId = AccountId::new([4; 32]);
7373

7474
pub const ARB_ACCOUNT: AccountId = AccountId::new([22; 32]);
75+
pub const PROFIT_RECEIVER: AccountId = AccountId::new([23; 32]);
7576

7677
pub const ONE: Balance = 1_000_000_000_000_000_000;
7778

@@ -193,6 +194,7 @@ parameter_types! {
193194
pub PalletId: frame_support::PalletId = frame_support::PalletId(*b"py/hsmdx");
194195
pub const GasLimit: u64 = 1_000_000;
195196
pub AmplificationRange: RangeInclusive<NonZeroU16> = RangeInclusive::new(NonZeroU16::new(2).unwrap(), NonZeroU16::new(10_000).unwrap());
197+
pub HsmArbProfitReceiver: AccountId = PROFIT_RECEIVER.into();
196198
}
197199

198200
pub struct DummyRegistry;
@@ -554,6 +556,7 @@ impl Config for Test {
554556
type WeightInfo = ();
555557
#[cfg(feature = "runtime-benchmarks")]
556558
type BenchmarkHelper = for_benchmark_tests::MockHSMBenchmarkHelper;
559+
type ArbitrageProfitReceiver = HsmArbProfitReceiver;
557560
}
558561

559562
pub struct Whitelist;

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 = "345.0.0"
3+
version = "346.0.0"
44
authors = ["GalacticCouncil"]
55
edition = "2021"
66
license = "Apache 2.0"

runtime/hydradx/src/assets.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,9 @@ pub struct DustRemovalWhitelist;
672672

673673
impl Contains<AccountId> for DustRemovalWhitelist {
674674
fn contains(a: &AccountId) -> bool {
675-
get_all_module_accounts().contains(a) || pallet_duster::DusterWhitelist::<Runtime>::contains(a)
675+
get_all_module_accounts().contains(a)
676+
|| HSM::is_flash_loan_account(a)
677+
|| pallet_duster::DusterWhitelist::<Runtime>::contains(a)
676678
}
677679
}
678680

@@ -1797,6 +1799,7 @@ impl pallet_hsm::Config for Runtime {
17971799
type PalletId = HsmPalletId;
17981800
type AuthorityOrigin = EitherOf<EnsureRoot<Self::AccountId>, EitherOf<EconomicParameters, GeneralAdmin>>;
17991801
type GhoContractAddress = AssetRegistry;
1802+
type ArbitrageProfitReceiver = TreasuryAccount;
18001803
type Currency = FungibleCurrencies<Runtime>;
18011804
#[cfg(feature = "runtime-benchmarks")]
18021805
type Evm = helpers::benchmark_helpers::DummyEvmForHsm;

runtime/hydradx/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
120120
spec_name: create_runtime_str!("hydradx"),
121121
impl_name: create_runtime_str!("hydradx"),
122122
authoring_version: 1,
123-
spec_version: 345,
123+
spec_version: 346,
124124
impl_version: 0,
125125
apis: RUNTIME_API_VERSIONS,
126126
transaction_version: 1,
@@ -142,6 +142,7 @@ pub fn get_all_module_accounts() -> Vec<AccountId> {
142142
VestingPalletId::get().into_account_truncating(),
143143
ReferralsPalletId::get().into_account_truncating(),
144144
BondsPalletId::get().into_account_truncating(),
145+
HsmPalletId::get().into_account_truncating(),
145146
pallet_route_executor::Pallet::<Runtime>::router_account(),
146147
]
147148
}

0 commit comments

Comments
 (0)