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