Skip to main content

tempo_bench/cmd/max_tps/
dex.rs

1use super::*;
2use alloy::providers::DynProvider;
3use indicatif::ProgressIterator;
4use tempo_contracts::precompiles::{IStablecoinDEX, 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: &[(Secp256k1Signer, 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 = IStablecoinDEX::new(STABLECOIN_DEX_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_DEX_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 =
126                        IStablecoinDEXInstance::new(STABLECOIN_DEX_ADDRESS, provider.clone());
127                    Box::pin(async move {
128                        let tx =
129                            exchange.placeFlip(token, order_amount, true, tick_under, tick_over);
130                        tx.send().await
131                    }) as BoxFuture<'static, _>
132                })
133            })
134            .progress_count((signer_providers.len() * user_tokens.len()) as u64),
135        max_concurrent_requests,
136        max_concurrent_transactions,
137    )
138    .await
139    .context("Failed to place flip orders")?;
140
141    Ok((*quote_token.address(), user_token_addresses))
142}
143
144/// Creates a test TIP20 token with issuer role granted to the provided address.
145async fn setup_test_token(
146    provider: DynProvider<TempoNetwork>,
147    admin: Address,
148    quote_token: Address,
149) -> eyre::Result<ITIP20Instance<DynProvider<TempoNetwork>, TempoNetwork>>
150where
151{
152    let factory = ITIP20Factory::new(TIP20_FACTORY_ADDRESS, provider.clone());
153    let salt = alloy::primitives::B256::random();
154    let receipt = factory
155        .createToken(
156            "Test".to_owned(),
157            "TEST".to_owned(),
158            "USD".to_owned(),
159            quote_token,
160            admin,
161            salt,
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 = event.token;
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}