diff --git a/Cargo.lock b/Cargo.lock index 5df3b0adf..6751390c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,6 +351,7 @@ dependencies = [ "cw721-base 0.17.0", "schemars", "serde", + "thiserror", ] [[package]] diff --git a/contracts/cw2981-royalties/Cargo.toml b/contracts/cw2981-royalties/Cargo.toml index 4c265b469..d9140bc37 100644 --- a/contracts/cw2981-royalties/Cargo.toml +++ b/contracts/cw2981-royalties/Cargo.toml @@ -26,3 +26,4 @@ cw721 = { workspace = true } cw721-base = { workspace = true, features = ["library"] } schemars = { workspace = true } serde = { workspace = true } +thiserror = { workspace = true } diff --git a/contracts/cw2981-royalties/src/error.rs b/contracts/cw2981-royalties/src/error.rs new file mode 100644 index 000000000..73c0e4bb4 --- /dev/null +++ b/contracts/cw2981-royalties/src/error.rs @@ -0,0 +1,14 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Debug, Error, PartialEq)] +pub enum ContractError { + #[error(transparent)] + Std(#[from] StdError), + + #[error(transparent)] + Base(#[from] cw721_base::ContractError), + + #[error("Royalty percentage must be between 0 and 100")] + InvalidRoyaltyPercentage, +} diff --git a/contracts/cw2981-royalties/src/lib.rs b/contracts/cw2981-royalties/src/lib.rs index 4fe26e2d8..566317ac5 100644 --- a/contracts/cw2981-royalties/src/lib.rs +++ b/contracts/cw2981-royalties/src/lib.rs @@ -1,3 +1,4 @@ +pub mod error; pub mod msg; pub mod query; @@ -6,8 +7,9 @@ pub use query::{check_royalties, query_royalties_info}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{to_binary, Empty}; use cw721_base::Cw721Contract; -pub use cw721_base::{ContractError, InstantiateMsg, MinterResponse}; +pub use cw721_base::{InstantiateMsg, MinterResponse}; +use crate::error::ContractError; use crate::msg::Cw2981QueryMsg; // Version info for migration @@ -77,7 +79,25 @@ pub mod entry { info: MessageInfo, msg: ExecuteMsg, ) -> Result { - Cw2981Contract::default().execute(deps, env, info, msg) + if let ExecuteMsg::Mint { + extension: + Some(Metadata { + royalty_percentage: Some(royalty_percentage), + .. + }), + .. + } = &msg + { + // validate royalty_percentage to be between 0 and 100 + // no need to check < 0 because royalty_percentage is u64 + if *royalty_percentage > 100 { + return Err(ContractError::InvalidRoyaltyPercentage); + } + } + + Cw2981Contract::default() + .execute(deps, env, info, msg) + .map_err(Into::into) } #[entry_point] @@ -140,6 +160,36 @@ mod tests { assert_eq!(res.extension, extension); } + #[test] + fn validate_royalty_information() { + let mut deps = mock_dependencies(); + let _contract = Cw2981Contract::default(); + + let info = mock_info(CREATOR, &[]); + let init_msg = InstantiateMsg { + name: "SpaceShips".to_string(), + symbol: "SPACE".to_string(), + minter: CREATOR.to_string(), + }; + entry::instantiate(deps.as_mut(), mock_env(), info.clone(), init_msg).unwrap(); + + let token_id = "Enterprise"; + let exec_msg = ExecuteMsg::Mint { + token_id: token_id.to_string(), + owner: "john".to_string(), + token_uri: Some("https://starships.example.com/Starship/Enterprise.json".into()), + extension: Some(Metadata { + description: Some("Spaceship with Warp Drive".into()), + name: Some("Starship USS Enterprise".to_string()), + royalty_percentage: Some(101), + ..Metadata::default() + }), + }; + // mint will return StdError + let err = entry::execute(deps.as_mut(), mock_env(), info, exec_msg).unwrap_err(); + assert_eq!(err, ContractError::InvalidRoyaltyPercentage); + } + #[test] fn check_royalties_response() { let mut deps = mock_dependencies();