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(
67 storage: &mut impl PrecompileStorageProvider,
68 admin: Address,
69 recipient: Address,
70) -> Result<(), TempoPrecompileError> {
71 initialize_tempo_genesis_at_hardfork(storage, admin, recipient, TempoHardfork::default())
72}
73
74pub fn initialize_tempo_genesis_at_hardfork(
76 storage: &mut impl PrecompileStorageProvider,
77 admin: Address,
78 recipient: Address,
79 hardfork: TempoHardfork,
80) -> Result<(), TempoPrecompileError> {
81 StorageCtx::enter(storage, || initialize_tempo_genesis_inner(admin, recipient, hardfork))
82}
83
84pub fn initialize_tempo_genesis_inner(
87 admin: Address,
88 recipient: Address,
89 hardfork: TempoHardfork,
90) -> Result<(), TempoPrecompileError> {
91 initialize_tempo_genesis_inner_with_precompiles(
92 admin,
93 recipient,
94 active_tempo_precompile_addresses(hardfork),
95 )
96}
97
98pub fn initialize_tempo_test_genesis_inner(
104 admin: Address,
105 recipient: Address,
106) -> Result<(), TempoPrecompileError> {
107 initialize_tempo_genesis_inner_with_precompiles(
108 admin,
109 recipient,
110 TEMPO_PRECOMPILE_ADDRESSES.iter().copied(),
111 )
112}
113
114fn initialize_tempo_genesis_inner_with_precompiles(
115 admin: Address,
116 recipient: Address,
117 precompiles: impl IntoIterator<Item = Address>,
118) -> Result<(), TempoPrecompileError> {
119 if TIP20Factory::new().is_tip20(PATH_USD_ADDRESS)? {
121 return Ok(());
122 }
123
124 let mut ctx = StorageCtx;
125
126 let sentinel = Bytecode::new_legacy(Bytes::from_static(SYSTEM_PRECOMPILE_STUB));
128 for precompile in precompiles {
129 ctx.set_code(precompile, sentinel.clone())?;
130 }
131
132 let path_usd_token_address = create_and_mint_token(
134 PATH_USD_ADDRESS,
135 "PathUSD",
136 "PathUSD",
137 "USD",
138 Address::ZERO,
139 admin,
140 recipient,
141 U256::from(u64::MAX),
142 )?;
143
144 let _alpha_usd_token_address = create_and_mint_token(
146 ALPHA_USD_ADDRESS,
147 "AlphaUSD",
148 "AlphaUSD",
149 "USD",
150 path_usd_token_address,
151 admin,
152 recipient,
153 U256::from(u64::MAX),
154 )?;
155
156 let _beta_usd_token_address = create_and_mint_token(
158 BETA_USD_ADDRESS,
159 "BetaUSD",
160 "BetaUSD",
161 "USD",
162 path_usd_token_address,
163 admin,
164 recipient,
165 U256::from(u64::MAX),
166 )?;
167
168 let _theta_usd_token_address = create_and_mint_token(
170 THETA_USD_ADDRESS,
171 "ThetaUSD",
172 "ThetaUSD",
173 "USD",
174 path_usd_token_address,
175 admin,
176 recipient,
177 U256::from(u64::MAX),
178 )?;
179
180 ctx.sstore(VALIDATOR_CONFIG_ADDRESS, validator_config::slots::OWNER, admin.into_word().into())?;
182
183 ctx.set_code(
185 MULTICALL3_ADDRESS,
186 Bytecode::new_legacy(Bytes::from_static(&Multicall3::DEPLOYED_BYTECODE)),
187 )?;
188 ctx.set_code(
189 CREATEX_ADDRESS,
190 Bytecode::new_legacy(Bytes::from_static(&CreateX::DEPLOYED_BYTECODE)),
191 )?;
192 ctx.set_code(
193 SAFE_DEPLOYER_ADDRESS,
194 Bytecode::new_legacy(Bytes::from_static(&SafeDeployer::DEPLOYED_BYTECODE)),
195 )?;
196 ctx.set_code(
197 PERMIT2_ADDRESS,
198 Bytecode::new_legacy(Bytes::from_static(&Permit2::DEPLOYED_BYTECODE)),
199 )?;
200 ctx.set_code(
201 ARACHNID_CREATE2_FACTORY_ADDRESS,
202 Bytecode::new_legacy(ARACHNID_CREATE2_FACTORY_BYTECODE),
203 )?;
204
205 Ok(())
206}
207
208#[allow(clippy::too_many_arguments)]
210fn create_and_mint_token(
211 address: Address,
212 symbol: &str,
213 name: &str,
214 currency: &str,
215 quote_token: Address,
216 admin: Address,
217 recipient: Address,
218 mint_amount: U256,
219) -> Result<Address, TempoPrecompileError> {
220 let mut tip20_factory = TIP20Factory::new();
221
222 let token_address = tip20_factory.create_token_reserved_address(
223 address,
224 name,
225 symbol,
226 currency,
227 quote_token,
228 admin,
229 )?;
230
231 let mut token = TIP20Token::from_address(token_address)?;
232 token.grant_role_internal(admin, TIP20Token::issuer_role())?;
233 token.mint(admin, ITIP20::mintCall { to: recipient, amount: mint_amount })?;
234 if admin != recipient {
235 token.mint(admin, ITIP20::mintCall { to: admin, amount: mint_amount })?;
236 }
237
238 Ok(token_address)
239}