Repository: public-awesome/launchpad
Pull request #518 (2023-03-01 22:31:51)

SG-559 add allowable sg721s to factory
add `allowable_sg721_code_ids` to `factory`
check `allowable_code_ids` when creating minter


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index d686fb7a..d819d1f6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3228,6 +3228,7 @@ version = "0.24.1"
 dependencies = [
  "cosmwasm-schema",
  "cosmwasm-std",
+ "cw-storage-plus 0.16.0",
  "cw-utils 0.16.0",
  "schemars",
  "serde",
diff --git a/contracts/base-factory/schema/base-factory.json b/contracts/base-factory/schema/base-factory.json
index e4641896..20973ea4 100644
--- a/contracts/base-factory/schema/base-factory.json
+++ b/contracts/base-factory/schema/base-factory.json
@@ -39,6 +39,7 @@
         "description": "Common params for all minters used for storage",
         "type": "object",
         "required": [
+          "allowed_sg721_code_ids",
           "code_id",
           "creation_fee",
           "max_trading_offset_secs",
@@ -46,6 +47,14 @@
           "mint_fee_bps"
         ],
         "properties": {
+          "allowed_sg721_code_ids": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "format": "uint64",
+              "minimum": 0.0
+            }
+          },
           "code_id": {
             "description": "The minter code id",
             "type": "integer",
diff --git a/contracts/base-factory/src/contract.rs b/contracts/base-factory/src/contract.rs
index db7b0037..a58cb2fe 100644
--- a/contracts/base-factory/src/contract.rs
+++ b/contracts/base-factory/src/contract.rs
@@ -7,7 +7,7 @@ use cw2::set_contract_version;
 use cw_utils::must_pay;
 use sg1::checked_fair_burn;
 use sg2::msg::UpdateMinterParamsMsg;
-use sg2::query::Sg2QueryMsg;
+use sg2::query::{AllowedCollectionCodeIdResponse, AllowedCollectionCodeIdsResponse, Sg2QueryMsg};
 use sg2::MinterParams;
 use sg_std::{Response, NATIVE_DENOM};
 
@@ -56,6 +56,7 @@ pub fn execute_create_minter(
     msg: BaseMinterCreateMsg,
 ) -> Result<Response, ContractError> {
     must_pay(&info, NATIVE_DENOM)?;
+    must_be_allowed_collection(deps.as_ref(), msg.collection_params.code_id)?;
 
     let params = SUDO_PARAMS.load(deps.storage)?;
 
@@ -79,6 +80,14 @@ pub fn execute_create_minter(
         .add_message(msg))
 }
 
+pub fn must_be_allowed_collection(deps: Deps, code_id: u64) -> Result<(), ContractError> {
+    let res = query_allowed_collection_code_id(deps, code_id)?;
+    if !res.allowed {
+        return Err(ContractError::InvalidCollectionCodeId { code_id });
+    }
+    Ok(())
+}
+
 #[cfg_attr(not(feature = "library"), entry_point)]
 pub fn sudo(deps: DepsMut, env: Env, msg: BaseSudoMsg) -> Result<Response, ContractError> {
     match msg {
@@ -126,6 +135,19 @@ pub fn update_params<T, C>(
         params.min_mint_price = min_mint_price;
     }
 
+    // add new code ids, then rm code ids
+    if let Some(add_sg721_code_ids) = param_msg.add_sg721_code_ids {
+        for code_id in add_sg721_code_ids {
+            params.allowed_sg721_code_ids.push(code_id);
+        }
+    }
+    params.allowed_sg721_code_ids.dedup();
+    if let Some(rm_sg721_code_ids) = param_msg.rm_sg721_code_ids {
+        for code_id in rm_sg721_code_ids {
+            params.allowed_sg721_code_ids.retain(|&x| x != code_id);
+        }
+    }
+
     params.mint_fee_bps = param_msg.mint_fee_bps.unwrap_or(params.mint_fee_bps);
 
     params.max_trading_offset_secs = param_msg
@@ -139,6 +161,12 @@ pub fn update_params<T, C>(
 pub fn query(deps: Deps, _env: Env, msg: Sg2QueryMsg) -> StdResult<Binary> {
     match msg {
         Sg2QueryMsg::Params {} => to_binary(&query_params(deps)?),
+        Sg2QueryMsg::AllowedCollectionCodeIds {} => {
+            to_binary(&query_allowed_collection_code_ids(deps)?)
+        }
+        Sg2QueryMsg::AllowedCollectionCodeId(code_id) => {
+            to_binary(&query_allowed_collection_code_id(deps, code_id)?)
+        }
     }
 }
 
@@ -146,3 +174,19 @@ fn query_params(deps: Deps) -> StdResult<ParamsResponse> {
     let params = SUDO_PARAMS.load(deps.storage)?;
     Ok(ParamsResponse { params })
 }
+
+fn query_allowed_collection_code_ids(deps: Deps) -> StdResult<AllowedCollectionCodeIdsResponse> {
+    let params = SUDO_PARAMS.load(deps.storage)?;
+    let code_ids = params.allowed_sg721_code_ids;
+    Ok(AllowedCollectionCodeIdsResponse { code_ids })
+}
+
+fn query_allowed_collection_code_id(
+    deps: Deps,
+    code_id: u64,
+) -> StdResult<AllowedCollectionCodeIdResponse> {
+    let params = SUDO_PARAMS.load(deps.storage)?;
+    let code_ids = params.allowed_sg721_code_ids;
+    let allowed = code_ids.contains(&code_id);
+    Ok(AllowedCollectionCodeIdResponse { allowed })
+}
diff --git a/contracts/base-factory/src/error.rs b/contracts/base-factory/src/error.rs
index 68fe7b1f..a9ef7b35 100644
--- a/contracts/base-factory/src/error.rs
+++ b/contracts/base-factory/src/error.rs
@@ -19,4 +19,7 @@ pub enum ContractError {
 
     #[error("InvalidDenom")]
     InvalidDenom {},
+
+    #[error("InvalidCollectionCodeId {code_id}")]
+    InvalidCollectionCodeId { code_id: u64 },
 }
diff --git a/contracts/base-factory/src/msg.rs b/contracts/base-factory/src/msg.rs
index d7786505..350c6b20 100644
--- a/contracts/base-factory/src/msg.rs
+++ b/contracts/base-factory/src/msg.rs
@@ -1,5 +1,5 @@
+use crate::state::Extension;
 use cosmwasm_schema::cw_serde;
-use cosmwasm_std::Empty;
 use sg2::msg::{CreateMinterMsg, Sg2ExecuteMsg, UpdateMinterParamsMsg};
 
 use crate::state::BaseMinterParams;
@@ -9,8 +9,6 @@ pub struct InstantiateMsg {
     pub params: BaseMinterParams,
 }
 
-pub type Extension = Option<Empty>;
-
 pub type BaseMinterCreateMsg = CreateMinterMsg<Extension>;
 
 pub type ExecuteMsg = Sg2ExecuteMsg<Extension>;
diff --git a/contracts/base-minter/schema/base-minter.json b/contracts/base-minter/schema/base-minter.json
index d57babdb..4b52b0ca 100644
--- a/contracts/base-minter/schema/base-minter.json
+++ b/contracts/base-minter/schema/base-minter.json
@@ -148,6 +148,7 @@
         "description": "Common params for all minters used for storage",
         "type": "object",
         "required": [
+          "allowed_sg721_code_ids",
           "code_id",
           "creation_fee",
           "max_trading_offset_secs",
@@ -155,6 +156,14 @@
           "mint_fee_bps"
         ],
         "properties": {
+          "allowed_sg721_code_ids": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "format": "uint64",
+              "minimum": 0.0
+            }
+          },
           "code_id": {
             "description": "The minter code id",
             "type": "integer",
diff --git a/contracts/base-minter/src/contract.rs b/contracts/base-minter/src/contract.rs
index 5c32d195..795c7016 100644
--- a/contracts/base-minter/src/contract.rs
+++ b/contracts/base-minter/src/contract.rs
@@ -2,8 +2,9 @@ use crate::error::ContractError;
 use crate::msg::{ConfigResponse, ExecuteMsg};
 use crate::state::{increment_token_index, Config, COLLECTION_ADDRESS, CONFIG, STATUS};
 
-use base_factory::msg::{BaseMinterCreateMsg, Extension, ParamsResponse};
+use base_factory::msg::{BaseMinterCreateMsg, ParamsResponse};
 
+use base_factory::state::Extension;
 #[cfg(not(feature = "library"))]
 use cosmwasm_std::entry_point;
 use cosmwasm_std::{
diff --git a/contracts/vending-factory/schema/instantiate_msg.json b/contracts/vending-factory/schema/instantiate_msg.json
index 53ad6236..39ccd972 100644
--- a/contracts/vending-factory/schema/instantiate_msg.json
+++ b/contracts/vending-factory/schema/instantiate_msg.json
@@ -31,6 +31,7 @@
       "description": "Common params for all minters used for storage",
       "type": "object",
       "required": [
+        "allowed_sg721_code_ids",
         "code_id",
         "creation_fee",
         "extension",
@@ -39,6 +40,14 @@
         "mint_fee_bps"
       ],
       "properties": {
+        "allowed_sg721_code_ids": {
+          "type": "array",
+          "items": {
+            "type": "integer",
+            "format": "uint64",
+            "minimum": 0.0
+          }
+        },
         "code_id": {
           "description": "The minter code id",
           "type": "integer",
diff --git a/contracts/vending-factory/schema/sg2_query_msg.json b/contracts/vending-factory/schema/sg2_query_msg.json
index 6a7c193e..865ce436 100644
--- a/contracts/vending-factory/schema/sg2_query_msg.json
+++ b/contracts/vending-factory/schema/sg2_query_msg.json
@@ -15,6 +15,33 @@
         }
       },
       "additionalProperties": false
+    },
+    {
+      "type": "object",
+      "required": [
+        "allowed_collection_code_ids"
+      ],
+      "properties": {
+        "allowed_collection_code_ids": {
+          "type": "object",
+          "additionalProperties": false
+        }
+      },
+      "additionalProperties": false
+    },
+    {
+      "type": "object",
+      "required": [
+        "allowed_collection_code_id"
+      ],
+      "properties": {
+        "allowed_collection_code_id": {
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        }
+      },
+      "additionalProperties": false
     }
   ]
 }
diff --git a/contracts/vending-factory/src/contract.rs b/contracts/vending-factory/src/contract.rs
index 0c764a24..c8249816 100644
--- a/contracts/vending-factory/src/contract.rs
+++ b/contracts/vending-factory/src/contract.rs
@@ -1,4 +1,4 @@
-use base_factory::contract::update_params;
+use base_factory::contract::{must_be_allowed_collection, update_params};
 use base_factory::ContractError as BaseContractError;
 #[cfg(not(feature = "library"))]
 use cosmwasm_std::entry_point;
@@ -8,7 +8,7 @@ use cosmwasm_std::{
 use cw2::set_contract_version;
 use cw_utils::must_pay;
 use sg1::checked_fair_burn;
-use sg2::query::Sg2QueryMsg;
+use sg2::query::{AllowedCollectionCodeIdResponse, AllowedCollectionCodeIdsResponse, Sg2QueryMsg};
 use sg_std::{Response, NATIVE_DENOM};
 
 use crate::error::ContractError;
@@ -56,6 +56,7 @@ pub fn execute_create_minter(
     msg: VendingMinterCreateMsg,
 ) -> Result<Response, ContractError> {
     must_pay(&info, NATIVE_DENOM)?;
+    must_be_allowed_collection(deps.as_ref(), msg.collection_params.code_id)?;
 
     let params = SUDO_PARAMS.load(deps.storage)?;
 
@@ -164,6 +165,12 @@ pub fn sudo_update_params(
 pub fn query(deps: Deps, _env: Env, msg: Sg2QueryMsg) -> StdResult<Binary> {
     match msg {
         Sg2QueryMsg::Params {} => to_binary(&query_params(deps)?),
+        Sg2QueryMsg::AllowedCollectionCodeIds {} => {
+            to_binary(&query_allowed_collection_code_ids(deps)?)
+        }
+        Sg2QueryMsg::AllowedCollectionCodeId(code_id) => {
+            to_binary(&query_allowed_collection_code_id(deps, code_id)?)
+        }
     }
 }
 
@@ -171,3 +178,19 @@ fn query_params(deps: Deps) -> StdResult<ParamsResponse> {
     let params = SUDO_PARAMS.load(deps.storage)?;
     Ok(ParamsResponse { params })
 }
+
+fn query_allowed_collection_code_ids(deps: Deps) -> StdResult<AllowedCollectionCodeIdsResponse> {
+    let params = SUDO_PARAMS.load(deps.storage)?;
+    let code_ids = params.allowed_sg721_code_ids;
+    Ok(AllowedCollectionCodeIdsResponse { code_ids })
+}
+
+fn query_allowed_collection_code_id(
+    deps: Deps,
+    code_id: u64,
+) -> StdResult<AllowedCollectionCodeIdResponse> {
+    let params = SUDO_PARAMS.load(deps.storage)?;
+    let code_ids = params.allowed_sg721_code_ids;
+    let allowed = code_ids.contains(&code_id);
+    Ok(AllowedCollectionCodeIdResponse { allowed })
+}
diff --git a/contracts/vending-factory/src/msg.rs b/contracts/vending-factory/src/msg.rs
index d9735c0d..60c90142 100644
--- a/contracts/vending-factory/src/msg.rs
+++ b/contracts/vending-factory/src/msg.rs
@@ -28,7 +28,7 @@ pub enum SudoMsg {
     UpdateParams(Box<VendingUpdateParamsMsg>),
 }
 
-/// Message for params so they can be updated invidiually by governance
+/// Message for params so they can be updated individually by governance
 #[cw_serde]
 pub struct VendingUpdateParamsExtension {
     pub max_token_limit: Option<u32>,
diff --git a/contracts/vending-minter/schema/instantiate_msg.json b/contracts/vending-minter/schema/instantiate_msg.json
index cb142dc3..bd5d4469 100644
--- a/contracts/vending-minter/schema/instantiate_msg.json
+++ b/contracts/vending-minter/schema/instantiate_msg.json
@@ -134,6 +134,7 @@
       "description": "Common params for all minters used for storage",
       "type": "object",
       "required": [
+        "allowed_sg721_code_ids",
         "code_id",
         "creation_fee",
         "extension",
@@ -142,6 +143,14 @@
         "mint_fee_bps"
       ],
       "properties": {
+        "allowed_sg721_code_ids": {
+          "type": "array",
+          "items": {
+            "type": "integer",
+            "format": "uint64",
+            "minimum": 0.0
+          }
+        },
         "code_id": {
           "description": "The minter code id",
           "type": "integer",
diff --git a/contracts/vending-minter/src/helpers.rs b/contracts/vending-minter/src/helpers.rs
index 7806234d..173587cb 100644
--- a/contracts/vending-minter/src/helpers.rs
+++ b/contracts/vending-minter/src/helpers.rs
@@ -56,8 +56,7 @@ impl MinterContract {
     }
 
     pub fn config(&self, querier: &QuerierWrapper) -> StdResult<ConfigResponse> {
-        let res: ConfigResponse =
-            querier.query_wasm_smart(self.addr(), &QueryMsg::Config {})?;
+        let res: ConfigResponse = querier.query_wasm_smart(self.addr(), &QueryMsg::Config {})?;
         Ok(res)
     }
 }
diff --git a/packages/sg2/Cargo.toml b/packages/sg2/Cargo.toml
index 051be6cd..84c86785 100644
--- a/packages/sg2/Cargo.toml
+++ b/packages/sg2/Cargo.toml
@@ -1,16 +1,20 @@
 [package]
-name        = "sg2"
-authors     = ["Shane Vitarana <s@noreply.publicawesome.com>"]
+name = "sg2"
+authors = [
+    "Shane Vitarana <s@noreply.publicawesome.com>",
+    "John Y <j@noreply.publicawesome.com>",
+]
 description = "Definition and types for the SG2 interface"
-version     = { workspace = true }
-edition     = { workspace = true }
-homepage    = { workspace = true }
-repository  = { workspace = true }
-license     = { workspace = true }
+version = { workspace = true }
+edition = { workspace = true }
+homepage = { workspace = true }
+repository = { workspace = true }
+license = { workspace = true }
 
 [dependencies]
 cosmwasm-schema = { workspace = true }
 cosmwasm-std    = { workspace = true }
+cw-storage-plus = { workspace = true }
 cw-utils        = { workspace = true }
 schemars        = { workspace = true }
 serde           = { workspace = true }
diff --git a/packages/sg2/README.md b/packages/sg2/README.md
index bcda617a..8b8c7a42 100644
--- a/packages/sg2/README.md
+++ b/packages/sg2/README.md
@@ -4,6 +4,8 @@ Common types needed for minter factories. New minter factories should extend the
 
 Every minter requires a factory that stores the minter's governance paramaters. A minter factory creates minters based on these paramaters.
 
+Factories also restrict minters to a set of allowed sg721 code ids.
+
 For example, the vending minter factory needs a `shuffle_fee`. This is added as a custom extension to `MinterParams` and `UpdateParamsMsg`.
 
 ```rs
diff --git a/packages/sg2/src/lib.rs b/packages/sg2/src/lib.rs
index 78e2273d..07de7d54 100644
--- a/packages/sg2/src/lib.rs
+++ b/packages/sg2/src/lib.rs
@@ -5,11 +5,14 @@ pub mod msg;
 pub mod query;
 pub mod tests;
 
+pub type CodeId = u64;
+
 /// Common params for all minters used for storage
 #[cw_serde]
 pub struct MinterParams<T> {
     /// The minter code id
     pub code_id: u64,
+    pub allowed_sg721_code_ids: Vec<CodeId>,
     pub creation_fee: Coin,
     pub min_mint_price: Coin,
     pub mint_fee_bps: u64,
diff --git a/packages/sg2/src/msg.rs b/packages/sg2/src/msg.rs
index 9117a342..8a9e9a9b 100644
--- a/packages/sg2/src/msg.rs
+++ b/packages/sg2/src/msg.rs
@@ -17,11 +17,13 @@ pub struct CollectionParams {
     pub info: CollectionInfo<RoyaltyInfoResponse>,
 }
 
-/// Message for params so they can be updated invidiually by governance
+/// Message for params so they can be updated individually by governance
 #[cw_serde]
 pub struct UpdateMinterParamsMsg<T> {
     /// The minter code id
     pub code_id: Option<u64>,
+    pub add_sg721_code_ids: Option<Vec<u64>>,
+    pub rm_sg721_code_ids: Option<Vec<u64>>,
     pub creation_fee: Option<Coin>,
     pub min_mint_price: Option<Coin>,
     pub mint_fee_bps: Option<u64>,
diff --git a/packages/sg2/src/query.rs b/packages/sg2/src/query.rs
index ad22164c..f3fa0850 100644
--- a/packages/sg2/src/query.rs
+++ b/packages/sg2/src/query.rs
@@ -1,14 +1,27 @@
 use cosmwasm_schema::cw_serde;
 
+use crate::CodeId;
 use crate::MinterParams;
 
 #[cw_serde]
 pub enum Sg2QueryMsg {
     /// Returns `ParamsResponse`
     Params {},
+    AllowedCollectionCodeIds {},
+    AllowedCollectionCodeId(CodeId),
 }
 
 #[cw_serde]
 pub struct ParamsResponse<T> {
     pub params: MinterParams<T>,
 }
+
+#[cw_serde]
+pub struct AllowedCollectionCodeIdsResponse {
+    pub code_ids: Vec<CodeId>,
+}
+
+#[cw_serde]
+pub struct AllowedCollectionCodeIdResponse {
+    pub allowed: bool,
+}
diff --git a/ts/package.json b/ts/package.json
index 1723a78e..733b41c1 100644
--- a/ts/package.json
+++ b/ts/package.json
@@ -16,7 +16,7 @@
     "@cosmjs/proto-signing": "^0.29.5",
     "@cosmjs/stargate": "^0.29.5",
     "@cosmjs/tendermint-rpc": "^0.29.5",
-    "@cosmwasm/ts-codegen": "^0.24.0",
+    "@cosmwasm/ts-codegen": "^0.25.2",
     "cosmjs-types": "^0.6.1",
     "cosmwasm": "^1.1.1",
     "ts-node": "^10.9.1",
diff --git a/ts/src/BaseFactory.react-query.ts b/ts/src/BaseFactory.react-query.ts
deleted file mode 100644
index 1de28ecb..00000000
--- a/ts/src/BaseFactory.react-query.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
-* This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
-* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
-* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
-*/
-
-import { Uint128, InstantiateMsg, MinterParamsForNullable_Empty, Coin, Empty, Sg2QueryMsg } from "./BaseFactory.types";
-import "./BaseFactory.client";
\ No newline at end of file
diff --git a/ts/src/BaseFactory.types.ts b/ts/src/BaseFactory.types.ts
index f0d1d7a6..6758cea9 100644
--- a/ts/src/BaseFactory.types.ts
+++ b/ts/src/BaseFactory.types.ts
@@ -9,6 +9,7 @@ export interface InstantiateMsg {
   params: MinterParamsForNullable_Empty;
 }
 export interface MinterParamsForNullable_Empty {
+  allowed_sg721_code_ids: number[];
   code_id: number;
   creation_fee: Coin;
   extension?: Empty | null;
diff --git a/ts/src/BaseMinter.react-query.ts b/ts/src/BaseMinter.react-query.ts
deleted file mode 100644
index f1d66982..00000000
--- a/ts/src/BaseMinter.react-query.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
- * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
- * and run the @cosmwasm/ts-codegen generate command to regenerate this file.
- */
-
-import {
-  UseQueryOptions,
-  useQuery,
-  useMutation,
-  UseMutationOptions,
-} from "@tanstack/react-query";
-import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
-import { StdFee } from "@cosmjs/amino";
-import {
-  ExecuteMsg,
-  Timestamp,
-  Uint64,
-  Decimal,
-  Uint128,
-  InstantiateMsg,
-  CreateMinterMsgForNullable_Empty,
-  CollectionParams,
-  CollectionInfoForRoyaltyInfoResponse,
-  RoyaltyInfoResponse,
-  Empty,
-  MinterParamsForNullable_Empty,
-  Coin,
-  Addr,
-  MinterConfigForEmpty,
-  MinterConfigResponseForEmpty,
-  QueryMsg,
-} from "./BaseMinter.types";
-import { BaseMinterQueryClient, BaseMinterClient } from "./BaseMinter.client";
-export const baseMinterQueryKeys = {
-  contract: [
-    {
-      contract: "baseMinter",
-    },
-  ] as const,
-  address: (contractAddress: string | undefined) =>
-    [{ ...baseMinterQueryKeys.contract[0], address: contractAddress }] as const,
-  config: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...baseMinterQueryKeys.address(contractAddress)[0],
-        method: "config",
-        args,
-      },
-    ] as const,
-  status: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...baseMinterQueryKeys.address(contractAddress)[0],
-        method: "status",
-        args,
-      },
-    ] as const,
-};
-export interface BaseMinterReactQuery<TResponse, TData = TResponse> {
-  client: BaseMinterQueryClient | undefined;
-  options?: Omit<
-    UseQueryOptions<TResponse, Error, TData>,
-    "'queryKey' | 'queryFn' | 'initialData'"
-  > & {
-    initialData?: undefined;
-  };
-}
-export interface BaseMinterStatusQuery<TData>
-  extends BaseMinterReactQuery<StatusResponse, TData> {}
-export function useBaseMinterStatusQuery<TData = StatusResponse>({
-  client,
-  options,
-}: BaseMinterStatusQuery<TData>) {
-  return useQuery<StatusResponse, Error, TData>(
-    baseMinterQueryKeys.status(client?.contractAddress),
-    () =>
-      client ? client.status() : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface BaseMinterConfigQuery<TData>
-  extends BaseMinterReactQuery<ConfigResponse, TData> {}
-export function useBaseMinterConfigQuery<TData = ConfigResponse>({
-  client,
-  options,
-}: BaseMinterConfigQuery<TData>) {
-  return useQuery<ConfigResponse, Error, TData>(
-    baseMinterQueryKeys.config(client?.contractAddress),
-    () =>
-      client ? client.config() : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface BaseMinterUpdateStartTradingTimeMutation {
-  client: BaseMinterClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useBaseMinterUpdateStartTradingTimeMutation(
-  options?: Omit<
-    UseMutationOptions<
-      ExecuteResult,
-      Error,
-      BaseMinterUpdateStartTradingTimeMutation
-    >,
-    "mutationFn"
-  >
-) {
-  return useMutation<
-    ExecuteResult,
-    Error,
-    BaseMinterUpdateStartTradingTimeMutation
-  >(
-    ({ client, args: { fee, memo, funds } = {} }) =>
-      client.UpdateStartTradingTime(fee, memo, funds),
-    options
-  );
-}
-export interface BaseMinterMintMutation {
-  client: BaseMinterClient;
-  msg: {
-    tokenUri: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useBaseMinterMintMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, BaseMinterMintMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, BaseMinterMintMutation>(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.mint(msg, fee, memo, funds),
-    options
-  );
-}
diff --git a/ts/src/BaseMinter.types.ts b/ts/src/BaseMinter.types.ts
index 8d5ecb95..92a55bc5 100644
--- a/ts/src/BaseMinter.types.ts
+++ b/ts/src/BaseMinter.types.ts
@@ -39,6 +39,7 @@ export interface Empty {
   [k: string]: unknown;
 }
 export interface MinterParamsForNullable_Empty {
+  allowed_sg721_code_ids: number[];
   code_id: number;
   creation_fee: Coin;
   extension?: Empty | null;
diff --git a/ts/src/Sg721Base.react-query.ts b/ts/src/Sg721Base.react-query.ts
deleted file mode 100644
index 1d56b5e0..00000000
--- a/ts/src/Sg721Base.react-query.ts
+++ /dev/null
@@ -1,257 +0,0 @@
-/**
-* This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
-* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
-* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
-*/
-
-import { UseQueryOptions, useQuery } from "@tanstack/react-query";
-import { Expiration, Timestamp, Uint64, AllNftInfoResponse, OwnerOfResponse, Approval, NftInfoResponseForEmpty, Empty, AllOperatorsResponse, AllTokensResponse, ApprovalResponse, ApprovalsResponse, Decimal, CollectionInfoResponse, RoyaltyInfoResponse, ContractInfoResponse, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, MinterResponse, NftInfoResponse, NumTokensResponse, OperatorsResponse, QueryMsg, TokensResponse } from "./Sg721Base.types";
-import { Sg721BaseQueryClient } from "./Sg721Base.client";
-export const sg721BaseQueryKeys = {
-  contract: ([{
-    contract: "sg721Base"
-  }] as const),
-  address: (contractAddress: string | undefined) => ([{ ...sg721BaseQueryKeys.contract[0],
-    address: contractAddress
-  }] as const),
-  ownerOf: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "owner_of",
-    args
-  }] as const),
-  approval: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "approval",
-    args
-  }] as const),
-  approvals: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "approvals",
-    args
-  }] as const),
-  allOperators: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "all_operators",
-    args
-  }] as const),
-  numTokens: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "num_tokens",
-    args
-  }] as const),
-  contractInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "contract_info",
-    args
-  }] as const),
-  nftInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "nft_info",
-    args
-  }] as const),
-  allNftInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "all_nft_info",
-    args
-  }] as const),
-  tokens: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "tokens",
-    args
-  }] as const),
-  allTokens: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "all_tokens",
-    args
-  }] as const),
-  minter: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "minter",
-    args
-  }] as const),
-  collectionInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721BaseQueryKeys.address(contractAddress)[0],
-    method: "collection_info",
-    args
-  }] as const)
-};
-export interface Sg721BaseReactQuery<TResponse, TData = TResponse> {
-  client: Sg721BaseQueryClient | undefined;
-  options?: Omit<UseQueryOptions<TResponse, Error, TData>, "'queryKey' | 'queryFn' | 'initialData'"> & {
-    initialData?: undefined;
-  };
-}
-export interface Sg721BaseCollectionInfoQuery<TData> extends Sg721BaseReactQuery<CollectionInfoResponse, TData> {}
-export function useSg721BaseCollectionInfoQuery<TData = CollectionInfoResponse>({
-  client,
-  options
-}: Sg721BaseCollectionInfoQuery<TData>) {
-  return useQuery<CollectionInfoResponse, Error, TData>(sg721BaseQueryKeys.collectionInfo(client?.contractAddress), () => client ? client.collectionInfo() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseMinterQuery<TData> extends Sg721BaseReactQuery<MinterResponse, TData> {}
-export function useSg721BaseMinterQuery<TData = MinterResponse>({
-  client,
-  options
-}: Sg721BaseMinterQuery<TData>) {
-  return useQuery<MinterResponse, Error, TData>(sg721BaseQueryKeys.minter(client?.contractAddress), () => client ? client.minter() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseAllTokensQuery<TData> extends Sg721BaseReactQuery<AllTokensResponse, TData> {
-  args: {
-    limit?: number;
-    startAfter?: string;
-  };
-}
-export function useSg721BaseAllTokensQuery<TData = AllTokensResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseAllTokensQuery<TData>) {
-  return useQuery<AllTokensResponse, Error, TData>(sg721BaseQueryKeys.allTokens(client?.contractAddress, args), () => client ? client.allTokens({
-    limit: args.limit,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseTokensQuery<TData> extends Sg721BaseReactQuery<TokensResponse, TData> {
-  args: {
-    limit?: number;
-    owner: string;
-    startAfter?: string;
-  };
-}
-export function useSg721BaseTokensQuery<TData = TokensResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseTokensQuery<TData>) {
-  return useQuery<TokensResponse, Error, TData>(sg721BaseQueryKeys.tokens(client?.contractAddress, args), () => client ? client.tokens({
-    limit: args.limit,
-    owner: args.owner,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseAllNftInfoQuery<TData> extends Sg721BaseReactQuery<AllNftInfoResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    tokenId: string;
-  };
-}
-export function useSg721BaseAllNftInfoQuery<TData = AllNftInfoResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseAllNftInfoQuery<TData>) {
-  return useQuery<AllNftInfoResponse, Error, TData>(sg721BaseQueryKeys.allNftInfo(client?.contractAddress, args), () => client ? client.allNftInfo({
-    includeExpired: args.includeExpired,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseNftInfoQuery<TData> extends Sg721BaseReactQuery<NftInfoResponse, TData> {
-  args: {
-    tokenId: string;
-  };
-}
-export function useSg721BaseNftInfoQuery<TData = NftInfoResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseNftInfoQuery<TData>) {
-  return useQuery<NftInfoResponse, Error, TData>(sg721BaseQueryKeys.nftInfo(client?.contractAddress, args), () => client ? client.nftInfo({
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseContractInfoQuery<TData> extends Sg721BaseReactQuery<ContractInfoResponse, TData> {}
-export function useSg721BaseContractInfoQuery<TData = ContractInfoResponse>({
-  client,
-  options
-}: Sg721BaseContractInfoQuery<TData>) {
-  return useQuery<ContractInfoResponse, Error, TData>(sg721BaseQueryKeys.contractInfo(client?.contractAddress), () => client ? client.contractInfo() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseNumTokensQuery<TData> extends Sg721BaseReactQuery<NumTokensResponse, TData> {}
-export function useSg721BaseNumTokensQuery<TData = NumTokensResponse>({
-  client,
-  options
-}: Sg721BaseNumTokensQuery<TData>) {
-  return useQuery<NumTokensResponse, Error, TData>(sg721BaseQueryKeys.numTokens(client?.contractAddress), () => client ? client.numTokens() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseAllOperatorsQuery<TData> extends Sg721BaseReactQuery<AllOperatorsResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    limit?: number;
-    owner: string;
-    startAfter?: string;
-  };
-}
-export function useSg721BaseAllOperatorsQuery<TData = AllOperatorsResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseAllOperatorsQuery<TData>) {
-  return useQuery<AllOperatorsResponse, Error, TData>(sg721BaseQueryKeys.allOperators(client?.contractAddress, args), () => client ? client.allOperators({
-    includeExpired: args.includeExpired,
-    limit: args.limit,
-    owner: args.owner,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseApprovalsQuery<TData> extends Sg721BaseReactQuery<ApprovalsResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    tokenId: string;
-  };
-}
-export function useSg721BaseApprovalsQuery<TData = ApprovalsResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseApprovalsQuery<TData>) {
-  return useQuery<ApprovalsResponse, Error, TData>(sg721BaseQueryKeys.approvals(client?.contractAddress, args), () => client ? client.approvals({
-    includeExpired: args.includeExpired,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseApprovalQuery<TData> extends Sg721BaseReactQuery<ApprovalResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    spender: string;
-    tokenId: string;
-  };
-}
-export function useSg721BaseApprovalQuery<TData = ApprovalResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseApprovalQuery<TData>) {
-  return useQuery<ApprovalResponse, Error, TData>(sg721BaseQueryKeys.approval(client?.contractAddress, args), () => client ? client.approval({
-    includeExpired: args.includeExpired,
-    spender: args.spender,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721BaseOwnerOfQuery<TData> extends Sg721BaseReactQuery<OwnerOfResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    tokenId: string;
-  };
-}
-export function useSg721BaseOwnerOfQuery<TData = OwnerOfResponse>({
-  client,
-  args,
-  options
-}: Sg721BaseOwnerOfQuery<TData>) {
-  return useQuery<OwnerOfResponse, Error, TData>(sg721BaseQueryKeys.ownerOf(client?.contractAddress, args), () => client ? client.ownerOf({
-    includeExpired: args.includeExpired,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
\ No newline at end of file
diff --git a/ts/src/Sg721MetadataOnchain.react-query.ts b/ts/src/Sg721MetadataOnchain.react-query.ts
deleted file mode 100644
index a67e121f..00000000
--- a/ts/src/Sg721MetadataOnchain.react-query.ts
+++ /dev/null
@@ -1,458 +0,0 @@
-/**
-* This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
-* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
-* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
-*/
-
-import { UseQueryOptions, useQuery, useMutation, UseMutationOptions } from "@tanstack/react-query";
-import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
-import { StdFee, Coin } from "@cosmjs/amino";
-import { Expiration, Timestamp, Uint64, AllNftInfoResponse, OwnerOfResponse, Approval, NftInfoResponseForMetadata, Metadata, Trait, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, ExecuteMsg, Binary, MintMsgForMetadata, Decimal, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, RoyaltyInfoResponse, MinterResponse, NftInfoResponse, NumTokensResponse, OperatorsResponse, QueryMsg, TokensResponse } from "./Sg721MetadataOnchain.types";
-import { Sg721MetadataOnchainQueryClient, Sg721MetadataOnchainClient } from "./Sg721MetadataOnchain.client";
-export const sg721MetadataOnchainQueryKeys = {
-  contract: ([{
-    contract: "sg721MetadataOnchain"
-  }] as const),
-  address: (contractAddress: string | undefined) => ([{ ...sg721MetadataOnchainQueryKeys.contract[0],
-    address: contractAddress
-  }] as const),
-  ownerOf: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "owner_of",
-    args
-  }] as const),
-  approval: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "approval",
-    args
-  }] as const),
-  approvals: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "approvals",
-    args
-  }] as const),
-  allOperators: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "all_operators",
-    args
-  }] as const),
-  numTokens: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "num_tokens",
-    args
-  }] as const),
-  contractInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "contract_info",
-    args
-  }] as const),
-  nftInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "nft_info",
-    args
-  }] as const),
-  allNftInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "all_nft_info",
-    args
-  }] as const),
-  tokens: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "tokens",
-    args
-  }] as const),
-  allTokens: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "all_tokens",
-    args
-  }] as const),
-  minter: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "minter",
-    args
-  }] as const),
-  collectionInfo: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...sg721MetadataOnchainQueryKeys.address(contractAddress)[0],
-    method: "collection_info",
-    args
-  }] as const)
-};
-export interface Sg721MetadataOnchainReactQuery<TResponse, TData = TResponse> {
-  client: Sg721MetadataOnchainQueryClient | undefined;
-  options?: Omit<UseQueryOptions<TResponse, Error, TData>, "'queryKey' | 'queryFn' | 'initialData'"> & {
-    initialData?: undefined;
-  };
-}
-export interface Sg721MetadataOnchainCollectionInfoQuery<TData> extends Sg721MetadataOnchainReactQuery<CollectionInfoResponse, TData> {}
-export function useSg721MetadataOnchainCollectionInfoQuery<TData = CollectionInfoResponse>({
-  client,
-  options
-}: Sg721MetadataOnchainCollectionInfoQuery<TData>) {
-  return useQuery<CollectionInfoResponse, Error, TData>(sg721MetadataOnchainQueryKeys.collectionInfo(client?.contractAddress), () => client ? client.collectionInfo() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainMinterQuery<TData> extends Sg721MetadataOnchainReactQuery<MinterResponse, TData> {}
-export function useSg721MetadataOnchainMinterQuery<TData = MinterResponse>({
-  client,
-  options
-}: Sg721MetadataOnchainMinterQuery<TData>) {
-  return useQuery<MinterResponse, Error, TData>(sg721MetadataOnchainQueryKeys.minter(client?.contractAddress), () => client ? client.minter() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainAllTokensQuery<TData> extends Sg721MetadataOnchainReactQuery<AllTokensResponse, TData> {
-  args: {
-    limit?: number;
-    startAfter?: string;
-  };
-}
-export function useSg721MetadataOnchainAllTokensQuery<TData = AllTokensResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainAllTokensQuery<TData>) {
-  return useQuery<AllTokensResponse, Error, TData>(sg721MetadataOnchainQueryKeys.allTokens(client?.contractAddress, args), () => client ? client.allTokens({
-    limit: args.limit,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainTokensQuery<TData> extends Sg721MetadataOnchainReactQuery<TokensResponse, TData> {
-  args: {
-    limit?: number;
-    owner: string;
-    startAfter?: string;
-  };
-}
-export function useSg721MetadataOnchainTokensQuery<TData = TokensResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainTokensQuery<TData>) {
-  return useQuery<TokensResponse, Error, TData>(sg721MetadataOnchainQueryKeys.tokens(client?.contractAddress, args), () => client ? client.tokens({
-    limit: args.limit,
-    owner: args.owner,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainAllNftInfoQuery<TData> extends Sg721MetadataOnchainReactQuery<AllNftInfoResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    tokenId: string;
-  };
-}
-export function useSg721MetadataOnchainAllNftInfoQuery<TData = AllNftInfoResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainAllNftInfoQuery<TData>) {
-  return useQuery<AllNftInfoResponse, Error, TData>(sg721MetadataOnchainQueryKeys.allNftInfo(client?.contractAddress, args), () => client ? client.allNftInfo({
-    includeExpired: args.includeExpired,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainNftInfoQuery<TData> extends Sg721MetadataOnchainReactQuery<NftInfoResponse, TData> {
-  args: {
-    tokenId: string;
-  };
-}
-export function useSg721MetadataOnchainNftInfoQuery<TData = NftInfoResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainNftInfoQuery<TData>) {
-  return useQuery<NftInfoResponse, Error, TData>(sg721MetadataOnchainQueryKeys.nftInfo(client?.contractAddress, args), () => client ? client.nftInfo({
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainContractInfoQuery<TData> extends Sg721MetadataOnchainReactQuery<ContractInfoResponse, TData> {}
-export function useSg721MetadataOnchainContractInfoQuery<TData = ContractInfoResponse>({
-  client,
-  options
-}: Sg721MetadataOnchainContractInfoQuery<TData>) {
-  return useQuery<ContractInfoResponse, Error, TData>(sg721MetadataOnchainQueryKeys.contractInfo(client?.contractAddress), () => client ? client.contractInfo() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainNumTokensQuery<TData> extends Sg721MetadataOnchainReactQuery<NumTokensResponse, TData> {}
-export function useSg721MetadataOnchainNumTokensQuery<TData = NumTokensResponse>({
-  client,
-  options
-}: Sg721MetadataOnchainNumTokensQuery<TData>) {
-  return useQuery<NumTokensResponse, Error, TData>(sg721MetadataOnchainQueryKeys.numTokens(client?.contractAddress), () => client ? client.numTokens() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainAllOperatorsQuery<TData> extends Sg721MetadataOnchainReactQuery<AllOperatorsResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    limit?: number;
-    owner: string;
-    startAfter?: string;
-  };
-}
-export function useSg721MetadataOnchainAllOperatorsQuery<TData = AllOperatorsResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainAllOperatorsQuery<TData>) {
-  return useQuery<AllOperatorsResponse, Error, TData>(sg721MetadataOnchainQueryKeys.allOperators(client?.contractAddress, args), () => client ? client.allOperators({
-    includeExpired: args.includeExpired,
-    limit: args.limit,
-    owner: args.owner,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainApprovalsQuery<TData> extends Sg721MetadataOnchainReactQuery<ApprovalsResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    tokenId: string;
-  };
-}
-export function useSg721MetadataOnchainApprovalsQuery<TData = ApprovalsResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainApprovalsQuery<TData>) {
-  return useQuery<ApprovalsResponse, Error, TData>(sg721MetadataOnchainQueryKeys.approvals(client?.contractAddress, args), () => client ? client.approvals({
-    includeExpired: args.includeExpired,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainApprovalQuery<TData> extends Sg721MetadataOnchainReactQuery<ApprovalResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    spender: string;
-    tokenId: string;
-  };
-}
-export function useSg721MetadataOnchainApprovalQuery<TData = ApprovalResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainApprovalQuery<TData>) {
-  return useQuery<ApprovalResponse, Error, TData>(sg721MetadataOnchainQueryKeys.approval(client?.contractAddress, args), () => client ? client.approval({
-    includeExpired: args.includeExpired,
-    spender: args.spender,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainOwnerOfQuery<TData> extends Sg721MetadataOnchainReactQuery<OwnerOfResponse, TData> {
-  args: {
-    includeExpired?: boolean;
-    tokenId: string;
-  };
-}
-export function useSg721MetadataOnchainOwnerOfQuery<TData = OwnerOfResponse>({
-  client,
-  args,
-  options
-}: Sg721MetadataOnchainOwnerOfQuery<TData>) {
-  return useQuery<OwnerOfResponse, Error, TData>(sg721MetadataOnchainQueryKeys.ownerOf(client?.contractAddress, args), () => client ? client.ownerOf({
-    includeExpired: args.includeExpired,
-    tokenId: args.tokenId
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface Sg721MetadataOnchainBurnMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    tokenId: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainBurnMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainBurnMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainBurnMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.burn(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainMintMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: MintMsgForMetadata;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainMintMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainMintMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainMintMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.mint(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainRevokeAllMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    operator: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainRevokeAllMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainRevokeAllMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainRevokeAllMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.revokeAll(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainApproveAllMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    expires?: Expiration;
-    operator: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainApproveAllMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainApproveAllMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainApproveAllMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.approveAll(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainRevokeMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    spender: string;
-    tokenId: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainRevokeMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainRevokeMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainRevokeMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.revoke(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainApproveMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    expires?: Expiration;
-    spender: string;
-    tokenId: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainApproveMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainApproveMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainApproveMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.approve(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainSendNftMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    contract: string;
-    msg: Binary;
-    tokenId: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainSendNftMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainSendNftMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainSendNftMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.sendNft(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainTransferNftMutation {
-  client: Sg721MetadataOnchainClient;
-  msg: {
-    recipient: string;
-    tokenId: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainTransferNftMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainTransferNftMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainTransferNftMutation>(({
-    client,
-    msg,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.transferNft(msg, fee, memo, funds), options);
-}
-export interface Sg721MetadataOnchainReadyMutation {
-  client: Sg721MetadataOnchainClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSg721MetadataOnchainReadyMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, Sg721MetadataOnchainReadyMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, Sg721MetadataOnchainReadyMutation>(({
-    client,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.ready(fee, memo, funds), options);
-}
\ No newline at end of file
diff --git a/ts/src/Sg721Nt.react-query.ts b/ts/src/Sg721Nt.react-query.ts
deleted file mode 100644
index 80886ba5..00000000
--- a/ts/src/Sg721Nt.react-query.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
-* This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
-* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
-* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
-*/
-
-import { Expiration, Timestamp, Uint64, AllNftInfoResponse, OwnerOfResponse, Approval, NftInfoResponseForEmpty, Empty, AllOperatorsResponse, AllTokensResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, Cw721QueryMsg, Decimal, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, RoyaltyInfoResponse, MinterResponse, NftInfoResponse, NumTokensResponse, OperatorsResponse, TokensResponse } from "./Sg721Nt.types";
-import "./Sg721Nt.client";
\ No newline at end of file
diff --git a/ts/src/Splits.react-query.ts b/ts/src/Splits.react-query.ts
deleted file mode 100644
index 1ae6b525..00000000
--- a/ts/src/Splits.react-query.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
-* This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
-* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
-* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
-*/
-
-import { UseQueryOptions, useQuery, useMutation, UseMutationOptions } from "@tanstack/react-query";
-import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
-import { StdFee, Coin } from "@cosmjs/amino";
-import { Cw4Contract, Addr, Config, ExecuteMsg, InstantiateMsg, QueryMsg } from "./Splits.types";
-import { SplitsQueryClient, SplitsClient } from "./Splits.client";
-export const splitsQueryKeys = {
-  contract: ([{
-    contract: "splits"
-  }] as const),
-  address: (contractAddress: string | undefined) => ([{ ...splitsQueryKeys.contract[0],
-    address: contractAddress
-  }] as const),
-  config: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...splitsQueryKeys.address(contractAddress)[0],
-    method: "config",
-    args
-  }] as const),
-  member: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...splitsQueryKeys.address(contractAddress)[0],
-    method: "member",
-    args
-  }] as const),
-  listMembers: (contractAddress: string | undefined, args?: Record<string, unknown>) => ([{ ...splitsQueryKeys.address(contractAddress)[0],
-    method: "list_members",
-    args
-  }] as const)
-};
-export interface SplitsReactQuery<TResponse, TData = TResponse> {
-  client: SplitsQueryClient | undefined;
-  options?: Omit<UseQueryOptions<TResponse, Error, TData>, "'queryKey' | 'queryFn' | 'initialData'"> & {
-    initialData?: undefined;
-  };
-}
-export interface SplitsListMembersQuery<TData> extends SplitsReactQuery<ListMembersResponse, TData> {
-  args: {
-    limit?: number;
-    startAfter?: string;
-  };
-}
-export function useSplitsListMembersQuery<TData = ListMembersResponse>({
-  client,
-  args,
-  options
-}: SplitsListMembersQuery<TData>) {
-  return useQuery<ListMembersResponse, Error, TData>(splitsQueryKeys.listMembers(client?.contractAddress, args), () => client ? client.listMembers({
-    limit: args.limit,
-    startAfter: args.startAfter
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface SplitsMemberQuery<TData> extends SplitsReactQuery<MemberResponse, TData> {
-  args: {
-    address: string;
-  };
-}
-export function useSplitsMemberQuery<TData = MemberResponse>({
-  client,
-  args,
-  options
-}: SplitsMemberQuery<TData>) {
-  return useQuery<MemberResponse, Error, TData>(splitsQueryKeys.member(client?.contractAddress, args), () => client ? client.member({
-    address: args.address
-  }) : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface SplitsConfigQuery<TData> extends SplitsReactQuery<ConfigResponse, TData> {}
-export function useSplitsConfigQuery<TData = ConfigResponse>({
-  client,
-  options
-}: SplitsConfigQuery<TData>) {
-  return useQuery<ConfigResponse, Error, TData>(splitsQueryKeys.config(client?.contractAddress), () => client ? client.config() : Promise.reject(new Error("Invalid client")), { ...options,
-    enabled: !!client && (options?.enabled != undefined ? options.enabled : true)
-  });
-}
-export interface SplitsDistributeMutation {
-  client: SplitsClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useSplitsDistributeMutation(options?: Omit<UseMutationOptions<ExecuteResult, Error, SplitsDistributeMutation>, "mutationFn">) {
-  return useMutation<ExecuteResult, Error, SplitsDistributeMutation>(({
-    client,
-    args: {
-      fee,
-      memo,
-      funds
-    } = {}
-  }) => client.distribute(fee, memo, funds), options);
-}
\ No newline at end of file
diff --git a/ts/src/VendingFactory.react-query.ts b/ts/src/VendingFactory.react-query.ts
deleted file mode 100644
index 1b40c4ac..00000000
--- a/ts/src/VendingFactory.react-query.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
-* This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
-* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
-* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
-*/
-
-import { Uint128, InstantiateMsg, MinterParamsForParamsExtension, Coin, ParamsExtension, Sg2QueryMsg } from "./VendingFactory.types";
-import "./VendingFactory.client";
\ No newline at end of file
diff --git a/ts/src/VendingFactory.types.ts b/ts/src/VendingFactory.types.ts
index 57672470..5aa27755 100644
--- a/ts/src/VendingFactory.types.ts
+++ b/ts/src/VendingFactory.types.ts
@@ -9,6 +9,7 @@ export interface InstantiateMsg {
   params: MinterParamsForParamsExtension;
 }
 export interface MinterParamsForParamsExtension {
+  allowed_sg721_code_ids: number[];
   code_id: number;
   creation_fee: Coin;
   extension: ParamsExtension;
@@ -30,4 +31,8 @@ export interface ParamsExtension {
 }
 export type Sg2QueryMsg = {
   params: {};
+} | {
+  allowed_collection_code_ids: {};
+} | {
+  allowed_collection_code_id: number;
 };
\ No newline at end of file
diff --git a/ts/src/VendingMinter.react-query.ts b/ts/src/VendingMinter.react-query.ts
deleted file mode 100644
index f87a7d14..00000000
--- a/ts/src/VendingMinter.react-query.ts
+++ /dev/null
@@ -1,514 +0,0 @@
-/**
- * This file was automatically generated by @cosmwasm/ts-codegen@0.16.5.
- * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
- * and run the @cosmwasm/ts-codegen generate command to regenerate this file.
- */
-
-import {
-  UseQueryOptions,
-  useQuery,
-  useMutation,
-  UseMutationOptions,
-} from "@tanstack/react-query";
-import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
-import { StdFee } from "@cosmjs/amino";
-import {
-  Uint128,
-  Timestamp,
-  Uint64,
-  ConfigResponse,
-  Coin,
-  ExecuteMsg,
-  Decimal,
-  InstantiateMsg,
-  CreateMinterMsgForVendingMinterInitMsgExtension,
-  CollectionParams,
-  CollectionInfoForRoyaltyInfoResponse,
-  RoyaltyInfoResponse,
-  VendingMinterInitMsgExtension,
-  MinterParamsForParamsExtension,
-  ParamsExtension,
-  MintCountResponse,
-  MintPriceResponse,
-  MintableNumTokensResponse,
-  Addr,
-  MinterConfigForConfigExtension,
-  ConfigExtension,
-  QueryMsg,
-  StartTimeResponse,
-} from "./VendingMinter.types";
-import {
-  VendingMinterQueryClient,
-  VendingMinterClient,
-} from "./VendingMinter.client";
-export const vendingMinterQueryKeys = {
-  contract: [
-    {
-      contract: "vendingMinter",
-    },
-  ] as const,
-  address: (contractAddress: string | undefined) =>
-    [
-      { ...vendingMinterQueryKeys.contract[0], address: contractAddress },
-    ] as const,
-  config: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...vendingMinterQueryKeys.address(contractAddress)[0],
-        method: "config",
-        args,
-      },
-    ] as const,
-  mintableNumTokens: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...vendingMinterQueryKeys.address(contractAddress)[0],
-        method: "mintable_num_tokens",
-        args,
-      },
-    ] as const,
-  startTime: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...vendingMinterQueryKeys.address(contractAddress)[0],
-        method: "start_time",
-        args,
-      },
-    ] as const,
-  mintPrice: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...vendingMinterQueryKeys.address(contractAddress)[0],
-        method: "mint_price",
-        args,
-      },
-    ] as const,
-  mintCount: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...vendingMinterQueryKeys.address(contractAddress)[0],
-        method: "mint_count",
-        args,
-      },
-    ] as const,
-  status: (
-    contractAddress: string | undefined,
-    args?: Record<string, unknown>
-  ) =>
-    [
-      {
-        ...vendingMinterQueryKeys.address(contractAddress)[0],
-        method: "status",
-        args,
-      },
-    ] as const,
-};
-export interface VendingMinterReactQuery<TResponse, TData = TResponse> {
-  client: VendingMinterQueryClient | undefined;
-  options?: Omit<
-    UseQueryOptions<TResponse, Error, TData>,
-    "'queryKey' | 'queryFn' | 'initialData'"
-  > & {
-    initialData?: undefined;
-  };
-}
-export interface VendingMinterStatusQuery<TData>
-  extends VendingMinterReactQuery<StatusResponse, TData> {}
-export function useVendingMinterStatusQuery<TData = StatusResponse>({
-  client,
-  options,
-}: VendingMinterStatusQuery<TData>) {
-  return useQuery<StatusResponse, Error, TData>(
-    vendingMinterQueryKeys.status(client?.contractAddress),
-    () =>
-      client ? client.status() : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface VendingMinterMintCountQuery<TData>
-  extends VendingMinterReactQuery<MintCountResponse, TData> {
-  args: {
-    address: string;
-  };
-}
-export function useVendingMinterMintCountQuery<TData = MintCountResponse>({
-  client,
-  args,
-  options,
-}: VendingMinterMintCountQuery<TData>) {
-  return useQuery<MintCountResponse, Error, TData>(
-    vendingMinterQueryKeys.mintCount(client?.contractAddress, args),
-    () =>
-      client
-        ? client.mintCount({
-            address: args.address,
-          })
-        : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface VendingMinterMintPriceQuery<TData>
-  extends VendingMinterReactQuery<MintPriceResponse, TData> {}
-export function useVendingMinterMintPriceQuery<TData = MintPriceResponse>({
-  client,
-  options,
-}: VendingMinterMintPriceQuery<TData>) {
-  return useQuery<MintPriceResponse, Error, TData>(
-    vendingMinterQueryKeys.mintPrice(client?.contractAddress),
-    () =>
-      client ? client.mintPrice() : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface VendingMinterStartTimeQuery<TData>
-  extends VendingMinterReactQuery<StartTimeResponse, TData> {}
-export function useVendingMinterStartTimeQuery<TData = StartTimeResponse>({
-  client,
-  options,
-}: VendingMinterStartTimeQuery<TData>) {
-  return useQuery<StartTimeResponse, Error, TData>(
-    vendingMinterQueryKeys.startTime(client?.contractAddress),
-    () =>
-      client ? client.startTime() : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface VendingMinterMintableNumTokensQuery<TData>
-  extends VendingMinterReactQuery<MintableNumTokensResponse, TData> {}
-export function useVendingMinterMintableNumTokensQuery<
-  TData = MintableNumTokensResponse
->({ client, options }: VendingMinterMintableNumTokensQuery<TData>) {
-  return useQuery<MintableNumTokensResponse, Error, TData>(
-    vendingMinterQueryKeys.mintableNumTokens(client?.contractAddress),
-    () =>
-      client
-        ? client.mintableNumTokens()
-        : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface VendingMinterConfigQuery<TData>
-  extends VendingMinterReactQuery<ConfigResponse, TData> {}
-export function useVendingMinterConfigQuery<TData = ConfigResponse>({
-  client,
-  options,
-}: VendingMinterConfigQuery<TData>) {
-  return useQuery<ConfigResponse, Error, TData>(
-    vendingMinterQueryKeys.config(client?.contractAddress),
-    () =>
-      client ? client.config() : Promise.reject(new Error("Invalid client")),
-    {
-      ...options,
-      enabled:
-        !!client && (options?.enabled != undefined ? options.enabled : true),
-    }
-  );
-}
-export interface VendingMinterBurnRemainingMutation {
-  client: VendingMinterClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterBurnRemainingMutation(
-  options?: Omit<
-    UseMutationOptions<
-      ExecuteResult,
-      Error,
-      VendingMinterBurnRemainingMutation
-    >,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterBurnRemainingMutation>(
-    ({ client, args: { fee, memo, funds } = {} }) =>
-      client.burnRemaining(fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterShuffleMutation {
-  client: VendingMinterClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterShuffleMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, VendingMinterShuffleMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterShuffleMutation>(
-    ({ client, args: { fee, memo, funds } = {} }) =>
-      client.shuffle(fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterMintForMutation {
-  client: VendingMinterClient;
-  msg: {
-    recipient: string;
-    tokenId: number;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterMintForMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, VendingMinterMintForMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterMintForMutation>(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.mintFor(msg, fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterMintToMutation {
-  client: VendingMinterClient;
-  msg: {
-    recipient: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterMintToMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, VendingMinterMintToMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterMintToMutation>(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.mintTo(msg, fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterUpdatePerAddressLimitMutation {
-  client: VendingMinterClient;
-  msg: {
-    perAddressLimit: number;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterUpdatePerAddressLimitMutation(
-  options?: Omit<
-    UseMutationOptions<
-      ExecuteResult,
-      Error,
-      VendingMinterUpdatePerAddressLimitMutation
-    >,
-    "mutationFn"
-  >
-) {
-  return useMutation<
-    ExecuteResult,
-    Error,
-    VendingMinterUpdatePerAddressLimitMutation
-  >(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.updatePerAddressLimit(msg, fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterUpdateStartTradingTimeMutation {
-  client: VendingMinterClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterUpdateStartTradingTimeMutation(
-  options?: Omit<
-    UseMutationOptions<
-      ExecuteResult,
-      Error,
-      VendingMinterUpdateStartTradingTimeMutation
-    >,
-    "mutationFn"
-  >
-) {
-  return useMutation<
-    ExecuteResult,
-    Error,
-    VendingMinterUpdateStartTradingTimeMutation
-  >(
-    ({ client, args: { fee, memo, funds } = {} }) =>
-      client.UpdateStartTradingTime(fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterUpdateStartTimeMutation {
-  client: VendingMinterClient;
-  msg: Timestamp;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterUpdateStartTimeMutation(
-  options?: Omit<
-    UseMutationOptions<
-      ExecuteResult,
-      Error,
-      VendingMinterUpdateStartTimeMutation
-    >,
-    "mutationFn"
-  >
-) {
-  return useMutation<
-    ExecuteResult,
-    Error,
-    VendingMinterUpdateStartTimeMutation
-  >(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.updateStartTime(msg, fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterUpdateMintPriceMutation {
-  client: VendingMinterClient;
-  msg: {
-    price: number;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterUpdateMintPriceMutation(
-  options?: Omit<
-    UseMutationOptions<
-      ExecuteResult,
-      Error,
-      VendingMinterUpdateMintPriceMutation
-    >,
-    "mutationFn"
-  >
-) {
-  return useMutation<
-    ExecuteResult,
-    Error,
-    VendingMinterUpdateMintPriceMutation
-  >(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.updateMintPrice(msg, fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterPurgeMutation {
-  client: VendingMinterClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterPurgeMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, VendingMinterPurgeMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterPurgeMutation>(
-    ({ client, args: { fee, memo, funds } = {} }) =>
-      client.purge(fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterSetWhitelistMutation {
-  client: VendingMinterClient;
-  msg: {
-    whitelist: string;
-  };
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterSetWhitelistMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, VendingMinterSetWhitelistMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterSetWhitelistMutation>(
-    ({ client, msg, args: { fee, memo, funds } = {} }) =>
-      client.setWhitelist(msg, fee, memo, funds),
-    options
-  );
-}
-export interface VendingMinterMintMutation {
-  client: VendingMinterClient;
-  args?: {
-    fee?: number | StdFee | "auto";
-    memo?: string;
-    funds?: Coin[];
-  };
-}
-export function useVendingMinterMintMutation(
-  options?: Omit<
-    UseMutationOptions<ExecuteResult, Error, VendingMinterMintMutation>,
-    "mutationFn"
-  >
-) {
-  return useMutation<ExecuteResult, Error, VendingMinterMintMutation>(
-    ({ client, args: { fee, memo, funds } = {} }) =>
-      client.mint(fee, memo, funds),
-    options
-  );
-}
diff --git a/ts/src/VendingMinter.types.ts b/ts/src/VendingMinter.types.ts
index ff9c1a2d..90a160c1 100644
--- a/ts/src/VendingMinter.types.ts
+++ b/ts/src/VendingMinter.types.ts
@@ -103,6 +103,7 @@ export interface VendingMinterInitMsgExtension {
   whitelist?: string | null;
 }
 export interface MinterParamsForParamsExtension {
+  allowed_sg721_code_ids: number[];
   code_id: number;
   creation_fee: Coin;
   extension: ParamsExtension;
diff --git a/ts/yarn.lock b/ts/yarn.lock
index bfbf82e9..3efe4776 100644
--- a/ts/yarn.lock
+++ b/ts/yarn.lock
@@ -1334,10 +1334,10 @@
   resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.29.5.tgz#3fed1b3528ae8c5f1eb5d29b68755bebfd3294ee"
   integrity sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ==
 
-"@cosmwasm/ts-codegen@^0.24.0":
-  version "0.24.0"
-  resolved "https://registry.yarnpkg.com/@cosmwasm/ts-codegen/-/ts-codegen-0.24.0.tgz#61015220a9dccfd35dec46bcb67786441111f096"
-  integrity sha512-g5ufDroLzOzsMvnKyAz7i5M3Z3k8XYetRv9PnGW0Zbgj4sziw6jDimPJ3Ubnput+i380day7LnCwVT7zLIEzCQ==
+"@cosmwasm/ts-codegen@^0.25.2":
+  version "0.25.2"
+  resolved "https://registry.yarnpkg.com/@cosmwasm/ts-codegen/-/ts-codegen-0.25.2.tgz#68bbddbafbbc4488446cf2c2986318e18ec65446"
+  integrity sha512-XCrEXOgFjJvkvSWg6fXh2Ika9unHCJWH2ffbeKeGnzr6x6UX1iCH+8KDcgqMPdvpIOCBaxy9keFoaAqVFue9Ag==
   dependencies:
     "@babel/core" "7.18.10"
     "@babel/generator" "7.18.12"
@@ -1365,7 +1365,7 @@
     parse-package-name "1.0.0"
     rimraf "3.0.2"
     shelljs "0.8.5"
-    wasm-ast-types "^0.17.0"
+    wasm-ast-types "^0.18.2"
 
 "@cspotcode/source-map-support@^0.8.0":
   version "0.8.1"
@@ -3498,10 +3498,10 @@ walker@^1.0.8:
   dependencies:
     makeerror "1.0.12"
 
-wasm-ast-types@^0.17.0:
-  version "0.17.0"
-  resolved "https://registry.yarnpkg.com/wasm-ast-types/-/wasm-ast-types-0.17.0.tgz#417280a61d60ea9964667cf2edb8f5281dc295d7"
-  integrity sha512-WeriXPbG67iI51Mf/5qRR0xcpEaTO/Wyjpl+vsmjZ5K6q/0W6iO03zHsESNIH/hpc5FPTpb0Y0L9xAtnnNe9Ow==
+wasm-ast-types@^0.18.2:
+  version "0.18.2"
+  resolved "https://registry.yarnpkg.com/wasm-ast-types/-/wasm-ast-types-0.18.2.tgz#2161f390e7a2e4ad45a46bfdeda6d2d56801ece5"
+  integrity sha512-SKsuc56aYcl2UQM1Zm8IJZ2efvNAYhu/pPgH2OJZvUahGDi8W+jqnrKx9hIJeKW2GQdhboIIPFKY7PihWzgzgQ==
   dependencies:
     "@babel/runtime" "^7.18.9"
     "@babel/types" "7.18.10"


Test patch:
diff --git a/e2e/src/helpers/helper.rs b/e2e/src/helpers/helper.rs
index 3dc68ce5..858a0298 100644
--- a/e2e/src/helpers/helper.rs
+++ b/e2e/src/helpers/helper.rs
@@ -38,6 +38,7 @@ pub fn instantiate_factory(
         &InstantiateMsg {
             params: MinterParams {
                 code_id: chain.orc.contract_map.code_id(MINTER_NAME).unwrap(),
+                allowed_sg721_code_ids: vec![chain.orc.contract_map.code_id(SG721_NAME).unwrap()],
                 creation_fee: Coin {
                     amount: Uint128::new(CREATION_FEE),
                     denom: denom.to_string(),
diff --git a/test-suite/src/base_minter/tests/integration_tests.rs b/test-suite/src/base_minter/tests/integration_tests.rs
index 0e845dc4..2608c22a 100644
--- a/test-suite/src/base_minter/tests/integration_tests.rs
+++ b/test-suite/src/base_minter/tests/integration_tests.rs
@@ -1,14 +1,90 @@
+use crate::common_setup::contract_boxes::contract_sg721_base;
 use crate::common_setup::setup_accounts_and_block::{CREATION_FEE, INITIAL_BALANCE};
 use crate::common_setup::setup_minter::base_minter::mock_params::mock_params;
 use crate::common_setup::setup_minter::common::constants::MIN_MINT_PRICE;
-use crate::common_setup::templates::{base_minter_with_sg721, base_minter_with_sg721nt};
+use crate::common_setup::templates::{
+    base_minter_with_sg721, base_minter_with_sg721nt, base_minter_with_specified_sg721,
+};
+use base_factory::msg::{BaseMinterCreateMsg, BaseUpdateParamsMsg, SudoMsg};
+
 use base_minter::msg::{ConfigResponse, ExecuteMsg};
 use cosmwasm_std::{coin, coins, Addr, Timestamp};
 use cw721::{Cw721ExecuteMsg, Cw721QueryMsg, OwnerOfResponse};
 use cw_multi_test::Executor;
+use sg2::msg::Sg2ExecuteMsg;
+use sg2::query::{AllowedCollectionCodeIdsResponse, Sg2QueryMsg};
+use sg2::tests::mock_collection_params_1;
 use sg4::QueryMsg;
 use sg721_base::msg::{CollectionInfoResponse, QueryMsg as Sg721QueryMsg};
-use sg_std::NATIVE_DENOM;
+use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
+
+#[test]
+fn init() {
+    let bmt = base_minter_with_sg721nt(1);
+    bmt.collection_response_vec[0].minter.clone().unwrap();
+    bmt.collection_response_vec[0].collection.clone().unwrap();
+}
+
+#[test]
+fn update_code_id() {
+    let sg721_code_id = 7u64;
+    let bmt = base_minter_with_specified_sg721(1, sg721_code_id);
+    let (mut router, creator, _) = (bmt.router, bmt.accts.creator, bmt.accts.buyer);
+    let factory = bmt.collection_response_vec[0].factory.clone().unwrap();
+
+    // sg721 code id not in allowed code ids
+    let res = bmt.collection_response_vec[0].minter.clone();
+    assert!(res.is_none());
+
+    // add sg721_code_id to allowed code ids
+    let update_msg = BaseUpdateParamsMsg {
+        add_sg721_code_ids: Some(vec![sg721_code_id]),
+        rm_sg721_code_ids: None,
+        code_id: None,
+        creation_fee: None,
+        min_mint_price: None,
+        mint_fee_bps: None,
+        max_trading_offset_secs: None,
+        extension: None,
+    };
+    let sudo_msg = SudoMsg::UpdateParams(Box::new(update_msg));
+    let res = router.wasm_sudo(factory.clone(), &sudo_msg);
+    assert!(res.is_ok());
+
+    let msg = Sg2QueryMsg::AllowedCollectionCodeIds {};
+    let res: AllowedCollectionCodeIdsResponse = router
+        .wrap()
+        .query_wasm_smart(factory.clone(), &msg)
+        .unwrap();
+    assert!(res.code_ids.contains(&sg721_code_id));
+
+    // store sg721_base 4-7 code ids
+    for _ in 0..(sg721_code_id - 3) {
+        router.store_code(contract_sg721_base());
+    }
+
+    // create minter with sg721_code_id
+    let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
+    let mut collection_params = mock_collection_params_1(Some(start_time));
+    collection_params.code_id = sg721_code_id;
+
+    let mut msg = BaseMinterCreateMsg {
+        init_msg: None,
+        collection_params,
+    };
+    msg.collection_params.info.creator = creator.to_string();
+    let creation_fee = coins(CREATION_FEE, NATIVE_DENOM);
+    let msg = Sg2ExecuteMsg::CreateMinter(msg);
+    let res = router.execute_contract(creator, factory, &msg, &creation_fee);
+    assert!(res.is_ok());
+
+    // confirm new sg721 code id == sg721_code_id
+    let res = router
+        .wrap()
+        .query_wasm_contract_info("contract2".to_string())
+        .unwrap();
+    assert!(res.code_id == sg721_code_id);
+}
 
 #[test]
 fn check_mint() {
diff --git a/test-suite/src/common_setup/contract_boxes.rs b/test-suite/src/common_setup/contract_boxes.rs
index 1071cd81..655e25c0 100644
--- a/test-suite/src/common_setup/contract_boxes.rs
+++ b/test-suite/src/common_setup/contract_boxes.rs
@@ -11,7 +11,8 @@ pub fn contract_vending_factory() -> Box<dyn Contract<StargazeMsgWrapper>> {
         vending_factory::contract::execute,
         vending_factory::contract::instantiate,
         vending_factory::contract::query,
-    );
+    )
+    .with_sudo(vending_factory::contract::sudo);
     Box::new(contract)
 }
 
@@ -21,7 +22,7 @@ pub fn contract_base_factory() -> Box<dyn Contract<StargazeMsgWrapper>> {
         base_factory::contract::instantiate,
         base_factory::contract::query,
     )
-    .with_sudo(vending_factory::contract::sudo);
+    .with_sudo(base_factory::contract::sudo);
     Box::new(contract)
 }
 
diff --git a/test-suite/src/common_setup/msg.rs b/test-suite/src/common_setup/msg.rs
index 8c6486aa..ce4c80e7 100644
--- a/test-suite/src/common_setup/msg.rs
+++ b/test-suite/src/common_setup/msg.rs
@@ -39,13 +39,13 @@ pub struct CodeIds {
     pub sg721_code_id: u64,
 }
 
-pub struct VendingTemplateResponse<T> {
+pub struct MinterTemplateResponse<T> {
     pub collection_response_vec: Vec<MinterCollectionResponse>,
     pub router: StargazeApp,
     pub accts: T,
 }
 
-pub struct VendingAccounts {
+pub struct Accounts {
     pub creator: Addr,
     pub buyer: Addr,
 }
diff --git a/test-suite/src/common_setup/setup_minter/base_minter/mock_params.rs b/test-suite/src/common_setup/setup_minter/base_minter/mock_params.rs
index 8d6ac2bf..a0957c7c 100644
--- a/test-suite/src/common_setup/setup_minter/base_minter/mock_params.rs
+++ b/test-suite/src/common_setup/setup_minter/base_minter/mock_params.rs
@@ -10,6 +10,7 @@ const MINT_FEE_BPS: u64 = 10_000; // 100%
 pub fn mock_params() -> BaseMinterParams {
     BaseMinterParams {
         code_id: 1,
+        allowed_sg721_code_ids: vec![3],
         creation_fee: coin(CREATION_FEE, NATIVE_DENOM),
         min_mint_price: coin(MIN_MINT_PRICE, NATIVE_DENOM),
         mint_fee_bps: MINT_FEE_BPS,
diff --git a/test-suite/src/common_setup/setup_minter/vending_minter/mock_params.rs b/test-suite/src/common_setup/setup_minter/vending_minter/mock_params.rs
index a185dbd7..67c00bff 100644
--- a/test-suite/src/common_setup/setup_minter/vending_minter/mock_params.rs
+++ b/test-suite/src/common_setup/setup_minter/vending_minter/mock_params.rs
@@ -50,6 +50,7 @@ pub fn mock_create_minter_init_msg(
 pub fn mock_params() -> VendingMinterParams {
     VendingMinterParams {
         code_id: 1,
+        allowed_sg721_code_ids: vec![1, 3, 5, 6],
         creation_fee: coin(CREATION_FEE, NATIVE_DENOM),
         min_mint_price: coin(MIN_MINT_PRICE, NATIVE_DENOM),
         mint_fee_bps: MINT_FEE_FAIR_BURN,
diff --git a/test-suite/src/common_setup/templates.rs b/test-suite/src/common_setup/templates.rs
index 965c0232..730697cf 100644
--- a/test-suite/src/common_setup/templates.rs
+++ b/test-suite/src/common_setup/templates.rs
@@ -1,5 +1,5 @@
 use crate::common_setup::contract_boxes::custom_mock_app;
-use crate::common_setup::msg::VendingTemplateResponse;
+use crate::common_setup::msg::MinterTemplateResponse;
 use crate::common_setup::{
     msg::MinterCollectionResponse,
     setup_accounts_and_block::setup_accounts,
@@ -14,12 +14,12 @@ use sg2::tests::mock_collection_params_1;
 use sg_multi_test::StargazeApp;
 use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
 
-use super::msg::VendingAccounts;
+use super::msg::Accounts;
 use super::setup_minter::base_minter::setup::base_minter_sg721_collection_code_ids;
 use super::setup_minter::common::constants::MIN_MINT_PRICE;
 use super::setup_minter::common::minter_params::minter_params_all;
 
-pub fn vending_minter_template(num_tokens: u32) -> VendingTemplateResponse<VendingAccounts> {
+pub fn vending_minter_template(num_tokens: u32) -> MinterTemplateResponse<Accounts> {
     let mut app = custom_mock_app();
     let (creator, buyer) = setup_accounts(&mut app);
     let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
@@ -33,17 +33,17 @@ pub fn vending_minter_template(num_tokens: u32) -> VendingTemplateResponse<Vendi
         vec![minter_params],
         code_ids,
     );
-    VendingTemplateResponse {
+    MinterTemplateResponse {
         router: app,
         collection_response_vec: minter_collection_response,
-        accts: VendingAccounts { creator, buyer },
+        accts: Accounts { creator, buyer },
     }
 }
 
 pub fn vending_minter_per_address_limit(
     num_tokens: u32,
     per_address_limit: u32,
-) -> VendingTemplateResponse<VendingAccounts> {
+) -> MinterTemplateResponse<Accounts> {
     let mut app = custom_mock_app();
     let (creator, buyer) = setup_accounts(&mut app);
     let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
@@ -67,17 +67,17 @@ pub fn vending_minter_per_address_limit(
         vec![minter_params],
         code_ids,
     );
-    VendingTemplateResponse {
+    MinterTemplateResponse {
         router: app,
         collection_response_vec: minter_collection_response,
-        accts: VendingAccounts { creator, buyer },
+        accts: Accounts { creator, buyer },
     }
 }
 
 pub fn vending_minter_with_start_time(
     num_tokens: u32,
     start_time: Timestamp,
-) -> VendingTemplateResponse<VendingAccounts> {
+) -> MinterTemplateResponse<Accounts> {
     let mut app = custom_mock_app();
     let (creator, buyer) = setup_accounts(&mut app);
     let collection_params = mock_collection_params_1(Some(start_time));
@@ -90,17 +90,17 @@ pub fn vending_minter_with_start_time(
         vec![minter_params],
         code_ids,
     );
-    VendingTemplateResponse {
+    MinterTemplateResponse {
         router: app,
         collection_response_vec: minter_collection_response,
-        accts: VendingAccounts { creator, buyer },
+        accts: Accounts { creator, buyer },
     }
 }
 
 pub fn vending_minter_with_app(
     num_tokens: u32,
     mut app: StargazeApp,
-) -> VendingTemplateResponse<VendingAccounts> {
+) -> MinterTemplateResponse<Accounts> {
     let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
     let (creator, buyer) = setup_accounts(&mut app);
     let collection_params = mock_collection_params_1(Some(start_time));
@@ -113,14 +113,39 @@ pub fn vending_minter_with_app(
         vec![minter_params],
         code_ids,
     );
-    VendingTemplateResponse {
+    MinterTemplateResponse {
         router: app,
         collection_response_vec: minter_collection_response,
-        accts: VendingAccounts { creator, buyer },
+        accts: Accounts { creator, buyer },
     }
 }
 
-pub fn base_minter_with_sg721nt(num_tokens: u32) -> VendingTemplateResponse<VendingAccounts> {
+pub fn vending_minter_with_specified_sg721(
+    num_tokens: u32,
+    sg721_code_id: u64,
+) -> MinterTemplateResponse<Accounts> {
+    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(num_tokens);
+    let mut code_ids = vending_minter_code_ids(&mut app);
+    code_ids.sg721_code_id = sg721_code_id;
+    let minter_collection_response: Vec<MinterCollectionResponse> = configure_minter(
+        &mut app,
+        creator.clone(),
+        vec![collection_params],
+        vec![minter_params],
+        code_ids,
+    );
+    MinterTemplateResponse {
+        router: app,
+        collection_response_vec: minter_collection_response,
+        accts: Accounts { creator, buyer },
+    }
+}
+
+pub fn base_minter_with_sg721nt(num_tokens: u32) -> MinterTemplateResponse<Accounts> {
     let mut router = custom_mock_app();
     let (creator, buyer) = setup_accounts(&mut router);
     let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
@@ -134,14 +159,14 @@ pub fn base_minter_with_sg721nt(num_tokens: u32) -> VendingTemplateResponse<Vend
         vec![minter_params],
         code_ids,
     );
-    VendingTemplateResponse {
+    MinterTemplateResponse {
         router,
         collection_response_vec: minter_collection_response,
-        accts: VendingAccounts { creator, buyer },
+        accts: Accounts { creator, buyer },
     }
 }
 
-pub fn base_minter_with_sg721(num_tokens: u32) -> VendingTemplateResponse<VendingAccounts> {
+pub fn base_minter_with_sg721(num_tokens: u32) -> MinterTemplateResponse<Accounts> {
     let mut router = custom_mock_app();
     let (creator, buyer) = setup_accounts(&mut router);
     let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
@@ -155,9 +180,34 @@ pub fn base_minter_with_sg721(num_tokens: u32) -> VendingTemplateResponse<Vendin
         vec![minter_params],
         code_ids,
     );
-    VendingTemplateResponse {
+    MinterTemplateResponse {
+        router,
+        collection_response_vec: minter_collection_response,
+        accts: Accounts { creator, buyer },
+    }
+}
+
+pub fn base_minter_with_specified_sg721(
+    num_tokens: u32,
+    sg721_code_id: u64,
+) -> MinterTemplateResponse<Accounts> {
+    let mut router = custom_mock_app();
+    let (creator, buyer) = setup_accounts(&mut router);
+    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(num_tokens);
+    let mut code_ids = base_minter_sg721_collection_code_ids(&mut router);
+    code_ids.sg721_code_id = sg721_code_id;
+    let minter_collection_response = configure_base_minter(
+        &mut router,
+        creator.clone(),
+        vec![collection_params],
+        vec![minter_params],
+        code_ids,
+    );
+    MinterTemplateResponse {
         router,
         collection_response_vec: minter_collection_response,
-        accts: VendingAccounts { creator, buyer },
+        accts: Accounts { creator, buyer },
     }
 }
diff --git a/test-suite/src/vending_minter/tests.rs b/test-suite/src/vending_minter/tests.rs
index 88a689ce..c03c11f4 100644
--- a/test-suite/src/vending_minter/tests.rs
+++ b/test-suite/src/vending_minter/tests.rs
@@ -1,4 +1,5 @@
 mod address_limit;
+mod allowed_code_ids;
 mod happy_unhappy;
 mod mint_and_burn;
 mod splits;
diff --git a/test-suite/src/vending_minter/tests/allowed_code_ids.rs b/test-suite/src/vending_minter/tests/allowed_code_ids.rs
new file mode 100644
index 00000000..ef4c078d
--- /dev/null
+++ b/test-suite/src/vending_minter/tests/allowed_code_ids.rs
@@ -0,0 +1,96 @@
+use crate::common_setup::templates::vending_minter_template;
+use crate::common_setup::{
+    contract_boxes::contract_sg721_base, setup_minter::common::constants::CREATION_FEE,
+    setup_minter::vending_minter::mock_params::mock_init_extension,
+    templates::vending_minter_with_specified_sg721,
+};
+use cosmwasm_std::{coins, Timestamp};
+use cw_multi_test::Executor;
+use sg2::{
+    msg::Sg2ExecuteMsg,
+    query::{AllowedCollectionCodeIdsResponse, Sg2QueryMsg},
+    tests::mock_collection_params_1,
+};
+use sg_std::{GENESIS_MINT_START_TIME, NATIVE_DENOM};
+use vending_factory::msg::{
+    SudoMsg, VendingMinterCreateMsg, VendingMinterInitMsgExtension, VendingUpdateParamsExtension,
+    VendingUpdateParamsMsg,
+};
+
+#[test]
+fn init() {
+    let vt = vending_minter_template(2);
+    vt.collection_response_vec[0].minter.clone().unwrap();
+}
+
+#[test]
+fn update_code_id() {
+    let sg721_code_id = 7u64;
+
+    let vt = vending_minter_with_specified_sg721(200, sg721_code_id);
+    let (mut router, creator, _) = (vt.router, vt.accts.creator, vt.accts.buyer);
+    let factory = vt.collection_response_vec[0].factory.clone().unwrap();
+
+    // sg721 code id not in allowed code ids
+    let res = vt.collection_response_vec[0].minter.clone();
+    assert!(res.is_none());
+
+    // add sg721_code_id to allowed code ids
+    let extension = VendingUpdateParamsExtension {
+        max_token_limit: None,
+        max_per_address_limit: None,
+        airdrop_mint_price: None,
+        airdrop_mint_fee_bps: None,
+        shuffle_fee: None,
+    };
+    let update_msg = VendingUpdateParamsMsg {
+        add_sg721_code_ids: Some(vec![sg721_code_id]),
+        rm_sg721_code_ids: None,
+        code_id: None,
+        creation_fee: None,
+        min_mint_price: None,
+        mint_fee_bps: None,
+        max_trading_offset_secs: None,
+        extension,
+    };
+    let sudo_msg = SudoMsg::UpdateParams(Box::new(update_msg));
+    let res = router.wasm_sudo(factory.clone(), &sudo_msg);
+    assert!(res.is_ok());
+
+    let msg = Sg2QueryMsg::AllowedCollectionCodeIds {};
+    let res: AllowedCollectionCodeIdsResponse = router
+        .wrap()
+        .query_wasm_smart(factory.clone(), &msg)
+        .unwrap();
+    assert!(res.code_ids.contains(&sg721_code_id));
+
+    // store sg721_base 4-7 code ids
+    for _ in 0..(sg721_code_id - 3) {
+        router.store_code(contract_sg721_base());
+    }
+
+    // create minter with sg721_code_id
+    let start_time = Timestamp::from_nanos(GENESIS_MINT_START_TIME);
+    let mut collection_params = mock_collection_params_1(Some(start_time));
+    collection_params.code_id = sg721_code_id;
+
+    let init_msg = VendingMinterInitMsgExtension {
+        ..mock_init_extension(None, None)
+    };
+    let mut msg = VendingMinterCreateMsg {
+        init_msg,
+        collection_params,
+    };
+    msg.collection_params.info.creator = creator.to_string();
+    let creation_fee = coins(CREATION_FEE, NATIVE_DENOM);
+    let msg = Sg2ExecuteMsg::CreateMinter(msg);
+    let res = router.execute_contract(creator, factory, &msg, &creation_fee);
+    assert!(res.is_ok());
+
+    // confirm new sg721 code id == sg721_code_id
+    let res = router
+        .wrap()
+        .query_wasm_contract_info("contract2".to_string())
+        .unwrap();
+    assert!(res.code_id == sg721_code_id);
+}