tempo_bench/cmd/max_tps/
dex.rs

1use super::*;
2use alloy::providers::DynProvider;
3use indicatif::ProgressIterator;
4use tempo_contracts::precompiles::{IStablecoinExchange, PATH_USD_ADDRESS};
5use tempo_precompiles::tip20::U128_MAX;
6
7/// This method performs a one-time setup for sending a lot of transactions:
8/// * Deploys the specified number of user tokens.
9/// * Creates DEX pairs of user tokens with the quote token.
10/// * Mints user tokens for all signers and approves unlimited spending for DEX.
11/// * Seeds initial liquidity by placing DEX flip orders.
12pub(super) async fn setup(
13    signer_providers: &[(PrivateKeySigner, DynProvider<TempoNetwork>)],
14    user_tokens: usize,
15    max_concurrent_requests: usize,
16    max_concurrent_transactions: usize,
17) -> eyre::Result<(Address, Vec<Address>)> {
18    // Grab first signer provider
19    let (signer, provider) = signer_providers
20        .first()
21        .ok_or_eyre("No signer providers found")?;
22    let caller = signer.address();
23
24    info!(user_tokens, "Creating TIP-20 tokens");
25    let progress = ProgressBar::new(user_tokens as u64 + 1);
26    // Create quote token
27    let quote_token = setup_test_token(provider.clone(), caller, PATH_USD_ADDRESS).await?;
28    progress.inc(1);
29    // Create `user_tokens` tokens
30    let user_tokens = stream::iter((0..user_tokens).progress_with(progress))
31        .map(|_| setup_test_token(provider.clone(), caller, *quote_token.address()))
32        .buffered(max_concurrent_requests)
33        .try_collect::<Vec<_>>()
34        .await?;
35
36    let user_token_addresses = user_tokens
37        .iter()
38        .map(|token| *token.address())
39        .collect::<Vec<_>>();
40    let all_tokens = user_tokens
41        .iter()
42        .cloned()
43        .chain(std::iter::once(quote_token.clone()))
44        .collect::<Vec<_>>();
45    let all_token_addresses = all_tokens
46        .iter()
47        .map(|token| *token.address())
48        .collect::<Vec<_>>();
49
50    // Create exchange pairs for each user token
51    info!("Creating exchange pairs");
52    let exchange = IStablecoinExchange::new(STABLECOIN_EXCHANGE_ADDRESS, provider.clone());
53    join_all(
54        user_token_addresses
55            .iter()
56            .copied()
57            .map(|token| {
58                let exchange = exchange.clone();
59                Box::pin(async move {
60                    let tx = exchange.createPair(token);
61                    tx.send().await
62                }) as BoxFuture<'static, _>
63            })
64            .progress(),
65        max_concurrent_requests,
66        max_concurrent_transactions,
67    )
68    .await
69    .context("Failed to create exchange pairs")?;
70
71    // Mint user tokens to each signer
72    let mint_amount = U128_MAX / U256::from(signer_providers.len());
73    info!(%mint_amount, "Minting TIP-20 tokens");
74    join_all(
75        signer_providers
76            .iter()
77            .map(|(signer, _)| signer.address())
78            .flat_map(|signer| {
79                all_tokens.iter().map(move |token| {
80                    let token = token.clone();
81                    Box::pin(async move {
82                        let tx = token.mint(signer, mint_amount);
83                        tx.send().await
84                    }) as BoxFuture<'static, _>
85                })
86            })
87            .progress_count((signer_providers.len() * all_tokens.len()) as u64),
88        max_concurrent_requests,
89        max_concurrent_transactions,
90    )
91    .await
92    .context("Failed to mint TIP-20 tokens")?;
93
94    // Approve for each signer quote token and each user token to spend by exchange
95    info!("Approving tokens");
96    join_all(
97        signer_providers
98            .iter()
99            .flat_map(|(_, provider)| {
100                all_token_addresses.iter().copied().map(move |token| {
101                    let token = ITIP20Instance::new(token, provider.clone());
102                    Box::pin(async move {
103                        let tx = token.approve(STABLECOIN_EXCHANGE_ADDRESS, U256::MAX);
104                        tx.send().await
105                    }) as BoxFuture<'static, _>
106                })
107            })
108            .progress_count((signer_providers.len() * all_tokens.len()) as u64),
109        max_concurrent_requests,
110        max_concurrent_transactions,
111    )
112    .await
113    .context("Failed to approve TIP-20 tokens")?;
114
115    // Place flip orders of `order_amount` with tick `tick_over` and flip tick `tick_under` for each signer and each token
116    let order_amount = 1000000000000u128;
117    let tick_over = exchange.priceToTick(100010).call().await?;
118    let tick_under = exchange.priceToTick(99990).call().await?;
119    info!(order_amount, tick_over, tick_under, "Placing flip orders");
120    join_all(
121        signer_providers
122            .iter()
123            .flat_map(|(_, provider)| {
124                user_token_addresses.iter().copied().map(move |token| {
125                    let exchange = IStablecoinExchangeInstance::new(
126                        STABLECOIN_EXCHANGE_ADDRESS,
127                        provider.clone(),
128                    );
129                    Box::pin(async move {
130                        let tx =
131                            exchange.placeFlip(token, order_amount, true, tick_under, tick_over);
132                        tx.send().await
133                    }) as BoxFuture<'static, _>
134                })
135            })
136            .progress_count((signer_providers.len() * user_tokens.len()) as u64),
137        max_concurrent_requests,
138        max_concurrent_transactions,
139    )
140    .await
141    .context("Failed to place flip orders")?;
142
143    Ok((*quote_token.address(), user_token_addresses))
144}
145
146/// Creates a test TIP20 token with issuer role granted to the provided address.
147async fn setup_test_token(
148    provider: DynProvider<TempoNetwork>,
149    admin: Address,
150    quote_token: Address,
151) -> eyre::Result<ITIP20Instance<DynProvider<TempoNetwork>, TempoNetwork>>
152where
153{
154    let factory = ITIP20Factory::new(TIP20_FACTORY_ADDRESS, provider.clone());
155    let receipt = factory
156        .createToken(
157            "Test".to_owned(),
158            "TEST".to_owned(),
159            "USD".to_owned(),
160            quote_token,
161            admin,
162        )
163        .send()
164        .await?
165        .get_receipt()
166        .await?;
167    let event = receipt
168        .decoded_log::<ITIP20Factory::TokenCreated>()
169        .ok_or_eyre("Token creation event not found")?;
170    assert_receipt(receipt)
171        .await
172        .context("Failed to create TIP-20 token")?;
173
174    let token_addr = token_id_to_address(event.tokenId.to());
175    let token = ITIP20::new(token_addr, provider.clone());
176    let roles = IRolesAuth::new(*token.address(), provider);
177    let grant_role_receipt = roles
178        .grantRole(*ISSUER_ROLE, admin)
179        .send()
180        .await?
181        .get_receipt()
182        .await?;
183    assert_receipt(grant_role_receipt)
184        .await
185        .context("Failed to grant issuer role")?;
186
187    Ok(token)
188}