Repository: public-awesome/launchpad
Pull request #483 (2022-12-15 16:39:06)

Move sg-eth-airdrop and vending minter tests into testing-suite
PART 2
There are 3 PRs in this series: 
1) https://github.com/public-awesome/launchpad/pull/479  => Refactors the vending minter tests that will serve as the common core for other similar tests
2) https://github.com/public-awesome/launchpad/pull/483  => Create the test-suite folder where all tests will eventually go and move the two contracts affected most to the test-suite
3) https://github.com/public-awesome/launchpad/pull/486  => Shape and move all of the remaining tests to the test-suite folder

This PR follows refactor-vending-minter
1) In refactor-vending-minter organized the tests for vending-minter so that the setup code is separated out
2) In this PR create folder "testing-suite" in which all the tests will eventually go for launchpad

In this PR only doing this for sg-eth-airdrop and vending-minter. There will be another PR where I move the remaining tests in launchpad into testing-suite. 


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index a9e41534..74bfef89 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -11,10 +11,12 @@ workflows:
       - contract_vending_minter
       - contract_whitelist
       - sg-eth-airdrop
+      - test-suite
       - package_sg_std
       - package_sg_utils
       - lint
       - wasm-build
+
   deploy:
     jobs:
       - build_and_upload_contracts:
@@ -276,6 +278,29 @@ jobs:
             - /usr/local/cargo/registry
             - target
           key: cargocache-whitelist-rust:1.64.0-{{ checksum "~/project/Cargo.lock" }}
+  test-suite:
+    docker:
+      - image: rust:1.64.0
+    working_directory: ~/project/test-suite
+    steps:
+      - checkout:
+          path: ~/project
+      - run:
+          name: Version information
+          command: rustc --version; cargo --version; rustup --version
+      - restore_cache:
+          keys:
+            - cargocache-test-suite-rust:1.64.0-{{ checksum "~/project/Cargo.lock" }}
+      - run:
+          name: Unit Tests
+          environment:
+            RUST_BACKTRACE: 1
+          command: cargo unit-test --locked
+      - save_cache:
+          paths:
+            - /usr/local/cargo/registry
+            - target
+          key: cargocache-test-suite-rust:1.64.0-{{ checksum "~/project/Cargo.lock" }}
 
   package_sg_std:
     docker:
@@ -407,7 +432,7 @@ jobs:
           command: rustc --version; cargo --version; rustup --version
       - restore_cache:
           keys:
-            - cargocache-wasm-rust:1.64.0-{{ checksum "~/project/Cargo.lock" }}
+            - cargocache-wasm-rust-no-wasm:1.64.0-{{ checksum "~/project/Cargo.lock" }}
       - run:
           name: Add wasm32 target
           command: rustup target add wasm32-unknown-unknown
@@ -426,8 +451,10 @@ jobs:
       - save_cache:
           paths:
             - /usr/local/cargo/registry
-            - target
-          key: cargocache-wasm-rust:1.64.0-{{ checksum "~/project/Cargo.lock" }}
+            - /target/debug
+            - /target/release
+            - /target/tarpaulin
+          key: cargocache-wasm-rust-no-wasm:1.64.0-{{ checksum "~/project/Cargo.lock" }}
       - run:
           name: Check wasm contracts
           command: |
diff --git a/Cargo.lock b/Cargo.lock
index 42aa8c0b..f3fb5ea1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -480,9 +480,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.77"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
 
 [[package]]
 name = "cfg-if"
