use crate::staking::{constants::SYSTEM_ADDRESS, interface::IMonadStaking::*, STAKING_ADDRESS};
use alloy_sol_types::SolCall;
use revm::{
handler::system_call::SystemCallEvm,
primitives::{Address, Bytes, U256},
};
pub fn syscall_reward_calldata(block_author: Address, block_reward: U256) -> Bytes {
let mut data = syscallRewardCall { blockAuthor: block_author }.abi_encode();
data.extend_from_slice(&block_reward.to_be_bytes::<32>());
data.into()
}
pub fn syscall_snapshot_calldata() -> Bytes {
syscallSnapshotCall {}.abi_encode().into()
}
pub fn syscall_on_epoch_change_calldata(new_epoch: u64) -> Bytes {
syscallOnEpochChangeCall { epoch: new_epoch }.abi_encode().into()
}
pub fn apply_syscall_reward<EVM: SystemCallEvm>(
evm: &mut EVM,
block_author: Address,
block_reward: U256,
) -> Result<EVM::ExecutionResult, EVM::Error> {
let data = syscall_reward_calldata(block_author, block_reward);
evm.system_call_one_with_caller(SYSTEM_ADDRESS, STAKING_ADDRESS, data)
}
pub fn apply_syscall_snapshot<EVM: SystemCallEvm>(
evm: &mut EVM,
) -> Result<EVM::ExecutionResult, EVM::Error> {
let data = syscall_snapshot_calldata();
evm.system_call_one_with_caller(SYSTEM_ADDRESS, STAKING_ADDRESS, data)
}
pub fn apply_syscall_on_epoch_change<EVM: SystemCallEvm>(
evm: &mut EVM,
new_epoch: u64,
) -> Result<EVM::ExecutionResult, EVM::Error> {
let data = syscall_on_epoch_change_calldata(new_epoch);
evm.system_call_one_with_caller(SYSTEM_ADDRESS, STAKING_ADDRESS, data)
}
pub fn apply_epoch_boundary<EVM: SystemCallEvm>(
evm: &mut EVM,
new_epoch: u64,
) -> Result<(EVM::ExecutionResult, EVM::ExecutionResult), EVM::Error> {
let snapshot_result = apply_syscall_snapshot(evm)?;
let epoch_change_result = apply_syscall_on_epoch_change(evm, new_epoch)?;
Ok((snapshot_result, epoch_change_result))
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_sol_types::SolCall;
#[test]
fn test_syscall_reward_calldata_selector() {
let data = syscall_reward_calldata(Address::ZERO, U256::ZERO);
assert_eq!(&data[..4], &syscallRewardCall::SELECTOR);
}
#[test]
fn test_syscall_reward_calldata_length() {
let data = syscall_reward_calldata(Address::ZERO, U256::ZERO);
assert_eq!(data.len(), 68);
}
#[test]
fn test_syscall_reward_calldata_decodes_author() {
let author = Address::new([0xAB; 20]);
let data = syscall_reward_calldata(author, U256::ZERO);
let call = syscallRewardCall::abi_decode_raw(&data[4..])
.expect("should decode standard ABI portion");
assert_eq!(call.blockAuthor, author);
}
#[test]
fn test_syscall_reward_calldata_extended_reward() {
let reward = U256::from(1_000_000_000_000_000_000u128); let data = syscall_reward_calldata(Address::ZERO, reward);
let decoded = U256::from_be_slice(&data[36..68]);
assert_eq!(decoded, reward);
}
#[test]
fn test_syscall_snapshot_calldata_selector() {
let data = syscall_snapshot_calldata();
assert_eq!(&data[..4], &syscallSnapshotCall::SELECTOR);
}
#[test]
fn test_syscall_snapshot_calldata_length() {
let data = syscall_snapshot_calldata();
assert_eq!(data.len(), 4);
}
#[test]
fn test_syscall_on_epoch_change_calldata_selector() {
let data = syscall_on_epoch_change_calldata(42);
assert_eq!(&data[..4], &syscallOnEpochChangeCall::SELECTOR);
}
#[test]
fn test_syscall_on_epoch_change_calldata_decodes_epoch() {
let data = syscall_on_epoch_change_calldata(42);
let call =
syscallOnEpochChangeCall::abi_decode_raw(&data[4..]).expect("should decode epoch");
assert_eq!(call.epoch, 42);
}
}