tempo_precompiles/tip20_factory/
dispatch.rs1use crate::{
4 Precompile, SelectorSchedule, charge_input_cost, dispatch_call, mutate,
5 tip20_factory::TIP20Factory, view,
6};
7use alloy::{
8 primitives::Address,
9 sol_types::{SolCall, SolInterface},
10};
11use revm::precompile::PrecompileResult;
12use tempo_chainspec::hardfork::TempoHardfork;
13use tempo_contracts::precompiles::{ITIP20Factory::ITIP20FactoryCalls, createTokenWithLogoCall};
14
15const T5_ADDED: &[[u8; 4]] = &[createTokenWithLogoCall::SELECTOR];
17
18impl Precompile for TIP20Factory {
19 fn call(&mut self, calldata: &[u8], msg_sender: Address) -> PrecompileResult {
20 if let Some(err) = charge_input_cost(&mut self.storage, calldata) {
21 return err;
22 }
23
24 dispatch_call(
25 calldata,
26 &[SelectorSchedule::new(TempoHardfork::T5).with_added(T5_ADDED)],
27 ITIP20FactoryCalls::abi_decode,
28 |call| match call {
29 ITIP20FactoryCalls::createToken_0(call) => {
30 mutate(call, msg_sender, |s, c| self.create_token(s, c))
31 }
32 ITIP20FactoryCalls::createToken_1(call) => {
33 mutate(call, msg_sender, |s, c| self.create_token_with_logo(s, c))
34 }
35 ITIP20FactoryCalls::isTIP20(call) => view(call, |c| self.is_tip20(c.token)),
36 ITIP20FactoryCalls::getTokenAddress(call) => {
37 view(call, |c| self.get_token_address(c))
38 }
39 },
40 )
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use crate::{
48 storage::{StorageCtx, hashmap::HashMapStorageProvider},
49 test_util::{assert_full_coverage, check_selector_coverage},
50 };
51 use alloy::{
52 primitives::B256,
53 sol_types::{SolCall, SolError},
54 };
55 use tempo_chainspec::hardfork::TempoHardfork;
56 use tempo_contracts::precompiles::{
57 ITIP20Factory::ITIP20FactoryCalls, UnknownFunctionSelector,
58 };
59
60 #[test]
61 fn tip20_factory_test_selector_coverage() {
62 let mut storage = HashMapStorageProvider::new_with_spec(1, TempoHardfork::T5);
64
65 StorageCtx::enter(&mut storage, || {
66 let mut factory = TIP20Factory::new();
67
68 let unsupported = check_selector_coverage(
69 &mut factory,
70 ITIP20FactoryCalls::SELECTORS,
71 "ITIP20Factory",
72 ITIP20FactoryCalls::name_by_selector,
73 );
74
75 assert_full_coverage([unsupported]);
76 })
77 }
78
79 #[test]
80 fn test_create_token_with_logo_gated_behind_t5() -> eyre::Result<()> {
81 let mut storage = HashMapStorageProvider::new_with_spec(1, TempoHardfork::T4);
83 let sender = Address::random();
84
85 StorageCtx::enter(&mut storage, || {
86 let mut factory = TIP20Factory::new();
87
88 let calldata = createTokenWithLogoCall {
89 name: "Logo".to_string(),
90 symbol: "LOGO".to_string(),
91 currency: "USD".to_string(),
92 quoteToken: Address::ZERO,
93 admin: sender,
94 salt: B256::ZERO,
95 logoURI: String::new(),
96 }
97 .abi_encode();
98
99 let result = factory.call(&calldata, sender)?;
100 assert!(result.is_revert());
101 assert!(UnknownFunctionSelector::abi_decode(&result.bytes).is_ok());
102
103 Ok(())
104 })
105 }
106}