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