1use alloy_primitives::{Address, Bytes, U256};
9use revm::state::Bytecode;
10use tempo_contracts::{
11 ARACHNID_CREATE2_FACTORY_ADDRESS, CREATEX_ADDRESS, CreateX, MULTICALL3_ADDRESS, Multicall3,
12 PERMIT2_ADDRESS, Permit2, SAFE_DEPLOYER_ADDRESS, SafeDeployer,
13 contracts::ARACHNID_CREATE2_FACTORY_BYTECODE, precompiles::VALIDATOR_CONFIG_ADDRESS,
14};
15use tempo_hardfork::TempoHardfork;
16use tempo_precompiles::{
17 error::TempoPrecompileError,
18 storage::{PrecompileStorageProvider, StorageCtx},
19 tip20::{ITIP20, TIP20Token},
20 tip20_factory::TIP20Factory,
21 validator_config,
22};
23
24use crate::constants::SYSTEM_PRECOMPILE_STUB;
25
26pub use foundry_common::tempo::{
27 ALPHA_USD_ADDRESS, BETA_USD_ADDRESS, PATH_USD_ADDRESS, THETA_USD_ADDRESS,
28};
29pub use foundry_evm_networks::{
30 TEMPO_PRECOMPILE_ADDRESSES, active_tempo_precompile_addresses, is_tempo_precompile_active_at,
31};
32pub use tempo_contracts::precompiles::{
33 ACCOUNT_KEYCHAIN_ADDRESS, ADDRESS_REGISTRY_ADDRESS, IAccountKeychain, IAddressRegistry,
34 IFeeManager, IReceivePolicyGuard, ISignatureVerifier, IStablecoinDEX, ITIP20ChannelReserve,
35 ITIP403Registry, RECEIVE_POLICY_GUARD_ADDRESS, SIGNATURE_VERIFIER_ADDRESS,
36 STABLECOIN_DEX_ADDRESS, TIP_FEE_MANAGER_ADDRESS, TIP20_CHANNEL_RESERVE_ADDRESS,
37 TIP20_FACTORY_ADDRESS, TIP403_REGISTRY_ADDRESS,
38};
39pub use tempo_precompiles::{
40 address_registry::{AddressRegistry, IMPLICIT_APPROVAL_LIST, is_implicitly_approved},
41 signature_verifier::SignatureVerifier,
42 stablecoin_dex::StablecoinDEX,
43 tip_fee_manager::TipFeeManager,
44 tip20::is_tip20_prefix,
45 tip20_channel_reserve::TIP20ChannelReserve,
46};
47
48pub const TEMPO_TIP20_TOKENS: &[Address] = &[PATH_USD_ADDRESS];
50
51pub fn initialize_tempo_genesis_at_hardfork(
53 storage: &mut impl PrecompileStorageProvider,
54 admin: Address,
55 recipient: Address,
56 hardfork: TempoHardfork,
57) -> Result<(), TempoPrecompileError> {
58 StorageCtx::enter(storage, || initialize_tempo_genesis_inner(admin, recipient, hardfork))
59}
60
61pub fn initialize_tempo_genesis_inner(
64 admin: Address,
65 recipient: Address,
66 hardfork: TempoHardfork,
67) -> Result<(), TempoPrecompileError> {
68 initialize_tempo_genesis_inner_with_precompiles(
69 admin,
70 recipient,
71 active_tempo_precompile_addresses(hardfork),
72 )
73}
74
75pub fn initialize_tempo_test_genesis_inner(
81 admin: Address,
82 recipient: Address,
83) -> Result<(), TempoPrecompileError> {
84 initialize_tempo_genesis_inner_with_precompiles(
85 admin,
86 recipient,
87 TEMPO_PRECOMPILE_ADDRESSES.iter().copied(),
88 )
89}
90
91fn initialize_tempo_genesis_inner_with_precompiles(
92 admin: Address,
93 recipient: Address,
94 precompiles: impl IntoIterator<Item = Address>,
95) -> Result<(), TempoPrecompileError> {
96 if TIP20Factory::new().is_tip20(PATH_USD_ADDRESS)? {
98 return Ok(());
99 }
100
101 let mut ctx = StorageCtx;
102
103 let sentinel = Bytecode::new_legacy(Bytes::from_static(SYSTEM_PRECOMPILE_STUB));
105 for precompile in precompiles {
106 ctx.set_code(precompile, sentinel.clone())?;
107 }
108
109 let path_usd_token_address = create_and_mint_token(
111 PATH_USD_ADDRESS,
112 "PathUSD",
113 "PathUSD",
114 "USD",
115 Address::ZERO,
116 admin,
117 recipient,
118 U256::from(u64::MAX),
119 )?;
120
121 let _alpha_usd_token_address = create_and_mint_token(
123 ALPHA_USD_ADDRESS,
124 "AlphaUSD",
125 "AlphaUSD",
126 "USD",
127 path_usd_token_address,
128 admin,
129 recipient,
130 U256::from(u64::MAX),
131 )?;
132
133 let _beta_usd_token_address = create_and_mint_token(
135 BETA_USD_ADDRESS,
136 "BetaUSD",
137 "BetaUSD",
138 "USD",
139 path_usd_token_address,
140 admin,
141 recipient,
142 U256::from(u64::MAX),
143 )?;
144
145 let _theta_usd_token_address = create_and_mint_token(
147 THETA_USD_ADDRESS,
148 "ThetaUSD",
149 "ThetaUSD",
150 "USD",
151 path_usd_token_address,
152 admin,
153 recipient,
154 U256::from(u64::MAX),
155 )?;
156
157 ctx.sstore(VALIDATOR_CONFIG_ADDRESS, validator_config::slots::OWNER, admin.into_word().into())?;
159
160 ctx.set_code(
162 MULTICALL3_ADDRESS,
163 Bytecode::new_legacy(Bytes::from_static(&Multicall3::DEPLOYED_BYTECODE)),
164 )?;
165 ctx.set_code(
166 CREATEX_ADDRESS,
167 Bytecode::new_legacy(Bytes::from_static(&CreateX::DEPLOYED_BYTECODE)),
168 )?;
169 ctx.set_code(
170 SAFE_DEPLOYER_ADDRESS,
171 Bytecode::new_legacy(Bytes::from_static(&SafeDeployer::DEPLOYED_BYTECODE)),
172 )?;
173 ctx.set_code(
174 PERMIT2_ADDRESS,
175 Bytecode::new_legacy(Bytes::from_static(&Permit2::DEPLOYED_BYTECODE)),
176 )?;
177 ctx.set_code(
178 ARACHNID_CREATE2_FACTORY_ADDRESS,
179 Bytecode::new_legacy(ARACHNID_CREATE2_FACTORY_BYTECODE),
180 )?;
181
182 Ok(())
183}
184
185#[allow(clippy::too_many_arguments)]
187fn create_and_mint_token(
188 address: Address,
189 symbol: &str,
190 name: &str,
191 currency: &str,
192 quote_token: Address,
193 admin: Address,
194 recipient: Address,
195 mint_amount: U256,
196) -> Result<Address, TempoPrecompileError> {
197 let mut tip20_factory = TIP20Factory::new();
198
199 let token_address = tip20_factory.create_token_reserved_address(
200 address,
201 name,
202 symbol,
203 currency,
204 quote_token,
205 admin,
206 )?;
207
208 let mut token = TIP20Token::from_address(token_address)?;
209 token.grant_role_internal(admin, TIP20Token::issuer_role())?;
210 token.mint(admin, ITIP20::mintCall { to: recipient, amount: mint_amount })?;
211 if admin != recipient {
212 token.mint(admin, ITIP20::mintCall { to: admin, amount: mint_amount })?;
213 }
214
215 Ok(token_address)
216}