diff --git a/Cargo.lock b/Cargo.lock index 73b1fc1..2300607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -959,6 +959,7 @@ dependencies = [ "cw2 0.16.0", "cw721 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", "cw721-base 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pg721", "pg721-metadata-onchain", "schemars", "serde", @@ -1040,7 +1041,7 @@ dependencies = [ [[package]] name = "pg721-metadata-onchain" -version = "0.2.0" +version = "0.3.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", diff --git a/artifacts/auction_english.wasm b/artifacts/auction_english.wasm index 2dac10c..3268935 100644 Binary files a/artifacts/auction_english.wasm and b/artifacts/auction_english.wasm differ diff --git a/artifacts/checksums.txt b/artifacts/checksums.txt index f1a0cf3..f450355 100644 --- a/artifacts/checksums.txt +++ b/artifacts/checksums.txt @@ -1,13 +1,13 @@ -62ba5fa32ed8bbd6a43b8442906c6a98ad1a593bdce4af6a2485fd32aeff2d16 auction_english.wasm -dccfd7a9fe6f8c292280b79980dd6941738c2c56d5af194db9b3d94bdad6fc4d follow.wasm -d7ac0e7b68abd1b3b4ed8612ccce373b066fba044e8fda2186047a438073112a friend.wasm -61820208f932ac3e771cfbcc7115ca624e555e466b98ab6c17e134a5d6237399 marketplace_legacy.wasm -995fbd52328256930296561c8a486272cd7998761fe0cf99cf087ed923178193 marketplace_v2.wasm -aa8d7ca456732db687f93a859a882e57814a5f78c8836066a8454c22e657d522 minter.wasm -d82a4bcc8ef51dca7005851d0c059e548e1a1e1b7357158428d868b23f391138 minter_metadata_onchain.wasm -287715682a760726656e8366e6123077ee279048cad1b2a60ac17da1e7d539c0 nft_vault.wasm -0b4543555b4f053fa49e0a8d37a2f5fe0f18a2ca29c6b2243d8d3da8b9967f6b pg721.wasm -b8a55d471bd2713e2594a15077a58326b935c43ae75e4eddb8167da0c0163c41 pg721_legacy.wasm -9438a8062fcfbca53c76b76f60491112cba2edbc1a0e9532c71bb4c30091957d pg721_metadata_onchain.wasm -6e7dd43e8463f81d91bcbb83d175a1531cab72e4011fce5b4b5ea311ec87ebdc royalty_group.wasm -26cbdb6e116866c1981438185ae6198e0719708d8b735b851521eb15525c4872 whitelist.wasm +fe934edfcf99bf4af810b231303d8e8b9a09ebb7336e64de6e53483f1dea9f14 auction_english.wasm +33a363a84e22c7c1ce3ade7aeb84470969fc97b10e1c55f7ce9953f7efc9538a follow.wasm +061a91b100a07b1579f7aa27f10f3e8366d6096d4aee69a262c90c459fd4fb75 friend.wasm +67ec741014187717a9e19cb223a29f07a0f39e98764cf463a400fd9ae62e0f59 marketplace_legacy.wasm +d99776cdae47400d9285a456ed6d7d574bc7c5d6bcbbe4cc1a2900305dc84f63 marketplace_v2.wasm +4b1438a62a1d592ec68e73088e4c7a8fc5f2074e6a169fe862ee12ef0ed07a27 minter.wasm +efa70314a99cf60cb489966ab820826369b3e610e308f04b4e9f861974f35c44 minter_metadata_onchain.wasm +edc05bdc8e88efd75c61292bff809eefe0d6c03348e6ca13f0fea2caf5b89acd nft_vault.wasm +4d88c7ae224740c51ef44beb274dd71099083452c721d8d7cd909a9a1b62934b pg721.wasm +4588a67cf26c795f11e144a8e1a5f7cf4600f338a1a99df36aace992b60279d1 pg721_legacy.wasm +91329fc2ffca493dc6c0e78d7031450b7a1230ad2625d3067bfea8cb2d1a1b6f pg721_metadata_onchain.wasm +94e7a93ffd69544da9fe94302bff86769ac57ea3d8859cb2fb4761d2005a4a82 royalty_group.wasm +02057f47efaf01601a1979923d22b26c658384765ef6c382b660186760dfc88b whitelist.wasm diff --git a/artifacts/checksums_intermediate.txt b/artifacts/checksums_intermediate.txt index bc00531..1eca86a 100644 --- a/artifacts/checksums_intermediate.txt +++ b/artifacts/checksums_intermediate.txt @@ -1,13 +1,13 @@ -58735af4e08bb118cb6b4b9bb7819e5084ea5e7e98127253abc7ad068d169017 target/wasm32-unknown-unknown/release/auction_english.wasm -f1e2847148b2a634a40b57fabdfcbd5e752c1c742921743cf8598d9f5b44a0a3 target/wasm32-unknown-unknown/release/follow.wasm -296431e5b33aa80993f41c86aa166cf037a301e6aa50dfe54493fd73f4d88055 target/wasm32-unknown-unknown/release/friend.wasm -8541049c3e169da495d0cdaa6da5aa1fc2430b4a32e4795099a3106686b79949 target/wasm32-unknown-unknown/release/marketplace_legacy.wasm -13d870b87cc2582a3323d1dd44780ff79c17550e5951f31409637703ab5fe1ba target/wasm32-unknown-unknown/release/marketplace_v2.wasm -d31e544b669e61af2ae1942b0ac5e94c6d51472a69c7b80f92365aa8004c9436 target/wasm32-unknown-unknown/release/minter.wasm -ca2003c7fdadc10be1bdbe2164dcddcee4f13c5f43e0678dafc72e7a66747375 target/wasm32-unknown-unknown/release/minter_metadata_onchain.wasm -fb8de512291ddda27e24a222d698ac3b15e778261d50d8479c741d43e740f47c target/wasm32-unknown-unknown/release/nft_vault.wasm -06108ce86ec17b8debedcac200b1e8d1be025037883269ff39107cc1c5998b80 target/wasm32-unknown-unknown/release/pg721.wasm -6635fc111eae087bb33610bb14aed0bfe7e347567442030eabb45209f3928e4f target/wasm32-unknown-unknown/release/pg721_legacy.wasm -8222b3586f55473b30ccec1a80e798e04f05b7ce491f9f3911f4c1eeaeb5ed25 target/wasm32-unknown-unknown/release/pg721_metadata_onchain.wasm -8873c4e7fc6d73b74b7abf057707d77feea7a139dad12d74a662de192e903c83 target/wasm32-unknown-unknown/release/royalty_group.wasm -9d571d50284840e4ce4895a4534a2f6424dd6e7056b0d8dd412580fd75e3386b target/wasm32-unknown-unknown/release/whitelist.wasm +4b6aef9a3a723313627d93ff61d61e5c6ec05aa35884d4e71554d2cc7f951ba4 target/wasm32-unknown-unknown/release/auction_english.wasm +f153cbb1a894b6c438847b14788fb4451b48a80dabfb56efbd51c8029e673eb2 target/wasm32-unknown-unknown/release/follow.wasm +da40aa647b5b9dfc3d8c8b0c1fbb2dc84d7926d13393c8af764b91104efccad6 target/wasm32-unknown-unknown/release/friend.wasm +51a1292ccf72cf65823bd2dd61be454dafe1e26fba346ebfae2f1fbb615f3fdb target/wasm32-unknown-unknown/release/marketplace_legacy.wasm +76644a7029667479508fec38c5c50b18ea849cef92923712be49df7833f5e7ef target/wasm32-unknown-unknown/release/marketplace_v2.wasm +6f82de16b47e7946d5b97632f2324320b14308903913ce66a22c2c3cf21ef1d3 target/wasm32-unknown-unknown/release/nft_vault.wasm +09fbc1368b7e6b8b12e82c639ce70ae85838ee10056ce2840391d8702b7f0b17 target/wasm32-unknown-unknown/release/royalty_group.wasm +565e37388c8783e229c89522fe69a49b8beb3f68cc029d9fdd55768c06d6fd67 target/wasm32-unknown-unknown/release/whitelist.wasm +e843ca3447ff9025fa41359478c9b5ffb3dce6af6035f8af7ff919bccd51e902 target/wasm32-unknown-unknown/release/minter.wasm +84c6af042ebb2c27e3804460aa2c84f9099711f430151e4b70f3a079bbcad84b target/wasm32-unknown-unknown/release/pg721.wasm +a5958ad5857e759f42083b2e43370db0e81d537231bebb877d38f1542dbf92d5 target/wasm32-unknown-unknown/release/pg721_legacy.wasm +54727af070dbd68ba61f0db5f741fb52cc9857b13a5c9680674317a12cc27f45 target/wasm32-unknown-unknown/release/minter_metadata_onchain.wasm +121aab9ab64e37bc66c3eb6260fa78dc5334f719aeb4883db4079ec007d6f773 target/wasm32-unknown-unknown/release/pg721_metadata_onchain.wasm diff --git a/artifacts/follow.wasm b/artifacts/follow.wasm index c5e47d3..4845ffd 100644 Binary files a/artifacts/follow.wasm and b/artifacts/follow.wasm differ diff --git a/artifacts/friend.wasm b/artifacts/friend.wasm index 58b4c0d..92ff9b1 100644 Binary files a/artifacts/friend.wasm and b/artifacts/friend.wasm differ diff --git a/artifacts/marketplace_legacy.wasm b/artifacts/marketplace_legacy.wasm index ce452a6..5ff2cfa 100644 Binary files a/artifacts/marketplace_legacy.wasm and b/artifacts/marketplace_legacy.wasm differ diff --git a/artifacts/marketplace_v2.wasm b/artifacts/marketplace_v2.wasm index 2444170..eb2b33d 100644 Binary files a/artifacts/marketplace_v2.wasm and b/artifacts/marketplace_v2.wasm differ diff --git a/artifacts/minter.wasm b/artifacts/minter.wasm index 33892e5..6257efe 100644 Binary files a/artifacts/minter.wasm and b/artifacts/minter.wasm differ diff --git a/artifacts/minter_metadata_onchain.wasm b/artifacts/minter_metadata_onchain.wasm index a4b22eb..bfdaf1a 100644 Binary files a/artifacts/minter_metadata_onchain.wasm and b/artifacts/minter_metadata_onchain.wasm differ diff --git a/artifacts/nft_vault.wasm b/artifacts/nft_vault.wasm index 8b023e2..75c5608 100644 Binary files a/artifacts/nft_vault.wasm and b/artifacts/nft_vault.wasm differ diff --git a/artifacts/pg721.wasm b/artifacts/pg721.wasm index 177ede8..130f63c 100644 Binary files a/artifacts/pg721.wasm and b/artifacts/pg721.wasm differ diff --git a/artifacts/pg721_legacy.wasm b/artifacts/pg721_legacy.wasm index 0d97e3d..bcda7ef 100644 Binary files a/artifacts/pg721_legacy.wasm and b/artifacts/pg721_legacy.wasm differ diff --git a/artifacts/pg721_metadata_onchain.wasm b/artifacts/pg721_metadata_onchain.wasm index be46393..b53ce7b 100644 Binary files a/artifacts/pg721_metadata_onchain.wasm and b/artifacts/pg721_metadata_onchain.wasm differ diff --git a/artifacts/royalty_group.wasm b/artifacts/royalty_group.wasm index a637721..adf8232 100644 Binary files a/artifacts/royalty_group.wasm and b/artifacts/royalty_group.wasm differ diff --git a/artifacts/whitelist.wasm b/artifacts/whitelist.wasm index 5cbde33..015e58e 100644 Binary files a/artifacts/whitelist.wasm and b/artifacts/whitelist.wasm differ diff --git a/contracts/nft/minter-metadata-onchain/Cargo.toml b/contracts/nft/minter-metadata-onchain/Cargo.toml index 335e447..1f8f605 100644 --- a/contracts/nft/minter-metadata-onchain/Cargo.toml +++ b/contracts/nft/minter-metadata-onchain/Cargo.toml @@ -29,6 +29,7 @@ cw-utils = "0.16.0" schemars = "0.8.8" serde = { version = "1.0.133", default-features = false, features = ["derive"] } pg721-metadata-onchain = { path = "../pg721-metadata-onchain", features = ["library"] } +pg721 = { path = "../pg721", features = ["library"] } thiserror = { version = "1.0" } whitelist = { path = "../whitelist", features = ["library"] } cw721 = "0.13.1" diff --git a/contracts/nft/minter-metadata-onchain/src/contract.rs b/contracts/nft/minter-metadata-onchain/src/contract.rs index 2f11265..504e107 100644 --- a/contracts/nft/minter-metadata-onchain/src/contract.rs +++ b/contracts/nft/minter-metadata-onchain/src/contract.rs @@ -12,12 +12,13 @@ use cw_utils::{may_pay, parse_reply_instantiate_data}; use pg721_metadata_onchain::msg::{ InstantiateMsg as Pg721InstantiateMsg, ExecuteMsg as Pg721ExecuteMsg, Metadata }; +use pg721::state::{MIGRATION_STATUS,MigrationStatus,migration_done,migration_status}; use crate::error::ContractError; use crate::msg::{ ConfigResponse, ExecuteMsg, InstantiateMsg, MintCountResponse, MintPriceResponse, QueryMsg, StartTimeResponse, TokenMetadata, TokenMintResponse, TokenMintsResponse, - NumMintedResponse, NumRemainingResponse, MigrateMsg + NumMintedResponse, NumRemainingResponse, MigrateMsg, Minter }; use crate::state::{ CONFIG, MINTER_ADDRS, CW721_ADDRESS, MINTABLE_TOKEN_IDS, @@ -89,6 +90,12 @@ pub fn instantiate( }; CONFIG.save(deps.storage, &config)?; MINTABLE_TOKEN_IDS.save(deps.storage, &vec![])?; + + let migration_status=MigrationStatus{ + done: false, + }; + + MIGRATION_STATUS.save(deps.storage, &migration_status)?; let response = match msg.cw721_address { Some(_addr) => { @@ -108,8 +115,8 @@ pub fn instantiate( minter: env.contract.address.to_string(), collection_info: cw721_instantiate_msg.collection_info, })?, - funds: info.funds, - admin: Some(info.sender.to_string()), + funds: info.funds.clone(), + admin: Some(info.sender.clone().to_string()), label: String::from("Fixed price minter"), } .into(), @@ -138,26 +145,58 @@ pub fn execute( let api = deps.api; match msg { - ExecuteMsg::UpsertTokenMetadatas { token_metadatas } => execute_upsert_token_metadatas(deps, info, token_metadatas ), - ExecuteMsg::Mint {} => execute_mint_sender(deps, env, info), - ExecuteMsg::UpdateStartTime(time) => execute_update_start_time(deps, env, info, time), - ExecuteMsg::UpdatePerAddressLimit { per_address_limit } => { - execute_update_per_address_limit(deps, env, info, per_address_limit) - } - ExecuteMsg::UpdateUnitPrice { unit_price } => execute_update_unit_price(deps, env, info, unit_price), - ExecuteMsg::MintTo { recipient } => execute_mint_to(deps, env, info, recipient), - ExecuteMsg::MintFor { - token_id, - recipient, - } => execute_mint_for(deps, env, info, token_id, recipient), - ExecuteMsg::SetAdmin { admin } => execute_set_admin(deps, info, api.addr_validate(&admin)?), - ExecuteMsg::SetWhitelist { whitelist } => { - execute_set_whitelist(deps, env, info, &whitelist) + ExecuteMsg::MigrateData { migrations } => migrate_tokens(deps, info, migrations.tokens, migrations.mintable_tokens, migrations.minters), + ExecuteMsg::MigrationDone { } => migrated(deps, info), + _ => { + if migration_status(deps.as_ref()){ + match msg { + ExecuteMsg::UpsertTokenMetadatas { token_metadatas } => execute_upsert_token_metadatas(deps, info, token_metadatas ), + ExecuteMsg::Mint {} => execute_mint_sender(deps, env, info), + ExecuteMsg::UpdateStartTime(time) => execute_update_start_time(deps, env, info, time), + ExecuteMsg::UpdatePerAddressLimit { per_address_limit } => { + execute_update_per_address_limit(deps, env, info, per_address_limit) + } + ExecuteMsg::UpdateUnitPrice { unit_price } => execute_update_unit_price(deps, env, info, unit_price), + ExecuteMsg::MintTo { recipient } => execute_mint_to(deps, env, info, recipient), + ExecuteMsg::MintFor { + token_id, + recipient, + } => execute_mint_for(deps, env, info, token_id, recipient), + ExecuteMsg::SetAdmin { admin } => execute_set_admin(deps, info, api.addr_validate(&admin)?), + ExecuteMsg::SetWhitelist { whitelist } => { + execute_set_whitelist(deps, env, info, &whitelist) + } + ExecuteMsg::Withdraw { recipient } => execute_withdraw(deps, env, info, api.addr_validate(&recipient)?), + ExecuteMsg::MigrateData { migrations:_ } => return Err(ContractError::MigrationDone { }), + ExecuteMsg::MigrationDone { } => migrated(deps, info), + } + } else { + return Err(ContractError::MigrationInProgress { }) + } } - ExecuteMsg::Withdraw { recipient } => execute_withdraw(deps, env, info, api.addr_validate(&recipient)?), } } +fn migrated( + deps: DepsMut, + info: MessageInfo, +)->Result{ + + let config = CONFIG.load(deps.storage)?; + if config.admin != info.sender { + return Err(ContractError::Unauthorized( + "Sender is not an admin".to_owned(), + )); + }; + + migration_done(deps)?; + + Ok(Response::new() + .add_attribute("action", "migration_done") + .add_attribute("marked done as", true.to_string()) + ) +} + pub fn execute_upsert_token_metadatas( deps: DepsMut, info: MessageInfo, @@ -208,6 +247,86 @@ pub fn execute_upsert_token_metadatas( Ok(response) } +fn migrate_tokens( + deps: DepsMut, + info: MessageInfo, + tokens: Option>, + mintable_ids: Option>, + minters: Option> +) -> Result { + + if migration_status(deps.as_ref()){ + return Err(ContractError::MigrationDone { }); + } + + let config = CONFIG.load(deps.storage)?; + if config.admin != info.sender { + return Err(ContractError::Unauthorized( + "Sender is not an admin".to_owned(), + )); + }; + + // migrate token mints + let mut append_token_ids = vec![]; + if tokens.is_some(){ + for token in tokens.unwrap_or_default() { + if token.token_id == 0 { + return Err(ContractError::InvalidTokenId {}); + } + token_mints().update( + deps.storage, + token.token_id.clone(), + |existing_token_mint| -> Result { + if let Some(_existing_token_mint) = existing_token_mint { + if let true = _existing_token_mint.is_minted { + return Err(ContractError::TokenAlreadyMinted { token_id: _existing_token_mint.token_id }); + } + }; + Ok(TokenMint { + token_id: token.clone().token_id, + metadata: token.clone().metadata, + is_minted: token.is_minted, + }) + } + )?; + append_token_ids.push(token.token_id); + } + } + + // migrate minters + if minters.is_some(){ + for minter in minters.clone().unwrap_or_default() { + MINTER_ADDRS.save(deps.storage, Addr::unchecked(minter.address), &minter.mints)?; + } + } + + + // migrate mintable tokens + if mintable_ids.is_some(){ + let mut mintable_token_ids = MINTABLE_TOKEN_IDS.load(deps.storage)?; + mintable_token_ids.append(&mut &mut mintable_ids.clone().unwrap_or_default()); + MINTABLE_TOKEN_IDS.save(deps.storage, &mintable_token_ids)?; + } + + + + // response + let mut response = Response::new(); + let append_token_ids_fmt: Vec = append_token_ids + .into_iter().map(|token_id| token_id.to_string()).collect(); + let mut event = Event::new("migrate data") + .add_attribute("mintable-ids",mintable_ids.is_some().to_string()) + .add_attribute("minters", minters.is_some().to_string()); + + if append_token_ids_fmt.len()>0{ + event=event.add_attribute("token-ids",append_token_ids_fmt.join(",")) + } + + response.events.push(event); + + Ok(response) +} + pub fn execute_withdraw( deps: DepsMut, env: Env, diff --git a/contracts/nft/minter-metadata-onchain/src/error.rs b/contracts/nft/minter-metadata-onchain/src/error.rs index 1251e92..3b4ea4b 100644 --- a/contracts/nft/minter-metadata-onchain/src/error.rs +++ b/contracts/nft/minter-metadata-onchain/src/error.rs @@ -81,4 +81,10 @@ pub enum ContractError { #[error("{0}")] Payment(#[from] PaymentError), + + #[error("Migration in progress")] + MigrationInProgress{}, + + #[error("Migration completed")] + MigrationDone{}, } diff --git a/contracts/nft/minter-metadata-onchain/src/msg.rs b/contracts/nft/minter-metadata-onchain/src/msg.rs index ea1fa2c..b6e18fe 100644 --- a/contracts/nft/minter-metadata-onchain/src/msg.rs +++ b/contracts/nft/minter-metadata-onchain/src/msg.rs @@ -30,6 +30,8 @@ pub enum ExecuteMsg { MintTo { recipient: String }, MintFor { token_id: u32, recipient: String }, Withdraw { recipient: String }, + MigrateData {migrations: Migration}, + MigrationDone{}, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -109,3 +111,16 @@ pub struct TokenMetadata { pub token_id: u32, pub metadata: Metadata } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Migration{ + pub tokens: Option>, + pub mintable_tokens: Option>, + pub minters: Option>, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Minter{ + pub address: String, + pub mints: u32 +} \ No newline at end of file diff --git a/contracts/nft/pg721-metadata-onchain/Cargo.toml b/contracts/nft/pg721-metadata-onchain/Cargo.toml index ea29c74..44daf7f 100644 --- a/contracts/nft/pg721-metadata-onchain/Cargo.toml +++ b/contracts/nft/pg721-metadata-onchain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pg721-metadata-onchain" -version = "0.2.0" +version = "0.3.0" authors = ["Tasio Victoria "] edition = "2018" description = "Passage NFT collection contract with the metadata stored onchain" diff --git a/contracts/nft/pg721-metadata-onchain/examples/schema.rs b/contracts/nft/pg721-metadata-onchain/examples/schema.rs index 3a4b366..cadc12a 100644 --- a/contracts/nft/pg721-metadata-onchain/examples/schema.rs +++ b/contracts/nft/pg721-metadata-onchain/examples/schema.rs @@ -12,7 +12,6 @@ use cw721_base::{ MinterResponse }; use pg721_metadata_onchain::msg::{CollectionInfoResponse, InstantiateMsg, QueryMsg, ExecuteMsg}; - fn main() { let mut out_dir = current_dir().unwrap(); out_dir.push("schema"); diff --git a/contracts/nft/pg721-metadata-onchain/src/contract.rs b/contracts/nft/pg721-metadata-onchain/src/contract.rs index 8315597..2f2c550 100644 --- a/contracts/nft/pg721-metadata-onchain/src/contract.rs +++ b/contracts/nft/pg721-metadata-onchain/src/contract.rs @@ -5,14 +5,14 @@ use cw2::{set_contract_version, get_contract_version}; use crate::ContractError; use cw721::ContractInfoResponse; -use cw721_base::ContractError as BaseError; +use cw721_base::{ContractError as BaseError, MintMsg}; use url::Url; use crate::msg::{ CollectionInfoResponse, InstantiateMsg, QueryMsg, RoyaltyInfoResponse, Extension, ExecuteMsg, MigrateMsg }; -use crate::state::{CollectionInfo, RoyaltyInfo, COLLECTION_INFO}; +use crate::state::{CollectionInfo, RoyaltyInfo, COLLECTION_INFO,MIGRATION_STATUS,MigrationStatus,migration_status,migration_done}; pub type Pg721MetadataContract<'a> = cw721_base::Cw721Contract<'a, Extension, Empty>; @@ -76,6 +76,12 @@ pub fn instantiate( COLLECTION_INFO.save(deps.storage, &collection_info)?; + let migration_status=MigrationStatus{ + done: false, + }; + + MIGRATION_STATUS.save(deps.storage, &migration_status)?; + Ok(Response::default() .add_attribute("action", "instantiate") .add_attribute("contract_name", CONTRACT_NAME) @@ -90,7 +96,79 @@ pub fn execute( info: MessageInfo, msg: ExecuteMsg, ) -> Result { - Pg721MetadataContract::default().execute(deps, env, info, msg) + match msg{ + ExecuteMsg::Migrate{migrations}=>migrate_data(deps,env,info,migrations), + ExecuteMsg::MigrationDone{}=>migrated(deps, info), + _ => if migration_status(deps.as_ref()){ + Pg721MetadataContract::default().execute(deps, env, info, msg.into()) + } else { + return Err(ContractError::MigrationInProgress { }.into()); + }, + } +} + +fn migrate_data( + deps: DepsMut, + env: Env, + info: MessageInfo, + migrations: Vec>, +)-> Result{ + + // check migration status + if migration_status(deps.as_ref()){ + return Err(ContractError::MigrationDone { }.into()); + } + + // verify sender == minter + let minter = Pg721MetadataContract::default().minter.load(deps.storage)?; + if info.sender != minter { + return Err(BaseError::Unauthorized {}); + } + + // migrate tokens + for migration in migrations.into_iter(){ + let new_deps = DepsMut { storage: deps.storage, api: deps.api, querier: deps.querier }; + let exce_msg=ExecuteMsg::Mint(migration.clone()); + let res = Pg721MetadataContract::default().execute(new_deps, env.clone(), info.clone(), exce_msg.into()); + + match res { + Ok(response) => { + for attribute in response.attributes.iter() { + if attribute.key == "token_id" { + if attribute.value != migration.token_id { + return Err(ContractError::MintFalied(migration.token_id).into()); + } + } + } + }, + Err(error) => { + // Handle the error case + return Err(ContractError::MigrationFailed(error).into()); + } + } + } + + Ok(Response::new() + .add_attribute("action", "migrated") + .add_attribute("minter", info.sender)) +} + +fn migrated( + deps: DepsMut, + info: MessageInfo, +)->Result{ + // verify sender == minter + let minter = Pg721MetadataContract::default().minter.load(deps.storage)?; + if info.sender != minter { + return Err(BaseError::Unauthorized {}); + } + + migration_done(deps)?; + + Ok(Response::new() + .add_attribute("action", "migration_done") + .add_attribute("marked done as", true.to_string()) + ) } #[cfg_attr(not(feature = "library"), entry_point)] @@ -149,9 +227,11 @@ pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result = from_binary(&nft_res).unwrap(); + + let metadata = Metadata{ + name: Some("test nft".to_string()), + ..Default::default() + }; + + let nft = NftInfoResponse{ + token_uri: None, + extension: Some(metadata) + }; + assert_eq!(nft,nft_info) } #[test] diff --git a/contracts/nft/pg721-metadata-onchain/src/msg.rs b/contracts/nft/pg721-metadata-onchain/src/msg.rs index 3630278..f0af1c7 100644 --- a/contracts/nft/pg721-metadata-onchain/src/msg.rs +++ b/contracts/nft/pg721-metadata-onchain/src/msg.rs @@ -1,5 +1,8 @@ use serde::{Deserialize, Serialize}; use schemars::JsonSchema; +use cw721_base::{ExecuteMsg as Cw721ExecuteMsg,MintMsg}; +use cw721::Expiration; +use cosmwasm_std::Binary; pub use pg721::msg::*; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] @@ -23,7 +26,65 @@ pub struct Metadata { } pub type Extension = Option; -pub type ExecuteMsg = cw721_base::ExecuteMsg; + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub enum ExecuteMsg { + /// Transfer is a base message to move a token to another account without triggering actions + TransferNft { recipient: String, token_id: String }, + /// Send is a base message to transfer a token to a contract and trigger an action + /// on the receiving contract. + SendNft { + contract: String, + token_id: String, + msg: Binary, + }, + /// Allows operator to transfer / send the token from the owner's account. + /// If expiration is set, then this allowance has a time/height limit + Approve { + spender: String, + token_id: String, + expires: Option, + }, + /// Remove previously granted Approval + Revoke { spender: String, token_id: String }, + /// Allows operator to transfer / send any token from the owner's account. + /// If expiration is set, then this allowance has a time/height limit + ApproveAll { + operator: String, + expires: Option, + }, + /// Remove previously granted ApproveAll permission + RevokeAll { operator: String }, + + /// Mint a new NFT, can only be called by the contract minter + Mint(MintMsg), + + /// Burn an NFT the sender has access to + Burn { token_id: String }, + + // Migrate data + Migrate { migrations: Vec> }, + + // Migration done + MigrationDone{}, +} + +impl From for Cw721ExecuteMsg{ + fn from(msg: ExecuteMsg) -> Cw721ExecuteMsg{ + match msg { + ExecuteMsg::TransferNft { recipient, token_id } => Cw721ExecuteMsg::TransferNft { recipient, token_id }, + ExecuteMsg::SendNft { contract, token_id, msg } =>Cw721ExecuteMsg::SendNft { contract, token_id, msg }, + ExecuteMsg::Approve { spender, token_id, expires }=>Cw721ExecuteMsg::Approve { spender, token_id, expires }, + ExecuteMsg::ApproveAll { operator, expires } => Cw721ExecuteMsg::ApproveAll { operator, expires }, + ExecuteMsg::Revoke { spender, token_id }=>Cw721ExecuteMsg::Revoke { spender, token_id }, + ExecuteMsg::RevokeAll { operator }=>Cw721ExecuteMsg::RevokeAll { operator }, + ExecuteMsg::Mint(MintMsg { token_id, owner, token_uri, extension })=>Cw721ExecuteMsg::Mint(MintMsg { token_id, owner, token_uri, extension }), + ExecuteMsg::Burn { token_id }=>Cw721ExecuteMsg::Burn { token_id }, + _ => unreachable!("cannot convert {:?} to Cw721QueryMsg", msg), + } + } +} #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] pub struct MigrateMsg { diff --git a/contracts/nft/pg721/src/contract.rs b/contracts/nft/pg721/src/contract.rs index 9d08dde..aa0ee98 100644 --- a/contracts/nft/pg721/src/contract.rs +++ b/contracts/nft/pg721/src/contract.rs @@ -11,7 +11,7 @@ use url::Url; use crate::msg::{ CollectionInfoResponse, ExecuteMsg, InstantiateMsg, QueryMsg, RoyaltyInfoResponse, }; -use crate::state::{CollectionInfo, RoyaltyInfo, COLLECTION_INFO}; +use crate::state::{CollectionInfo, RoyaltyInfo, COLLECTION_INFO, MIGRATION_STATUS, MigrationStatus}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:pg-721"; @@ -75,6 +75,12 @@ pub fn instantiate( COLLECTION_INFO.save(deps.storage, &collection_info)?; + let migration_status=MigrationStatus{ + done: false, + }; + + MIGRATION_STATUS.save(deps.storage, &migration_status)?; + Ok(Response::default() .add_attribute("action", "instantiate") .add_attribute("contract_name", CONTRACT_NAME) @@ -145,7 +151,7 @@ mod tests { royalty_info: royalty_info, }, }; - let info = mock_info("creator", &coins(0, NATIVE_DENOM)); + let info = mock_info("minter", &coins(0, NATIVE_DENOM)); let res = instantiate(deps, mock_env(), info.clone(), msg).unwrap(); assert!(res.attributes[0].eq(&Attribute::new("action", "instantiate"))); assert!(res.attributes[1].eq(&Attribute::new("contract_name", CONTRACT_NAME))); diff --git a/contracts/nft/pg721/src/error.rs b/contracts/nft/pg721/src/error.rs index 14de977..93fffa4 100644 --- a/contracts/nft/pg721/src/error.rs +++ b/contracts/nft/pg721/src/error.rs @@ -35,6 +35,18 @@ pub enum ContractError { #[error("{0}")] Parse(#[from] ParseError), + + #[error("Migration failed {0}")] + MigrationFailed(Cw721ContractError), + + #[error("Mint failed for token id {0}")] + MintFalied(String), + + #[error("Migration in progress")] + MigrationInProgress{}, + + #[error("Migration completed")] + MigrationDone{}, } impl From for Cw721ContractError { @@ -43,6 +55,8 @@ impl From for Cw721ContractError { ContractError::Unauthorized {} => Cw721ContractError::Unauthorized {}, ContractError::Claimed {} => Cw721ContractError::Claimed {}, ContractError::Expired {} => Cw721ContractError::Expired {}, + ContractError::MigrationInProgress { }=>Cw721ContractError::Std(StdError::GenericErr { msg: "migration in progress".to_string() }), + ContractError::MigrationDone { }=>Cw721ContractError::Std(StdError::GenericErr { msg: "migration completed: cannont start again".to_string() }), _ => unreachable!("cannot convert {:?} to Cw721ContractError", err), } } diff --git a/contracts/nft/pg721/src/msg.rs b/contracts/nft/pg721/src/msg.rs index b8cd1c1..04f139c 100644 --- a/contracts/nft/pg721/src/msg.rs +++ b/contracts/nft/pg721/src/msg.rs @@ -1,6 +1,6 @@ use crate::{state::CollectionInfo, ContractError}; use cosmwasm_std::{Decimal, Empty}; -use cw721_base::msg::QueryMsg as Cw721QueryMsg; +use cw721_base::{msg::QueryMsg as Cw721QueryMsg}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/contracts/nft/pg721/src/state.rs b/contracts/nft/pg721/src/state.rs index beb5151..07c84e5 100644 --- a/contracts/nft/pg721/src/state.rs +++ b/contracts/nft/pg721/src/state.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Decimal}; +use cosmwasm_std::{Addr, Decimal, DepsMut, StdResult, Deps}; use cw_storage_plus::Item; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -18,4 +18,23 @@ pub struct RoyaltyInfo { pub share: Decimal, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct MigrationStatus { + pub done: bool, +} + +// marks migrations as done +pub fn migration_done(deps: DepsMut) -> StdResult<()>{ + let mut status=MIGRATION_STATUS.load(deps.storage)?; + status.done=true; + MIGRATION_STATUS.save(deps.storage, &status) +} + +// returns true if migration is done +pub fn migration_status(deps: Deps) -> bool { + let status = MIGRATION_STATUS.load(deps.storage).unwrap(); + return status.done; +} + pub const COLLECTION_INFO: Item> = Item::new("collection_info"); +pub const MIGRATION_STATUS: Item = Item::new("migration_status"); \ No newline at end of file