@@ -1622,9 +1622,9 @@ dependencies = [
 
 [[package]]
 name = "polling"
-version = "2.5.1"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748"
+checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6"
 dependencies = [
  "autocfg",
  "cfg-if",
@@ -1955,9 +1955,9 @@ dependencies = [
 
 [[package]]
 name = "scale-info"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d8a765117b237ef233705cc2cc4c6a27fccd46eea6ef0c8c6dae5f3ef407f8"
+checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608"
 dependencies = [
  "cfg-if",
  "derive_more",
@@ -1967,9 +1967,9 @@ dependencies = [
 
 [[package]]
 name = "scale-info-derive"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdcd47b380d8c4541044e341dcd9475f55ba37ddc50c908d945fc036a8642496"
+checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c"
 dependencies = [
  "proc-macro-crate 1.2.1",
  "proc-macro2",
@@ -2041,9 +2041,9 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 
 [[package]]
 name = "serde"
-version = "1.0.149"
+version = "1.0.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
+checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
 dependencies = [
  "serde_derive",
 ]
@@ -2059,9 +2059,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.149"
+version = "1.0.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
+checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2575,6 +2575,49 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 
+[[package]]
+name = "test-suite"
+version = "0.21.5"
+dependencies = [
+ "anyhow",
+ "async-std",
+ "cosmwasm-schema",
+ "cosmwasm-std",
+ "cw-multi-test",
+ "cw-storage-plus",
+ "cw-utils",
+ "cw2",
+ "cw4",
+ "cw4-group",
+ "cw721",
+ "cw721-base",
+ "ethers-core",
+ "ethers-signers",
+ "eyre",
+ "rand_core 0.6.4",
+ "rand_xoshiro",
+ "rlp",
+ "schemars",
+ "serde",
+ "sg-eth-airdrop",
+ "sg-multi-test 0.21.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sg-splits",
+ "sg-std 0.21.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sg-whitelist",
+ "sg1 0.21.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sg2 0.21.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sg4 0.21.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sg721 0.21.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sg721-base",
+ "sha2 0.10.6",
+ "shuffle",
+ "thiserror",
+ "url",
+ "vending-factory",
+ "vending-minter",
+ "whitelist-immutable",
+]
+
 [[package]]
 name = "thiserror"
 version = "1.0.37"
@@ -2621,9 +2664,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 
 [[package]]
 name = "toml"
-version = "0.5.9"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
+checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
 dependencies = [
  "serde",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index a9c327ae..7b935a79 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
 [workspace]
-members = ["packages/*", "contracts/*"]
+members = ["packages/*", "contracts/*", "test-suite/"]
 resolver = "2"
 
 [workspace.package]
@@ -41,7 +41,8 @@ vending-minter = { version = "0.21.5", path = "contracts/vending-minter" }
 whitelist-immutable = { version = "0.21.5", path = "contracts/whitelist-immutable" }
 sg-whitelist-basic = { version = "0.12.0" }
 ethereum-verify = { version = "0.21.5", path = "packages/ethereum-verify" }
-
+sg-eth-airdrop = {version = "0.21.5", path = "contracts/sg-eth-airdrop" }
+test-suite = { version = "0.21.5", path = "test-suite" }
 
 [profile.release.package.sg721]
 codegen-units = 1
@@ -103,7 +104,7 @@ incremental = false
 codegen-units = 1
 incremental = false
 
-[profile.release.package.whitelist-generic]
+[profile.release.package.whitelist-immutable]
 codegen-units = 1
 incremental = false
 
diff --git a/contracts/sg-eth-airdrop/src/lib.rs b/contracts/sg-eth-airdrop/src/lib.rs
index 28f8755b..76387429 100644
--- a/contracts/sg-eth-airdrop/src/lib.rs
+++ b/contracts/sg-eth-airdrop/src/lib.rs
@@ -1,11 +1,8 @@
 pub mod contract;
-mod error;
+pub mod error;
 pub mod msg;
 pub mod query;
 pub mod reply;
 pub mod state;
 pub use crate::error::ContractError;
 mod claim_airdrop;
-
-#[cfg(test)]
-mod testing;
diff --git a/contracts/vending-minter/src/lib.rs b/contracts/vending-minter/src/lib.rs
index 24063413..ccc96a84 100644
--- a/contracts/vending-minter/src/lib.rs
+++ b/contracts/vending-minter/src/lib.rs
@@ -1,7 +1,4 @@
 pub mod contract;
-#[cfg(test)]
-mod testing;
-
 mod error;
 pub mod msg;
 


Test patch:
diff --git a/contracts/sg-eth-airdrop/src/testing/constants.rs b/contracts/sg-eth-airdrop/src/testing/constants.rs
deleted file mode 100644
index 82c941a7..00000000
--- a/contracts/sg-eth-airdrop/src/testing/constants.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-mod claim_constants;
-pub use claim_constants::{
-    CONFIG_PLAINTEXT, MOCK_AIRDROP_ADDR_STR, MOCK_MINTER_ADDR_STR, NATIVE_DENOM, OWNER,
-    STARGAZE_WALLET_01, STARGAZE_WALLET_02,
-};
-mod collection_constants;
-pub use collection_constants::{
-    AIRDROP_ADDR_STR, AIRDROP_MINT_FEE_BPS, AIRDROP_MINT_PRICE, CREATION_FEE, INITIAL_BALANCE,
-    MAX_PER_ADDRESS_LIMIT, MAX_TOKEN_LIMIT, MINT_FEE_BPS, MINT_PRICE, MIN_MINT_PRICE, SHUFFLE_FEE,
-    WHITELIST_AMOUNT, WL_PER_ADDRESS_LIMIT,
-};
diff --git a/contracts/sg-eth-airdrop/src/testing/constants/collection_constants.rs b/contracts/sg-eth-airdrop/src/testing/constants/collection_constants.rs
deleted file mode 100644
index 32476ab8..00000000
--- a/contracts/sg-eth-airdrop/src/testing/constants/collection_constants.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-pub const CREATION_FEE: u128 = 5_000_000_000;
-pub const INITIAL_BALANCE: u128 = 2_000_000_000;
-
-pub const MINT_PRICE: u128 = 100_000_000;
-pub const WHITELIST_AMOUNT: u128 = 66_000_000;
-pub const WL_PER_ADDRESS_LIMIT: u32 = 1;
-pub const MAX_TOKEN_LIMIT: u32 = 10000;
-
-pub const MIN_MINT_PRICE: u128 = 50_000_000;
-pub const AIRDROP_MINT_PRICE: u128 = 0;
-pub const MINT_FEE_BPS: u64 = 1_000; // 10%
-pub const AIRDROP_MINT_FEE_BPS: u64 = 10_000; // 100%
-pub const SHUFFLE_FEE: u128 = 500_000_000;
-pub const MAX_PER_ADDRESS_LIMIT: u32 = 50;
-
-pub const AIRDROP_ADDR_STR: &str = "contract4";
diff --git a/contracts/sg-eth-airdrop/src/testing/setup.rs b/contracts/sg-eth-airdrop/src/testing/setup.rs
deleted file mode 100644
index 32f3482d..00000000
--- a/contracts/sg-eth-airdrop/src/testing/setup.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-mod mock_minter_contract;
-pub use mock_minter_contract::{
-    execute as mock_minter_execute, instantiate as mock_minter_instantiate,
-    query as mock_minter_query,
-};
-
-mod mock_whitelist_contract;
-pub use mock_whitelist_contract::{
-    execute as mock_whitelist_execute, instantiate as mock_whitelist_instantiate,
-    query as mock_whitelist_query,
-};
-
-mod setup_accounts_and_block;
-pub use setup_accounts_and_block::{setup_accounts, setup_block_time};
-
-mod setup_collection_whitelist;
-pub use setup_collection_whitelist::{configure_collection_whitelist, setup_whitelist_contract};
-
-mod setup_contracts;
-pub use setup_contracts::{
-    contract, contract_factory, contract_minter, contract_sg721, contract_whitelist,
-    custom_mock_app, execute_contract_error_with_msg, execute_contract_with_msg,
-    instantiate_contract, mock_minter, mock_whitelist, whitelist_immutable_contract,
-};
-
-mod setup_minter;
-pub use setup_minter::{
-    configure_minter_with_whitelist, configure_mock_minter_with_mock_whitelist,
-};
-
-mod setup_signatures;
-pub use setup_signatures::{get_msg_plaintext, get_signature, get_wallet_and_sig};
-
-mod test_msgs;
-pub use test_msgs::InstantiateParams;
-
-mod collection_whitelist_helpers;
-pub use collection_whitelist_helpers::{
-    execute_airdrop_claim, execute_mint_fail_not_on_whitelist, execute_mint_success,
-    send_funds_to_address, update_admin_for_whitelist,
-};
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/setup_accounts_and_block.rs b/contracts/sg-eth-airdrop/src/testing/setup/setup_accounts_and_block.rs
deleted file mode 100644
index 29e739fb..00000000
--- a/contracts/sg-eth-airdrop/src/testing/setup/setup_accounts_and_block.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use crate::testing::constants::{CREATION_FEE, INITIAL_BALANCE, NATIVE_DENOM};
-use cosmwasm_std::{coins, Addr, Timestamp};
-use cw_multi_test::{BankSudo, SudoMsg};
-use sg_multi_test::StargazeApp;
-
-// Set blockchain time to after mint by default
-pub fn setup_block_time(router: &mut StargazeApp, nanos: u64, height: Option<u64>) {
-    let mut block = router.block_info();
-    block.time = Timestamp::from_nanos(nanos);
-    if let Some(h) = height {
-        block.height = h;
-    }
-    router.set_block(block);
-}
-
-// Add a creator account with initial balances
-pub fn setup_accounts(router: &mut StargazeApp) -> (Addr, Addr) {
-    let buyer = Addr::unchecked("buyer");
-    let creator = Addr::unchecked("creator");
-    // 3,000 tokens
-    let creator_funds = coins(INITIAL_BALANCE + CREATION_FEE, NATIVE_DENOM);
-    // 2,000 tokens
-    let buyer_funds = coins(INITIAL_BALANCE, NATIVE_DENOM);
-    router
-        .sudo(SudoMsg::Bank({
-            BankSudo::Mint {
-                to_address: creator.to_string(),
-                amount: creator_funds.clone(),
-            }
-        }))
-        .map_err(|err| println!("{:?}", err))
-        .ok();
-
-    router
-        .sudo(SudoMsg::Bank({
-            BankSudo::Mint {
-                to_address: buyer.to_string(),
-                amount: buyer_funds.clone(),
-            }
-        }))
-        .map_err(|err| println!("{:?}", err))
-        .ok();
-
-    // Check native balances
-    let creator_native_balances = router.wrap().query_all_balances(creator.clone()).unwrap();
-    assert_eq!(creator_native_balances, creator_funds);
-
-    // Check native balances
-    let buyer_native_balances = router.wrap().query_all_balances(buyer.clone()).unwrap();
-    assert_eq!(buyer_native_balances, buyer_funds);
-
-    (creator, buyer)
-}
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/setup_collection_whitelist.rs b/contracts/sg-eth-airdrop/src/testing/setup/setup_collection_whitelist.rs
deleted file mode 100644
index 9f8f340a..00000000
--- a/contracts/sg-eth-airdrop/src/testing/setup/setup_collection_whitelist.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use crate::testing::constants::{WHITELIST_AMOUNT, WL_PER_ADDRESS_LIMIT};
-use crate::testing::setup::{contract_whitelist, setup_block_time};
-use cosmwasm_std::{coin, Addr, Timestamp};
-use cw_multi_test::Executor;
-use sg_multi_test::StargazeApp;
-use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
-
-pub fn setup_whitelist_contract(router: &mut StargazeApp, creator: &Addr, code_id: u64) -> Addr {
-    let msg = sg_whitelist::msg::InstantiateMsg {
-        members: vec![],
-        start_time: Timestamp::from_nanos(GENESIS_MINT_START_TIME + 100),
-        end_time: Timestamp::from_nanos(GENESIS_MINT_START_TIME + 10000000),
-        mint_price: coin(WHITELIST_AMOUNT, NATIVE_DENOM),
-        per_address_limit: WL_PER_ADDRESS_LIMIT,
-        member_limit: 1000,
-        admins: vec![creator.to_string()],
-        admins_mutable: true,
-    };
-    router
-        .instantiate_contract(
-            code_id,
-            creator.clone(),
-            &msg,
-            &[coin(100_000_000, NATIVE_DENOM)],
-            "whitelist",
-            None,
-        )
-        .unwrap()
-}
-
-pub fn configure_collection_whitelist(
-    router: &mut StargazeApp,
-    creator: Addr,
-    buyer: Addr,
-    minter_addr: Addr,
-) -> Addr {
-    let whitelist_code_id = router.store_code(contract_whitelist());
-    let whitelist_addr = setup_whitelist_contract(router, &creator, whitelist_code_id);
-    const AFTER_GENESIS_TIME: Timestamp = Timestamp::from_nanos(GENESIS_MINT_START_TIME + 100);
-
-    // Set to just before genesis mint start time
-    setup_block_time(router, GENESIS_MINT_START_TIME - 10, None);
-
-    // Update whitelist_expiration fails if not admin
-    let wl_msg = sg_whitelist::msg::ExecuteMsg::UpdateEndTime(AFTER_GENESIS_TIME);
-    router
-        .execute_contract(buyer, whitelist_addr.clone(), &wl_msg, &[])
-        .unwrap_err();
-
-    // Update whitelist_expiration succeeds when from admin
-    let wl_msg = sg_whitelist::msg::ExecuteMsg::UpdateEndTime(AFTER_GENESIS_TIME);
-    let res = router.execute_contract(creator.clone(), whitelist_addr.clone(), &wl_msg, &[]);
-    assert!(res.is_ok());
-
-    let wl_msg = sg_whitelist::msg::ExecuteMsg::UpdateStartTime(Timestamp::from_nanos(0));
-    let res = router.execute_contract(creator.clone(), whitelist_addr.clone(), &wl_msg, &[]);
-    assert!(res.is_ok());
-
-    // Set whitelist in minter contract
-    let set_whitelist_msg = vending_minter::msg::ExecuteMsg::SetWhitelist {
-        whitelist: whitelist_addr.to_string(),
-    };
-    let res = router.execute_contract(creator, minter_addr, &set_whitelist_msg, &[]);
-    assert!(res.is_ok());
-    whitelist_addr
-}
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/setup_contracts.rs b/contracts/sg-eth-airdrop/src/testing/setup/setup_contracts.rs
deleted file mode 100644
index ef8a6c39..00000000
--- a/contracts/sg-eth-airdrop/src/testing/setup/setup_contracts.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-use cosmwasm_std::{coins, Addr};
-use cw_multi_test::error::Error;
-use cw_multi_test::{AppResponse, BankSudo, Contract, ContractWrapper, Executor, SudoMsg};
-
-use sg_multi_test::StargazeApp;
-use sg_std::{self, StargazeMsgWrapper};
-
-use crate::msg::{ExecuteMsg, InstantiateMsg};
-use crate::testing::constants::WHITELIST_AMOUNT;
-use anyhow::Error as anyhow_error;
-use eyre::Result;
-extern crate whitelist_immutable;
-use super::test_msgs::InstantiateParams;
-use crate::testing::constants::{NATIVE_DENOM, OWNER};
-use crate::testing::setup::{
-    mock_minter_execute, mock_minter_instantiate, mock_minter_query, mock_whitelist_execute,
-    mock_whitelist_instantiate, mock_whitelist_query,
-};
-
-pub fn custom_mock_app() -> StargazeApp {
-    StargazeApp::default()
-}
-
-pub fn mock_minter() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        mock_minter_execute,
-        mock_minter_instantiate,
-        mock_minter_query,
-    );
-    Box::new(contract)
-}
-
-pub fn mock_whitelist() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        mock_whitelist_execute,
-        mock_whitelist_instantiate,
-        mock_whitelist_query,
-    );
-    Box::new(contract)
-}
-
-pub fn contract_minter() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        vending_minter::contract::execute,
-        vending_minter::contract::instantiate,
-        vending_minter::contract::query,
-    )
-    .with_reply(vending_minter::contract::reply);
-    Box::new(contract)
-}
-
-pub fn contract_whitelist() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        sg_whitelist::contract::execute,
-        sg_whitelist::contract::instantiate,
-        sg_whitelist::contract::query,
-    );
-    Box::new(contract)
-}
-
-pub fn contract_factory() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        vending_factory::contract::execute,
-        vending_factory::contract::instantiate,
-        vending_factory::contract::query,
-    );
-    Box::new(contract)
-}
-
-pub fn contract_sg721() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        sg721_base::entry::execute,
-        sg721_base::entry::instantiate,
-        sg721_base::entry::query,
-    );
-    Box::new(contract)
-}
-
-pub fn contract() -> Box<dyn Contract<sg_std::StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        crate::contract::execute,
-        crate::contract::instantiate,
-        crate::query::query,
-    )
-    .with_reply(crate::reply::reply);
-    Box::new(contract)
-}
-
-pub fn whitelist_immutable_contract() -> Box<dyn Contract<StargazeMsgWrapper>> {
-    let contract = ContractWrapper::new(
-        whitelist_immutable::contract::execute,
-        whitelist_immutable::contract::instantiate,
-        whitelist_immutable::contract::query,
-    );
-    Box::new(contract)
-}
-
-pub fn instantiate_contract(params: InstantiateParams) -> Result<cosmwasm_std::Addr, anyhow_error> {
-    let addresses = params.addresses;
-    let minter_address = params.minter_address;
-    let admin_account = params.admin_account;
-    let funds_amount = params.funds_amount;
-    let per_address_limit = params.per_address_limit;
-    let claim_msg_plaintext = params.claim_msg_plaintext;
-    params
-        .app
-        .sudo(SudoMsg::Bank({
-            BankSudo::Mint {
-                to_address: admin_account.to_string(),
-                amount: coins(params.funds_amount, NATIVE_DENOM),
-            }
-        }))
-        .map_err(|err| println!("{:?}", err))
-        .ok();
-
-    let sg_eth_id = params.app.store_code(contract());
-    let whitelist_code_id = params.app.store_code(whitelist_immutable_contract());
-    assert_eq!(sg_eth_id, params.expected_airdrop_contract_id);
-
-    let msg: InstantiateMsg = InstantiateMsg {
-        admin: Addr::unchecked(OWNER),
-        claim_msg_plaintext,
-        airdrop_amount: WHITELIST_AMOUNT,
-        addresses,
-        whitelist_code_id,
-        minter_address,
-        per_address_limit,
-    };
-    params.app.instantiate_contract(
-        sg_eth_id,
-        Addr::unchecked(admin_account.clone()),
-        &msg,
-        &coins(funds_amount, NATIVE_DENOM),
-        "sg-eg-airdrop",
-        Some(Addr::unchecked(admin_account).to_string()),
-    )
-}
-
-pub fn execute_contract_with_msg(
-    msg: ExecuteMsg,
-    app: &mut StargazeApp,
-    user: Addr,
-    target_address: Addr,
-) -> Result<AppResponse, Error> {
-    let result = app.execute_contract(user, target_address, &msg, &[]);
-    Ok(result.unwrap())
-}
-
-pub fn execute_contract_error_with_msg(
-    msg: ExecuteMsg,
-    app: &mut StargazeApp,
-    user: Addr,
-    target_address: Addr,
-) -> String {
-    let result = app
-        .execute_contract(user, target_address, &msg, &[])
-        .unwrap_err();
-    result.root_cause().to_string()
-}
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/setup_minter.rs b/contracts/sg-eth-airdrop/src/testing/setup/setup_minter.rs
deleted file mode 100644
index 78084332..00000000
--- a/contracts/sg-eth-airdrop/src/testing/setup/setup_minter.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-use crate::testing::setup::{
-    configure_collection_whitelist, mock_whitelist, setup_whitelist_contract,
-};
-use cosmwasm_std::{coin, coins, Addr, Timestamp};
-use cw_multi_test::Executor;
-use sg2::{msg::Sg2ExecuteMsg, tests::mock_collection_params};
-use sg_multi_test::StargazeApp;
-use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
-use vending_factory::{
-    msg::{VendingMinterCreateMsg, VendingMinterInitMsgExtension},
-    state::{ParamsExtension, VendingMinterParams},
-};
-
-use crate::testing::constants::{
-    AIRDROP_MINT_FEE_BPS, AIRDROP_MINT_PRICE, CREATION_FEE, MAX_PER_ADDRESS_LIMIT, MAX_TOKEN_LIMIT,
-    MINT_FEE_BPS, MINT_PRICE, MIN_MINT_PRICE, SHUFFLE_FEE,
-};
-use crate::testing::setup::{contract_factory, contract_minter, contract_sg721, mock_minter};
-use crate::testing::setup::{setup_accounts, setup_block_time};
-
-pub fn mock_init_extension(splits_addr: Option<String>) -> VendingMinterInitMsgExtension {
-    vending_factory::msg::VendingMinterInitMsgExtension {
-        base_token_uri: "ipfs://aldkfjads".to_string(),
-        payment_address: splits_addr,
-        start_time: Timestamp::from_nanos(GENESIS_MINT_START_TIME),
-        num_tokens: 100,
-        mint_price: coin(MIN_MINT_PRICE, NATIVE_DENOM),
-        per_address_limit: 5,
-        whitelist: None,
-    }
-}
-
-pub fn mock_create_minter(splits_addr: Option<String>) -> VendingMinterCreateMsg {
-    VendingMinterCreateMsg {
-        init_msg: mock_init_extension(splits_addr),
-        collection_params: mock_collection_params(),
-    }
-}
-
-pub fn mock_params() -> VendingMinterParams {
-    VendingMinterParams {
-        code_id: 1,
-        creation_fee: coin(CREATION_FEE, NATIVE_DENOM),
-        min_mint_price: coin(MIN_MINT_PRICE, NATIVE_DENOM),
-        mint_fee_bps: MINT_FEE_BPS,
-        max_trading_offset_secs: 60 * 60 * 24 * 7,
-        extension: ParamsExtension {
-            max_token_limit: MAX_TOKEN_LIMIT,
-            max_per_address_limit: MAX_PER_ADDRESS_LIMIT,
-            airdrop_mint_price: coin(AIRDROP_MINT_PRICE, NATIVE_DENOM),
-            airdrop_mint_fee_bps: AIRDROP_MINT_FEE_BPS,
-            shuffle_fee: coin(SHUFFLE_FEE, NATIVE_DENOM),
-        },
-    }
-}
-
-// Upload contract code and instantiate minter contract
-fn setup_minter_contract(
-    router: &mut StargazeApp,
-    creator: &Addr,
-    num_tokens: u32,
-    splits_addr: Option<String>,
-) -> (Addr, vending_minter::msg::ConfigResponse) {
-    let minter_code_id = router.store_code(contract_minter());
-    println!("minter_code_id: {}", minter_code_id);
-    let creation_fee = coins(CREATION_FEE, NATIVE_DENOM);
-
-    let factory_code_id = router.store_code(contract_factory());
-    println!("factory_code_id: {}", factory_code_id);
-
-    let mut params = mock_params();
-    params.code_id = minter_code_id;
-
-    let factory_addr = router
-        .instantiate_contract(
-            factory_code_id,
-            creator.clone(),
-            &vending_factory::msg::InstantiateMsg { params },
-            &[],
-            "factory",
-            None,
-        )
-        .unwrap();
-
-    let sg721_code_id = router.store_code(contract_sg721());
-    println!("sg721_code_id: {}", sg721_code_id);
-
-    let mut msg = mock_create_minter(splits_addr);
-    msg.init_msg.mint_price = coin(MINT_PRICE, NATIVE_DENOM);
-    msg.init_msg.num_tokens = num_tokens;
-    msg.collection_params.code_id = sg721_code_id;
-    msg.collection_params.info.creator = creator.to_string();
-
-    let msg = Sg2ExecuteMsg::CreateMinter(msg);
-
-    let res = router.execute_contract(creator.clone(), factory_addr, &msg, &creation_fee);
-    assert!(res.is_ok());
-
-    // could get the minter address from the response above, but we know its contract1
-    let minter_addr = Addr::unchecked("contract1");
-
-    let config: vending_minter::msg::ConfigResponse = router
-        .wrap()
-        .query_wasm_smart(
-            minter_addr.clone(),
-            &vending_minter::msg::QueryMsg::Config {},
-        )
-        .unwrap();
-
-    (minter_addr, config)
-}
-
-pub fn configure_minter_with_whitelist(
-    app: &mut StargazeApp,
-) -> (Addr, Addr, Addr, Addr, vending_minter::msg::ConfigResponse) {
-    let (creator, buyer) = setup_accounts(app);
-    let num_tokens = 1;
-    let (minter_addr, config) = setup_minter_contract(app, &creator, num_tokens, None);
-
-    let whitelist_addr =
-        configure_collection_whitelist(app, creator.clone(), buyer.clone(), minter_addr.clone());
-
-    setup_block_time(app, GENESIS_MINT_START_TIME, None);
-    (minter_addr, whitelist_addr, creator, buyer, config)
-}
-
-fn configure_mock_minter(app: &mut StargazeApp, creator: Addr) {
-    let minter_code_id = app.store_code(mock_minter());
-
-    println!("minter_code_id: {}", minter_code_id);
-    let creation_fee = coins(CREATION_FEE, NATIVE_DENOM);
-
-    let factory_code_id = app.store_code(contract_factory());
-    println!("factory_code_id: {}", factory_code_id);
-
-    let mut params = mock_params();
-    params.code_id = minter_code_id;
-
-    let factory_addr = app
-        .instantiate_contract(
-            factory_code_id,
-            creator.clone(),
-            &vending_factory::msg::InstantiateMsg { params },
-            &[],
-            "factory",
-            None,
-        )
-        .unwrap();
-
-    let msg = mock_create_minter(None);
-    let msg = Sg2ExecuteMsg::CreateMinter(msg);
-    let res = app.execute_contract(creator, factory_addr, &msg, &creation_fee);
-    assert!(res.is_ok());
-}
-pub fn configure_mock_minter_with_mock_whitelist(app: &mut StargazeApp) {
-    let (creator, _) = setup_accounts(app);
-    configure_mock_minter(app, creator.clone());
-    let whitelist_code_id = app.store_code(mock_whitelist());
-    setup_whitelist_contract(app, &creator, whitelist_code_id);
-}
diff --git a/contracts/sg-eth-airdrop/src/testing/tests/test_collection_whitelist.rs b/contracts/sg-eth-airdrop/src/testing/tests/test_collection_whitelist.rs
deleted file mode 100644
index b448210f..00000000
--- a/contracts/sg-eth-airdrop/src/testing/tests/test_collection_whitelist.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use cosmwasm_std::Addr;
-
-use crate::msg::QueryMsg;
-use crate::testing::constants::{
-    AIRDROP_ADDR_STR, CONFIG_PLAINTEXT, MINT_PRICE, STARGAZE_WALLET_01, WHITELIST_AMOUNT,
-};
-use crate::testing::setup::{
-    configure_minter_with_whitelist, custom_mock_app, execute_airdrop_claim,
-    execute_mint_fail_not_on_whitelist, execute_mint_success, get_msg_plaintext,
-    get_wallet_and_sig, instantiate_contract, send_funds_to_address, update_admin_for_whitelist,
-    InstantiateParams,
-};
-extern crate whitelist_immutable;
-use crate::contract::INSTANTIATION_FEE;
-
-#[test]
-fn test_set_minter_contract_success() {
-    let mut app = custom_mock_app();
-    let (minter_addr, _, _, _, config) = configure_minter_with_whitelist(&mut app);
-
-    let claim_plaintext = &get_msg_plaintext(STARGAZE_WALLET_01.to_string());
-    let (_, _, _, eth_addr_str) = get_wallet_and_sig(claim_plaintext.clone());
-
-    let contract_admin = Addr::unchecked(config.admin);
-    let params = InstantiateParams {
-        addresses: vec![eth_addr_str],
-        funds_amount: WHITELIST_AMOUNT + INSTANTIATION_FEE,
-        expected_airdrop_contract_id: 5,
-        minter_address: minter_addr.clone(),
-        admin_account: contract_admin,
-        app: &mut app,
-        per_address_limit: 1,
-        claim_msg_plaintext: CONFIG_PLAINTEXT.to_string(),
-    };
-    instantiate_contract(params).unwrap();
-    let airdrop_contract = Addr::unchecked(AIRDROP_ADDR_STR);
-    let query_msg = QueryMsg::GetMinter {};
-    let result: Addr = app
-        .wrap()
-        .query_wasm_smart(airdrop_contract, &query_msg)
-        .unwrap();
-    assert_eq!(result, minter_addr);
-}
-
-#[test]
-fn test_claim_added_to_minter_whitelist() {
-    let mut app = custom_mock_app();
-    let (minter_addr, whiltelist_addr, creator, _, _) = configure_minter_with_whitelist(&mut app);
-    let claim_plaintext = &get_msg_plaintext(STARGAZE_WALLET_01.to_string());
-    let (_, eth_sig_str, _, eth_addr_str) = get_wallet_and_sig(claim_plaintext.clone());
-
-    let airdrop_contract = Addr::unchecked(AIRDROP_ADDR_STR);
-    let params = InstantiateParams {
-        addresses: vec![eth_addr_str.clone()],
-        funds_amount: WHITELIST_AMOUNT + INSTANTIATION_FEE,
-        expected_airdrop_contract_id: 5,
-        minter_address: minter_addr.clone(),
-        admin_account: creator.clone(),
-        app: &mut app,
-        per_address_limit: 1,
-        claim_msg_plaintext: CONFIG_PLAINTEXT.to_string(),
-    };
-    instantiate_contract(params).unwrap();
-
-    let stargaze_wallet_01 = Addr::unchecked(STARGAZE_WALLET_01);
-    update_admin_for_whitelist(&mut app, creator, airdrop_contract.clone(), whiltelist_addr);
-    send_funds_to_address(&mut app, STARGAZE_WALLET_01, MINT_PRICE);
-    execute_mint_fail_not_on_whitelist(&mut app, minter_addr.clone());
-    execute_airdrop_claim(
-        &mut app,
-        eth_addr_str,
-        eth_sig_str,
-        stargaze_wallet_01.clone(),
-        airdrop_contract,
-    );
-    execute_mint_success(&mut app, stargaze_wallet_01, minter_addr);
-}
diff --git a/test-suite/Cargo.toml b/test-suite/Cargo.toml
new file mode 100644
index 00000000..91cc1008
--- /dev/null
+++ b/test-suite/Cargo.toml
@@ -0,0 +1,77 @@
+[package]
+name = "test-suite"
+authors = [
+  "Michael Scotto <m@publicawesome.com>",
+]
+description = "Stargaze test-suite for launchpad"
+version = { workspace = true }
+edition = { workspace = true }
+homepage = { workspace = true }
+repository = { workspace = true }
+license = { workspace = true }
+
+exclude = [
+  # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication.
+  "contract.wasm",
+  "hash.txt",
+]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[features]
+# for more explicit tests, cargo test --features=backtraces
+backtraces = ["cosmwasm-std/backtraces"]
+# use library feature to disable all instantiate/execute/query exports
+library = []
+
+[package.metadata.scripts]
+optimize = """docker run --rm -v "$(pwd)":/code \
+  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
+  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
+  cosmwasm/rust-optimizer:0.12.9
+"""
+
+
+[dev-dependencies]
+serde = { workspace = true }
+cosmwasm-schema = { workspace = true }
+sg-std = { workspace = true }
+cosmwasm-std = { workspace = true }
+thiserror = { workspace = true }
+
+cw4 = { workspace = true }
+cw-multi-test = { workspace = true }
+sg-multi-test = { workspace = true }
+sg721-base = { workspace = true }
+cw4-group = { workspace = true }
+sg-splits = { workspace = true }
+anyhow = "1.0.66"
+sg-eth-airdrop = {workspace = true}
+async-std = "1.12.0"
+ethers-signers = "1.0.0"
+ethers-core = "1.0.0"
+eyre = "0.6"
+rlp = "0.5"
+whitelist-immutable = { workspace = true, features = ["library"] }
+
+cw2 = { workspace = true }
+cw721 = { workspace = true }
+cw721-base = { workspace = true, features = ["library"] }
+cw-storage-plus = { workspace = true }
+cw-utils = { workspace = true }
+rand_core = { version = "0.6.4", default-features = false }
+rand_xoshiro = { version = "0.6.0", default-features = false }
+schemars = { workspace = true }
+sha2 = { workspace = true }
+shuffle = { git = "https://github.com/webmaster128/shuffle", branch = "rm-getrandom", version = "0.1.7" }
+sg1 = { workspace = true }
+sg2 = { workspace = true }
+sg4 = { workspace = true }
+sg721 = { workspace = true }
+sg-whitelist = { workspace = true, features = ["library"] }
+url = { workspace = true }
+vending-factory = { workspace = true, features = ["library"] }
+vending-minter = { workspace = true, features = ["library"] }
\ No newline at end of file
diff --git a/contracts/vending-minter/src/testing/setup.rs b/test-suite/src/common_setup.rs
similarity index 100%
rename from contracts/vending-minter/src/testing/setup.rs
rename to test-suite/src/common_setup.rs
diff --git a/contracts/vending-minter/src/testing/setup/contract_boxes.rs b/test-suite/src/common_setup/contract_boxes.rs
similarity index 67%
rename from contracts/vending-minter/src/testing/setup/contract_boxes.rs
rename to test-suite/src/common_setup/contract_boxes.rs
index d72f3ff3..be3e1172 100644
--- a/contracts/vending-minter/src/testing/setup/contract_boxes.rs
+++ b/test-suite/src/common_setup/contract_boxes.rs
@@ -26,11 +26,11 @@ pub fn contract_whitelist() -> Box<dyn Contract<StargazeMsgWrapper>> {
 
 pub fn contract_minter() -> Box<dyn Contract<StargazeMsgWrapper>> {
     let contract = ContractWrapper::new(
-        crate::contract::execute,
-        crate::contract::instantiate,
-        crate::contract::query,
+        vending_minter::contract::execute,
+        vending_minter::contract::instantiate,
+        vending_minter::contract::query,
     )
-    .with_reply(crate::contract::reply);
+    .with_reply(vending_minter::contract::reply);
     Box::new(contract)
 }
 
@@ -60,3 +60,22 @@ pub fn contract_group() -> Box<dyn Contract<StargazeMsgWrapper>> {
     );
     Box::new(contract)
 }
