1
use crate::{
2
    helpers::Scaled,
3
    msg::{ExecuteMsg, FeeRecipient, InstantiateMsg},
4
    types::FPCoin,
5
};
6

            
7
use cosmwasm_std::{
8
    coin,
9
    testing::{MockApi, MockStorage},
10
    to_json_binary, Addr, Coin, ContractResult, OwnedDeps, QuerierResult, SystemError, SystemResult, Uint256,
11
};
12
use injective_cosmwasm::{
13
    create_orderbook_response_handler, create_spot_multi_market_handler, get_default_subaccount_id_for_checked_address, inj_mock_deps,
14
    test_market_ids, HandlesMarketIdQuery, InjectiveQueryWrapper, MarketId, PriceLevel, QueryMarketAtomicExecutionFeeMultiplierResponse, SpotMarket,
15
    WasmMockQuerier, TEST_MARKET_ID_1, TEST_MARKET_ID_2,
16
};
17
use injective_math::FPDecimal;
18
use injective_std::{
19
    shim::{Any, Timestamp},
20
    types::injective::exchange::v1beta1::MsgInstantSpotMarketLaunch,
21
    types::{
22
        cosmos::{
23
            authz::v1beta1::{Grant, MsgGrant},
24
            bank::v1beta1::{QueryAllBalancesRequest, QueryBalanceRequest},
25
        },
26
        cosmwasm::wasm::v1::{AcceptedMessageKeysFilter, ContractExecutionAuthorization, ContractGrant, MaxCallsLimit},
27
        injective::exchange::v1beta1::{MsgCreateSpotLimitOrder, OrderInfo, OrderType, SpotOrder},
28
    },
29
};
30
use injective_test_tube::{Account, Authz, Bank, Exchange, InjectiveTestApp, Module, SigningAccount, Wasm};
31
use injective_testing::{
32
    test_tube::bank::send,
33
    test_tube::exchange::{add_denom_notional_and_decimal, get_spot_market_id},
34
    utils::dec_to_proto,
35
    utils::scale_price_quantity_spot_market,
36
};
37
use std::{collections::HashMap, str::FromStr};
38
use test_tube_inj::cosmrs::proto::prost::Message;
39

            
40
pub const TEST_CONTRACT_ADDR: &str = "inj14hj2tavq8fpesdwxxcu44rty3hh90vhujaxlnz";
41
pub const TEST_USER_ADDR: &str = "inj1p7z8p649xspcey7wp5e4leqf7wa39kjjj6wja8";
42

            
43
pub const ETH: &str = "eth";
44
pub const ATOM: &str = "atom";
45
pub const USDT: &str = "usdt";
46
pub const USDC: &str = "usdc";
47
pub const INJ: &str = "inj";
48
pub const INJ_2: &str = "inj_2";
49
pub const NINJA: &str = "ninja";
50

            
51
pub const DEFAULT_TAKER_FEE: f64 = 0.001;
52
pub const DEFAULT_ATOMIC_MULTIPLIER: f64 = 2.5;
53
pub const DEFAULT_SELF_RELAYING_FEE_PART: f64 = 0.6;
54

            
55
#[allow(clippy::too_many_arguments)]
56
124
pub fn launch_spot_market_custom(
57
124
    exchange: &Exchange<InjectiveTestApp>,
58
124
    signer: &SigningAccount,
59
124
    ticker: String,
60
124
    base_denom: String,
61
124
    quote_denom: String,
62
124
    min_price_tick_size: String,
63
124
    min_quantity_tick_size: String,
64
124
    base_decimals: i32,
65
124
    quote_decimals: i32,
66
124
) -> String {
67
124
    exchange
68
124
        .instant_spot_market_launch(
69
124
            MsgInstantSpotMarketLaunch {
70
124
                sender: signer.address(),
71
124
                ticker: ticker.clone(),
72
124
                base_denom,
73
124
                quote_denom,
74
124
                min_price_tick_size: dec_to_proto(FPDecimal::must_from_str(&min_price_tick_size)),
75
124
                min_quantity_tick_size: dec_to_proto(FPDecimal::must_from_str(&min_quantity_tick_size)),
76
124
                min_notional: dec_to_proto(FPDecimal::must_from_str("1")),
77
124
                base_decimals: base_decimals as u32,
78
124
                quote_decimals: quote_decimals as u32,
79
124
            },
80
124
            signer,
81
124
        )
82
124
        .unwrap();
83
124

            
84
124
    get_spot_market_id(exchange, ticker)
85
124
}
86

            
87
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
88
#[repr(i32)]
89
pub enum Decimals {
90
    Eighteen = 18,
91
    Six = 6,
92
}
93

            
94
impl Decimals {
95
3326
    pub fn get_decimals(&self) -> i32 {
96
3326
        match self {
97
1772
            Decimals::Eighteen => 18,
98
1554
            Decimals::Six => 6,
99
        }
100
3326
    }
101
}
102

            
103
// Helper function to create a PriceLevel
104
46
pub fn create_price_level(p: u128, q: u128) -> PriceLevel {
105
46
    PriceLevel {
106
46
        p: FPDecimal::from(p),
107
46
        q: FPDecimal::from(q),
108
46
    }
109
46
}
110

            
111
#[derive(PartialEq)]
112
pub enum MultiplierQueryBehavior {
113
    Success,
114
    Fail,
115
}
116

            
117
42
pub fn mock_deps_eth_inj(
118
42
    multiplier_query_behavior: MultiplierQueryBehavior,
119
42
) -> OwnedDeps<MockStorage, MockApi, WasmMockQuerier, InjectiveQueryWrapper> {
120
63
    inj_mock_deps(|querier| {
121
42
        let mut markets = HashMap::new();
122
42
        markets.insert(
123
42
            MarketId::new(TEST_MARKET_ID_1).unwrap(),
124
42
            create_mock_spot_market("eth", FPDecimal::must_from_str("0.001"), FPDecimal::must_from_str("0.001"), 0),
125
42
        );
126
42
        markets.insert(
127
42
            MarketId::new(TEST_MARKET_ID_2).unwrap(),
128
42
            create_mock_spot_market("inj", FPDecimal::must_from_str("0.001"), FPDecimal::must_from_str("0.001"), 1),
129
42
        );
130
42
        querier.spot_market_response_handler = create_spot_multi_market_handler(markets);
131
42

            
132
42
        let mut orderbooks = HashMap::new();
133
42
        let eth_buy_orderbook = vec![
134
42
            PriceLevel {
135
42
                p: 201000u128.into(),
136
42
                q: FPDecimal::from_str("5").unwrap(),
137
42
            },
138
42
            PriceLevel {
139
42
                p: 195000u128.into(),
140
42
                q: FPDecimal::from_str("4").unwrap(),
141
42
            },
142
42
            PriceLevel {
143
42
                p: 192000u128.into(),
144
42
                q: FPDecimal::from_str("3").unwrap(),
145
42
            },
146
42
        ];
147
42
        orderbooks.insert(MarketId::new(TEST_MARKET_ID_1).unwrap(), eth_buy_orderbook);
148
42

            
149
42
        let inj_sell_orderbook = vec![
150
42
            PriceLevel {
151
42
                p: 800u128.into(),
152
42
                q: 800u128.into(),
153
42
            },
154
42
            PriceLevel {
155
42
                p: 810u128.into(),
156
42
                q: 800u128.into(),
157
42
            },
158
42
            PriceLevel {
159
42
                p: 820u128.into(),
160
42
                q: 800u128.into(),
161
42
            },
162
42
            PriceLevel {
163
42
                p: 830u128.into(),
164
42
                q: 800u128.into(),
165
42
            },
166
42
        ];
167
42
        orderbooks.insert(MarketId::new(TEST_MARKET_ID_2).unwrap(), inj_sell_orderbook);
168
42

            
169
42
        querier.spot_market_orderbook_response_handler = create_orderbook_response_handler(orderbooks);
170
42

            
171
42
        if multiplier_query_behavior == MultiplierQueryBehavior::Fail {
172
2
            pub fn create_spot_error_multiplier_handler() -> Option<Box<dyn HandlesMarketIdQuery>> {
173
                struct Temp {}
174

            
175
                impl HandlesMarketIdQuery for Temp {
176
2
                    fn handle(&self, _: MarketId) -> QuerierResult {
177
2
                        SystemResult::Err(SystemError::Unknown {})
178
2
                    }
179
                }
180

            
181
2
                Some(Box::new(Temp {}))
182
2
            }
183

            
184
2
            querier.market_atomic_execution_fee_multiplier_response_handler = create_spot_error_multiplier_handler()
185
        } else {
186
40
            pub fn create_spot_ok_multiplier_handler() -> Option<Box<dyn HandlesMarketIdQuery>> {
187
                struct Temp {}
188

            
189
                impl HandlesMarketIdQuery for Temp {
190
16
                    fn handle(&self, _: MarketId) -> QuerierResult {
191
16
                        let response = QueryMarketAtomicExecutionFeeMultiplierResponse {
192
16
                            multiplier: FPDecimal::from_str("2.5").unwrap(),
193
16
                        };
194
16
                        SystemResult::Ok(ContractResult::from(to_json_binary(&response)))
195
16
                    }
196
                }
197

            
198
40
                Some(Box::new(Temp {}))
199
40
            }
200

            
201
40
            querier.market_atomic_execution_fee_multiplier_response_handler = create_spot_ok_multiplier_handler()
202
        }
203
63
    })
204
42
}
205

            
206
4
pub fn mock_realistic_deps_eth_atom(
207
4
    multiplier_query_behavior: MultiplierQueryBehavior,
208
4
) -> OwnedDeps<MockStorage, MockApi, WasmMockQuerier, InjectiveQueryWrapper> {
209
6
    inj_mock_deps(|querier| {
210
4
        let mut markets = HashMap::new();
211
4
        markets.insert(
212
4
            MarketId::new(TEST_MARKET_ID_1).unwrap(),
213
4
            create_mock_spot_market(
214
4
                "eth",
215
4
                FPDecimal::must_from_str("0.000000000000001"),
216
4
                FPDecimal::must_from_str("1000000000000000"),
217
4
                0,
218
4
            ),
219
4
        );
220
4
        markets.insert(
221
4
            MarketId::new(TEST_MARKET_ID_2).unwrap(),
222
4
            create_mock_spot_market("atom", FPDecimal::must_from_str("0.001"), FPDecimal::must_from_str("10000"), 1),
223
4
        );
224
4
        querier.spot_market_response_handler = create_spot_multi_market_handler(markets);
225
4

            
226
4
        let mut orderbooks = HashMap::new();
227
4
        let eth_buy_orderbook = vec![
228
4
            PriceLevel {
229
4
                p: FPDecimal::must_from_str("0.000000002107200000"),
230
4
                q: FPDecimal::from_str("784000000000000000.000000000000000000").unwrap(),
231
4
            },
232
4
            PriceLevel {
233
4
                p: FPDecimal::must_from_str("0.000000001978000000"),
234
4
                q: FPDecimal::from_str("1230000000000000000.000000000000000000").unwrap(),
235
4
            },
236
4
            PriceLevel {
237
4
                p: FPDecimal::must_from_str("0.000000001966660000"),
238
4
                q: FPDecimal::from_str("2070000000000000000.000000000000000000").unwrap(),
239
4
            },
240
4
        ];
241
4
        orderbooks.insert(MarketId::new(TEST_MARKET_ID_1).unwrap(), eth_buy_orderbook);
242
4

            
243
4
        let inj_sell_orderbook = vec![
244
4
            PriceLevel {
245
4
                p: 800u128.into(),
246
4
                q: 800u128.into(),
247
4
            },
248
4
            PriceLevel {
249
4
                p: 810u128.into(),
250
4
                q: 800u128.into(),
251
4
            },
252
4
            PriceLevel {
253
4
                p: 820u128.into(),
254
4
                q: 800u128.into(),
255
4
            },
256
4
            PriceLevel {
257
4
                p: 830u128.into(),
258
4
                q: 800u128.into(),
259
4
            },
260
4
        ];
261
4
        orderbooks.insert(MarketId::new(TEST_MARKET_ID_2).unwrap(), inj_sell_orderbook);
262
4

            
263
4
        querier.spot_market_orderbook_response_handler = create_orderbook_response_handler(orderbooks);
264
4

            
265
4
        if multiplier_query_behavior == MultiplierQueryBehavior::Fail {
266
            pub fn create_spot_error_multiplier_handler() -> Option<Box<dyn HandlesMarketIdQuery>> {
267
                struct Temp {}
268

            
269
                impl HandlesMarketIdQuery for Temp {
270
                    fn handle(&self, _: MarketId) -> QuerierResult {
271
                        SystemResult::Err(SystemError::Unknown {})
272
                    }
273
                }
274

            
275
                Some(Box::new(Temp {}))
276
            }
277

            
278
            querier.market_atomic_execution_fee_multiplier_response_handler = create_spot_error_multiplier_handler()
279
        } else {
280
4
            pub fn create_spot_ok_multiplier_handler() -> Option<Box<dyn HandlesMarketIdQuery>> {
281
                struct Temp {}
282

            
283
                impl HandlesMarketIdQuery for Temp {
284
8
                    fn handle(&self, _: MarketId) -> QuerierResult {
285
8
                        let response = QueryMarketAtomicExecutionFeeMultiplierResponse {
286
8
                            multiplier: FPDecimal::from_str("2.5").unwrap(),
287
8
                        };
288
8
                        SystemResult::Ok(ContractResult::from(to_json_binary(&response)))
289
8
                    }
290
                }
291

            
292
4
                Some(Box::new(Temp {}))
293
4
            }
294

            
295
4
            querier.market_atomic_execution_fee_multiplier_response_handler = create_spot_ok_multiplier_handler()
296
        }
297
6
    })
298
4
}
299

            
300
92
fn create_mock_spot_market(base: &str, min_price_tick_size: FPDecimal, min_quantity_tick_size: FPDecimal, idx: u32) -> SpotMarket {
301
92
    SpotMarket {
302
92
        ticker: format!("{base}usdt"),
303
92
        base_denom: base.to_string(),
304
92
        quote_denom: "usdt".to_string(),
305
92
        maker_fee_rate: FPDecimal::from_str("0.01").unwrap(),
306
92
        taker_fee_rate: FPDecimal::from_str("0.001").unwrap(),
307
92
        relayer_fee_share_rate: FPDecimal::from_str("0.4").unwrap(),
308
92
        market_id: test_market_ids()[idx as usize].clone(),
309
92
        status: injective_cosmwasm::MarketStatus::Active,
310
92
        min_price_tick_size,
311
92
        min_quantity_tick_size,
312
92
        min_notional: FPDecimal::from_str("0.000000001").unwrap(),
313
92
    }
314
92
}
315

            
316
34
pub fn launch_realistic_inj_usdt_spot_market(exchange: &Exchange<InjectiveTestApp>, signer: &SigningAccount) -> String {
317
34
    launch_spot_market_custom(
318
34
        exchange,
319
34
        signer,
320
34
        "INJ2/USDT".to_string(),
321
34
        INJ_2.to_string(),
322
34
        USDT.to_string(),
323
34
        "0.000000000000001".to_string(),
324
34
        "1000000000000000".to_string(),
325
34
        Decimals::Eighteen.get_decimals(),
326
34
        Decimals::Six.get_decimals(),
327
34
    )
328
34
}
329

            
330
38
pub fn launch_realistic_weth_usdt_spot_market(exchange: &Exchange<InjectiveTestApp>, signer: &SigningAccount) -> String {
331
38
    launch_spot_market_custom(
332
38
        exchange,
333
38
        signer,
334
38
        "ETH/USDT".to_string(),
335
38
        ETH.to_string(),
336
38
        USDT.to_string(),
337
38
        "0.0000000000001".to_string(),
338
38
        "1000000000000000".to_string(),
339
38
        Decimals::Eighteen.get_decimals(),
340
38
        Decimals::Six.get_decimals(),
341
38
    )
342
38
}
343

            
344
42
pub fn launch_realistic_atom_usdt_spot_market(exchange: &Exchange<InjectiveTestApp>, signer: &SigningAccount) -> String {
345
42
    launch_spot_market_custom(
346
42
        exchange,
347
42
        signer,
348
42
        "ATOM/USDT".to_string(),
349
42
        ATOM.to_string(),
350
42
        USDT.to_string(),
351
42
        "0.001".to_string(),
352
42
        "10000".to_string(),
353
42
        Decimals::Six.get_decimals(),
354
42
        Decimals::Six.get_decimals(),
355
42
    )
356
42
}
357

            
358
8
pub fn launch_realistic_usdt_usdc_spot_market(exchange: &Exchange<InjectiveTestApp>, signer: &SigningAccount) -> String {
359
8
    launch_spot_market_custom(
360
8
        exchange,
361
8
        signer,
362
8
        "USDT/USDC".to_string(),
363
8
        USDT.to_string(),
364
8
        USDC.to_string(),
365
8
        "0.0001".to_string(),
366
8
        "100".to_string(),
367
8
        Decimals::Six.get_decimals(),
368
8
        Decimals::Six.get_decimals(),
369
8
    )
370
8
}
371

            
372
2
pub fn launch_realistic_ninja_inj_spot_market(exchange: &Exchange<InjectiveTestApp>, signer: &SigningAccount) -> String {
373
2
    launch_spot_market_custom(
374
2
        exchange,
375
2
        signer,
376
2
        "NINJA/INJ2".to_string(),
377
2
        NINJA.to_string(),
378
2
        INJ_2.to_string(),
379
2
        "1000000".to_string(),
380
2
        "10000000".to_string(),
381
2
        Decimals::Six.get_decimals(),
382
2
        Decimals::Eighteen.get_decimals(),
383
2
    )
384
2
}
385

            
386
422
pub fn create_realistic_eth_usdt_buy_orders_from_spreadsheet(
387
422
    app: &InjectiveTestApp,
388
422
    market_id: &str,
389
422
    trader1: &SigningAccount,
390
422
    trader2: &SigningAccount,
391
422
) {
392
422
    create_realistic_limit_order(
393
422
        app,
394
422
        trader1,
395
422
        market_id,
396
422
        OrderSide::Buy,
397
422
        "2107.2",
398
422
        "0.78",
399
422
        Decimals::Eighteen,
400
422
        Decimals::Six,
401
422
    );
402
422

            
403
422
    create_realistic_limit_order(app, trader2, market_id, OrderSide::Buy, "1978", "1.23", Decimals::Eighteen, Decimals::Six);
404
422

            
405
422
    create_realistic_limit_order(
406
422
        app,
407
422
        trader2,
408
422
        market_id,
409
422
        OrderSide::Buy,
410
422
        "1966.6",
411
422
        "2.07",
412
422
        Decimals::Eighteen,
413
422
        Decimals::Six,
414
422
    );
415
422
}
416

            
417
12
pub fn create_realistic_eth_usdt_sell_orders_from_spreadsheet(
418
12
    app: &InjectiveTestApp,
419
12
    market_id: &str,
420
12
    trader1: &SigningAccount,
421
12
    trader2: &SigningAccount,
422
12
    trader3: &SigningAccount,
423
12
) {
424
12
    create_realistic_limit_order(
425
12
        app,
426
12
        trader1,
427
12
        market_id,
428
12
        OrderSide::Sell,
429
12
        "2115.2",
430
12
        "0.5",
431
12
        Decimals::Eighteen,
432
12
        Decimals::Six,
433
12
    );
434
12

            
435
12
    create_realistic_limit_order(
436
12
        app,
437
12
        trader2,
438
12
        market_id,
439
12
        OrderSide::Sell,
440
12
        "2118.9",
441
12
        "1.22",
442
12
        Decimals::Eighteen,
443
12
        Decimals::Six,
444
12
    );
445
12

            
446
12
    create_realistic_limit_order(
447
12
        app,
448
12
        trader2,
449
12
        market_id,
450
12
        OrderSide::Sell,
451
12
        "2120.1",
452
12
        "1.72",
453
12
        Decimals::Eighteen,
454
12
        Decimals::Six,
455
12
    );
456
12

            
457
12
    create_realistic_limit_order(
458
12
        app,
459
12
        trader3,
460
12
        market_id,
461
12
        OrderSide::Sell,
462
12
        "2121",
463
12
        "2.11",
464
12
        Decimals::Eighteen,
465
12
        Decimals::Six,
466
12
    );
467
12
}
468

            
469
32
pub fn create_realistic_inj_usdt_buy_orders_from_spreadsheet(
470
32
    app: &InjectiveTestApp,
471
32
    market_id: &str,
472
32
    trader1: &SigningAccount,
473
32
    trader2: &SigningAccount,
474
32
) {
475
32
    create_realistic_limit_order(
476
32
        app,
477
32
        trader1,
478
32
        market_id,
479
32
        OrderSide::Buy,
480
32
        "8.91",
481
32
        "282.001",
482
32
        Decimals::Eighteen,
483
32
        Decimals::Six,
484
32
    );
485
32

            
486
32
    create_realistic_limit_order(
487
32
        app,
488
32
        trader2,
489
32
        market_id,
490
32
        OrderSide::Buy,
491
32
        "8.78",
492
32
        "283.65",
493
32
        Decimals::Eighteen,
494
32
        Decimals::Six,
495
32
    );
496
32

            
497
32
    create_realistic_limit_order(
498
32
        app,
499
32
        trader2,
500
32
        market_id,
501
32
        OrderSide::Buy,
502
32
        "8.56",
503
32
        "407.607",
504
32
        Decimals::Eighteen,
505
32
        Decimals::Six,
506
32
    );
507
32
}
508

            
509
2
pub fn create_realistic_inj_usdt_sell_orders_from_spreadsheet(app: &InjectiveTestApp, market_id: &str, trader1: &SigningAccount) {
510
2
    create_realistic_limit_order(
511
2
        app,
512
2
        trader1,
513
2
        market_id,
514
2
        OrderSide::Sell,
515
2
        "36",
516
2
        "2821.001",
517
2
        Decimals::Eighteen,
518
2
        Decimals::Six,
519
2
    );
520
2
}
521

            
522
438
pub fn create_realistic_atom_usdt_sell_orders_from_spreadsheet(
523
438
    app: &InjectiveTestApp,
524
438
    market_id: &str,
525
438
    trader1: &SigningAccount,
526
438
    trader2: &SigningAccount,
527
438
    trader3: &SigningAccount,
528
438
) {
529
438
    create_realistic_limit_order(app, trader1, market_id, OrderSide::Sell, "8.89", "197.89", Decimals::Six, Decimals::Six);
530
438

            
531
438
    create_realistic_limit_order(app, trader2, market_id, OrderSide::Sell, "8.93", "181.02", Decimals::Six, Decimals::Six);
532
438

            
533
438
    create_realistic_limit_order(app, trader3, market_id, OrderSide::Sell, "8.99", "203.12", Decimals::Six, Decimals::Six);
534
438

            
535
438
    create_realistic_limit_order(app, trader1, market_id, OrderSide::Sell, "9.01", "421.11", Decimals::Six, Decimals::Six);
536
438
}
537

            
538
4
pub fn create_realistic_usdt_usdc_both_side_orders(app: &InjectiveTestApp, market_id: &str, trader1: &SigningAccount) {
539
4
    create_realistic_limit_order(
540
4
        app,
541
4
        trader1,
542
4
        market_id,
543
4
        OrderSide::Buy,
544
4
        "0.9982",
545
4
        "1000.001",
546
4
        Decimals::Six,
547
4
        Decimals::Six,
548
4
    );
549
4

            
550
4
    create_realistic_limit_order(
551
4
        app,
552
4
        trader1,
553
4
        market_id,
554
4
        OrderSide::Sell,
555
4
        "1.0008",
556
4
        "1000.001",
557
4
        Decimals::Six,
558
4
        Decimals::Six,
559
4
    );
560
4
}
561

            
562
// not really realistic yet
563
2
pub fn create_ninja_inj_both_side_orders(app: &InjectiveTestApp, market_id: &str, trader1: &SigningAccount) {
564
2
    create_realistic_limit_order(
565
2
        app,
566
2
        trader1,
567
2
        market_id,
568
2
        OrderSide::Sell,
569
2
        "0.00021",
570
2
        "1001000",
571
2
        Decimals::Six,
572
2
        Decimals::Eighteen,
573
2
    );
574
2
}
575

            
576
#[derive(PartialEq)]
577
pub enum OrderSide {
578
    Buy,
579
    Sell,
580
}
581

            
582
#[allow(clippy::too_many_arguments)]
583
3186
pub fn create_realistic_limit_order(
584
3186
    app: &InjectiveTestApp,
585
3186
    trader: &SigningAccount,
586
3186
    market_id: &str,
587
3186
    order_side: OrderSide,
588
3186
    price: &str,
589
3186
    quantity: &str,
590
3186
    base_decimals: Decimals,
591
3186
    quote_decimals: Decimals,
592
3186
) {
593
3186
    let (price_to_send, quantity_to_send) = scale_price_quantity_spot_market(price, quantity, &(base_decimals as i32), &(quote_decimals as i32));
594
3186

            
595
3186
    let exchange = Exchange::new(app);
596
3186
    exchange
597
3186
        .create_spot_limit_order(
598
3186
            MsgCreateSpotLimitOrder {
599
3186
                sender: trader.address(),
600
3186
                order: Some(SpotOrder {
601
3186
                    market_id: market_id.to_string(),
602
3186
                    order_info: Some(OrderInfo {
603
3186
                        subaccount_id: get_default_subaccount_id_for_checked_address(&Addr::unchecked(trader.address())).to_string(),
604
3186
                        fee_recipient: trader.address(),
605
3186
                        price: price_to_send,
606
3186
                        quantity: quantity_to_send,
607
3186
                        cid: "".to_string(),
608
3186
                    }),
609
3186
                    order_type: if order_side == OrderSide::Buy {
610
1372
                        OrderType::BuyAtomic.into()
611
                    } else {
612
1814
                        OrderType::SellAtomic.into()
613
                    },
614
3186
                    trigger_price: "".to_string(),
615
3186
                }),
616
3186
            },
617
3186
            trader,
618
3186
        )
619
3186
        .unwrap();
620
3186
}
621

            
622
56
pub fn init_self_relaying_contract_and_get_address(wasm: &Wasm<InjectiveTestApp>, owner: &SigningAccount, initial_balance: &[Coin]) -> String {
623
56
    let release_wasm_path = format!("{}/../../artifacts/swap_contract.wasm", env!("CARGO_MANIFEST_DIR"));
624
56
    let release_wasm = std::fs::read(release_wasm_path).expect("build the optimized release artifact before running TestTube tests");
625
56
    let code_id = wasm.store_code(&release_wasm, None, owner).unwrap().data.code_id;
626
56
    wasm.instantiate(
627
56
        code_id,
628
56
        &InstantiateMsg {
629
56
            fee_recipient: FeeRecipient::SwapContract,
630
56
            admin: Addr::unchecked(owner.address()),
631
56
        },
632
56
        Some(&owner.address()),
633
56
        Some("Swap"),
634
56
        initial_balance,
635
56
        owner,
636
56
    )
637
56
    .unwrap()
638
56
    .data
639
56
    .address
640
56
}
641

            
642
64
pub fn set_route_and_assert_success(
643
64
    wasm: &Wasm<InjectiveTestApp>,
644
64
    signer: &SigningAccount,
645
64
    contr_addr: &str,
646
64
    from_denom: &str,
647
64
    target_denom: &str,
648
64
    route: Vec<MarketId>,
649
64
) {
650
64
    wasm.execute(
651
64
        contr_addr,
652
64
        &ExecuteMsg::SetRoute {
653
64
            source_denom: from_denom.to_string(),
654
64
            target_denom: target_denom.to_string(),
655
64
            route,
656
64
        },
657
64
        &[],
658
64
        signer,
659
64
    )
660
64
    .unwrap();
661
64
}
662

            
663
pub struct InitialCoin {
664
    pub coin: Coin,
665
    pub decimals: u32,
666
}
667

            
668
174
pub fn must_init_account_with_funds(app: &InjectiveTestApp, initial_funds: &[Coin]) -> SigningAccount {
669
174
    app.init_account(initial_funds).unwrap()
670
174
}
671

            
672
170
pub fn must_init_account_with_funds_and_setting_denoms(
673
170
    app: &InjectiveTestApp,
674
170
    validator: &SigningAccount,
675
170
    initial_funds: &[InitialCoin],
676
170
) -> SigningAccount {
677
509
    let mut initial_funds_coin: Vec<Coin> = initial_funds.iter().map(|ic| ic.coin.clone()).collect();
678
509
    let mut initial_funds_decimals = initial_funds.iter().map(|ic| ic.decimals).collect::<Vec<u32>>();
679

            
680
    // add 1000000000000000000000 inj to initial funds with adding to element if inj already in it
681
469
    if let Some(pos) = initial_funds_coin.iter().position(|c| c.denom == INJ) {
682
170
        initial_funds_coin[pos].amount += Uint256::from(1_000_000_000_000_000_000_000u128);
683
170
    } else {
684
        initial_funds_coin.push(coin(1_000_000_000_000_000_000_000u128, INJ.to_string()));
685
        initial_funds_decimals.push(18);
686
    }
687

            
688
170
    let account = app.init_account_decimals(&initial_funds_coin, &initial_funds_decimals).unwrap();
689
170
    send(&Bank::new(app), "1000000000000000000000", "inj", &account, validator);
690

            
691
594
    for initial_coin in initial_funds {
692
424
        add_denom_notional_and_decimal(
693
424
            app,
694
424
            validator,
695
424
            initial_coin.coin.denom.to_string(),
696
424
            "1".to_string(),
697
424
            initial_coin.decimals as u64,
698
424
        );
699
424
    }
700

            
701
170
    account
702
170
}
703

            
704
112
pub fn query_all_bank_balances(bank: &Bank<InjectiveTestApp>, address: &str) -> Vec<injective_std::types::cosmos::base::v1beta1::Coin> {
705
112
    bank.query_all_balances(&QueryAllBalancesRequest {
706
112
        address: address.to_string(),
707
112
        resolve_denom: false,
708
112
        pagination: None,
709
112
    })
710
112
    .unwrap()
711
112
    .balances
712
112
}
713

            
714
122
pub fn query_bank_balance(bank: &Bank<InjectiveTestApp>, denom: &str, address: &str) -> FPDecimal {
715
122
    FPDecimal::from_str(
716
122
        bank.query_balance(&QueryBalanceRequest {
717
122
            address: address.to_string(),
718
122
            denom: denom.to_string(),
719
122
        })
720
122
        .unwrap()
721
122
        .balance
722
122
        .unwrap()
723
122
        .amount
724
122
        .as_str(),
725
122
    )
726
122
    .unwrap()
727
122
}
728

            
729
2
pub fn create_contract_authorization(
730
2
    app: &InjectiveTestApp,
731
2
    contract: String,
732
2
    granter: &SigningAccount,
733
2
    grantee: String,
734
2
    message: String,
735
2
    limit: u64,
736
2
    expiration: Option<Timestamp>,
737
2
) {
738
2
    let authz = Authz::new(app);
739
2

            
740
2
    let mut filter_buf = vec![];
741
2
    AcceptedMessageKeysFilter::encode(&AcceptedMessageKeysFilter { keys: vec![message] }, &mut filter_buf).unwrap();
742
2

            
743
2
    let mut limit_buf = vec![];
744
2
    MaxCallsLimit::encode(&MaxCallsLimit { remaining: limit }, &mut limit_buf).unwrap();
745
2

            
746
2
    let contract_grant = ContractGrant {
747
2
        contract,
748
2
        limit: Some(Any {
749
2
            type_url: MaxCallsLimit::TYPE_URL.to_string(),
750
2
            value: limit_buf,
751
2
        }),
752
2
        filter: Some(Any {
753
2
            type_url: AcceptedMessageKeysFilter::TYPE_URL.to_string(),
754
2
            value: filter_buf,
755
2
        }),
756
2
    };
757
2

            
758
2
    let mut buf = vec![];
759
2
    ContractExecutionAuthorization::encode(
760
2
        &ContractExecutionAuthorization {
761
2
            grants: vec![contract_grant],
762
2
        },
763
2
        &mut buf,
764
2
    )
765
2
    .unwrap();
766
2

            
767
2
    authz
768
2
        .grant(
769
2
            MsgGrant {
770
2
                granter: granter.address(),
771
2
                grantee,
772
2
                grant: Some(Grant {
773
2
                    authorization: Some(Any {
774
2
                        type_url: ContractExecutionAuthorization::TYPE_URL.to_string(),
775
2
                        value: buf.clone(),
776
2
                    }),
777
2
                    expiration,
778
2
                }),
779
2
            },
780
2
            granter,
781
2
        )
782
2
        .unwrap();
783
2
}
784

            
785
172
pub fn init_rich_account(app: &InjectiveTestApp) -> SigningAccount {
786
172
    must_init_account_with_funds(
787
172
        app,
788
172
        &[
789
172
            str_coin("100_000", ETH, Decimals::Eighteen),
790
172
            str_coin("100_000", ATOM, Decimals::Six),
791
172
            str_coin("100_000_000", USDT, Decimals::Six),
792
172
            str_coin("100_000_000", USDC, Decimals::Six),
793
172
            str_coin("100_000", INJ, Decimals::Eighteen),
794
172
            str_coin("100_000", INJ_2, Decimals::Eighteen),
795
172
            str_coin("100_000_000_000_000_000", NINJA, Decimals::Six),
796
172
        ],
797
172
    )
798
172
}
799

            
800
2636
pub fn human_to_dec(raw_number: &str, decimals: Decimals) -> FPDecimal {
801
2636
    FPDecimal::must_from_str(&raw_number.replace('_', "")).scaled(decimals.get_decimals())
802
2636
}
803

            
804
22
pub fn human_to_proto(raw_number: &str, decimals: i32) -> String {
805
22
    FPDecimal::must_from_str(&raw_number.replace('_', "")).scaled(18 + decimals).to_string()
806
22
}
807

            
808
2160
pub fn str_coin(human_amount: &str, denom: &str, decimals: Decimals) -> Coin {
809
2160
    let scaled_amount = human_to_dec(human_amount, decimals);
810
2160
    let as_int: u128 = scaled_amount.into();
811
2160
    coin(as_int, denom)
812
2160
}
813

            
814
424
pub fn initial_coin(human_amount: &str, denom: &str, decimals: Decimals) -> InitialCoin {
815
424
    InitialCoin {
816
424
        coin: str_coin(human_amount, denom, decimals),
817
424
        decimals: decimals.get_decimals() as u32,
818
424
    }
819
424
}
820

            
821
mod tests {
822
    use crate::testing::test_utils::{human_to_dec, human_to_proto, scale_price_quantity_spot_market, Decimals};
823
    use injective_math::FPDecimal;
824

            
825
    #[test]
826
2
    fn it_converts_integer_to_dec() {
827
2
        let integer = "1";
828
2
        let mut decimals = Decimals::Eighteen;
829
2
        let mut expected = FPDecimal::must_from_str("1000000000000000000");
830
2

            
831
2
        let actual = human_to_dec(integer, decimals);
832
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
833

            
834
2
        decimals = Decimals::Six;
835
2
        expected = FPDecimal::must_from_str("1000000");
836
2

            
837
2
        let actual = human_to_dec(integer, decimals);
838
2
        assert_eq!(actual, expected, "failed to convert integer with 6 decimal to dec");
839
2
    }
840

            
841
    #[test]
842
2
    fn it_converts_decimals_above_zero_to_dec() {
843
2
        let integer = "1.1";
844
2
        let mut decimals = Decimals::Eighteen;
845
2
        let mut expected = FPDecimal::must_from_str("1100000000000000000");
846
2

            
847
2
        let actual = human_to_dec(integer, decimals);
848
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
849

            
850
2
        decimals = Decimals::Six;
851
2
        expected = FPDecimal::must_from_str("1100000");
852
2

            
853
2
        let actual = human_to_dec(integer, decimals);
854
2
        assert_eq!(actual, expected, "failed to convert integer with 6 decimal to dec");
855
2
    }
856

            
857
    #[test]
858
2
    fn it_converts_decimals_above_zero_with_max_precision_limit_of_18_to_dec() {
859
2
        let integer = "1.000000000000000001";
860
2
        let decimals = Decimals::Eighteen;
861
2
        let expected = FPDecimal::must_from_str("1000000000000000001");
862
2

            
863
2
        let actual = human_to_dec(integer, decimals);
864
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
865
2
    }
866

            
867
    #[test]
868
2
    fn it_converts_decimals_above_zero_with_max_precision_limit_of_6_to_dec() {
869
2
        let integer = "1.000001";
870
2
        let decimals = Decimals::Six;
871
2
        let expected = FPDecimal::must_from_str("1000001");
872
2

            
873
2
        let actual = human_to_dec(integer, decimals);
874
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
875
2
    }
876

            
877
    #[test]
878
2
    fn it_converts_decimals_below_zero_to_dec() {
879
2
        let integer = "0.1123";
880
2
        let mut decimals = Decimals::Eighteen;
881
2
        let mut expected = FPDecimal::must_from_str("112300000000000000");
882
2

            
883
2
        let actual = human_to_dec(integer, decimals);
884
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
885

            
886
2
        decimals = Decimals::Six;
887
2
        expected = FPDecimal::must_from_str("112300");
888
2

            
889
2
        let actual = human_to_dec(integer, decimals);
890
2
        assert_eq!(actual, expected, "failed to convert integer with 6 decimal to dec");
891
2
    }
892

            
893
    #[test]
894
2
    fn it_converts_decimals_below_zero_with_max_precision_limit_of_18_to_dec() {
895
2
        let integer = "0.000000000000000001";
896
2
        let decimals = Decimals::Eighteen;
897
2
        let expected = FPDecimal::must_from_str("1");
898
2

            
899
2
        let actual = human_to_dec(integer, decimals);
900
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
901
2
    }
902

            
903
    #[test]
904
2
    fn it_converts_decimals_below_zero_with_max_precision_limit_of_6_to_dec() {
905
2
        let integer = "0.000001";
906
2
        let decimals = Decimals::Six;
907
2
        let expected = FPDecimal::must_from_str("1");
908
2

            
909
2
        let actual = human_to_dec(integer, decimals);
910
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to dec");
911
2
    }
912

            
913
    #[test]
914
2
    fn it_converts_integer_to_proto() {
915
2
        let integer = "1";
916
2
        let mut decimals = Decimals::Eighteen;
917
2
        let mut expected = "1000000000000000000000000000000000000";
918
2

            
919
2
        let actual = human_to_proto(integer, decimals.get_decimals());
920
2
        assert_eq!(actual, expected, "failed to convert integer with 18 decimal to proto");
921

            
922
2
        decimals = Decimals::Six;
923
2
        expected = "1000000000000000000000000";
924
2

            
925
2
        let actual = human_to_proto(integer, decimals.get_decimals());
926
2
        assert_eq!(actual, expected, "failed to convert integer with 6 decimal to proto");
927
2
    }
928

            
929
    #[test]
930
2
    fn it_converts_decimal_above_zero_to_proto() {
931
2
        let number = "1.1";
932
2
        let mut decimals = Decimals::Eighteen;
933
2
        let mut expected = "1100000000000000000000000000000000000";
934
2

            
935
2
        let actual = human_to_proto(number, decimals.get_decimals());
936
2
        assert_eq!(actual, expected, "failed to convert decimal with 18 decimal to proto");
937

            
938
2
        decimals = Decimals::Six;
939
2
        expected = "1100000000000000000000000";
940
2

            
941
2
        let actual = human_to_proto(number, decimals.get_decimals());
942
2
        assert_eq!(actual, expected, "failed to convert decimal with 6 decimal to proto");
943
2
    }
944

            
945
    #[test]
946
2
    fn it_converts_decimal_below_zero_to_proto() {
947
2
        let number = "0.1";
948
2
        let mut decimals = Decimals::Eighteen;
949
2
        let mut expected = "100000000000000000000000000000000000";
950
2

            
951
2
        let actual = human_to_proto(number, decimals.get_decimals());
952
2
        assert_eq!(actual, expected, "failed to convert decimal with 18 decimal to proto");
953

            
954
2
        decimals = Decimals::Six;
955
2
        expected = "100000000000000000000000";
956
2

            
957
2
        let actual = human_to_proto(number, decimals.get_decimals());
958
2
        assert_eq!(actual, expected, "failed to convert decimal with 6 decimal to proto");
959
2
    }
960

            
961
    #[test]
962
2
    fn it_converts_decimal_below_zero_with_18_decimals_with_max_precision_to_proto() {
963
2
        let number = "0.000000000000000001";
964
2
        let decimals = Decimals::Eighteen;
965
2
        let expected = "1000000000000000000";
966
2

            
967
2
        let actual = human_to_proto(number, decimals.get_decimals());
968
2
        assert_eq!(actual, expected, "failed to convert decimal with 18 decimal to proto");
969
2
    }
970

            
971
    #[test]
972
    #[should_panic]
973
2
    fn it_panics_when_converting_decimal_below_zero_with_18_decimals_with_too_high_precision_to_proto() {
974
2
        let number = "0.0000000000000000001";
975
2
        let decimals = Decimals::Eighteen;
976
2

            
977
2
        human_to_proto(number, decimals.get_decimals());
978
2
    }
979

            
980
    #[test]
981
2
    fn it_converts_decimal_below_zero_with_6_decimals_with_max_precision_to_proto() {
982
2
        let number = "0.000001";
983
2
        let decimals = Decimals::Six;
984
2
        let expected = "1000000000000000000";
985
2

            
986
2
        let actual = human_to_proto(number, decimals.get_decimals());
987
2
        assert_eq!(actual, expected, "failed to convert decimal with 6 decimal to proto");
988
2
    }
989

            
990
    #[test]
991
2
    fn it_converts_decimal_above_zero_with_0_precision_to_proto() {
992
2
        let number = "1.000001";
993
2
        let expected = "1000001000000000000";
994
2

            
995
2
        let actual = human_to_proto(number, 0);
996
2
        assert_eq!(actual, expected, "failed to convert decimal with 0 decimal to proto");
997
2
    }
998

            
999
    #[test]
2
    fn it_converts_decimal_below_zero_with_0_precision_to_proto() {
2
        let number = "0.000001";
2
        let expected = "1000000000000";
2

            
2
        let actual = human_to_proto(number, 0);
2
        assert_eq!(actual, expected, "failed to convert decimal with 0 decimal to proto");
2
    }
    #[test]
2
    fn it_scales_integer_values_correctly_for_inj_usdt() {
2
        let price = "1";
2
        let quantity = "1";
2

            
2
        let base_decimals = Decimals::Eighteen;
2
        let quote_decimals = Decimals::Six;
2

            
2
        let (scaled_price, scaled_quantity) = scale_price_quantity_spot_market(price, quantity, &(base_decimals as i32), &(quote_decimals as i32));
2

            
2
        // 1 => 1 * 10^6 - 10^18 => 0.000000000001000000 * 10^18 => 1000000
2
        assert_eq!(scaled_price, "1000000", "price was scaled incorrectly");
        // 1 => 1(10^18).(10^18) => 1000000000000000000000000000000000000
2
        assert_eq!(
            scaled_quantity, "1000000000000000000000000000000000000",
            "quantity was scaled incorrectly"
        );
2
    }
    #[test]
2
    fn it_scales_decimal_values_correctly_for_inj_usdt() {
2
        let price = "8.782";
2
        let quantity = "1.12";
2

            
2
        let base_decimals = Decimals::Eighteen;
2
        let quote_decimals = Decimals::Six;
2

            
2
        let (scaled_price, scaled_quantity) = scale_price_quantity_spot_market(price, quantity, &(base_decimals as i32), &(quote_decimals as i32));
2

            
2
        // 0.000000000008782000 * 10^18 = 8782000
2
        assert_eq!(scaled_price, "8782000", "price was scaled incorrectly");
2
        assert_eq!(
            scaled_quantity, "1120000000000000000000000000000000000",
            "quantity was scaled incorrectly"
        );
2
    }
    #[test]
2
    fn it_scales_integer_values_correctly_for_atom_usdt() {
2
        let price = "1";
2
        let quantity = "1";
2

            
2
        let base_decimals = Decimals::Six;
2
        let quote_decimals = Decimals::Six;
2

            
2
        let (scaled_price, scaled_quantity) = scale_price_quantity_spot_market(price, quantity, &(base_decimals as i32), &(quote_decimals as i32));
2

            
2
        // 1 => 1.(10^18) => 1000000000000000000
2
        assert_eq!(scaled_price, "1000000000000000000", "price was scaled incorrectly");
        // 1 => 1(10^6).(10^18) => 1000000000000000000000000
2
        assert_eq!(scaled_quantity, "1000000000000000000000000", "quantity was scaled incorrectly");
2
    }
    #[test]
2
    fn it_scales_decimal_values_correctly_for_atom_usdt() {
2
        let price = "1.129";
2
        let quantity = "1.62";
2

            
2
        let base_decimals = Decimals::Six;
2
        let quote_decimals = Decimals::Six;
2

            
2
        let (scaled_price, scaled_quantity) = scale_price_quantity_spot_market(price, quantity, &(base_decimals as i32), &(quote_decimals as i32));
2

            
2
        // 1.129 => 1.129(10^15) => 1129000000000000000
2
        assert_eq!(scaled_price, "1129000000000000000", "price was scaled incorrectly");
        // 1.62 => 1.62(10^4)(10^18) => 1000000000000000000000000
2
        assert_eq!(scaled_quantity, "1620000000000000000000000", "quantity was scaled incorrectly");
2
    }
}
162
pub fn are_fpdecimals_approximately_equal(first: FPDecimal, second: FPDecimal, max_diff: FPDecimal) -> bool {
162
    (first - second).abs() <= max_diff
162
}
14
pub fn assert_fee_is_as_expected(raw_fees: &mut [FPCoin], expected_fees: &mut [FPCoin], max_diff: FPDecimal) {
14
    assert_eq!(raw_fees.len(), expected_fees.len(), "Wrong number of fee denoms received");
35
    raw_fees.sort_by_key(|f| f.denom.clone());
35
    expected_fees.sort_by_key(|f| f.denom.clone());
28
    for (raw_fee, expected_fee) in raw_fees.iter().zip(expected_fees.iter()) {
28
        assert!(
28
            are_fpdecimals_approximately_equal(expected_fee.amount, raw_fee.amount, max_diff,),
            "Wrong amount of trx fee received. Expected: {}, Actual: {}, Max diff: {}",
            expected_fee.amount,
            raw_fee.amount,
            max_diff
        );
    }
14
}