1use alloy_primitives::{Address, Bytes, U256, address};
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,
14 precompiles::{
15 ACCOUNT_KEYCHAIN_ADDRESS, ADDRESS_REGISTRY_ADDRESS, NONCE_PRECOMPILE_ADDRESS,
16 SIGNATURE_VERIFIER_ADDRESS, STABLECOIN_DEX_ADDRESS, TIP_FEE_MANAGER_ADDRESS,
17 TIP20_FACTORY_ADDRESS, TIP403_REGISTRY_ADDRESS, VALIDATOR_CONFIG_ADDRESS,
18 VALIDATOR_CONFIG_V2_ADDRESS,
19 },
20};
21use tempo_precompiles::{
22 error::TempoPrecompileError,
23 storage::{PrecompileStorageProvider, StorageCtx},
24 tip20::{ISSUER_ROLE, ITIP20, TIP20Token},
25 tip20_factory::TIP20Factory,
26 validator_config,
27};
28
29pub use tempo_contracts::precompiles::PATH_USD_ADDRESS;
30
31pub const TEMPO_PRECOMPILE_ADDRESSES: &[Address] = &[
33 NONCE_PRECOMPILE_ADDRESS,
34 STABLECOIN_DEX_ADDRESS,
35 TIP20_FACTORY_ADDRESS,
36 TIP403_REGISTRY_ADDRESS,
37 TIP_FEE_MANAGER_ADDRESS,
38 VALIDATOR_CONFIG_ADDRESS,
39 VALIDATOR_CONFIG_V2_ADDRESS,
40 ACCOUNT_KEYCHAIN_ADDRESS,
41 SIGNATURE_VERIFIER_ADDRESS,
42 ADDRESS_REGISTRY_ADDRESS,
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 StorageCtx::enter(storage, || initialize_tempo_genesis_inner(admin, recipient))
69}
70
71pub fn initialize_tempo_genesis_inner(
74 admin: Address,
75 recipient: Address,
76) -> Result<(), TempoPrecompileError> {
77 if TIP20Factory::new().is_tip20(PATH_USD_ADDRESS)? {
79 return Ok(());
80 }
81
82 let mut ctx = StorageCtx;
83
84 let sentinel = Bytecode::new_legacy(Bytes::from_static(&[0xef]));
86 for precompile in TEMPO_PRECOMPILE_ADDRESSES {
87 ctx.set_code(*precompile, sentinel.clone())?;
88 }
89
90 let path_usd_token_address = create_and_mint_token(
92 PATH_USD_ADDRESS,
93 "PathUSD",
94 "PathUSD",
95 "USD",
96 Address::ZERO,
97 admin,
98 recipient,
99 U256::from(u64::MAX),
100 )?;
101
102 let _alpha_usd_token_address = create_and_mint_token(
104 address!("20C0000000000000000000000000000000000001"),
105 "AlphaUSD",
106 "AlphaUSD",
107 "USD",
108 path_usd_token_address,
109 admin,
110 recipient,
111 U256::from(u64::MAX),
112 )?;
113
114 let _beta_usd_token_address = create_and_mint_token(
116 address!("20C0000000000000000000000000000000000002"),
117 "BetaUSD",
118 "BetaUSD",
119 "USD",
120 path_usd_token_address,
121 admin,
122 recipient,
123 U256::from(u64::MAX),
124 )?;
125
126 let _theta_usd_token_address = create_and_mint_token(
128 address!("20C0000000000000000000000000000000000003"),
129 "ThetaUSD",
130 "ThetaUSD",
131 "USD",
132 path_usd_token_address,
133 admin,
134 recipient,
135 U256::from(u64::MAX),
136 )?;
137
138 ctx.sstore(VALIDATOR_CONFIG_ADDRESS, validator_config::slots::OWNER, admin.into_word().into())?;
140
141 ctx.set_code(
143 MULTICALL3_ADDRESS,
144 Bytecode::new_legacy(Bytes::from_static(&Multicall3::DEPLOYED_BYTECODE)),
145 )?;
146 ctx.set_code(
147 CREATEX_ADDRESS,
148 Bytecode::new_legacy(Bytes::from_static(&CreateX::DEPLOYED_BYTECODE)),
149 )?;
150 ctx.set_code(
151 SAFE_DEPLOYER_ADDRESS,
152 Bytecode::new_legacy(Bytes::from_static(&SafeDeployer::DEPLOYED_BYTECODE)),
153 )?;
154 ctx.set_code(
155 PERMIT2_ADDRESS,
156 Bytecode::new_legacy(Bytes::from_static(&Permit2::DEPLOYED_BYTECODE)),
157 )?;
158 ctx.set_code(
159 ARACHNID_CREATE2_FACTORY_ADDRESS,
160 Bytecode::new_legacy(ARACHNID_CREATE2_FACTORY_BYTECODE),
161 )?;
162
163 Ok(())
164}
165
166#[allow(clippy::too_many_arguments)]
168fn create_and_mint_token(
169 address: Address,
170 symbol: &str,
171 name: &str,
172 currency: &str,
173 quote_token: Address,
174 admin: Address,
175 recipient: Address,
176 mint_amount: U256,
177) -> Result<Address, TempoPrecompileError> {
178 let mut tip20_factory = TIP20Factory::new();
179
180 let token_address = tip20_factory.create_token_reserved_address(
181 address,
182 name,
183 symbol,
184 currency,
185 quote_token,
186 admin,
187 )?;
188
189 let mut token = TIP20Token::from_address(token_address)?;
190 token.grant_role_internal(admin, *ISSUER_ROLE)?;
191 token.mint(admin, ITIP20::mintCall { to: recipient, amount: mint_amount })?;
192 if admin != recipient {
193 token.mint(admin, ITIP20::mintCall { to: admin, amount: mint_amount })?;
194 }
195
196 Ok(token_address)
197}