+
+pub fn contract_eth_airdrop() -> Box<dyn Contract<StargazeMsgWrapper>> {
+    let contract = ContractWrapper::new(
+        sg_eth_airdrop::contract::execute,
+        sg_eth_airdrop::contract::instantiate,
+        sg_eth_airdrop::query::query,
+    )
+    .with_reply(sg_eth_airdrop::reply::reply);
+    Box::new(contract)
+}
+
+pub fn whitelist_immutable_contract() -> Box<dyn Contract<StargazeMsgWrapper>> {
+    let contract = ContractWrapper::new(
+        whitelist_immutable::contract::execute,
+        whitelist_immutable::contract::instantiate,
+        whitelist_immutable::contract::query,
+    );
+    Box::new(contract)
+}
diff --git a/contracts/vending-minter/src/testing/setup/msg.rs b/test-suite/src/common_setup/msg.rs
similarity index 100%
rename from contracts/vending-minter/src/testing/setup/msg.rs
rename to test-suite/src/common_setup/msg.rs
diff --git a/contracts/vending-minter/src/testing/setup/setup_accounts_and_block.rs b/test-suite/src/common_setup/setup_accounts_and_block.rs
similarity index 97%
rename from contracts/vending-minter/src/testing/setup/setup_accounts_and_block.rs
rename to test-suite/src/common_setup/setup_accounts_and_block.rs
index 738baaa7..ab99204e 100644
--- a/contracts/vending-minter/src/testing/setup/setup_accounts_and_block.rs
+++ b/test-suite/src/common_setup/setup_accounts_and_block.rs
@@ -4,7 +4,7 @@ use cw_multi_test::{BankSudo, Executor, SudoMsg};
 use sg_multi_test::StargazeApp;
 use sg_std::NATIVE_DENOM;
 
