aurora_engine_precompiles/
promise_result.rs1use aurora_engine_sdk::promise::ReadOnlyPromiseHandler;
2use aurora_engine_types::{Cow, Vec, borsh};
3use aurora_evm::{Context, ExitError};
4
5use super::{EvmPrecompileResult, Precompile};
6use crate::prelude::types::{Address, EthGas, make_address};
7use crate::{PrecompileOutput, utils};
8
9pub const ADDRESS: Address = make_address(0x0a3540f7, 0x9be10ef14890e87c1a0040a68cc6af71);
14
15pub mod costs {
16 use crate::prelude::types::EthGas;
17
18 pub const PROMISE_RESULT_BASE_COST: EthGas = EthGas::new(111);
20 pub const PROMISE_RESULT_BYTE_COST: EthGas = EthGas::new(2);
22}
23
24pub struct PromiseResult<H> {
25 handler: H,
26}
27
28impl<H> PromiseResult<H> {
29 pub const fn new(handler: H) -> Self {
30 Self { handler }
31 }
32}
33
34impl<H: ReadOnlyPromiseHandler> Precompile for PromiseResult<H> {
35 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
36 Ok(costs::PROMISE_RESULT_BASE_COST)
39 }
40
41 fn run(
42 &self,
43 input: &[u8],
44 target_gas: Option<EthGas>,
45 context: &Context,
46 _is_static: bool,
47 ) -> EvmPrecompileResult {
48 utils::validate_no_value_attached_to_precompile(context.apparent_value)?;
49 let mut cost = Self::required_gas(input)?;
50 let check_cost = |cost: EthGas| -> Result<(), ExitError> {
51 if let Some(target_gas) = target_gas {
52 if cost > target_gas {
53 return Err(ExitError::OutOfGas);
54 }
55 }
56 Ok(())
57 };
58 check_cost(cost)?;
59
60 let num_promises = self.handler.ro_promise_results_count();
61 let n_usize = usize::try_from(num_promises).map_err(utils::err_usize_conv)?;
62 let mut results = Vec::with_capacity(n_usize);
63 for i in 0..num_promises {
64 if let Some(result) = self.handler.ro_promise_result(i) {
65 let n_bytes = u64::try_from(result.size()).map_err(utils::err_usize_conv)?;
66 cost = EthGas::new(n_bytes)
67 .checked_mul(costs::PROMISE_RESULT_BYTE_COST)
68 .and_then(|result| result.checked_add(cost))
69 .ok_or(ExitError::Other(Cow::Borrowed("ERR_OVERFLOW_NUMBER")))?;
70 check_cost(cost)?;
71 results.push(result);
72 }
73 }
74
75 let bytes = borsh::to_vec(&results)
76 .map_err(|_| ExitError::Other(Cow::Borrowed("ERR_PROMISE_RESULT_SERIALIZATION")))?;
77 Ok(PrecompileOutput::without_logs(cost, bytes))
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::prelude::sdk::types::near_account_to_evm_address;
84 use crate::promise_result;
85
86 #[test]
87 fn test_get_promise_results_precompile_id() {
88 assert_eq!(
89 promise_result::ADDRESS,
90 near_account_to_evm_address(b"getPromiseResults")
91 );
92 }
93}