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