-use crate::testing::setup::contract_boxes::contract_group;
+use crate::common_setup::contract_boxes::contract_group;
 
 const OWNER: &str = "admin0001";
 
diff --git a/contracts/vending-minter/src/testing/setup/setup_collection_whitelist.rs b/test-suite/src/common_setup/setup_collection_whitelist.rs
similarity index 86%
rename from contracts/vending-minter/src/testing/setup/setup_collection_whitelist.rs
rename to test-suite/src/common_setup/setup_collection_whitelist.rs
index 10adcbd4..1f869ac3 100644
--- a/contracts/vending-minter/src/testing/setup/setup_collection_whitelist.rs
+++ b/test-suite/src/common_setup/setup_collection_whitelist.rs
@@ -4,15 +4,22 @@ use sg_multi_test::StargazeApp;
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
 use sg_whitelist::msg::InstantiateMsg as WhitelistInstantiateMsg;
 
-use crate::testing::setup::{
+use crate::common_setup::{
     contract_boxes::contract_whitelist, setup_accounts_and_block::setup_block_time,
 };
 
 const WHITELIST_AMOUNT: u128 = 66_000_000;
 const WL_PER_ADDRESS_LIMIT: u32 = 1;
 
-pub fn setup_whitelist_contract(router: &mut StargazeApp, creator: &Addr) -> Addr {
-    let whitelist_code_id = router.store_code(contract_whitelist());
+pub fn setup_whitelist_contract(
+    router: &mut StargazeApp,
+    creator: &Addr,
+    whitelist_code_id: Option<u64>,
+) -> Addr {
+    let whitelist_code_id = match whitelist_code_id {
+        Some(value) => value,
+        None => router.store_code(contract_whitelist()),
+    };
 
     let msg = WhitelistInstantiateMsg {
         members: vec![],
@@ -42,7 +49,7 @@ pub fn configure_collection_whitelist(
     buyer: Addr,
     minter_addr: Addr,
 ) -> Addr {
-    let whitelist_addr = setup_whitelist_contract(router, &creator);
+    let whitelist_addr = setup_whitelist_contract(router, &creator, None);
     const AFTER_GENESIS_TIME: Timestamp = Timestamp::from_nanos(GENESIS_MINT_START_TIME + 100);
 
     // Set to just before genesis mint start time
@@ -64,7 +71,7 @@ pub fn configure_collection_whitelist(
     assert!(res.is_ok());
 
     // Set whitelist in minter contract
-    let set_whitelist_msg = crate::msg::ExecuteMsg::SetWhitelist {
+    let set_whitelist_msg = vending_minter::msg::ExecuteMsg::SetWhitelist {
         whitelist: whitelist_addr.to_string(),
     };
     let res = router.execute_contract(creator, minter_addr, &set_whitelist_msg, &[]);
diff --git a/contracts/vending-minter/src/testing/setup/setup_minter.rs b/test-suite/src/common_setup/setup_minter.rs
similarity index 97%
rename from contracts/vending-minter/src/testing/setup/setup_minter.rs
rename to test-suite/src/common_setup/setup_minter.rs
index ec6cd1a1..335623b1 100644
--- a/contracts/vending-minter/src/testing/setup/setup_minter.rs
+++ b/test-suite/src/common_setup/setup_minter.rs
@@ -1,6 +1,6 @@
-use crate::testing::setup::contract_boxes::{contract_factory, contract_minter, contract_sg721};
-use crate::testing::setup::msg::MinterCollectionResponse;
-use crate::testing::setup::msg::MinterSetupParams;
+use crate::common_setup::contract_boxes::{contract_factory, contract_minter, contract_sg721};
+use crate::common_setup::msg::MinterCollectionResponse;
+use crate::common_setup::msg::MinterSetupParams;
 use anyhow::Error;
 use cosmwasm_std::{coin, coins, Addr, Timestamp};
 use cw_multi_test::{AppResponse, Executor};
diff --git a/test-suite/src/lib.rs b/test-suite/src/lib.rs
new file mode 100644
index 00000000..f9ff9256
--- /dev/null
+++ b/test-suite/src/lib.rs
@@ -0,0 +1,6 @@
+#[cfg(test)]
+mod common_setup;
+#[cfg(test)]
+mod sg_eth_airdrop;
+#[cfg(test)]
+mod vending_minter;
diff --git a/test-suite/src/sg_eth_airdrop.rs b/test-suite/src/sg_eth_airdrop.rs
new file mode 100644
index 00000000..50d470ed
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop.rs
@@ -0,0 +1,3 @@
+mod constants;
+mod setup;
+mod tests;
diff --git a/test-suite/src/sg_eth_airdrop/constants.rs b/test-suite/src/sg_eth_airdrop/constants.rs
new file mode 100644
index 00000000..9d284135
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop/constants.rs
@@ -0,0 +1,2 @@
+pub mod claim_constants;
+pub mod collection_constants;
diff --git a/contracts/sg-eth-airdrop/src/testing/constants/claim_constants.rs b/test-suite/src/sg_eth_airdrop/constants/claim_constants.rs
similarity index 100%
rename from contracts/sg-eth-airdrop/src/testing/constants/claim_constants.rs
rename to test-suite/src/sg_eth_airdrop/constants/claim_constants.rs
diff --git a/test-suite/src/sg_eth_airdrop/constants/collection_constants.rs b/test-suite/src/sg_eth_airdrop/constants/collection_constants.rs
new file mode 100644
index 00000000..1c29cc2d
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop/constants/collection_constants.rs
@@ -0,0 +1,5 @@
+pub const CREATION_FEE: u128 = 5_000_000_000;
+pub const MINT_PRICE: u128 = 100_000_000;
+pub const WHITELIST_AMOUNT: u128 = 66_000_000;
+
+pub const AIRDROP_ADDR_STR: &str = "contract4";
diff --git a/test-suite/src/sg_eth_airdrop/setup.rs b/test-suite/src/sg_eth_airdrop/setup.rs
new file mode 100644
index 00000000..fc673442
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop/setup.rs
@@ -0,0 +1,7 @@
+pub mod collection_whitelist_helpers;
+pub mod configure_mock_minter;
+pub mod execute_msg;
+pub mod mock_minter_contract;
+pub mod mock_whitelist_contract;
+pub mod setup_signatures;
+pub mod test_msgs;
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/collection_whitelist_helpers.rs b/test-suite/src/sg_eth_airdrop/setup/collection_whitelist_helpers.rs
similarity index 86%
rename from contracts/sg-eth-airdrop/src/testing/setup/collection_whitelist_helpers.rs
rename to test-suite/src/sg_eth_airdrop/setup/collection_whitelist_helpers.rs
index c4f8bd29..6dcb1b49 100644
--- a/contracts/sg-eth-airdrop/src/testing/setup/collection_whitelist_helpers.rs
+++ b/test-suite/src/sg_eth_airdrop/setup/collection_whitelist_helpers.rs
@@ -1,10 +1,11 @@
-use crate::testing::constants::{MINT_PRICE, NATIVE_DENOM, STARGAZE_WALLET_01, WHITELIST_AMOUNT};
+use crate::sg_eth_airdrop::constants::claim_constants::{NATIVE_DENOM, STARGAZE_WALLET_01};
+use crate::sg_eth_airdrop::constants::collection_constants::{MINT_PRICE, WHITELIST_AMOUNT};
+
+use crate::sg_eth_airdrop::setup::execute_msg::execute_contract_with_msg;
 use cosmwasm_std::{coins, Addr};
 use cw_multi_test::{BankSudo, Executor, SudoMsg};
 use sg_multi_test::StargazeApp;
 
-use super::setup_contracts::execute_contract_with_msg;
-
 extern crate whitelist_immutable;
 
 pub fn update_admin_for_whitelist(
@@ -53,7 +54,7 @@ pub fn execute_airdrop_claim(
     target_wallet: Addr,
     airdrop_contract: Addr,
 ) {
-    let claim_message = crate::msg::ExecuteMsg::ClaimAirdrop {
+    let claim_message = sg_eth_airdrop::msg::ExecuteMsg::ClaimAirdrop {
         eth_address: eth_addr_str,
         eth_sig: eth_sig_str,
     };
diff --git a/test-suite/src/sg_eth_airdrop/setup/configure_mock_minter.rs b/test-suite/src/sg_eth_airdrop/setup/configure_mock_minter.rs
new file mode 100644
index 00000000..32f5c930
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop/setup/configure_mock_minter.rs
@@ -0,0 +1,50 @@
+use crate::common_setup::setup_accounts_and_block::setup_accounts;
+use crate::common_setup::setup_collection_whitelist::setup_whitelist_contract;
+use crate::common_setup::setup_minter::mock_create_minter;
+use crate::common_setup::{contract_boxes::contract_factory, setup_minter::mock_params};
+use crate::sg_eth_airdrop::constants::collection_constants::CREATION_FEE;
+use crate::sg_eth_airdrop::setup::mock_minter_contract::mock_minter;
+use cosmwasm_std::{coins, Addr, Timestamp};
+use cw_multi_test::Executor;
+use sg2::msg::Sg2ExecuteMsg;
+use sg2::tests::mock_collection_params_1;
+use sg_multi_test::StargazeApp;
+use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
+
+use crate::sg_eth_airdrop::setup::mock_whitelist_contract::mock_whitelist;
+
+fn configure_mock_minter(app: &mut StargazeApp, creator: Addr) {
+    let minter_code_id = app.store_code(mock_minter());
+
+    println!("minter_code_id: {}", minter_code_id);
+    let creation_fee = coins(CREATION_FEE, NATIVE_DENOM);
+
+    let factory_code_id = app.store_code(contract_factory());
+    println!("factory_code_id: {}", factory_code_id);
+
+    let mut params = mock_params();
+    params.code_id = minter_code_id;
+
+    let factory_addr = app
+        .instantiate_contract(
+            factory_code_id,
+            creator.clone(),
+            &vending_factory::msg::InstantiateMsg { params },
+            &[],
+            "factory",
+            None,
+        )
+        .unwrap();
+    let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
+    let collection_params = mock_collection_params_1(Some(start_time));
+    let msg = mock_create_minter(None, collection_params, None);
+    let msg = Sg2ExecuteMsg::CreateMinter(msg);
+    let res = app.execute_contract(creator, factory_addr, &msg, &creation_fee);
+    assert!(res.is_ok());
+}
+pub fn configure_mock_minter_with_mock_whitelist(app: &mut StargazeApp) {
+    let (creator, _) = setup_accounts(app);
+    configure_mock_minter(app, creator.clone());
+    let whitelist_code_id = app.store_code(mock_whitelist());
+    setup_whitelist_contract(app, &creator, Some(whitelist_code_id));
+}
diff --git a/test-suite/src/sg_eth_airdrop/setup/execute_msg.rs b/test-suite/src/sg_eth_airdrop/setup/execute_msg.rs
new file mode 100644
index 00000000..39addaf2
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop/setup/execute_msg.rs
@@ -0,0 +1,77 @@
+use crate::sg_eth_airdrop::constants::claim_constants::OWNER;
+use crate::sg_eth_airdrop::constants::collection_constants::WHITELIST_AMOUNT;
+use crate::{
+    common_setup::contract_boxes::{contract_eth_airdrop, whitelist_immutable_contract},
+    sg_eth_airdrop::setup::test_msgs::InstantiateParams,
+};
+use anyhow::Error as anyhow_error;
+use cosmwasm_std::{coins, Addr};
+use cw_multi_test::error::Error;
+use cw_multi_test::{AppResponse, BankSudo, Executor, SudoMsg};
+use eyre::Result;
+use sg_eth_airdrop::msg::{ExecuteMsg, InstantiateMsg};
+use sg_multi_test::StargazeApp;
+use sg_std::NATIVE_DENOM;
+
+pub fn instantiate_contract(params: InstantiateParams) -> Result<cosmwasm_std::Addr, anyhow_error> {
+    let addresses = params.addresses;
+    let minter_address = params.minter_address;
+    let admin_account = params.admin_account;
+    let funds_amount = params.funds_amount;
+    let per_address_limit = params.per_address_limit;
+    let claim_msg_plaintext = params.claim_msg_plaintext;
+    params
+        .app
+        .sudo(SudoMsg::Bank({
+            BankSudo::Mint {
+                to_address: admin_account.to_string(),
+                amount: coins(params.funds_amount, NATIVE_DENOM),
+            }
+        }))
+        .map_err(|err| println!("{:?}", err))
+        .ok();
+
+    let sg_eth_id = params.app.store_code(contract_eth_airdrop());
+    let whitelist_code_id = params.app.store_code(whitelist_immutable_contract());
+    assert_eq!(sg_eth_id, params.expected_airdrop_contract_id);
+
+    let msg: InstantiateMsg = InstantiateMsg {
+        admin: Addr::unchecked(OWNER),
+        claim_msg_plaintext,
+        airdrop_amount: WHITELIST_AMOUNT,
+        addresses,
+        whitelist_code_id,
+        minter_address,
+        per_address_limit,
+    };
+    params.app.instantiate_contract(
+        sg_eth_id,
+        Addr::unchecked(admin_account.clone()),
+        &msg,
+        &coins(funds_amount, NATIVE_DENOM),
+        "sg-eg-airdrop",
+        Some(Addr::unchecked(admin_account).to_string()),
+    )
+}
+
+pub fn execute_contract_with_msg(
+    msg: ExecuteMsg,
+    app: &mut StargazeApp,
+    user: Addr,
+    target_address: Addr,
+) -> Result<AppResponse, Error> {
+    let result = app.execute_contract(user, target_address, &msg, &[]);
+    Ok(result.unwrap())
+}
+
+pub fn execute_contract_error_with_msg(
+    msg: ExecuteMsg,
+    app: &mut StargazeApp,
+    user: Addr,
+    target_address: Addr,
+) -> String {
+    let result = app
+        .execute_contract(user, target_address, &msg, &[])
+        .unwrap_err();
+    result.root_cause().to_string()
+}
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/mock_minter_contract.rs b/test-suite/src/sg_eth_airdrop/setup/mock_minter_contract.rs
similarity index 85%
rename from contracts/sg-eth-airdrop/src/testing/setup/mock_minter_contract.rs
rename to test-suite/src/sg_eth_airdrop/setup/mock_minter_contract.rs
index 928983f1..07a84c06 100644
--- a/contracts/sg-eth-airdrop/src/testing/setup/mock_minter_contract.rs
+++ b/test-suite/src/sg_eth_airdrop/setup/mock_minter_contract.rs
@@ -1,9 +1,10 @@
-use crate::error::ContractError;
 use cosmwasm_std::entry_point;
 use cosmwasm_std::{
     to_binary, Binary, Coin, Deps, DepsMut, Env, MessageInfo, StdResult, Timestamp,
 };
-use sg_std::Response;
+use cw_multi_test::{Contract, ContractWrapper};
+use sg_eth_airdrop::error::ContractError;
+use sg_std::{Response, StargazeMsgWrapper};
 use vending_factory::msg::VendingMinterCreateMsg;
 use vending_minter::msg::{ExecuteMsg, QueryMsg};
 
@@ -64,3 +65,8 @@ fn query_config() -> ConfigResponse {
         factory: "some_factory".to_string(),
     }
 }
+
+pub fn mock_minter() -> Box<dyn Contract<StargazeMsgWrapper>> {
+    let contract = ContractWrapper::new(execute, instantiate, query);
+    Box::new(contract)
+}
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/mock_whitelist_contract.rs b/test-suite/src/sg_eth_airdrop/setup/mock_whitelist_contract.rs
similarity index 77%
rename from contracts/sg-eth-airdrop/src/testing/setup/mock_whitelist_contract.rs
rename to test-suite/src/sg_eth_airdrop/setup/mock_whitelist_contract.rs
index 7d7bd0c2..28581e8a 100644
--- a/contracts/sg-eth-airdrop/src/testing/setup/mock_whitelist_contract.rs
+++ b/test-suite/src/sg_eth_airdrop/setup/mock_whitelist_contract.rs
@@ -1,7 +1,8 @@
-use crate::error::ContractError;
 use cosmwasm_std::entry_point;
 use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, StdResult};
-use sg_std::Response;
+use cw_multi_test::{Contract, ContractWrapper};
+use sg_eth_airdrop::error::ContractError;
+use sg_std::{Response, StargazeMsgWrapper};
 use sg_whitelist::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
 
 #[cfg_attr(not(feature = "library"), entry_point)]
@@ -37,3 +38,8 @@ fn execute_add_members() -> Result<Response, ContractError> {
     let res = Response::new();
     Ok(res)
 }
+
+pub fn mock_whitelist() -> Box<dyn Contract<StargazeMsgWrapper>> {
+    let contract = ContractWrapper::new(execute, instantiate, query);
+    Box::new(contract)
+}
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/setup_signatures.rs b/test-suite/src/sg_eth_airdrop/setup/setup_signatures.rs
similarity index 93%
rename from contracts/sg-eth-airdrop/src/testing/setup/setup_signatures.rs
rename to test-suite/src/sg_eth_airdrop/setup/setup_signatures.rs
index 0fb518fa..2b1e7236 100644
--- a/contracts/sg-eth-airdrop/src/testing/setup/setup_signatures.rs
+++ b/test-suite/src/sg_eth_airdrop/setup/setup_signatures.rs
@@ -1,4 +1,4 @@
-use crate::testing::constants::CONFIG_PLAINTEXT;
+use crate::sg_eth_airdrop::constants::claim_constants::CONFIG_PLAINTEXT;
 use async_std::task;
 use ethers_core::{k256::ecdsa::SigningKey, rand::thread_rng, types::H160};
 use ethers_signers::{LocalWallet, Signer, Wallet, WalletError};
diff --git a/contracts/sg-eth-airdrop/src/testing/setup/test_msgs.rs b/test-suite/src/sg_eth_airdrop/setup/test_msgs.rs
similarity index 100%
rename from contracts/sg-eth-airdrop/src/testing/setup/test_msgs.rs
rename to test-suite/src/sg_eth_airdrop/setup/test_msgs.rs
diff --git a/contracts/sg-eth-airdrop/src/testing/tests.rs b/test-suite/src/sg_eth_airdrop/tests.rs
similarity index 100%
rename from contracts/sg-eth-airdrop/src/testing/tests.rs
rename to test-suite/src/sg_eth_airdrop/tests.rs
diff --git a/contracts/sg-eth-airdrop/src/testing/tests/test_claim.rs b/test-suite/src/sg_eth_airdrop/tests/test_claim.rs
similarity index 96%
rename from contracts/sg-eth-airdrop/src/testing/tests/test_claim.rs
rename to test-suite/src/sg_eth_airdrop/tests/test_claim.rs
index d141af18..e5929c0b 100644
--- a/contracts/sg-eth-airdrop/src/testing/tests/test_claim.rs
+++ b/test-suite/src/sg_eth_airdrop/tests/test_claim.rs
@@ -1,23 +1,29 @@
-use crate::msg::{ExecuteMsg, QueryMsg};
-use crate::testing::constants::WHITELIST_AMOUNT;
+use crate::common_setup::contract_boxes::custom_mock_app;
+use crate::sg_eth_airdrop::constants::collection_constants::WHITELIST_AMOUNT;
+use crate::sg_eth_airdrop::setup::configure_mock_minter::configure_mock_minter_with_mock_whitelist;
+use crate::sg_eth_airdrop::setup::setup_signatures::{
+    get_msg_plaintext, get_signature, get_wallet_and_sig,
+};
+use crate::sg_eth_airdrop::setup::test_msgs::InstantiateParams;
 use async_std::task;
 use cosmwasm_std::{Addr, Attribute, Coin, Uint128};
+use sg_eth_airdrop::msg::{ExecuteMsg, QueryMsg};
 
 use ethers_core::rand::thread_rng;
 use ethers_signers::{LocalWallet, Signer};
 use sg_multi_test::StargazeApp;
 
-use crate::contract::INSTANTIATION_FEE;
-use crate::testing::constants::{
+use crate::sg_eth_airdrop::constants::claim_constants::{
     CONFIG_PLAINTEXT, MOCK_AIRDROP_ADDR_STR, MOCK_MINTER_ADDR_STR, NATIVE_DENOM, OWNER,
     STARGAZE_WALLET_01, STARGAZE_WALLET_02,
 };
-use crate::testing::setup::{
-    configure_mock_minter_with_mock_whitelist, custom_mock_app, execute_contract_error_with_msg,
-    execute_contract_with_msg, get_msg_plaintext, get_signature, get_wallet_and_sig,
-    instantiate_contract, InstantiateParams,
+
+use crate::sg_eth_airdrop::setup::execute_msg::{
+    execute_contract_error_with_msg, execute_contract_with_msg, instantiate_contract,
 };
 
+use sg_eth_airdrop::contract::INSTANTIATION_FEE;
+
 fn query_minter_as_expected(app: &mut StargazeApp, airdrop_contract: Addr, minter_addr: Addr) {
     let query_msg = QueryMsg::GetMinter {};
     let result: Addr = app
diff --git a/test-suite/src/sg_eth_airdrop/tests/test_collection_whitelist.rs b/test-suite/src/sg_eth_airdrop/tests/test_collection_whitelist.rs
new file mode 100644
index 00000000..3ab6015d
--- /dev/null
+++ b/test-suite/src/sg_eth_airdrop/tests/test_collection_whitelist.rs
@@ -0,0 +1,109 @@
+use cosmwasm_std::{Addr, Timestamp};
+use sg2::tests::mock_collection_params_1;
+use sg_std::GENESIS_MINT_START_TIME;
+
+use crate::common_setup::contract_boxes::custom_mock_app;
+use crate::common_setup::msg::MinterCollectionResponse;
+use crate::common_setup::setup_accounts_and_block::{setup_accounts, setup_block_time};
+use crate::common_setup::setup_collection_whitelist::configure_collection_whitelist;
+use crate::common_setup::setup_minter::{configure_minter, minter_params_token};
+use crate::sg_eth_airdrop::constants::claim_constants::{CONFIG_PLAINTEXT, STARGAZE_WALLET_01};
+use crate::sg_eth_airdrop::constants::collection_constants::{
+    AIRDROP_ADDR_STR, MINT_PRICE, WHITELIST_AMOUNT,
+};
+use crate::sg_eth_airdrop::setup::collection_whitelist_helpers::{
+    execute_airdrop_claim, execute_mint_fail_not_on_whitelist, execute_mint_success,
+    send_funds_to_address, update_admin_for_whitelist,
+};
+use crate::sg_eth_airdrop::setup::execute_msg::instantiate_contract;
+use crate::sg_eth_airdrop::setup::setup_signatures::{get_msg_plaintext, get_wallet_and_sig};
+use crate::sg_eth_airdrop::setup::test_msgs::InstantiateParams;
+use sg_eth_airdrop::msg::QueryMsg;
+extern crate whitelist_immutable;
+use sg_eth_airdrop::contract::INSTANTIATION_FEE;
+
+#[test]
+fn test_set_minter_contract_success() {
+    let mut app = custom_mock_app();
+    let (creator, _) = setup_accounts(&mut app);
+    let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
+    let collection_params = mock_collection_params_1(Some(start_time));
+    let minter_params = minter_params_token(1);
+    let minter_collection_response: Vec<MinterCollectionResponse> = configure_minter(
+        &mut app,
+        creator.clone(),
+        vec![collection_params],
+        vec![minter_params],
+    );
+    let minter_addr = minter_collection_response[0].minter.clone().unwrap();
+
+    let claim_plaintext = &get_msg_plaintext(STARGAZE_WALLET_01.to_string());
+    let (_, _, _, eth_addr_str) = get_wallet_and_sig(claim_plaintext.clone());
+
+    let contract_admin = Addr::unchecked(creator);
+    let params = InstantiateParams {
+        addresses: vec![eth_addr_str],
+        funds_amount: WHITELIST_AMOUNT + INSTANTIATION_FEE,
+        expected_airdrop_contract_id: 4,
+        minter_address: minter_addr.clone(),
+        admin_account: contract_admin,
+        app: &mut app,
+        per_address_limit: 1,
+        claim_msg_plaintext: CONFIG_PLAINTEXT.to_string(),
+    };
+    instantiate_contract(params).unwrap();
+    let airdrop_contract = Addr::unchecked("contract3");
+    let query_msg = QueryMsg::GetMinter {};
+    let result: Addr = app
+        .wrap()
+        .query_wasm_smart(airdrop_contract, &query_msg)
+        .unwrap();
+    assert_eq!(result, minter_addr);
+}
+
+#[test]
+fn test_claim_added_to_minter_whitelist() {
+    let mut app = custom_mock_app();
+    let (creator, buyer) = setup_accounts(&mut app);
+    let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
+    let collection_params = mock_collection_params_1(Some(start_time));
+    let minter_params = minter_params_token(1);
+    let minter_collection_response: Vec<MinterCollectionResponse> = configure_minter(
+        &mut app,
+        creator.clone(),
+        vec![collection_params],
+        vec![minter_params],
+    );
+    let minter_addr = minter_collection_response[0].minter.clone().unwrap();
+    let whitelist_addr =
+        configure_collection_whitelist(&mut app, creator.clone(), buyer, minter_addr.clone());
+    setup_block_time(&mut app, GENESIS_MINT_START_TIME, None);
+    let claim_plaintext = &get_msg_plaintext(STARGAZE_WALLET_01.to_string());
+    let (_, eth_sig_str, _, eth_addr_str) = get_wallet_and_sig(claim_plaintext.clone());
+
+    let airdrop_contract = Addr::unchecked(AIRDROP_ADDR_STR);
+    let params = InstantiateParams {
+        addresses: vec![eth_addr_str.clone()],
+        funds_amount: WHITELIST_AMOUNT + INSTANTIATION_FEE,
+        expected_airdrop_contract_id: 5,
+        minter_address: minter_addr.clone(),
+        admin_account: creator.clone(),
+        app: &mut app,
+        per_address_limit: 1,
+        claim_msg_plaintext: CONFIG_PLAINTEXT.to_string(),
+    };
+    instantiate_contract(params).unwrap();
+
+    let stargaze_wallet_01 = Addr::unchecked(STARGAZE_WALLET_01);
+    update_admin_for_whitelist(&mut app, creator, airdrop_contract.clone(), whitelist_addr);
+    send_funds_to_address(&mut app, STARGAZE_WALLET_01, MINT_PRICE);
+    execute_mint_fail_not_on_whitelist(&mut app, minter_addr.clone());
+    execute_airdrop_claim(
+        &mut app,
+        eth_addr_str,
+        eth_sig_str,
+        stargaze_wallet_01.clone(),
+        airdrop_contract,
+    );
+    execute_mint_success(&mut app, stargaze_wallet_01, minter_addr);
+}
diff --git a/contracts/sg-eth-airdrop/src/testing/tests/test_immutable_whitelist.rs b/test-suite/src/sg_eth_airdrop/tests/test_immutable_whitelist.rs
similarity index 91%
rename from contracts/sg-eth-airdrop/src/testing/tests/test_immutable_whitelist.rs
rename to test-suite/src/sg_eth_airdrop/tests/test_immutable_whitelist.rs
index 56f4b39d..4d64e992 100644
--- a/contracts/sg-eth-airdrop/src/testing/tests/test_immutable_whitelist.rs
+++ b/test-suite/src/sg_eth_airdrop/tests/test_immutable_whitelist.rs
@@ -1,13 +1,15 @@
-use crate::contract::INSTANTIATION_FEE;
-use crate::msg::QueryMsg;
-use crate::testing::constants::{
-    CONFIG_PLAINTEXT, MOCK_AIRDROP_ADDR_STR, MOCK_MINTER_ADDR_STR, OWNER, WHITELIST_AMOUNT,
-};
-use crate::testing::setup::{
-    configure_mock_minter_with_mock_whitelist, custom_mock_app, instantiate_contract,
-    InstantiateParams,
+use crate::common_setup::contract_boxes::custom_mock_app;
+use crate::sg_eth_airdrop::constants::claim_constants::{
+    CONFIG_PLAINTEXT, MOCK_AIRDROP_ADDR_STR, MOCK_MINTER_ADDR_STR, OWNER,
 };
+use crate::sg_eth_airdrop::constants::collection_constants::WHITELIST_AMOUNT;
+use crate::sg_eth_airdrop::setup::configure_mock_minter::configure_mock_minter_with_mock_whitelist;
+use crate::sg_eth_airdrop::setup::execute_msg::instantiate_contract;
+use crate::sg_eth_airdrop::setup::test_msgs::InstantiateParams;
+
 use cosmwasm_std::Addr;
+use sg_eth_airdrop::contract::INSTANTIATION_FEE;
+use sg_eth_airdrop::msg::QueryMsg;
 use whitelist_immutable::helpers::WhitelistImmutableContract;
 
 #[test]
diff --git a/test-suite/src/vending_minter.rs b/test-suite/src/vending_minter.rs
new file mode 100644
index 00000000..14f00389
--- /dev/null
+++ b/test-suite/src/vending_minter.rs
@@ -0,0 +1,1 @@
+mod tests;
diff --git a/contracts/vending-minter/src/testing/tests.rs b/test-suite/src/vending_minter/tests.rs
similarity index 100%
rename from contracts/vending-minter/src/testing/tests.rs
rename to test-suite/src/vending_minter/tests.rs
diff --git a/contracts/vending-minter/src/testing/tests/address_limit.rs b/test-suite/src/vending_minter/tests/address_limit.rs
similarity index 97%
rename from contracts/vending-minter/src/testing/tests/address_limit.rs
rename to test-suite/src/vending_minter/tests/address_limit.rs
index ce3e79c2..93868c75 100644
--- a/contracts/vending-minter/src/testing/tests/address_limit.rs
+++ b/test-suite/src/vending_minter/tests/address_limit.rs
@@ -1,19 +1,18 @@
-use crate::{
-    msg::{ExecuteMsg, MintableNumTokensResponse, QueryMsg},
-    testing::setup::{
-        contract_boxes::custom_mock_app,
-        msg::MinterCollectionResponse,
-        setup_accounts_and_block::{coins_for_msg, setup_accounts, setup_block_time},
-        setup_minter::{configure_minter, minter_params_token},
-    },
-    ContractError,
+use crate::common_setup::{
+    contract_boxes::custom_mock_app,
+    msg::MinterCollectionResponse,
+    setup_accounts_and_block::{coins_for_msg, setup_accounts, setup_block_time},
+    setup_minter::{configure_minter, minter_params_token},
 };
 use cosmwasm_std::{coin, coins, Coin, Timestamp, Uint128};
 use cw721::{Cw721QueryMsg, OwnerOfResponse, TokensResponse};
 use cw_multi_test::Executor;
 use sg2::tests::mock_collection_params_1;
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
-
+use vending_minter::{
+    msg::{ExecuteMsg, MintableNumTokensResponse, QueryMsg},
+    ContractError,
+};
 const MINT_PRICE: u128 = 100_000_000;
 const ADMIN_MINT_PRICE: u128 = 0;
 
diff --git a/contracts/vending-minter/src/testing/tests/happy_unhappy.rs b/test-suite/src/vending_minter/tests/happy_unhappy.rs
similarity index 95%
rename from contracts/vending-minter/src/testing/tests/happy_unhappy.rs
rename to test-suite/src/vending_minter/tests/happy_unhappy.rs
index a1cdb09e..2529f0fa 100644
--- a/contracts/vending-minter/src/testing/tests/happy_unhappy.rs
+++ b/test-suite/src/vending_minter/tests/happy_unhappy.rs
@@ -7,24 +7,17 @@ use cw_multi_test::Executor;
 use sg2::tests::mock_collection_params_1;
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
 
-use crate::{
-    contract::instantiate,
-    msg::MintCountResponse,
-    testing::setup::{
-        contract_boxes::custom_mock_app,
-        msg::MinterCollectionResponse,
-        setup_accounts_and_block::coins_for_msg,
-        setup_minter::{configure_minter, minter_params_token},
-    },
-};
-use crate::{
-    msg::{ExecuteMsg, QueryMsg, StartTimeResponse},
-    testing::setup::{
-        setup_accounts_and_block::{setup_accounts, setup_block_time},
-        setup_minter::mock_create_minter,
-    },
+use crate::common_setup::{
+    contract_boxes::custom_mock_app,
+    msg::MinterCollectionResponse,
+    setup_accounts_and_block::coins_for_msg,
+    setup_accounts_and_block::{setup_accounts, setup_block_time},
+    setup_minter::mock_create_minter,
+    setup_minter::{configure_minter, minter_params_token},
 };
 use cw721::{Cw721QueryMsg, OwnerOfResponse};
+use vending_minter::msg::{ExecuteMsg, QueryMsg, StartTimeResponse};
+use vending_minter::{contract::instantiate, msg::MintCountResponse};
 
 const INITIAL_BALANCE: u128 = 2_000_000_000;
 const MINT_PRICE: u128 = 100_000_000;
diff --git a/contracts/vending-minter/src/testing/tests/mint_and_burn.rs b/test-suite/src/vending_minter/tests/mint_and_burn.rs
similarity index 95%
rename from contracts/vending-minter/src/testing/tests/mint_and_burn.rs
rename to test-suite/src/vending_minter/tests/mint_and_burn.rs
index ce24e403..c126ac72 100644
--- a/contracts/vending-minter/src/testing/tests/mint_and_burn.rs
+++ b/test-suite/src/vending_minter/tests/mint_and_burn.rs
@@ -1,15 +1,15 @@
-use crate::msg::{ExecuteMsg, MintCountResponse, QueryMsg, StartTimeResponse};
-use crate::testing::setup::contract_boxes::custom_mock_app;
-use crate::testing::setup::msg::MinterCollectionResponse;
-use crate::testing::setup::setup_minter::{configure_minter, minter_params_token};
-use crate::ContractError;
+use crate::common_setup::contract_boxes::custom_mock_app;
+use crate::common_setup::msg::MinterCollectionResponse;
+use crate::common_setup::setup_minter::{configure_minter, minter_params_token};
 use cosmwasm_std::Coin;
 use cosmwasm_std::{coins, Timestamp, Uint128};
 use cw_multi_test::Executor;
 use sg2::tests::mock_collection_params_1;
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
+use vending_minter::msg::{ExecuteMsg, MintCountResponse, QueryMsg, StartTimeResponse};
+use vending_minter::ContractError;
 
-use crate::testing::setup::setup_accounts_and_block::{
+use crate::common_setup::setup_accounts_and_block::{
     coins_for_msg, setup_accounts, setup_block_time,
 };
 const INITIAL_BALANCE: u128 = 2_000_000_000;
diff --git a/contracts/vending-minter/src/testing/tests/splits.rs b/test-suite/src/vending_minter/tests/splits.rs
similarity index 97%
rename from contracts/vending-minter/src/testing/tests/splits.rs
rename to test-suite/src/vending_minter/tests/splits.rs
index 348b3204..4f26b5a1 100644
--- a/contracts/vending-minter/src/testing/tests/splits.rs
+++ b/test-suite/src/vending_minter/tests/splits.rs
@@ -1,4 +1,4 @@
-use crate::testing::setup::{
+use crate::common_setup::{
     contract_boxes::{contract_splits, custom_mock_app},
     msg::MinterCollectionResponse,
     setup_accounts_and_block::{instantiate_group, setup_accounts, setup_block_time},
@@ -82,7 +82,7 @@ fn mint_and_split() {
     let minter_addr = minter_collection_response[0].minter.clone().unwrap();
     setup_block_time(&mut app, GENESIS_MINT_START_TIME + 1, None);
 
-    let mint_msg = crate::msg::ExecuteMsg::Mint {};
+    let mint_msg = vending_minter::msg::ExecuteMsg::Mint {};
     let res = app.execute_contract(
         buyer,
         minter_addr,
diff --git a/contracts/vending-minter/src/testing/tests/trading_time.rs b/test-suite/src/vending_minter/tests/trading_time.rs
similarity index 96%
rename from contracts/vending-minter/src/testing/tests/trading_time.rs
rename to test-suite/src/vending_minter/tests/trading_time.rs
index c7d3a3f2..3c286650 100644
--- a/contracts/vending-minter/src/testing/tests/trading_time.rs
+++ b/test-suite/src/vending_minter/tests/trading_time.rs
@@ -1,14 +1,14 @@
-use crate::msg::{ExecuteMsg, QueryMsg, StartTimeResponse};
-use crate::testing::setup::contract_boxes::custom_mock_app;
-use crate::testing::setup::msg::{MinterCollectionResponse, MinterInstantiateParams};
-use crate::testing::setup::setup_accounts_and_block::{setup_accounts, setup_block_time};
-use crate::testing::setup::setup_minter::{configure_minter, minter_params_token};
-use crate::ContractError;
+use crate::common_setup::contract_boxes::custom_mock_app;
+use crate::common_setup::msg::{MinterCollectionResponse, MinterInstantiateParams};
+use crate::common_setup::setup_accounts_and_block::{setup_accounts, setup_block_time};
+use crate::common_setup::setup_minter::{configure_minter, minter_params_token};
 use cosmwasm_std::{coins, Addr, Timestamp};
 use cw_multi_test::Executor;
 use sg2::tests::mock_collection_params_1;
 use sg721_base::msg::{CollectionInfoResponse, QueryMsg as Sg721QueryMsg};
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
+use vending_minter::msg::{ExecuteMsg, QueryMsg, StartTimeResponse};
+use vending_minter::ContractError;
 
 const MINT_PRICE: u128 = 100_000_000;
 
diff --git a/contracts/vending-minter/src/testing/tests/whitelist.rs b/test-suite/src/vending_minter/tests/whitelist.rs
similarity index 97%
rename from contracts/vending-minter/src/testing/tests/whitelist.rs
rename to test-suite/src/vending_minter/tests/whitelist.rs
index 1ba0f5d2..358190ce 100644
--- a/contracts/vending-minter/src/testing/tests/whitelist.rs
+++ b/test-suite/src/vending_minter/tests/whitelist.rs
@@ -5,20 +5,18 @@ use cw_multi_test::Executor;
 use sg2::tests::mock_collection_params_1;
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
 
-use crate::msg::{ExecuteMsg, MintCountResponse, MintPriceResponse, QueryMsg};
-use crate::testing::setup::msg::MinterCollectionResponse;
-use crate::testing::setup::setup_accounts_and_block::coins_for_msg;
-use crate::testing::setup::setup_collection_whitelist::{
+use crate::common_setup::msg::MinterCollectionResponse;
+use crate::common_setup::setup_accounts_and_block::coins_for_msg;
+use crate::common_setup::setup_collection_whitelist::{
     configure_collection_whitelist, setup_whitelist_contract,
 };
-use crate::testing::setup::setup_minter::{
-    configure_minter, minter_params_all, minter_params_token,
-};
-use crate::testing::setup::{
+use crate::common_setup::setup_minter::{configure_minter, minter_params_all, minter_params_token};
+use crate::common_setup::{
     contract_boxes::custom_mock_app,
     setup_accounts_and_block::{setup_accounts, setup_block_time},
 };
-use crate::ContractError;
+use vending_minter::msg::{ExecuteMsg, MintCountResponse, MintPriceResponse, QueryMsg};
+use vending_minter::ContractError;
 
 use sg_whitelist::msg::{
     AddMembersMsg, ConfigResponse as WhitelistConfigResponse, ExecuteMsg as WhitelistExecuteMsg,
@@ -77,7 +75,7 @@ fn set_invalid_whitelist() {
         vec![minter_params],
     );
     let minter_addr = minter_collection_response[0].minter.clone().unwrap();
-    let whitelist_addr = setup_whitelist_contract(&mut router, &creator);
+    let whitelist_addr = setup_whitelist_contract(&mut router, &creator, None);
     const EXPIRATION_TIME: Timestamp = Timestamp::from_nanos(GENESIS_MINT_START_TIME + 10_000);
 
     // Set block to before genesis mint start time
@@ -155,7 +153,7 @@ fn whitelist_mint_count_query() {
     let minter_addr = minter_collection_response[0].minter.clone().unwrap();
     let collection_addr = minter_collection_response[0].collection.clone().unwrap();
 
-    let whitelist_addr = setup_whitelist_contract(&mut router, &creator);
+    let whitelist_addr = setup_whitelist_contract(&mut router, &creator, None);
     const EXPIRATION_TIME: Timestamp = Timestamp::from_nanos(GENESIS_MINT_START_TIME + 10_000);
 
     // Set block to before genesis mint start time
@@ -360,7 +358,7 @@ fn whitelist_already_started() {
         vec![minter_params],
     );
     let minter_addr = minter_collection_response[0].minter.clone().unwrap();
-    let whitelist_addr = setup_whitelist_contract(&mut router, &creator);
+    let whitelist_addr = setup_whitelist_contract(&mut router, &creator, None);
 
     setup_block_time(&mut router, GENESIS_MINT_START_TIME + 101, None);
 
@@ -393,7 +391,7 @@ fn whitelist_can_update_before_start() {
         vec![minter_params],
     );
     let minter_addr = minter_collection_response[0].minter.clone().unwrap();
-    let whitelist_addr = setup_whitelist_contract(&mut router, &creator);
+    let whitelist_addr = setup_whitelist_contract(&mut router, &creator, None);
 
     setup_block_time(&mut router, GENESIS_MINT_START_TIME - 1000, None);