1
use crate::{
2
    contract::{migrate, CONTRACT_NAME, CONTRACT_VERSION},
3
    msg::{FeeRecipient, InstantiateMsg, MigrateMsg, QueryMsg},
4
    state::{read_swap_route, store_swap_route, CONFIG},
5
    testing::{
6
        integration_realistic_tests_min_quantity::happy_path_two_hops_test,
7
        test_utils::{
8
            initial_coin, launch_realistic_usdt_usdc_spot_market, must_init_account_with_funds_and_setting_denoms, query_bank_balance,
9
            set_route_and_assert_success, str_coin, Decimals, ATOM, ETH, INJ, USDC, USDT,
10
        },
11
    },
12
    types::{Config, ConfigResponse, SwapRoute},
13
    ContractError,
14
};
15

            
16
use cosmwasm_std::{testing::mock_env, Addr};
17
use cw2::{get_contract_version, set_contract_version};
18
use injective_cosmwasm::{inj_mock_deps, MarketId, TEST_MARKET_ID_1};
19
use injective_math::FPDecimal;
20
use injective_std::types::cosmwasm::wasm::v1::{QueryContractInfoRequest, QueryContractInfoResponse};
21
use injective_test_tube::{Account, Bank, Exchange, InjectiveTestApp, Module, Runner, Wasm};
22

            
23
const CODE_67_CW2_NAME: &str = "crates.io:atomic-order-example";
24
const CODE_67_CW2_VERSION: &str = "0.1.0";
25
const CODE_1962_CW2_NAME: &str = "swap-contract";
26
const CODE_1962_CW2_VERSION: &str = "1.1.2";
27

            
28
#[test]
29
2
fn migrates_persistent_state_from_code_67() {
30
2
    assert_storage_migration(CODE_67_CW2_NAME, CODE_67_CW2_VERSION, "code_67");
31
2
}
32

            
33
#[test]
34
2
fn migrates_persistent_state_from_code_1962() {
35
2
    assert_storage_migration(CODE_1962_CW2_NAME, CODE_1962_CW2_VERSION, "code_1962");
36
2
}
37

            
38
#[test]
39
2
fn rejects_unknown_migration_source() {
40
3
    let mut deps = inj_mock_deps(|_| {});
41
2
    set_contract_version(deps.as_mut().storage, "swap-contract", "9.9.9").unwrap();
42
2

            
43
2
    let result = migrate(deps.as_mut(), mock_env(), MigrateMsg {});
44
2

            
45
2
    assert!(matches!(result, Err(ContractError::MigrationError {})));
46
2
}
47

            
48
#[test]
49
#[cfg_attr(not(feature = "integration"), ignore)]
50
2
fn migrates_the_deployed_code_67_artifact() {
51
2
    assert_deployed_artifact_migrates("mainnet_code_67.wasm");
52
2
}
53

            
54
#[test]
55
#[cfg_attr(not(feature = "integration"), ignore)]
56
2
fn migrates_the_deployed_code_1962_artifact() {
57
2
    assert_deployed_artifact_migrates("mainnet_code_1962.wasm");
58
2
}
59

            
60
4
fn assert_storage_migration(previous_name: &str, previous_version: &str, expected_source: &str) {
61
6
    let mut deps = inj_mock_deps(|_| {});
62
4
    let expected_config = Config {
63
4
        fee_recipient: Addr::unchecked("fee_recipient"),
64
4
        admin: Addr::unchecked("admin"),
65
4
    };
66
4
    let expected_route = SwapRoute {
67
4
        steps: vec![MarketId::unchecked(TEST_MARKET_ID_1)],
68
4
        source_denom: "source".to_string(),
69
4
        target_denom: "target".to_string(),
70
4
    };
71
4

            
72
4
    CONFIG.save(deps.as_mut().storage, &expected_config).unwrap();
73
4
    store_swap_route(deps.as_mut().storage, &expected_route).unwrap();
74
4
    set_contract_version(deps.as_mut().storage, previous_name, previous_version).unwrap();
75
4

            
76
4
    let response = migrate(deps.as_mut(), mock_env(), MigrateMsg {}).unwrap();
77
4

            
78
4
    assert_eq!(CONFIG.load(&deps.storage).unwrap(), expected_config);
79
4
    assert_eq!(read_swap_route(&deps.storage, "source", "target").unwrap(), expected_route);
80
4
    assert_eq!(
81
4
        get_contract_version(&deps.storage).unwrap(),
82
4
        cw2::ContractVersion {
83
4
            contract: CONTRACT_NAME.to_string(),
84
4
            version: CONTRACT_VERSION.to_string(),
85
4
        }
86
4
    );
87
4
    assert!(response
88
4
        .attributes
89
4
        .iter()
90
6
        .any(|attribute| attribute.key == "migration_source" && attribute.value == expected_source));
91
4
}
92

            
93
4
fn assert_deployed_artifact_migrates(fixture_name: &str) {
94
4
    let app = InjectiveTestApp::new();
95
4
    let wasm = Wasm::new(&app);
96
4
    let bank = Bank::new(&app);
97
4
    let exchange = Exchange::new(&app);
98
4
    let validator = app.get_first_validator_signing_account(INJ.to_string(), 1.2f64).unwrap();
99
4
    let owner = must_init_account_with_funds_and_setting_denoms(
100
4
        &app,
101
4
        &validator,
102
4
        &[
103
4
            initial_coin("1", ETH, Decimals::Eighteen),
104
4
            initial_coin("1", ATOM, Decimals::Six),
105
4
            initial_coin("1_000", USDT, Decimals::Six),
106
4
            initial_coin("1", USDC, Decimals::Six),
107
4
            initial_coin("10_000", INJ, Decimals::Eighteen),
108
4
        ],
109
4
    );
110
4
    let persisted_market_id = launch_realistic_usdt_usdc_spot_market(&exchange, &owner);
111
4
    let fixture_path = format!("{}/src/testing/test_artifacts/{fixture_name}", env!("CARGO_MANIFEST_DIR"));
112
4
    let previous_wasm = std::fs::read(fixture_path).unwrap();
113
4
    let previous_code_id = wasm.store_code(&previous_wasm, None, &owner).unwrap().data.code_id;
114
4
    let contract_address = wasm
115
4
        .instantiate(
116
4
            previous_code_id,
117
4
            &InstantiateMsg {
118
4
                admin: Addr::unchecked(owner.address()),
119
4
                fee_recipient: FeeRecipient::SwapContract,
120
4
            },
121
4
            Some(&owner.address()),
122
4
            Some("swap-contract-migration-test"),
123
4
            &[str_coin("100", USDT, Decimals::Six)],
124
4
            &owner,
125
4
        )
126
4
        .unwrap()
127
4
        .data
128
4
        .address;
129
4
    let balance_before = query_bank_balance(&bank, USDT, &contract_address);
130
4
    set_route_and_assert_success(&wasm, &owner, &contract_address, USDT, USDC, vec![persisted_market_id.as_str().into()]);
131
4
    let route_before: SwapRoute = wasm
132
4
        .query(
133
4
            &contract_address,
134
4
            &QueryMsg::GetRoute {
135
4
                source_denom: USDT.to_string(),
136
4
                target_denom: USDC.to_string(),
137
4
            },
138
4
        )
139
4
        .unwrap();
140
4

            
141
4
    let release_wasm_path = format!("{}/../../artifacts/swap_contract.wasm", env!("CARGO_MANIFEST_DIR"));
142
4
    let release_wasm = std::fs::read(release_wasm_path).unwrap();
143
4
    let new_code_id = wasm.store_code(&release_wasm, None, &owner).unwrap().data.code_id;
144
4
    wasm.migrate(new_code_id, &contract_address, &MigrateMsg {}, &owner).unwrap();
145
4

            
146
4
    let contract_info: QueryContractInfoResponse = app
147
4
        .query(
148
4
            "/cosmwasm.wasm.v1.Query/ContractInfo",
149
4
            &QueryContractInfoRequest {
150
4
                address: contract_address.clone(),
151
4
            },
152
4
        )
153
4
        .unwrap();
154
4
    let config: ConfigResponse = wasm.query(&contract_address, &QueryMsg::GetConfig {}).unwrap();
155
4
    let route_after: SwapRoute = wasm
156
4
        .query(
157
4
            &contract_address,
158
4
            &QueryMsg::GetRoute {
159
4
                source_denom: USDT.to_string(),
160
4
                target_denom: USDC.to_string(),
161
4
            },
162
4
        )
163
4
        .unwrap();
164
4

            
165
4
    assert_eq!(contract_info.contract_info.unwrap().code_id, new_code_id);
166
4
    assert_eq!(config.contract_version, CONTRACT_VERSION);
167
4
    assert_eq!(config.config.admin, Addr::unchecked(owner.address()));
168
4
    assert_eq!(config.config.fee_recipient, Addr::unchecked(contract_address.clone()));
169
4
    assert_eq!(query_bank_balance(&bank, USDT, &contract_address), balance_before);
170
4
    assert_eq!(balance_before, FPDecimal::from(100_000_000u128));
171
4
    assert_eq!(route_after, route_before);
172

            
173
4
    happy_path_two_hops_test(app, owner, contract_address);
174
4
}