1#![cfg_attr(not(feature = "std"), no_std)]
20
21#[cfg(test)]
22mod mock;
23#[cfg(test)]
24mod tests;
25
26use fp_evm::PrecompileHandle;
27use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo};
28use frame_support::pallet_prelude::MaxEncodedLen;
29use frame_support::sp_runtime::Percent;
30use frame_support::traits::{fungible::Inspect, Get};
31use pallet_evm::AddressMapping;
32use pallet_parachain_staking::ScheduledRequest;
33use precompile_utils::prelude::*;
34use sp_core::{H160, U256};
35use sp_runtime::traits::Dispatchable;
36use sp_std::{convert::TryInto, marker::PhantomData, vec::Vec};
37
38type BalanceOf<Runtime> = <<Runtime as pallet_parachain_staking::Config>::Currency as Inspect<
39 <Runtime as frame_system::Config>::AccountId,
40>>::Balance;
41
42pub struct ParachainStakingPrecompile<Runtime>(PhantomData<Runtime>);
50
51#[precompile_utils::precompile]
52impl<Runtime> ParachainStakingPrecompile<Runtime>
53where
54 Runtime: pallet_parachain_staking::Config + pallet_evm::Config,
55 Runtime::AccountId: Into<H160>,
56 Runtime::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
57 Runtime::RuntimeCall: From<pallet_parachain_staking::Call<Runtime>>,
58 BalanceOf<Runtime>: TryFrom<U256> + Into<U256> + solidity::Codec,
59 <Runtime as pallet_evm::Config>::AddressMapping: AddressMapping<Runtime::AccountId>,
60{
61 #[precompile::public("minDelegation()")]
63 #[precompile::public("min_delegation()")]
64 #[precompile::view]
65 fn min_delegation(_handle: &mut impl PrecompileHandle) -> EvmResult<u128> {
66 let min_nomination: u128 =
67 <<Runtime as pallet_parachain_staking::Config>::MinDelegation as Get<
68 BalanceOf<Runtime>,
69 >>::get()
70 .try_into()
71 .map_err(|_| revert("Amount is too large for provided balance type"))?;
72
73 Ok(min_nomination)
74 }
75
76 #[precompile::public("points(uint256)")]
78 #[precompile::view]
79 fn points(handle: &mut impl PrecompileHandle, round: Convert<U256, u32>) -> EvmResult<u32> {
80 let round = round.converted();
81 handle.record_db_read::<Runtime>(16)?;
83 let points: u32 = pallet_parachain_staking::Pallet::<Runtime>::points(round);
84
85 Ok(points)
86 }
87
88 #[precompile::public("awardedPoints(uint32,address)")]
89 #[precompile::view]
90 fn awarded_points(
91 handle: &mut impl PrecompileHandle,
92 round: u32,
93 candidate: Address,
94 ) -> EvmResult<u32> {
95 handle.record_db_read::<Runtime>(44)?;
98
99 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
100
101 let points = <pallet_parachain_staking::Pallet<Runtime>>::awarded_pts(&round, &candidate);
102
103 Ok(points)
104 }
105
106 #[precompile::public("candidateCount()")]
107 #[precompile::public("candidate_count()")]
108 #[precompile::view]
109 fn candidate_count(handle: &mut impl PrecompileHandle) -> EvmResult<u32> {
110 handle.record_db_read::<Runtime>(7200)?;
113 let candidate_count: u32 = <pallet_parachain_staking::Pallet<Runtime>>::candidate_pool()
115 .0
116 .len() as u32;
117
118 Ok(candidate_count)
120 }
121
122 #[precompile::public("round()")]
123 #[precompile::view]
124 fn round(handle: &mut impl PrecompileHandle) -> EvmResult<u32> {
125 handle.record_db_read::<Runtime>(12)?;
127 let round: u32 = <pallet_parachain_staking::Pallet<Runtime>>::round().current;
128
129 Ok(round)
130 }
131
132 #[precompile::public("candidateDelegationCount(address)")]
133 #[precompile::public("candidate_delegation_count(address)")]
134 #[precompile::view]
135 fn candidate_delegation_count(
136 handle: &mut impl PrecompileHandle,
137 candidate: Address,
138 ) -> EvmResult<u32> {
139 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
140 handle.record_db_read::<Runtime>(133)?;
142 let result = if let Some(state) =
143 <pallet_parachain_staking::Pallet<Runtime>>::candidate_info(&candidate)
144 {
145 let candidate_delegation_count: u32 = state.delegation_count;
146
147 log::trace!(
148 target: "staking-precompile",
149 "Result from pallet is {:?}",
150 candidate_delegation_count
151 );
152 candidate_delegation_count
153 } else {
154 log::trace!(
155 target: "staking-precompile",
156 "Candidate {:?} not found, so delegation count is 0",
157 candidate
158 );
159 0u32
160 };
161
162 Ok(result)
163 }
164
165 #[precompile::public("candidateAutoCompoundingDelegationCount(address)")]
166 #[precompile::view]
167 fn candidate_auto_compounding_delegation_count(
168 handle: &mut impl PrecompileHandle,
169 candidate: Address,
170 ) -> EvmResult<u32> {
171 handle.record_db_read::<Runtime>(
177 36 + (
178 22 * (<Runtime as pallet_parachain_staking::Config>::MaxTopDelegationsPerCandidate::get()
179 + <Runtime as pallet_parachain_staking::Config>::MaxBottomDelegationsPerCandidate::get())
180 as usize),
181 )?;
182
183 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
184
185 let count =
186 <pallet_parachain_staking::Pallet<Runtime>>::auto_compounding_delegations(&candidate)
187 .len() as u32;
188
189 Ok(count)
190 }
191
192 #[precompile::public("delegatorDelegationCount(address)")]
193 #[precompile::public("delegator_delegation_count(address)")]
194 #[precompile::view]
195 fn delegator_delegation_count(
196 handle: &mut impl PrecompileHandle,
197 delegator: Address,
198 ) -> EvmResult<u32> {
199 let delegator = Runtime::AddressMapping::into_account_id(delegator.0);
200 handle.record_db_read::<Runtime>(
203 84 + (<Runtime as pallet_parachain_staking::Config>::MaxDelegationsPerDelegator::get()
204 as usize),
205 )?;
206 let result = if let Some(state) =
207 <pallet_parachain_staking::Pallet<Runtime>>::delegator_state(&delegator)
208 {
209 let delegator_delegation_count: u32 = state.delegations.0.len() as u32;
210
211 log::trace!(
212 target: "staking-precompile",
213 "Result from pallet is {:?}",
214 delegator_delegation_count
215 );
216
217 delegator_delegation_count
218 } else {
219 log::trace!(
220 target: "staking-precompile",
221 "Delegator {:?} not found, so delegation count is 0",
222 delegator
223 );
224 0u32
225 };
226
227 Ok(result)
228 }
229
230 #[precompile::public("selectedCandidates()")]
231 #[precompile::public("selected_candidates()")]
232 #[precompile::view]
233 fn selected_candidates(handle: &mut impl PrecompileHandle) -> EvmResult<Vec<Address>> {
234 handle.record_db_read::<Runtime>(4)?;
236 let total_selected = pallet_parachain_staking::Pallet::<Runtime>::total_selected();
237 handle.record_db_read::<Runtime>(20 * (total_selected as usize))?;
239 let selected_candidates: Vec<Address> =
240 pallet_parachain_staking::Pallet::<Runtime>::selected_candidates()
241 .into_iter()
242 .map(|address| Address(address.into()))
243 .collect();
244
245 Ok(selected_candidates)
246 }
247
248 #[precompile::public("delegationAmount(address,address)")]
249 #[precompile::view]
250 fn delegation_amount(
251 handle: &mut impl PrecompileHandle,
252 delegator: Address,
253 candidate: Address,
254 ) -> EvmResult<U256> {
255 handle.record_db_read::<Runtime>(
258 84 + (<Runtime as pallet_parachain_staking::Config>::MaxDelegationsPerDelegator::get()
259 as usize),
260 )?;
261 let (candidate, delegator) = (
262 Runtime::AddressMapping::into_account_id(candidate.0),
263 Runtime::AddressMapping::into_account_id(delegator.0),
264 );
265 let amount = pallet_parachain_staking::Pallet::<Runtime>::delegator_state(&delegator)
266 .and_then(|state| {
267 state
268 .delegations
269 .0
270 .into_iter()
271 .find(|b| b.owner == candidate)
272 })
273 .map_or(
274 U256::zero(),
275 |pallet_parachain_staking::Bond { amount, .. }| amount.into(),
276 );
277
278 Ok(amount)
279 }
280
281 #[precompile::public("isInTopDelegations(address,address)")]
283 #[precompile::view]
284 fn is_in_top_delegations(
285 handle: &mut impl PrecompileHandle,
286 delegator: Address,
287 candidate: Address,
288 ) -> EvmResult<bool> {
289 let (candidate, delegator) = (
290 Runtime::AddressMapping::into_account_id(candidate.0),
291 Runtime::AddressMapping::into_account_id(delegator.0),
292 );
293 handle.record_db_read::<Runtime>(
297 44 + ((36
298 * <Runtime as pallet_parachain_staking::Config>::MaxTopDelegationsPerCandidate::get(
299 )) as usize),
300 )?;
301 let is_in_top_delegations = pallet_parachain_staking::Pallet::<Runtime>::top_delegations(
302 &candidate,
303 )
304 .map_or(false, |delegations| {
305 delegations
306 .delegations
307 .into_iter()
308 .any(|b| b.owner == delegator)
309 });
310
311 Ok(is_in_top_delegations)
312 }
313
314 #[precompile::public("isDelegator(address)")]
315 #[precompile::public("is_delegator(address)")]
316 #[precompile::view]
317 fn is_delegator(handle: &mut impl PrecompileHandle, delegator: Address) -> EvmResult<bool> {
318 let delegator = Runtime::AddressMapping::into_account_id(delegator.0);
319 handle.record_db_read::<Runtime>(
322 84 + (<Runtime as pallet_parachain_staking::Config>::MaxDelegationsPerDelegator::get()
323 as usize),
324 )?;
325 let is_delegator = pallet_parachain_staking::Pallet::<Runtime>::is_delegator(&delegator);
326
327 Ok(is_delegator)
328 }
329
330 #[precompile::public("isCandidate(address)")]
331 #[precompile::public("is_candidate(address)")]
332 #[precompile::view]
333 fn is_candidate(handle: &mut impl PrecompileHandle, candidate: Address) -> EvmResult<bool> {
334 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
335
336 handle.record_db_read::<Runtime>(133)?;
338 let is_candidate = pallet_parachain_staking::Pallet::<Runtime>::is_candidate(&candidate);
339
340 Ok(is_candidate)
341 }
342
343 #[precompile::public("isSelectedCandidate(address)")]
344 #[precompile::public("is_selected_candidate(address)")]
345 #[precompile::view]
346 fn is_selected_candidate(
347 handle: &mut impl PrecompileHandle,
348 candidate: Address,
349 ) -> EvmResult<bool> {
350 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
351
352 handle.record_db_read::<Runtime>(4)?;
354 let total_selected = pallet_parachain_staking::Pallet::<Runtime>::total_selected();
355 handle.record_db_read::<Runtime>(20 * (total_selected as usize))?;
357 let is_selected =
358 pallet_parachain_staking::Pallet::<Runtime>::is_selected_candidate(&candidate);
359
360 Ok(is_selected)
361 }
362
363 #[precompile::public("delegationRequestIsPending(address,address)")]
364 #[precompile::public("delegation_request_is_pending(address,address)")]
365 #[precompile::view]
366 fn delegation_request_is_pending(
367 handle: &mut impl PrecompileHandle,
368 delegator: Address,
369 candidate: Address,
370 ) -> EvmResult<bool> {
371 let delegator = Runtime::AddressMapping::into_account_id(delegator.0);
372 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
373
374 handle.record_db_read::<Runtime>(
386 72 + ScheduledRequest::<BalanceOf<Runtime>>::max_encoded_len()
387 * (<Runtime as pallet_parachain_staking::Config>::MaxScheduledRequestsPerDelegator::get()
388 as usize),
389 )?;
390
391 let pending = <pallet_parachain_staking::Pallet<Runtime>>::delegation_request_exists(
394 &candidate, &delegator,
395 );
396
397 Ok(pending)
398 }
399
400 #[precompile::public("candidateExitIsPending(address)")]
401 #[precompile::public("candidate_exit_is_pending(address)")]
402 #[precompile::view]
403 fn candidate_exit_is_pending(
404 handle: &mut impl PrecompileHandle,
405 candidate: Address,
406 ) -> EvmResult<bool> {
407 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
408
409 handle.record_db_read::<Runtime>(133)?;
411
412 let pending = if let Some(state) =
415 <pallet_parachain_staking::Pallet<Runtime>>::candidate_info(&candidate)
416 {
417 state.is_leaving()
418 } else {
419 log::trace!(
420 target: "staking-precompile",
421 "Candidate state for {:?} not found, so pending exit is false",
422 candidate
423 );
424 false
425 };
426
427 Ok(pending)
428 }
429
430 #[precompile::public("candidateRequestIsPending(address)")]
431 #[precompile::public("candidate_request_is_pending(address)")]
432 #[precompile::view]
433 fn candidate_request_is_pending(
434 handle: &mut impl PrecompileHandle,
435 candidate: Address,
436 ) -> EvmResult<bool> {
437 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
438
439 handle.record_db_read::<Runtime>(133)?;
441
442 let pending = if let Some(state) =
445 <pallet_parachain_staking::Pallet<Runtime>>::candidate_info(&candidate)
446 {
447 state.request.is_some()
448 } else {
449 log::trace!(
450 target: "staking-precompile",
451 "Candidate metadata for {:?} not found, so pending request is false",
452 candidate
453 );
454 false
455 };
456
457 Ok(pending)
458 }
459
460 #[precompile::public("delegationAutoCompound(address,address)")]
461 #[precompile::view]
462 fn delegation_auto_compound(
463 handle: &mut impl PrecompileHandle,
464 delegator: Address,
465 candidate: Address,
466 ) -> EvmResult<u8> {
467 let delegator = Runtime::AddressMapping::into_account_id(delegator.0);
468 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
469
470 handle.record_db_read::<Runtime>(
476 36 + (
477 22 * (<Runtime as pallet_parachain_staking::Config>::MaxTopDelegationsPerCandidate::get()
478 + <Runtime as pallet_parachain_staking::Config>::MaxBottomDelegationsPerCandidate::get())
479 as usize),
480 )?;
481
482 let value = <pallet_parachain_staking::Pallet<Runtime>>::delegation_auto_compound(
483 &candidate, &delegator,
484 );
485
486 Ok(value.deconstruct())
487 }
488
489 #[precompile::public("joinCandidates(uint256,uint256)")]
492 #[precompile::public("join_candidates(uint256,uint256)")]
493 fn join_candidates(
494 handle: &mut impl PrecompileHandle,
495 amount: U256,
496 candidate_count: Convert<U256, u32>,
497 ) -> EvmResult {
498 let amount = Self::u256_to_amount(amount).in_field("amount")?;
499 let candidate_count = candidate_count.converted();
500
501 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
503 let call = pallet_parachain_staking::Call::<Runtime>::join_candidates {
504 bond: amount,
505 candidate_count,
506 };
507
508 RuntimeHelper::<Runtime>::try_dispatch(
510 handle,
511 frame_system::RawOrigin::Signed(origin).into(),
512 call,
513 0,
514 )?;
515
516 Ok(())
517 }
518
519 #[precompile::public("scheduleLeaveCandidates(uint256)")]
520 #[precompile::public("schedule_leave_candidates(uint256)")]
521 fn schedule_leave_candidates(
522 handle: &mut impl PrecompileHandle,
523 candidate_count: Convert<U256, u32>,
524 ) -> EvmResult {
525 let candidate_count = candidate_count.converted();
526
527 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
529 let call = pallet_parachain_staking::Call::<Runtime>::schedule_leave_candidates {
530 candidate_count,
531 };
532
533 RuntimeHelper::<Runtime>::try_dispatch(
535 handle,
536 frame_system::RawOrigin::Signed(origin).into(),
537 call,
538 0,
539 )?;
540
541 Ok(())
542 }
543
544 #[precompile::public("executeLeaveCandidates(address,uint256)")]
545 #[precompile::public("execute_leave_candidates(address,uint256)")]
546 fn execute_leave_candidates(
547 handle: &mut impl PrecompileHandle,
548 candidate: Address,
549 candidate_count: Convert<U256, u32>,
550 ) -> EvmResult {
551 let candidate_count = candidate_count.converted();
552 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
553
554 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
556 let call = pallet_parachain_staking::Call::<Runtime>::execute_leave_candidates {
557 candidate,
558 candidate_delegation_count: candidate_count,
559 };
560
561 RuntimeHelper::<Runtime>::try_dispatch(
563 handle,
564 frame_system::RawOrigin::Signed(origin).into(),
565 call,
566 0,
567 )?;
568
569 Ok(())
570 }
571
572 #[precompile::public("cancelLeaveCandidates(uint256)")]
573 #[precompile::public("cancel_leave_candidates(uint256)")]
574 fn cancel_leave_candidates(
575 handle: &mut impl PrecompileHandle,
576 candidate_count: Convert<U256, u32>,
577 ) -> EvmResult {
578 let candidate_count = candidate_count.converted();
579
580 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
582 let call =
583 pallet_parachain_staking::Call::<Runtime>::cancel_leave_candidates { candidate_count };
584
585 RuntimeHelper::<Runtime>::try_dispatch(
587 handle,
588 frame_system::RawOrigin::Signed(origin).into(),
589 call,
590 0,
591 )?;
592
593 Ok(())
594 }
595
596 #[precompile::public("goOffline()")]
597 #[precompile::public("go_offline()")]
598 fn go_offline(handle: &mut impl PrecompileHandle) -> EvmResult {
599 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
601 let call = pallet_parachain_staking::Call::<Runtime>::go_offline {};
602
603 RuntimeHelper::<Runtime>::try_dispatch(
605 handle,
606 frame_system::RawOrigin::Signed(origin).into(),
607 call,
608 0,
609 )?;
610
611 Ok(())
612 }
613
614 #[precompile::public("goOnline()")]
615 #[precompile::public("go_online()")]
616 fn go_online(handle: &mut impl PrecompileHandle) -> EvmResult {
617 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
619 let call = pallet_parachain_staking::Call::<Runtime>::go_online {};
620
621 RuntimeHelper::<Runtime>::try_dispatch(
623 handle,
624 frame_system::RawOrigin::Signed(origin).into(),
625 call,
626 0,
627 )?;
628
629 Ok(())
630 }
631
632 #[precompile::public("candidateBondMore(uint256)")]
633 #[precompile::public("candidate_bond_more(uint256)")]
634 fn candidate_bond_more(handle: &mut impl PrecompileHandle, more: U256) -> EvmResult {
635 let more = Self::u256_to_amount(more).in_field("more")?;
636
637 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
639 let call = pallet_parachain_staking::Call::<Runtime>::candidate_bond_more { more };
640
641 RuntimeHelper::<Runtime>::try_dispatch(
643 handle,
644 frame_system::RawOrigin::Signed(origin).into(),
645 call,
646 0,
647 )?;
648
649 Ok(())
650 }
651
652 #[precompile::public("scheduleCandidateBondLess(uint256)")]
653 #[precompile::public("schedule_candidate_bond_less(uint256)")]
654 fn schedule_candidate_bond_less(handle: &mut impl PrecompileHandle, less: U256) -> EvmResult {
655 let less = Self::u256_to_amount(less).in_field("less")?;
656
657 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
659 let call = pallet_parachain_staking::Call::<Runtime>::schedule_candidate_bond_less { less };
660
661 RuntimeHelper::<Runtime>::try_dispatch(
663 handle,
664 frame_system::RawOrigin::Signed(origin).into(),
665 call,
666 0,
667 )?;
668
669 Ok(())
670 }
671
672 #[precompile::public("executeCandidateBondLess(address)")]
673 #[precompile::public("execute_candidate_bond_less(address)")]
674 fn execute_candidate_bond_less(
675 handle: &mut impl PrecompileHandle,
676 candidate: Address,
677 ) -> EvmResult {
678 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
679
680 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
682 let call =
683 pallet_parachain_staking::Call::<Runtime>::execute_candidate_bond_less { candidate };
684
685 RuntimeHelper::<Runtime>::try_dispatch(
687 handle,
688 frame_system::RawOrigin::Signed(origin).into(),
689 call,
690 0,
691 )?;
692
693 Ok(())
694 }
695
696 #[precompile::public("cancelCandidateBondLess()")]
697 #[precompile::public("cancel_candidate_bond_less()")]
698 fn cancel_candidate_bond_less(handle: &mut impl PrecompileHandle) -> EvmResult {
699 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
701 let call = pallet_parachain_staking::Call::<Runtime>::cancel_candidate_bond_less {};
702
703 RuntimeHelper::<Runtime>::try_dispatch(
705 handle,
706 frame_system::RawOrigin::Signed(origin).into(),
707 call,
708 0,
709 )?;
710
711 Ok(())
712 }
713
714 #[precompile::public("delegateWithAutoCompound(address,uint256,uint8,uint256,uint256,uint256)")]
715 fn delegate_with_auto_compound(
716 handle: &mut impl PrecompileHandle,
717 candidate: Address,
718 amount: U256,
719 auto_compound: u8,
720 candidate_delegation_count: Convert<U256, u32>,
721 candidate_auto_compounding_delegation_count: Convert<U256, u32>,
722 delegator_delegation_count: Convert<U256, u32>,
723 ) -> EvmResult {
724 if auto_compound > 100 {
725 return Err(
726 RevertReason::custom("Must be an integer between 0 and 100 included")
727 .in_field("auto_compound")
728 .into(),
729 );
730 }
731
732 let amount = Self::u256_to_amount(amount).in_field("amount")?;
733 let auto_compound = Percent::from_percent(auto_compound);
734 let candidate_delegation_count = candidate_delegation_count.converted();
735 let candidate_auto_compounding_delegation_count =
736 candidate_auto_compounding_delegation_count.converted();
737 let delegator_delegation_count = delegator_delegation_count.converted();
738
739 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
740
741 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
743 let call = pallet_parachain_staking::Call::<Runtime>::delegate_with_auto_compound {
744 candidate,
745 amount,
746 auto_compound,
747 candidate_delegation_count,
748 candidate_auto_compounding_delegation_count,
749 delegation_count: delegator_delegation_count,
750 };
751
752 RuntimeHelper::<Runtime>::try_dispatch(
754 handle,
755 frame_system::RawOrigin::Signed(origin).into(),
756 call,
757 0,
758 )?;
759
760 Ok(())
761 }
762
763 #[precompile::public("scheduleRevokeDelegation(address)")]
764 #[precompile::public("schedule_revoke_delegation(address)")]
765 fn schedule_revoke_delegation(
766 handle: &mut impl PrecompileHandle,
767 candidate: Address,
768 ) -> EvmResult {
769 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
770
771 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
773 let call = pallet_parachain_staking::Call::<Runtime>::schedule_revoke_delegation {
774 collator: candidate,
775 };
776
777 RuntimeHelper::<Runtime>::try_dispatch(
779 handle,
780 frame_system::RawOrigin::Signed(origin).into(),
781 call,
782 0,
783 )?;
784
785 Ok(())
786 }
787
788 #[precompile::public("delegatorBondMore(address,uint256)")]
789 #[precompile::public("delegator_bond_more(address,uint256)")]
790 fn delegator_bond_more(
791 handle: &mut impl PrecompileHandle,
792 candidate: Address,
793 more: U256,
794 ) -> EvmResult {
795 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
796 let more = Self::u256_to_amount(more).in_field("more")?;
797
798 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
800 let call =
801 pallet_parachain_staking::Call::<Runtime>::delegator_bond_more { candidate, more };
802
803 RuntimeHelper::<Runtime>::try_dispatch(
805 handle,
806 frame_system::RawOrigin::Signed(origin).into(),
807 call,
808 0,
809 )?;
810
811 Ok(())
812 }
813
814 #[precompile::public("scheduleDelegatorBondLess(address,uint256)")]
815 #[precompile::public("schedule_delegator_bond_less(address,uint256)")]
816 fn schedule_delegator_bond_less(
817 handle: &mut impl PrecompileHandle,
818 candidate: Address,
819 less: U256,
820 ) -> EvmResult {
821 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
822 let less = Self::u256_to_amount(less).in_field("less")?;
823
824 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
826 let call = pallet_parachain_staking::Call::<Runtime>::schedule_delegator_bond_less {
827 candidate,
828 less,
829 };
830
831 RuntimeHelper::<Runtime>::try_dispatch(
833 handle,
834 frame_system::RawOrigin::Signed(origin).into(),
835 call,
836 0,
837 )?;
838
839 Ok(())
840 }
841
842 #[precompile::public("executeDelegationRequest(address,address)")]
843 #[precompile::public("execute_delegation_request(address,address)")]
844 fn execute_delegation_request(
845 handle: &mut impl PrecompileHandle,
846 delegator: Address,
847 candidate: Address,
848 ) -> EvmResult {
849 let delegator = Runtime::AddressMapping::into_account_id(delegator.0);
850 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
851
852 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
854 let call = pallet_parachain_staking::Call::<Runtime>::execute_delegation_request {
855 delegator,
856 candidate,
857 };
858
859 RuntimeHelper::<Runtime>::try_dispatch(
861 handle,
862 frame_system::RawOrigin::Signed(origin).into(),
863 call,
864 0,
865 )?;
866
867 Ok(())
868 }
869
870 #[precompile::public("cancelDelegationRequest(address)")]
871 #[precompile::public("cancel_delegation_request(address)")]
872 fn cancel_delegation_request(
873 handle: &mut impl PrecompileHandle,
874 candidate: Address,
875 ) -> EvmResult {
876 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
877
878 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
880 let call =
881 pallet_parachain_staking::Call::<Runtime>::cancel_delegation_request { candidate };
882
883 RuntimeHelper::<Runtime>::try_dispatch(
885 handle,
886 frame_system::RawOrigin::Signed(origin).into(),
887 call,
888 0,
889 )?;
890
891 Ok(())
892 }
893
894 #[precompile::public("setAutoCompound(address,uint8,uint256,uint256)")]
895 fn set_auto_compound(
896 handle: &mut impl PrecompileHandle,
897 candidate: Address,
898 value: u8,
899 candidate_auto_compounding_delegation_count: Convert<U256, u32>,
900 delegator_delegation_count: Convert<U256, u32>,
901 ) -> EvmResult {
902 if value > 100 {
903 return Err(
904 RevertReason::custom("Must be an integer between 0 and 100 included")
905 .in_field("value")
906 .into(),
907 );
908 }
909
910 let value = Percent::from_percent(value);
911 let candidate_auto_compounding_delegation_count_hint =
912 candidate_auto_compounding_delegation_count.converted();
913 let delegation_count_hint = delegator_delegation_count.converted();
914
915 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
916
917 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
919 let call = pallet_parachain_staking::Call::<Runtime>::set_auto_compound {
920 candidate,
921 value,
922 candidate_auto_compounding_delegation_count_hint,
923 delegation_count_hint,
924 };
925
926 RuntimeHelper::<Runtime>::try_dispatch(
928 handle,
929 frame_system::RawOrigin::Signed(origin).into(),
930 call,
931 0,
932 )?;
933
934 Ok(())
935 }
936
937 #[precompile::public("getDelegatorTotalStaked(address)")]
938 #[precompile::view]
939 fn get_delegator_total_staked(
940 handle: &mut impl PrecompileHandle,
941 delegator: Address,
942 ) -> EvmResult<U256> {
943 handle.record_db_read::<Runtime>(
946 84 + (<Runtime as pallet_parachain_staking::Config>::MaxDelegationsPerDelegator::get()
947 as usize),
948 )?;
949
950 let delegator = Runtime::AddressMapping::into_account_id(delegator.0);
951
952 let amount = <pallet_parachain_staking::Pallet<Runtime>>::delegator_state(&delegator)
953 .map(|state| state.total)
954 .unwrap_or_default();
955
956 Ok(amount.into())
957 }
958
959 #[precompile::public("getCandidateTotalCounted(address)")]
960 #[precompile::view]
961 fn get_candidate_total_counted(
962 handle: &mut impl PrecompileHandle,
963 candidate: Address,
964 ) -> EvmResult<U256> {
965 handle.record_db_read::<Runtime>(133)?;
967
968 let candidate = Runtime::AddressMapping::into_account_id(candidate.0);
969
970 let amount = <pallet_parachain_staking::Pallet<Runtime>>::candidate_info(&candidate)
971 .map(|state| state.total_counted)
972 .unwrap_or_default();
973
974 Ok(amount.into())
975 }
976
977 fn u256_to_amount(value: U256) -> MayRevert<BalanceOf<Runtime>> {
978 value
979 .try_into()
980 .map_err(|_| RevertReason::value_is_too_large("balance type").into())
981 }
982}