Repository: public-awesome/launchpad
Pull request #415 (2022-09-23 15:12:33)

airdrop price query and allow 0 fee airdrops


Patch:
diff --git a/contracts/base-minter/schema/instantiate_msg.json b/contracts/base-minter/schema/instantiate_msg.json
index 680933b6..466fa71e 100644
--- a/contracts/base-minter/schema/instantiate_msg.json
+++ b/contracts/base-minter/schema/instantiate_msg.json
@@ -35,6 +35,7 @@
       "required": [
         "creator",
         "description",
+        "explicit_content",
         "image"
       ],
       "properties": {
@@ -44,6 +45,9 @@
         "description": {
           "type": "string"
         },
+        "explicit_content": {
+          "type": "boolean"
+        },
         "external_link": {
           "type": [
             "string",
diff --git a/contracts/sg721-base/schema/collection_info_response.json b/contracts/sg721-base/schema/collection_info_response.json
index a20ea7f8..e8c1be9f 100644
--- a/contracts/sg721-base/schema/collection_info_response.json
+++ b/contracts/sg721-base/schema/collection_info_response.json
@@ -5,6 +5,7 @@
   "required": [
     "creator",
     "description",
+    "explicit_content",
     "image"
   ],
   "properties": {
@@ -14,6 +15,9 @@
     "description": {
       "type": "string"
     },
+    "explicit_content": {
+      "type": "boolean"
+    },
     "external_link": {
       "type": [
         "string",
diff --git a/contracts/sg721-base/schema/instantiate_msg.json b/contracts/sg721-base/schema/instantiate_msg.json
index 7f4b6031..62106814 100644
--- a/contracts/sg721-base/schema/instantiate_msg.json
+++ b/contracts/sg721-base/schema/instantiate_msg.json
@@ -28,6 +28,7 @@
       "required": [
         "creator",
         "description",
+        "explicit_content",
         "image"
       ],
       "properties": {
@@ -37,6 +38,9 @@
         "description": {
           "type": "string"
         },
+        "explicit_content": {
+          "type": "boolean"
+        },
         "external_link": {
           "type": [
             "string",
diff --git a/contracts/sg721-base/src/contract.rs b/contracts/sg721-base/src/contract.rs
index 7de063bd..60b9748f 100644
--- a/contracts/sg721-base/src/contract.rs
+++ b/contracts/sg721-base/src/contract.rs
@@ -81,6 +81,7 @@ where
             description: msg.collection_info.description,
             image: msg.collection_info.image,
             external_link: msg.collection_info.external_link,
+            explicit_content: msg.collection_info.explicit_content,
             trading_start_time: msg.collection_info.trading_start_time,
             royalty_info,
         };
@@ -188,6 +189,10 @@ where
             .unwrap_or_else(|| collection.external_link.as_ref().map(|s| s.to_string()));
         Url::parse(collection.external_link.as_ref().unwrap())?;
 
+        collection.explicit_content = collection_msg
+            .explicit_content
+            .unwrap_or(collection.explicit_content);
+
         // convert collection royalty info to response for comparison
         // convert from response to royalty info for storage
         let royalty_info_res = collection
@@ -320,6 +325,7 @@ where
             description: info.description,
             image: info.image,
             external_link: info.external_link,
+            explicit_content: info.explicit_content,
             trading_start_time: info.trading_start_time,
             royalty_info: royalty_info_res,
         })
diff --git a/contracts/sg721-base/src/msg.rs b/contracts/sg721-base/src/msg.rs
index ac196544..63483ede 100644
--- a/contracts/sg721-base/src/msg.rs
+++ b/contracts/sg721-base/src/msg.rs
@@ -119,6 +119,7 @@ pub struct CollectionInfoResponse {
     pub description: String,
     pub image: String,
     pub external_link: Option<String>,
+    pub explicit_content: bool,
     pub trading_start_time: Option<Timestamp>,
     pub royalty_info: Option<RoyaltyInfoResponse>,
 }
diff --git a/contracts/sg721-metadata-onchain/src/lib.rs b/contracts/sg721-metadata-onchain/src/lib.rs
index 7ea30d9c..3856126a 100644
--- a/contracts/sg721-metadata-onchain/src/lib.rs
+++ b/contracts/sg721-metadata-onchain/src/lib.rs
@@ -126,6 +126,7 @@ mod tests {
                 description: "this is a test".to_string(),
                 image: "https://larry.engineer".to_string(),
                 external_link: None,
+                explicit_content: false,
                 trading_start_time: None,
                 royalty_info: None,
             },
diff --git a/contracts/sg721-nt/schema/instantiate_msg.json b/contracts/sg721-nt/schema/instantiate_msg.json
index 7f4b6031..62106814 100644
--- a/contracts/sg721-nt/schema/instantiate_msg.json
+++ b/contracts/sg721-nt/schema/instantiate_msg.json
@@ -28,6 +28,7 @@
       "required": [
         "creator",
         "description",
+        "explicit_content",
         "image"
       ],
       "properties": {
@@ -37,6 +38,9 @@
         "description": {
           "type": "string"
         },
+        "explicit_content": {
+          "type": "boolean"
+        },
         "external_link": {
           "type": [
             "string",
diff --git a/contracts/vending-minter/schema/instantiate_msg.json b/contracts/vending-minter/schema/instantiate_msg.json
index 27dc4d25..722c9f9e 100644
--- a/contracts/vending-minter/schema/instantiate_msg.json
+++ b/contracts/vending-minter/schema/instantiate_msg.json
@@ -35,6 +35,7 @@
       "required": [
         "creator",
         "description",
+        "explicit_content",
         "image"
       ],
       "properties": {
@@ -44,6 +45,9 @@
         "description": {
           "type": "string"
         },
+        "explicit_content": {
+          "type": "boolean"
+        },
         "external_link": {
           "type": [
             "string",
diff --git a/contracts/vending-minter/schema/mint_price_response.json b/contracts/vending-minter/schema/mint_price_response.json
index 628d25e4..94518076 100644
--- a/contracts/vending-minter/schema/mint_price_response.json
+++ b/contracts/vending-minter/schema/mint_price_response.json
@@ -3,10 +3,14 @@
   "title": "MintPriceResponse",
   "type": "object",
   "required": [
+    "airdrop_price",
     "current_price",
     "public_price"
   ],
   "properties": {
+    "airdrop_price": {
+      "$ref": "#/definitions/Coin"
+    },
     "current_price": {
       "$ref": "#/definitions/Coin"
     },
diff --git a/contracts/vending-minter/src/contract.rs b/contracts/vending-minter/src/contract.rs
index f6e5e499..9afb87e7 100644
--- a/contracts/vending-minter/src/contract.rs
+++ b/contracts/vending-minter/src/contract.rs
@@ -972,8 +972,14 @@ fn query_mintable_num_tokens(deps: Deps) -> StdResult<MintableNumTokensResponse>
 fn query_mint_price(deps: Deps) -> StdResult<MintPriceResponse> {
     let config = CONFIG.load(deps.storage)?;
 
+    let factory: ParamsResponse = deps
+        .querier
+        .query_wasm_smart(config.factory, &Sg2QueryMsg::Params {})?;
+
+    let factory_params = factory.params;
+
     let current_price = mint_price(deps, false)?;
-    let public_price = config.mint_price;
+    let public_price = config.mint_price.clone();
     let whitelist_price: Option<Coin> = if let Some(whitelist) = config.extension.whitelist {
         let wl_config: WhitelistConfigResponse = deps
             .querier
@@ -982,10 +988,15 @@ fn query_mint_price(deps: Deps) -> StdResult<MintPriceResponse> {
     } else {
         None
     };
+    let airdrop_price = coin(
+        factory_params.extension.airdrop_mint_price.amount.u128(),
+        config.mint_price.denom,
+    );
     Ok(MintPriceResponse {
-        current_price,
         public_price,
+        airdrop_price,
         whitelist_price,
+        current_price,
     })
 }
 
diff --git a/contracts/vending-minter/src/msg.rs b/contracts/vending-minter/src/msg.rs
index 82195b90..c96bfdb7 100644
--- a/contracts/vending-minter/src/msg.rs
+++ b/contracts/vending-minter/src/msg.rs
@@ -75,6 +75,7 @@ pub struct StartTimeResponse {
 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
 pub struct MintPriceResponse {
     pub public_price: Coin,
+    pub airdrop_price: Coin,
     pub whitelist_price: Option<Coin>,
     pub current_price: Coin,
 }
diff --git a/packages/sg1/src/lib.rs b/packages/sg1/src/lib.rs
index c8162d3e..3b51c4d8 100644
--- a/packages/sg1/src/lib.rs
+++ b/packages/sg1/src/lib.rs
@@ -1,5 +1,5 @@
 use cosmwasm_std::{coins, Addr, BankMsg, Decimal, Event, MessageInfo, Uint128};
-use cw_utils::{must_pay, PaymentError};
+use cw_utils::{may_pay, PaymentError};
 use sg_std::{create_fund_fairburn_pool_msg, Response, SubMsg, NATIVE_DENOM};
 use thiserror::Error;
 
@@ -14,12 +14,15 @@ pub fn checked_fair_burn(
     developer: Option<Addr>,
     res: &mut Response,
 ) -> Result<(), FeeError> {
-    let payment = must_pay(info, NATIVE_DENOM)?;
+    // Use may_pay because fees could be 0. Add check to avoid transferring 0 funds
+    let payment = may_pay(info, NATIVE_DENOM)?;
     if payment.u128() < fee {
         return Err(FeeError::InsufficientFee(fee, payment.u128()));
     };
 
-    fair_burn(fee, developer, res);
+    if payment.u128() != 0u128 {
+        fair_burn(fee, developer, res);
+    }
 
     Ok(())
 }
diff --git a/packages/sg721/src/lib.rs b/packages/sg721/src/lib.rs
index accb57c8..7c7ea89b 100644
--- a/packages/sg721/src/lib.rs
+++ b/packages/sg721/src/lib.rs
@@ -76,6 +76,7 @@ pub struct CollectionInfo<T> {
     pub description: String,
     pub image: String,
     pub external_link: Option<String>,
+    pub explicit_content: bool,
     pub trading_start_time: Option<Timestamp>,
     pub royalty_info: Option<T>,
 }
@@ -85,6 +86,7 @@ pub struct UpdateCollectionInfoMsg<T> {
     pub description: Option<String>,
     pub image: Option<String>,
     pub external_link: Option<Option<String>>,
+    pub explicit_content: Option<bool>,
     pub royalty_info: Option<Option<T>>,
 }
 


Test patch:
diff --git a/contracts/sg721-base/src/integration_tests.rs b/contracts/sg721-base/src/integration_tests.rs
index 3d14896e..ea99a0de 100644
--- a/contracts/sg721-base/src/integration_tests.rs
+++ b/contracts/sg721-base/src/integration_tests.rs
@@ -179,6 +179,7 @@ mod tests {
                     description: "description".to_string(),
                     image: "description".to_string(),
                     external_link: None,
+                    explicit_content: false,
                     trading_start_time: None,
                     royalty_info: None,
                 },
@@ -237,6 +238,7 @@ mod tests {
                         description: Some(params.info.description.clone()),
                         image: Some(params.info.image.clone()),
                         external_link: Some(params.info.external_link.clone()),
+                        explicit_content: None,
                         royalty_info: None,
                     },
                 },
@@ -257,6 +259,7 @@ mod tests {
                         description: Some(params.info.description.clone()),
                         image: Some(params.info.image.clone()),
                         external_link: Some(params.info.external_link.clone()),
+                        explicit_content: None,
                         royalty_info: Some(royalty_info.clone()),
                     },
                 },
@@ -268,7 +271,31 @@ mod tests {
                 .wrap()
                 .query_wasm_smart(contract.clone(), &QueryMsg::CollectionInfo {})
                 .unwrap();
-            assert_eq!(res.royalty_info.unwrap(), royalty_info.unwrap());
+            assert_eq!(res.royalty_info.unwrap(), royalty_info.clone().unwrap());
+
+            // update explicit content
+            let res = app.execute_contract(
+                creator.clone(),
+                contract.clone(),
+                &Sg721ExecuteMsg::<Empty>::UpdateCollectionInfo {
+                    collection_info: UpdateCollectionInfoMsg {
+                        description: Some(params.info.description.clone()),
+                        image: Some(params.info.image.clone()),
+                        external_link: Some(params.info.external_link.clone()),
+                        explicit_content: Some(true),
+                        royalty_info: Some(royalty_info),
+                    },
+                },
+                &[],
+            );
+            assert!(res.is_ok());
+
+            let res: CollectionInfoResponse = app
+                .wrap()
+                .query_wasm_smart(contract.clone(), &QueryMsg::CollectionInfo {})
+                .unwrap();
+            // check explicit content changed to true
+            assert!(res.explicit_content);
 
             // try update royalty_info higher
             let royalty_info: Option<RoyaltyInfoResponse> = Some(RoyaltyInfoResponse {
@@ -283,6 +310,7 @@ mod tests {
                         description: None,
                         image: None,
                         external_link: None,
+                        explicit_content: None,
                         royalty_info: Some(royalty_info),
                     },
                 },
@@ -316,6 +344,7 @@ mod tests {
                         description: Some(params.info.description.clone()),
                         image: Some(params.info.image.clone()),
                         external_link: Some(params.info.external_link),
+                        explicit_content: None,
                         royalty_info: None,
                     },
                 },
diff --git a/contracts/vending-minter/src/integration_tests.rs b/contracts/vending-minter/src/integration_tests.rs
index a2b57589..942e34e2 100644
--- a/contracts/vending-minter/src/integration_tests.rs
+++ b/contracts/vending-minter/src/integration_tests.rs
@@ -29,11 +29,11 @@ const MINT_PRICE: u128 = 100_000_000;
 const MINT_FEE: u128 = 10_000_000;
 const WHITELIST_AMOUNT: u128 = 66_000_000;
 const WL_PER_ADDRESS_LIMIT: u32 = 1;
-const ADMIN_MINT_PRICE: u128 = 15_000_000;
+const ADMIN_MINT_PRICE: u128 = 0;
 const MAX_TOKEN_LIMIT: u32 = 10000;
 
 pub const MIN_MINT_PRICE: u128 = 50_000_000;
-pub const AIRDROP_MINT_PRICE: u128 = 15_000_000;
+pub const AIRDROP_MINT_PRICE: u128 = 0;
 pub const MINT_FEE_BPS: u64 = 1_000; // 10%
 pub const AIRDROP_MINT_FEE_BPS: u64 = 10_000; // 100%
 pub const SHUFFLE_FEE: u128 = 500_000_000;
@@ -1364,14 +1364,14 @@ fn mint_for_token_id_addr() {
             minter_addr.clone(),
             &mint_for_msg,
             &coins_for_msg(Coin {
-                amount: Uint128::from(ADMIN_MINT_PRICE - 1),
+                amount: Uint128::from(ADMIN_MINT_PRICE + 1),
                 denom: NATIVE_DENOM.to_string(),
             }),
         )
         .unwrap_err();
     assert_eq!(
         ContractError::IncorrectPaymentAmount(
-            coin(ADMIN_MINT_PRICE - 1, NATIVE_DENOM.to_string()),
+            coin(ADMIN_MINT_PRICE + 1, NATIVE_DENOM.to_string()),
             coin(ADMIN_MINT_PRICE, NATIVE_DENOM.to_string())
         )
         .to_string(),
diff --git a/packages/sg2/src/tests.rs b/packages/sg2/src/tests.rs
index 500e392c..e41aaba5 100644
--- a/packages/sg2/src/tests.rs
+++ b/packages/sg2/src/tests.rs
@@ -14,6 +14,7 @@ pub fn mock_collection_params() -> CollectionParams {
             image: "https://example.com/image.png".to_string(),
             external_link: Some("https://example.com/external.html".to_string()),
             trading_start_time: None,
+            explicit_content: false,
             royalty_info: Some(RoyaltyInfoResponse {
                 payment_address: "creator".to_string(),
                 share: Decimal::percent(10),