From 0ca58b541d88c2bbb2c2d34ab2b218f744c7b23d Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 14:45:29 -0700 Subject: [PATCH 01/12] MVP cw721-template --- Cargo.lock | 1 + contracts/cw721-template/.cargo/config | 5 + .../.github/workflows/basic.yml | 69 + contracts/cw721-template/Cargo.toml | 27 + contracts/cw721-template/NOTICE | 14 + contracts/cw721-template/README.md | 64 + contracts/cw721-template/cargo-generate.toml | 5 + contracts/cw721-template/examples/schema.rs | 11 + .../schema/cw721-metadata-onchain.json | 1769 +++++++++++++++++ contracts/cw721-template/src/lib.rs | 134 ++ contracts/cw721-template/test_generate.sh | 38 + 11 files changed, 2137 insertions(+) create mode 100644 contracts/cw721-template/.cargo/config create mode 100644 contracts/cw721-template/.github/workflows/basic.yml create mode 100644 contracts/cw721-template/Cargo.toml create mode 100644 contracts/cw721-template/NOTICE create mode 100644 contracts/cw721-template/README.md create mode 100644 contracts/cw721-template/cargo-generate.toml create mode 100644 contracts/cw721-template/examples/schema.rs create mode 100644 contracts/cw721-template/schema/cw721-metadata-onchain.json create mode 100644 contracts/cw721-template/src/lib.rs create mode 100644 contracts/cw721-template/test_generate.sh diff --git a/Cargo.lock b/Cargo.lock index 757b0c3d6..ae91ac352 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,6 +462,7 @@ version = "0.17.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", + "cw-ownable", "cw-storage-plus 1.0.1", "cw2 1.0.1 (git+https://github.com/mars-protocol/cw-plus?rev=1a3a944)", "cw721 0.17.0", diff --git a/contracts/cw721-template/.cargo/config b/contracts/cw721-template/.cargo/config new file mode 100644 index 000000000..7d1a066c8 --- /dev/null +++ b/contracts/cw721-template/.cargo/config @@ -0,0 +1,5 @@ +[alias] +wasm = "build --release --target wasm32-unknown-unknown" +wasm-debug = "build --target wasm32-unknown-unknown" +unit-test = "test --lib" +schema = "run --example schema" diff --git a/contracts/cw721-template/.github/workflows/basic.yml b/contracts/cw721-template/.github/workflows/basic.yml new file mode 100644 index 000000000..8cb3dfd08 --- /dev/null +++ b/contracts/cw721-template/.github/workflows/basic.yml @@ -0,0 +1,69 @@ +# Based on https://github.com/actions-rs/example/blob/master/.github/workflows/quickstart.yml +# As well as: https://github.com/DA0-DA0/dao-contracts/blob/main/.github/workflows/basic.yml + +on: [push, pull_request] + +name: Basic + +jobs: + test: + name: Test Suite + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install latest nightly toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + target: wasm32-unknown-unknown + override: true + + - name: Run tests + uses: actions-rs/cargo@v1 + with: + toolchain: nightly + command: unit-test + args: --locked + env: + RUST_BACKTRACE: 1 + + - name: Compile WASM contract + uses: actions-rs/cargo@v1 + with: + toolchain: nightly + command: wasm + args: --locked + env: + RUSTFLAGS: "-C link-arg=-s" + + lints: + name: Lints + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rustfmt, clippy + + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + toolchain: nightly + command: fmt + args: --all -- --check + + - name: Run cargo clippy + uses: actions-rs/cargo@v1 + with: + toolchain: nightly + command: clippy + args: --all-targets -- -D warnings diff --git a/contracts/cw721-template/Cargo.toml b/contracts/cw721-template/Cargo.toml new file mode 100644 index 000000000..f5573a4d1 --- /dev/null +++ b/contracts/cw721-template/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "{{project-name}}" +description = "A custom cw721 NFT contract." +version = "0.1.0" +authors = ["{{authors}}"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +cosmwasm-schema = "1.2.1" +cosmwasm-std = "1.2.1" +cw2 = "1.0.1" +cw20 = "1.0.1" +cw721 = "0.17.0" +cw721-base = { version = "0.17.0", features = ["library"] } +schemars = "0.8.11" +serde = { version = "1.0.152", default-features = false, features = ["derive"] } diff --git a/contracts/cw721-template/NOTICE b/contracts/cw721-template/NOTICE new file mode 100644 index 000000000..bd298d741 --- /dev/null +++ b/contracts/cw721-template/NOTICE @@ -0,0 +1,14 @@ +Cw721_metadata_onchain +Copyright (C) 2021 Confio OÜ + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/contracts/cw721-template/README.md b/contracts/cw721-template/README.md new file mode 100644 index 000000000..dd449656e --- /dev/null +++ b/contracts/cw721-template/README.md @@ -0,0 +1,64 @@ +# CW721 Metadata Onchain + +NFT creators may want to store their NFT metadata on-chain so other contracts are able to interact with it. +With CW721-Base in CosmWasm, we allow you to store any data on chain you wish, using a generic `extension: T`. + +In order to support on-chain metadata, and to demonstrate how to use the extension ability, we have created this simple contract. +There is no business logic here, but looking at `lib.rs` will show you how do define custom data that is included when minting and +available in all queries. + +In particular, here we define: + +```rust +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct Trait { + pub display_type: Option, + pub trait_type: String, + pub value: String, +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct Metadata { + pub image: Option, + pub image_data: Option, + pub external_url: Option, + pub description: Option, + pub name: Option, + pub attributes: Option>, + pub background_color: Option, + pub animation_url: Option, + pub youtube_url: Option, +} + +pub type Extension = Option; +``` + +In particular, the fields defined conform to the properties supported in the [OpenSea Metadata Standard](https://docs.opensea.io/docs/metadata-standards). + + +This means when you query `NftInfo{name: "Enterprise"}`, you will get something like: + +```json +{ + "name": "Enterprise", + "token_uri": "https://starships.example.com/Starship/Enterprise.json", + "extension": { + "image": null, + "image_data": null, + "external_url": null, + "description": "Spaceship with Warp Drive", + "name": "Starship USS Enterprise", + "attributes": null, + "background_color": null, + "animation_url": null, + "youtube_url": null + } +} +``` + +Please look at the test code for an example usage in Rust. + +## Notice + +Feel free to use this contract out of the box, or as inspiration for further customization of cw721-base. +We will not be adding new features or business logic here. diff --git a/contracts/cw721-template/cargo-generate.toml b/contracts/cw721-template/cargo-generate.toml new file mode 100644 index 000000000..2270694dc --- /dev/null +++ b/contracts/cw721-template/cargo-generate.toml @@ -0,0 +1,5 @@ +[placeholders.minimal] +type = "bool" +prompt = """The full template includes more example code on how to extend a basic cw721 contract. +Would you still like to generate the minimal template?""" +default = false diff --git a/contracts/cw721-template/examples/schema.rs b/contracts/cw721-template/examples/schema.rs new file mode 100644 index 000000000..c713a8bb4 --- /dev/null +++ b/contracts/cw721-template/examples/schema.rs @@ -0,0 +1,11 @@ +use cosmwasm_schema::write_api; + +use {{crate_name}}::{ExecuteMsg, InstantiateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + execute: ExecuteMsg, + query: QueryMsg, + } +} diff --git a/contracts/cw721-template/schema/cw721-metadata-onchain.json b/contracts/cw721-template/schema/cw721-metadata-onchain.json new file mode 100644 index 000000000..7115bad36 --- /dev/null +++ b/contracts/cw721-template/schema/cw721-metadata-onchain.json @@ -0,0 +1,1769 @@ +{ + "contract_name": "cw721-metadata-onchain", + "contract_version": "0.17.0", + "idl_version": "1.0.0", + "instantiate": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "minter", + "name", + "symbol" + ], + "properties": { + "minter": { + "description": "The minter is the only one who can create new NFTs. This is designed for a base NFT that is controlled by an external program or contract. You will likely replace this with custom logic in custom NFTs", + "type": "string" + }, + "name": { + "description": "Name of the NFT contract", + "type": "string" + }, + "symbol": { + "description": "Symbol of the NFT contract", + "type": "string" + } + }, + "additionalProperties": false + }, + "execute": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "description": "This is like Cw721ExecuteMsg but we add a Mint command for an owner to make this stand-alone. You will likely want to remove mint and use other control logic in any contract that inherits this.", + "oneOf": [ + { + "description": "Transfer is a base message to move a token to another account without triggering actions", + "type": "object", + "required": [ + "transfer_nft" + ], + "properties": { + "transfer_nft": { + "type": "object", + "required": [ + "recipient", + "token_id" + ], + "properties": { + "recipient": { + "type": "string" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Send is a base message to transfer a token to a contract and trigger an action on the receiving contract.", + "type": "object", + "required": [ + "send_nft" + ], + "properties": { + "send_nft": { + "type": "object", + "required": [ + "contract", + "msg", + "token_id" + ], + "properties": { + "contract": { + "type": "string" + }, + "msg": { + "$ref": "#/definitions/Binary" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allows operator to transfer / send the token from the owner's account. If expiration is set, then this allowance has a time/height limit", + "type": "object", + "required": [ + "approve" + ], + "properties": { + "approve": { + "type": "object", + "required": [ + "spender", + "token_id" + ], + "properties": { + "expires": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "spender": { + "type": "string" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Remove previously granted Approval", + "type": "object", + "required": [ + "revoke" + ], + "properties": { + "revoke": { + "type": "object", + "required": [ + "spender", + "token_id" + ], + "properties": { + "spender": { + "type": "string" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit", + "type": "object", + "required": [ + "approve_all" + ], + "properties": { + "approve_all": { + "type": "object", + "required": [ + "operator" + ], + "properties": { + "expires": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "operator": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Remove previously granted ApproveAll permission", + "type": "object", + "required": [ + "revoke_all" + ], + "properties": { + "revoke_all": { + "type": "object", + "required": [ + "operator" + ], + "properties": { + "operator": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Mint a new NFT, can only be called by the contract minter", + "type": "object", + "required": [ + "mint" + ], + "properties": { + "mint": { + "type": "object", + "required": [ + "owner", + "token_id" + ], + "properties": { + "extension": { + "description": "Any custom extension used by this contract", + "anyOf": [ + { + "$ref": "#/definitions/Metadata" + }, + { + "type": "null" + } + ] + }, + "owner": { + "description": "The owner of the newly minter NFT", + "type": "string" + }, + "token_id": { + "description": "Unique ID of the NFT", + "type": "string" + }, + "token_uri": { + "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Burn an NFT the sender has access to", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Extension msg", + "type": "object", + "required": [ + "extension" + ], + "properties": { + "extension": { + "type": "object", + "required": [ + "msg" + ], + "properties": { + "msg": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Update the contract's ownership. The `action` to be provided can be either to propose transferring ownership to an account, accept a pending ownership transfer, or renounce the ownership permanently.", + "type": "object", + "required": [ + "update_ownership" + ], + "properties": { + "update_ownership": { + "$ref": "#/definitions/Action" + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Action": { + "description": "Actions that can be taken to alter the contract's ownership", + "oneOf": [ + { + "description": "Propose to transfer the contract's ownership to another account, optionally with an expiry time.\n\nCan only be called by the contract's current owner.\n\nAny existing pending ownership transfer is overwritten.", + "type": "object", + "required": [ + "transfer_ownership" + ], + "properties": { + "transfer_ownership": { + "type": "object", + "required": [ + "new_owner" + ], + "properties": { + "expiry": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "new_owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Accept the pending ownership transfer.\n\nCan only be called by the pending owner.", + "type": "string", + "enum": [ + "accept_ownership" + ] + }, + { + "description": "Give up the contract's ownership and the possibility of appointing a new owner.\n\nCan only be invoked by the contract's current owner.\n\nAny existing pending ownership transfer is canceled.", + "type": "string", + "enum": [ + "renounce_ownership" + ] + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Metadata": { + "type": "object", + "properties": { + "animation_url": { + "type": [ + "string", + "null" + ] + }, + "attributes": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Trait" + } + }, + "background_color": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "external_url": { + "type": [ + "string", + "null" + ] + }, + "image": { + "type": [ + "string", + "null" + ] + }, + "image_data": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "youtube_url": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Trait": { + "type": "object", + "required": [ + "trait_type", + "value" + ], + "properties": { + "display_type": { + "type": [ + "string", + "null" + ] + }, + "trait_type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "query": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "description": "Return the owner of the given token, error if token does not exist", + "type": "object", + "required": [ + "owner_of" + ], + "properties": { + "owner_of": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "include_expired": { + "description": "unset or false will filter out expired approvals, you must set to true to see them", + "type": [ + "boolean", + "null" + ] + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Return operator that can access all of the owner's tokens.", + "type": "object", + "required": [ + "approval" + ], + "properties": { + "approval": { + "type": "object", + "required": [ + "spender", + "token_id" + ], + "properties": { + "include_expired": { + "type": [ + "boolean", + "null" + ] + }, + "spender": { + "type": "string" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Return approvals that a token has", + "type": "object", + "required": [ + "approvals" + ], + "properties": { + "approvals": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "include_expired": { + "type": [ + "boolean", + "null" + ] + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Return approval of a given operator for all tokens of an owner, error if not set", + "type": "object", + "required": [ + "operator" + ], + "properties": { + "operator": { + "type": "object", + "required": [ + "operator", + "owner" + ], + "properties": { + "include_expired": { + "type": [ + "boolean", + "null" + ] + }, + "operator": { + "type": "string" + }, + "owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "List all operators that can access all of the owner's tokens", + "type": "object", + "required": [ + "all_operators" + ], + "properties": { + "all_operators": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "include_expired": { + "description": "unset or false will filter out expired items, you must set to true to see them", + "type": [ + "boolean", + "null" + ] + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "owner": { + "type": "string" + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Total number of tokens issued", + "type": "object", + "required": [ + "num_tokens" + ], + "properties": { + "num_tokens": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "With MetaData Extension. Returns top-level metadata about the contract", + "type": "object", + "required": [ + "contract_info" + ], + "properties": { + "contract_info": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "With MetaData Extension. Returns metadata about one particular token, based on *ERC721 Metadata JSON Schema* but directly from the contract", + "type": "object", + "required": [ + "nft_info" + ], + "properties": { + "nft_info": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "With MetaData Extension. Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization for clients", + "type": "object", + "required": [ + "all_nft_info" + ], + "properties": { + "all_nft_info": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "include_expired": { + "description": "unset or false will filter out expired approvals, you must set to true to see them", + "type": [ + "boolean", + "null" + ] + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset.", + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "owner": { + "type": "string" + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract.", + "type": "object", + "required": [ + "all_tokens" + ], + "properties": { + "all_tokens": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Return the minter", + "type": "object", + "required": [ + "minter" + ], + "properties": { + "minter": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Extension query", + "type": "object", + "required": [ + "extension" + ], + "properties": { + "extension": { + "type": "object", + "required": [ + "msg" + ], + "properties": { + "msg": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Query the contract's ownership information", + "type": "object", + "required": [ + "ownership" + ], + "properties": { + "ownership": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + } + } + }, + "migrate": null, + "sudo": null, + "responses": { + "all_nft_info": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AllNftInfoResponse_for_Empty", + "type": "object", + "required": [ + "access", + "info" + ], + "properties": { + "access": { + "description": "Who can transfer the token", + "allOf": [ + { + "$ref": "#/definitions/OwnerOfResponse" + } + ] + }, + "info": { + "description": "Data on the token itself,", + "allOf": [ + { + "$ref": "#/definitions/NftInfoResponse_for_Empty" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "NftInfoResponse_for_Empty": { + "type": "object", + "required": [ + "extension" + ], + "properties": { + "extension": { + "description": "You can add any custom metadata here when you extend cw721-base", + "allOf": [ + { + "$ref": "#/definitions/Empty" + } + ] + }, + "token_uri": { + "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "OwnerOfResponse": { + "type": "object", + "required": [ + "approvals", + "owner" + ], + "properties": { + "approvals": { + "description": "If set this address is approved to transfer/send the token as well", + "type": "array", + "items": { + "$ref": "#/definitions/Approval" + } + }, + "owner": { + "description": "Owner of the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "all_operators": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "OperatorsResponse", + "type": "object", + "required": [ + "operators" + ], + "properties": { + "operators": { + "type": "array", + "items": { + "$ref": "#/definitions/Approval" + } + } + }, + "additionalProperties": false, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "all_tokens": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TokensResponse", + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "description": "Contains all token_ids in lexicographical ordering If there are more than `limit`, use `start_from` in future queries to achieve pagination.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "approval": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovalResponse", + "type": "object", + "required": [ + "approval" + ], + "properties": { + "approval": { + "$ref": "#/definitions/Approval" + } + }, + "additionalProperties": false, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "approvals": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovalsResponse", + "type": "object", + "required": [ + "approvals" + ], + "properties": { + "approvals": { + "type": "array", + "items": { + "$ref": "#/definitions/Approval" + } + } + }, + "additionalProperties": false, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "contract_info": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ContractInfoResponse", + "type": "object", + "required": [ + "name", + "symbol" + ], + "properties": { + "name": { + "type": "string" + }, + "symbol": { + "type": "string" + } + }, + "additionalProperties": false + }, + "extension": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Null", + "type": "null" + }, + "minter": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MinterResponse", + "description": "Shows who can mint these tokens", + "type": "object", + "properties": { + "minter": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "nft_info": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "NftInfoResponse_for_Empty", + "type": "object", + "required": [ + "extension" + ], + "properties": { + "extension": { + "description": "You can add any custom metadata here when you extend cw721-base", + "allOf": [ + { + "$ref": "#/definitions/Empty" + } + ] + }, + "token_uri": { + "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false, + "definitions": { + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + } + } + }, + "num_tokens": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "NumTokensResponse", + "type": "object", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "operator": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "OperatorResponse", + "type": "object", + "required": [ + "approval" + ], + "properties": { + "approval": { + "$ref": "#/definitions/Approval" + } + }, + "additionalProperties": false, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "owner_of": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "OwnerOfResponse", + "type": "object", + "required": [ + "approvals", + "owner" + ], + "properties": { + "approvals": { + "description": "If set this address is approved to transfer/send the token as well", + "type": "array", + "items": { + "$ref": "#/definitions/Approval" + } + }, + "owner": { + "description": "Owner of the token", + "type": "string" + } + }, + "additionalProperties": false, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + }, + "additionalProperties": false + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "ownership": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Ownership_for_String", + "description": "The contract's ownership info", + "type": "object", + "properties": { + "owner": { + "description": "The contract's current owner. `None` if the ownership has been renounced.", + "type": [ + "string", + "null" + ] + }, + "pending_expiry": { + "description": "The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline.", + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "pending_owner": { + "description": "The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false, + "definitions": { + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, + "tokens": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TokensResponse", + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "description": "Contains all token_ids in lexicographical ordering If there are more than `limit`, use `start_from` in future queries to achieve pagination.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + } +} diff --git a/contracts/cw721-template/src/lib.rs b/contracts/cw721-template/src/lib.rs new file mode 100644 index 000000000..256589259 --- /dev/null +++ b/contracts/cw721-template/src/lib.rs @@ -0,0 +1,134 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::Empty; +pub use cw721_base::{ContractError,{% unless minimal %} CustomMsg,{% endunless %} InstantiateMsg, MinterResponse}; + +// Version info for migration +const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +{% if minimal %}pub type Cw721MetadataContract<'a> = cw721_base::Cw721Contract<'a, Empty, Empty, Empty, Empty>; + +pub type ExecuteMsg = cw721_base::ExecuteMsg; +pub type QueryMsg = cw721_base::QueryMsg;{% else %}// Implements extended on-chain metadata, by default cw721 NFTs only store a +// token_uri, which is a URL to off-chain metadata (same as ERC721). +#[cw_serde] +#[derive(Default)] +pub struct MetadataExt {} + +// This is the custom Execute message extension for this contract. +// Use it to implement custom functionality. +#[cw_serde] +pub struct ExecuteExt {} +impl CustomMsg for ExecuteExt {} + +// This is the custom Query message type for this contract. +// Use it to implement custom query messages. +#[cw_serde] +pub struct QueryExt {} +impl CustomMsg for QueryExt {} + +// This contrains default cw721 logic with extensions. +// If you don't need a particular extension, replace it with an +// `Empty` type. +pub type Cw721Contract<'a> = + cw721_base::Cw721Contract<'a, MetadataExt, Empty, ExecuteExt, QueryExt>; + +// The execute message type for this contract. +// If you don't need the Metadata and Execute extensions, you can use the +// `Empty` type. +pub type ExecuteMsg = cw721_base::ExecuteMsg; + +// The query message type for this contract. +// If you don't need the QueryExt extension, you can use the +// `Empty` type. +pub type QueryMsg = cw721_base::QueryMsg;{% endif %} + +#[cfg(not(feature = "library"))] +pub mod entry { + use super::*; + + use cosmwasm_std::entry_point; + use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; + + // This makes a conscious choice on the various generics used by the contract + #[entry_point] + pub fn instantiate( + mut deps: DepsMut, + env: Env, + info: MessageInfo, + msg: InstantiateMsg, + ) -> StdResult { + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + // Instantiate the base contract + Cw721Contract::default().instantiate(deps.branch(), env, info, msg) + } + + #[entry_point] + pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, + ) -> Result { + {% if minimal %}// Use the default cw721-base implementation + Cw721Contract::default().execute(deps, env, info, msg){% else %}match msg { + // Optionally override the default cw721-base behavior + // ExecuteMsg::Burn { token_id } => unimplemented!(), + + // Implment extension messages here, remove if you don't wish to use + // An ExecuteExt extension + ExecuteMsg::Extension { msg } => match msg { + _ => unimplemented!(), + }, + + // Use the default cw721-base implementation + _ => Cw721Contract::default().execute(deps, env, info, msg), + }{% endif %} + } + + #[entry_point] + pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { + {% if minimal %}// Use default cw721-base query implementation + Cw721Contract::default().query(deps, env, msg){% else %}match msg { + // Optionally override a default cw721-base query + // QueryMsg::Minter {} => unimplemented!(), + QueryMsg::Extension { msg } => match msg { + _ => unimplemented!(), + }, + + // Use default cw721-base query implementation + _ => Cw721Contract::default().query(deps, env, msg), + }{% endif %} + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + + /// Make sure cw2 version info is properly initialized during instantiation, + /// and NOT overwritten by the base contract. + #[test] + fn proper_cw2_initialization() { + let mut deps = mock_dependencies(); + + entry::instantiate( + deps.as_mut(), + mock_env(), + mock_info("larry", &[]), + InstantiateMsg { + name: "".into(), + symbol: "".into(), + minter: "larry".into(), + }, + ) + .unwrap(); + + let version = cw2::get_contract_version(deps.as_ref().storage).unwrap(); + assert_eq!(version.contract, CONTRACT_NAME); + assert_ne!(version.contract, cw721_base::CONTRACT_NAME); + } +} diff --git a/contracts/cw721-template/test_generate.sh b/contracts/cw721-template/test_generate.sh new file mode 100644 index 000000000..d7c55c1fe --- /dev/null +++ b/contracts/cw721-template/test_generate.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# From: https://github.com/CosmWasm/cw-template/blob/main/meta/test_generate.sh + +set -o errexit -o nounset -o pipefail +command -v shellcheck > /dev/null && shellcheck "$0" + +REPO_ROOT="$(realpath "$(dirname "$0")/..")" + +TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/cw-template.XXXXXXXXX") +PROJECT_NAME="testgen-local" + +( + echo "Navigating to $TMP_DIR" + cd "$TMP_DIR" + + echo "Generating project from local repository ..." + cargo generate --path "$REPO_ROOT" --name "$PROJECT_NAME" + + ( + cd "$PROJECT_NAME" + echo "This is what was generated" + ls -lA + + # Check formatting + echo "Checking formatting ..." + cargo fmt -- --check + + # Debug builds first to fail fast + echo "Running unit tests ..." + cargo unit-test + echo "Creating schema ..." + cargo schema + + echo "Building wasm ..." + cargo wasm + ) +) From 616003e9d12e77be4b70cbacb8abebda02ffaa42 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 19:06:22 -0700 Subject: [PATCH 02/12] Configure subfolders for cargo generate --- cargo-generate.toml | 2 + contracts/cw721-template/README.md | 102 +++++++++++++---------------- 2 files changed, 46 insertions(+), 58 deletions(-) create mode 100644 cargo-generate.toml diff --git a/cargo-generate.toml b/cargo-generate.toml new file mode 100644 index 000000000..c3da96bc6 --- /dev/null +++ b/cargo-generate.toml @@ -0,0 +1,2 @@ +[template] +sub_templates = ["contracts/cw721-template"] diff --git a/contracts/cw721-template/README.md b/contracts/cw721-template/README.md index dd449656e..88a1934b6 100644 --- a/contracts/cw721-template/README.md +++ b/contracts/cw721-template/README.md @@ -1,64 +1,50 @@ -# CW721 Metadata Onchain - -NFT creators may want to store their NFT metadata on-chain so other contracts are able to interact with it. -With CW721-Base in CosmWasm, we allow you to store any data on chain you wish, using a generic `extension: T`. - -In order to support on-chain metadata, and to demonstrate how to use the extension ability, we have created this simple contract. -There is no business logic here, but looking at `lib.rs` will show you how do define custom data that is included when minting and -available in all queries. - -In particular, here we define: - -```rust -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct Trait { - pub display_type: Option, - pub trait_type: String, - pub value: String, -} - -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct Metadata { - pub image: Option, - pub image_data: Option, - pub external_url: Option, - pub description: Option, - pub name: Option, - pub attributes: Option>, - pub background_color: Option, - pub animation_url: Option, - pub youtube_url: Option, -} - -pub type Extension = Option; +# CW721 Template + +A template for generating custom cw721 NFT contracts. Based on [cw-template](https://github.com/CosmWasm/cw-template). + +## Creating a new repo from template + +Assuming you have a recent version of Rust and Cargo installed +(via [rustup](https://rustup.rs/)), +then the following should get you a new repo to start a contract: + +Install [cargo-generate](https://github.com/ashleygwilliams/cargo-generate) and cargo-run-script. +Unless you did that before, run this line now: + +```sh +cargo install cargo-generate --features vendored-openssl +cargo install cargo-run-script +``` + +Now, use it to create your new contract. + +Go to the folder in which you want to place it and run: + +**Latest** + +```sh +cargo generate --git https://github.com/CosmWasm/cw-nfts.git --name PROJECT_NAME +``` + +For cloning a minimal NFT contract without example code for extensions: + +```sh +cargo generate --git https://github.com/CosmWasm/cw-nfts.git --name PROJECT_NAME -d minimal=true ``` -In particular, the fields defined conform to the properties supported in the [OpenSea Metadata Standard](https://docs.opensea.io/docs/metadata-standards). - - -This means when you query `NftInfo{name: "Enterprise"}`, you will get something like: - -```json -{ - "name": "Enterprise", - "token_uri": "https://starships.example.com/Starship/Enterprise.json", - "extension": { - "image": null, - "image_data": null, - "external_url": null, - "description": "Spaceship with Warp Drive", - "name": "Starship USS Enterprise", - "attributes": null, - "background_color": null, - "animation_url": null, - "youtube_url": null - } -} +**Older Versions** + +Pass version as branch flag: + +```sh +cargo generate --git https://github.com/CosmWasm/cw-nfts.git --branch --name PROJECT_NAME ``` -Please look at the test code for an example usage in Rust. +Example: -## Notice +```sh +cargo generate --git https://github.com/CosmWasm/cw-nfts.git --branch 0.16 --name PROJECT_NAME +``` -Feel free to use this contract out of the box, or as inspiration for further customization of cw721-base. -We will not be adding new features or business logic here. +You will now have a new folder called `PROJECT_NAME` (I hope you changed that to something else) +containing a simple working contract and build system that you can customize. From dbddffa43a9a82b5eb1aeeb7830a77cea2942067 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 19:15:23 -0700 Subject: [PATCH 03/12] Formatting fixups --- contracts/cw721-template/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/cw721-template/src/lib.rs b/contracts/cw721-template/src/lib.rs index 256589259..be6270512 100644 --- a/contracts/cw721-template/src/lib.rs +++ b/contracts/cw721-template/src/lib.rs @@ -1,14 +1,14 @@ -use cosmwasm_schema::cw_serde; -use cosmwasm_std::Empty; -pub use cw721_base::{ContractError,{% unless minimal %} CustomMsg,{% endunless %} InstantiateMsg, MinterResponse}; +{% unless minimal %}use cosmwasm_schema::cw_serde; +{% endunless %}use cosmwasm_std::{% unless minimal %}{CustomMsg, {% endunless %}Empty{% unless minimal %}}{% endunless %}; +pub use cw721_base::{ContractError, InstantiateMsg, MinterResponse}; // Version info for migration const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -{% if minimal %}pub type Cw721MetadataContract<'a> = cw721_base::Cw721Contract<'a, Empty, Empty, Empty, Empty>; +{% if minimal %}pub type Cw721Contract<'a> = cw721_base::Cw721Contract<'a, Empty, Empty, Empty, Empty>; -pub type ExecuteMsg = cw721_base::ExecuteMsg; +pub type ExecuteMsg = cw721_base::ExecuteMsg; pub type QueryMsg = cw721_base::QueryMsg;{% else %}// Implements extended on-chain metadata, by default cw721 NFTs only store a // token_uri, which is a URL to off-chain metadata (same as ERC721). #[cw_serde] From 42c3d6c0be68e611299b4b27489720f74d9c5b57 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 19:20:10 -0700 Subject: [PATCH 04/12] Update NOTICE --- contracts/cw721-template/NOTICE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/cw721-template/NOTICE b/contracts/cw721-template/NOTICE index bd298d741..457de3130 100644 --- a/contracts/cw721-template/NOTICE +++ b/contracts/cw721-template/NOTICE @@ -1,4 +1,4 @@ -Cw721_metadata_onchain +cw721_template Copyright (C) 2021 Confio OÜ Licensed under the Apache License, Version 2.0 (the "License"); From eb3aea28ef203469de071171db430ccf0e481352 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 19:25:10 -0700 Subject: [PATCH 05/12] Add .gitignore, exclude files from code gen --- contracts/cw721-template/.gitignore | 16 ++++++++++++++++ contracts/cw721-template/cargo-generate.toml | 7 +++++++ 2 files changed, 23 insertions(+) create mode 100644 contracts/cw721-template/.gitignore diff --git a/contracts/cw721-template/.gitignore b/contracts/cw721-template/.gitignore new file mode 100644 index 000000000..9095deaa4 --- /dev/null +++ b/contracts/cw721-template/.gitignore @@ -0,0 +1,16 @@ +# Build results +/target +/schema + +# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) +.cargo-ok + +# Text file backups +**/*.rs.bk + +# macOS +.DS_Store + +# IDEs +*.iml +.idea diff --git a/contracts/cw721-template/cargo-generate.toml b/contracts/cw721-template/cargo-generate.toml index 2270694dc..f04e97264 100644 --- a/contracts/cw721-template/cargo-generate.toml +++ b/contracts/cw721-template/cargo-generate.toml @@ -1,3 +1,10 @@ +[template] +# Files listed here will not be processed by the template engine when a project is generated. +# This is needed when files contains curly brackets as in `v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}`. +# The files will be copied 1:1 to the target project. To avoid shipping them completely add them to `.genignore`. +exclude = ["test_generate.sh", "cargo-generate.toml"] + + [placeholders.minimal] type = "bool" prompt = """The full template includes more example code on how to extend a basic cw721 contract. From 560faa9d7396ba5ecaf9def3fe2ff34efbef7b13 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 19:31:24 -0700 Subject: [PATCH 06/12] Update CLI prompt copy --- contracts/cw721-template/cargo-generate.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/cw721-template/cargo-generate.toml b/contracts/cw721-template/cargo-generate.toml index f04e97264..2dfcf91d1 100644 --- a/contracts/cw721-template/cargo-generate.toml +++ b/contracts/cw721-template/cargo-generate.toml @@ -4,9 +4,8 @@ # The files will be copied 1:1 to the target project. To avoid shipping them completely add them to `.genignore`. exclude = ["test_generate.sh", "cargo-generate.toml"] - [placeholders.minimal] type = "bool" -prompt = """The full template includes more example code on how to extend a basic cw721 contract. -Would you still like to generate the minimal template?""" +prompt = """The full template includes more example code on how to extend a basic cw721 contract. This is useful +if you are new to writing CosmWasm NFT contracts. Would you like the minimal template instead?""" default = false From aabb42d111fb24e54cd525ad33d3c77273ec74ba Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Fri, 21 Apr 2023 19:39:40 -0700 Subject: [PATCH 07/12] Exclude cw721-template from workspace --- Cargo.lock | 1 - Cargo.toml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ae91ac352..757b0c3d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,6 @@ version = "0.17.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-ownable", "cw-storage-plus 1.0.1", "cw2 1.0.1 (git+https://github.com/mars-protocol/cw-plus?rev=1a3a944)", "cw721 0.17.0", diff --git a/Cargo.toml b/Cargo.toml index 3fc75c507..927ca25b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["packages/*", "contracts/*"] +exclude = ["contracts/cw721-template"] [workspace.package] version = "0.17.0" From 66bcb57458ea1822aba99a46177d70beabb5f0e2 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Mon, 24 Apr 2023 18:30:42 -0700 Subject: [PATCH 08/12] Fix typo, execute and query extensions should be enums --- contracts/cw721-template/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/cw721-template/src/lib.rs b/contracts/cw721-template/src/lib.rs index be6270512..c931e2939 100644 --- a/contracts/cw721-template/src/lib.rs +++ b/contracts/cw721-template/src/lib.rs @@ -18,13 +18,13 @@ pub struct MetadataExt {} // This is the custom Execute message extension for this contract. // Use it to implement custom functionality. #[cw_serde] -pub struct ExecuteExt {} +pub enum ExecuteExt {} impl CustomMsg for ExecuteExt {} // This is the custom Query message type for this contract. // Use it to implement custom query messages. #[cw_serde] -pub struct QueryExt {} +pub enum QueryExt {} impl CustomMsg for QueryExt {} // This contrains default cw721 logic with extensions. From e8f1995fe6c316b662649d824e01cc93ef1ba443 Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Thu, 27 Apr 2023 16:30:04 -0700 Subject: [PATCH 09/12] Add custom errors, remove minmal template --- contracts/cw721-template/Cargo.toml | 1 + contracts/cw721-template/README.md | 6 --- contracts/cw721-template/cargo-generate.toml | 6 --- contracts/cw721-template/src/lib.rs | 39 ++++++++++++-------- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/contracts/cw721-template/Cargo.toml b/contracts/cw721-template/Cargo.toml index f5573a4d1..810881315 100644 --- a/contracts/cw721-template/Cargo.toml +++ b/contracts/cw721-template/Cargo.toml @@ -25,3 +25,4 @@ cw721 = "0.17.0" cw721-base = { version = "0.17.0", features = ["library"] } schemars = "0.8.11" serde = { version = "1.0.152", default-features = false, features = ["derive"] } +thiserror = "1.0.30" diff --git a/contracts/cw721-template/README.md b/contracts/cw721-template/README.md index 88a1934b6..f614e3255 100644 --- a/contracts/cw721-template/README.md +++ b/contracts/cw721-template/README.md @@ -26,12 +26,6 @@ Go to the folder in which you want to place it and run: cargo generate --git https://github.com/CosmWasm/cw-nfts.git --name PROJECT_NAME ``` -For cloning a minimal NFT contract without example code for extensions: - -```sh -cargo generate --git https://github.com/CosmWasm/cw-nfts.git --name PROJECT_NAME -d minimal=true -``` - **Older Versions** Pass version as branch flag: diff --git a/contracts/cw721-template/cargo-generate.toml b/contracts/cw721-template/cargo-generate.toml index 2dfcf91d1..51bf25720 100644 --- a/contracts/cw721-template/cargo-generate.toml +++ b/contracts/cw721-template/cargo-generate.toml @@ -3,9 +3,3 @@ # This is needed when files contains curly brackets as in `v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}`. # The files will be copied 1:1 to the target project. To avoid shipping them completely add them to `.genignore`. exclude = ["test_generate.sh", "cargo-generate.toml"] - -[placeholders.minimal] -type = "bool" -prompt = """The full template includes more example code on how to extend a basic cw721 contract. This is useful -if you are new to writing CosmWasm NFT contracts. Would you like the minimal template instead?""" -default = false diff --git a/contracts/cw721-template/src/lib.rs b/contracts/cw721-template/src/lib.rs index c931e2939..06633406d 100644 --- a/contracts/cw721-template/src/lib.rs +++ b/contracts/cw721-template/src/lib.rs @@ -1,15 +1,13 @@ -{% unless minimal %}use cosmwasm_schema::cw_serde; -{% endunless %}use cosmwasm_std::{% unless minimal %}{CustomMsg, {% endunless %}Empty{% unless minimal %}}{% endunless %}; -pub use cw721_base::{ContractError, InstantiateMsg, MinterResponse}; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{CustomMsg, Empty, StdError}; +pub use cw721_base::{InstantiateMsg, MinterResponse}; +use thiserror::Error; // Version info for migration const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -{% if minimal %}pub type Cw721Contract<'a> = cw721_base::Cw721Contract<'a, Empty, Empty, Empty, Empty>; - -pub type ExecuteMsg = cw721_base::ExecuteMsg; -pub type QueryMsg = cw721_base::QueryMsg;{% else %}// Implements extended on-chain metadata, by default cw721 NFTs only store a +// Implements extended on-chain metadata, by default cw721 NFTs only store a // token_uri, which is a URL to off-chain metadata (same as ERC721). #[cw_serde] #[derive(Default)] @@ -41,7 +39,18 @@ pub type ExecuteMsg = cw721_base::ExecuteMsg; // The query message type for this contract. // If you don't need the QueryExt extension, you can use the // `Empty` type. -pub type QueryMsg = cw721_base::QueryMsg;{% endif %} +pub type QueryMsg = cw721_base::QueryMsg; + +/// Custom errors for this contract, add additional errors here. +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + /// This inherits from cw721-base::ContractError to handle the base contract errors + #[error("{0}")] + Cw721Error(#[from] cw721_base::ContractError), +} #[cfg(not(feature = "library"))] pub mod entry { @@ -71,8 +80,7 @@ pub mod entry { info: MessageInfo, msg: ExecuteMsg, ) -> Result { - {% if minimal %}// Use the default cw721-base implementation - Cw721Contract::default().execute(deps, env, info, msg){% else %}match msg { + match msg { // Optionally override the default cw721-base behavior // ExecuteMsg::Burn { token_id } => unimplemented!(), @@ -83,14 +91,15 @@ pub mod entry { }, // Use the default cw721-base implementation - _ => Cw721Contract::default().execute(deps, env, info, msg), - }{% endif %} + _ => Cw721Contract::default() + .execute(deps, env, info, msg) + .map_err(Into::into), + } } #[entry_point] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { - {% if minimal %}// Use default cw721-base query implementation - Cw721Contract::default().query(deps, env, msg){% else %}match msg { + match msg { // Optionally override a default cw721-base query // QueryMsg::Minter {} => unimplemented!(), QueryMsg::Extension { msg } => match msg { @@ -99,7 +108,7 @@ pub mod entry { // Use default cw721-base query implementation _ => Cw721Contract::default().query(deps, env, msg), - }{% endif %} + } } } From 311902edfc62f575eaaa1ddc4e32676bbf46b81a Mon Sep 17 00:00:00 2001 From: Jake Hartnell Date: Thu, 27 Apr 2023 16:45:14 -0700 Subject: [PATCH 10/12] Move cw721-template to templates folder --- Cargo.toml | 1 - cargo-generate.toml | 2 +- .../schema/cw721-metadata-onchain.json | 1769 ----------------- .../cw721-template/.cargo/config | 0 .../.github/workflows/basic.yml | 0 .../cw721-template/.gitignore | 0 .../cw721-template/Cargo.toml | 0 .../cw721-template/NOTICE | 0 .../cw721-template/README.md | 0 .../cw721-template/cargo-generate.toml | 0 .../cw721-template/examples/schema.rs | 0 .../cw721-template/src/lib.rs | 0 .../cw721-template/test_generate.sh | 0 13 files changed, 1 insertion(+), 1771 deletions(-) delete mode 100644 contracts/cw721-template/schema/cw721-metadata-onchain.json rename {contracts => templates}/cw721-template/.cargo/config (100%) rename {contracts => templates}/cw721-template/.github/workflows/basic.yml (100%) rename {contracts => templates}/cw721-template/.gitignore (100%) rename {contracts => templates}/cw721-template/Cargo.toml (100%) rename {contracts => templates}/cw721-template/NOTICE (100%) rename {contracts => templates}/cw721-template/README.md (100%) rename {contracts => templates}/cw721-template/cargo-generate.toml (100%) rename {contracts => templates}/cw721-template/examples/schema.rs (100%) rename {contracts => templates}/cw721-template/src/lib.rs (100%) rename {contracts => templates}/cw721-template/test_generate.sh (100%) diff --git a/Cargo.toml b/Cargo.toml index 927ca25b7..3fc75c507 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = ["packages/*", "contracts/*"] -exclude = ["contracts/cw721-template"] [workspace.package] version = "0.17.0" diff --git a/cargo-generate.toml b/cargo-generate.toml index c3da96bc6..66ec89123 100644 --- a/cargo-generate.toml +++ b/cargo-generate.toml @@ -1,2 +1,2 @@ [template] -sub_templates = ["contracts/cw721-template"] +sub_templates = ["templates/cw721-template"] diff --git a/contracts/cw721-template/schema/cw721-metadata-onchain.json b/contracts/cw721-template/schema/cw721-metadata-onchain.json deleted file mode 100644 index 7115bad36..000000000 --- a/contracts/cw721-template/schema/cw721-metadata-onchain.json +++ /dev/null @@ -1,1769 +0,0 @@ -{ - "contract_name": "cw721-metadata-onchain", - "contract_version": "0.17.0", - "idl_version": "1.0.0", - "instantiate": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "InstantiateMsg", - "type": "object", - "required": [ - "minter", - "name", - "symbol" - ], - "properties": { - "minter": { - "description": "The minter is the only one who can create new NFTs. This is designed for a base NFT that is controlled by an external program or contract. You will likely replace this with custom logic in custom NFTs", - "type": "string" - }, - "name": { - "description": "Name of the NFT contract", - "type": "string" - }, - "symbol": { - "description": "Symbol of the NFT contract", - "type": "string" - } - }, - "additionalProperties": false - }, - "execute": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", - "description": "This is like Cw721ExecuteMsg but we add a Mint command for an owner to make this stand-alone. You will likely want to remove mint and use other control logic in any contract that inherits this.", - "oneOf": [ - { - "description": "Transfer is a base message to move a token to another account without triggering actions", - "type": "object", - "required": [ - "transfer_nft" - ], - "properties": { - "transfer_nft": { - "type": "object", - "required": [ - "recipient", - "token_id" - ], - "properties": { - "recipient": { - "type": "string" - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Send is a base message to transfer a token to a contract and trigger an action on the receiving contract.", - "type": "object", - "required": [ - "send_nft" - ], - "properties": { - "send_nft": { - "type": "object", - "required": [ - "contract", - "msg", - "token_id" - ], - "properties": { - "contract": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Allows operator to transfer / send the token from the owner's account. If expiration is set, then this allowance has a time/height limit", - "type": "object", - "required": [ - "approve" - ], - "properties": { - "approve": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Remove previously granted Approval", - "type": "object", - "required": [ - "revoke" - ], - "properties": { - "revoke": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit", - "type": "object", - "required": [ - "approve_all" - ], - "properties": { - "approve_all": { - "type": "object", - "required": [ - "operator" - ], - "properties": { - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "operator": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Remove previously granted ApproveAll permission", - "type": "object", - "required": [ - "revoke_all" - ], - "properties": { - "revoke_all": { - "type": "object", - "required": [ - "operator" - ], - "properties": { - "operator": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Mint a new NFT, can only be called by the contract minter", - "type": "object", - "required": [ - "mint" - ], - "properties": { - "mint": { - "type": "object", - "required": [ - "owner", - "token_id" - ], - "properties": { - "extension": { - "description": "Any custom extension used by this contract", - "anyOf": [ - { - "$ref": "#/definitions/Metadata" - }, - { - "type": "null" - } - ] - }, - "owner": { - "description": "The owner of the newly minter NFT", - "type": "string" - }, - "token_id": { - "description": "Unique ID of the NFT", - "type": "string" - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Burn an NFT the sender has access to", - "type": "object", - "required": [ - "burn" - ], - "properties": { - "burn": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Extension msg", - "type": "object", - "required": [ - "extension" - ], - "properties": { - "extension": { - "type": "object", - "required": [ - "msg" - ], - "properties": { - "msg": { - "$ref": "#/definitions/Empty" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Update the contract's ownership. The `action` to be provided can be either to propose transferring ownership to an account, accept a pending ownership transfer, or renounce the ownership permanently.", - "type": "object", - "required": [ - "update_ownership" - ], - "properties": { - "update_ownership": { - "$ref": "#/definitions/Action" - } - }, - "additionalProperties": false - } - ], - "definitions": { - "Action": { - "description": "Actions that can be taken to alter the contract's ownership", - "oneOf": [ - { - "description": "Propose to transfer the contract's ownership to another account, optionally with an expiry time.\n\nCan only be called by the contract's current owner.\n\nAny existing pending ownership transfer is overwritten.", - "type": "object", - "required": [ - "transfer_ownership" - ], - "properties": { - "transfer_ownership": { - "type": "object", - "required": [ - "new_owner" - ], - "properties": { - "expiry": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "new_owner": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Accept the pending ownership transfer.\n\nCan only be called by the pending owner.", - "type": "string", - "enum": [ - "accept_ownership" - ] - }, - { - "description": "Give up the contract's ownership and the possibility of appointing a new owner.\n\nCan only be invoked by the contract's current owner.\n\nAny existing pending ownership transfer is canceled.", - "type": "string", - "enum": [ - "renounce_ownership" - ] - } - ] - }, - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", - "type": "string" - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Metadata": { - "type": "object", - "properties": { - "animation_url": { - "type": [ - "string", - "null" - ] - }, - "attributes": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Trait" - } - }, - "background_color": { - "type": [ - "string", - "null" - ] - }, - "description": { - "type": [ - "string", - "null" - ] - }, - "external_url": { - "type": [ - "string", - "null" - ] - }, - "image": { - "type": [ - "string", - "null" - ] - }, - "image_data": { - "type": [ - "string", - "null" - ] - }, - "name": { - "type": [ - "string", - "null" - ] - }, - "youtube_url": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Trait": { - "type": "object", - "required": [ - "trait_type", - "value" - ], - "properties": { - "display_type": { - "type": [ - "string", - "null" - ] - }, - "trait_type": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "additionalProperties": false - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "query": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "QueryMsg", - "oneOf": [ - { - "description": "Return the owner of the given token, error if token does not exist", - "type": "object", - "required": [ - "owner_of" - ], - "properties": { - "owner_of": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "include_expired": { - "description": "unset or false will filter out expired approvals, you must set to true to see them", - "type": [ - "boolean", - "null" - ] - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Return operator that can access all of the owner's tokens.", - "type": "object", - "required": [ - "approval" - ], - "properties": { - "approval": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "include_expired": { - "type": [ - "boolean", - "null" - ] - }, - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Return approvals that a token has", - "type": "object", - "required": [ - "approvals" - ], - "properties": { - "approvals": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "include_expired": { - "type": [ - "boolean", - "null" - ] - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Return approval of a given operator for all tokens of an owner, error if not set", - "type": "object", - "required": [ - "operator" - ], - "properties": { - "operator": { - "type": "object", - "required": [ - "operator", - "owner" - ], - "properties": { - "include_expired": { - "type": [ - "boolean", - "null" - ] - }, - "operator": { - "type": "string" - }, - "owner": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "List all operators that can access all of the owner's tokens", - "type": "object", - "required": [ - "all_operators" - ], - "properties": { - "all_operators": { - "type": "object", - "required": [ - "owner" - ], - "properties": { - "include_expired": { - "description": "unset or false will filter out expired items, you must set to true to see them", - "type": [ - "boolean", - "null" - ] - }, - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "owner": { - "type": "string" - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Total number of tokens issued", - "type": "object", - "required": [ - "num_tokens" - ], - "properties": { - "num_tokens": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "With MetaData Extension. Returns top-level metadata about the contract", - "type": "object", - "required": [ - "contract_info" - ], - "properties": { - "contract_info": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "With MetaData Extension. Returns metadata about one particular token, based on *ERC721 Metadata JSON Schema* but directly from the contract", - "type": "object", - "required": [ - "nft_info" - ], - "properties": { - "nft_info": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "With MetaData Extension. Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization for clients", - "type": "object", - "required": [ - "all_nft_info" - ], - "properties": { - "all_nft_info": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "include_expired": { - "description": "unset or false will filter out expired approvals, you must set to true to see them", - "type": [ - "boolean", - "null" - ] - }, - "token_id": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset.", - "type": "object", - "required": [ - "tokens" - ], - "properties": { - "tokens": { - "type": "object", - "required": [ - "owner" - ], - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "owner": { - "type": "string" - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract.", - "type": "object", - "required": [ - "all_tokens" - ], - "properties": { - "all_tokens": { - "type": "object", - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Return the minter", - "type": "object", - "required": [ - "minter" - ], - "properties": { - "minter": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Extension query", - "type": "object", - "required": [ - "extension" - ], - "properties": { - "extension": { - "type": "object", - "required": [ - "msg" - ], - "properties": { - "msg": { - "$ref": "#/definitions/Empty" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Query the contract's ownership information", - "type": "object", - "required": [ - "ownership" - ], - "properties": { - "ownership": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ], - "definitions": { - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - } - } - }, - "migrate": null, - "sudo": null, - "responses": { - "all_nft_info": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "AllNftInfoResponse_for_Empty", - "type": "object", - "required": [ - "access", - "info" - ], - "properties": { - "access": { - "description": "Who can transfer the token", - "allOf": [ - { - "$ref": "#/definitions/OwnerOfResponse" - } - ] - }, - "info": { - "description": "Data on the token itself,", - "allOf": [ - { - "$ref": "#/definitions/NftInfoResponse_for_Empty" - } - ] - } - }, - "additionalProperties": false, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "NftInfoResponse_for_Empty": { - "type": "object", - "required": [ - "extension" - ], - "properties": { - "extension": { - "description": "You can add any custom metadata here when you extend cw721-base", - "allOf": [ - { - "$ref": "#/definitions/Empty" - } - ] - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, - "OwnerOfResponse": { - "type": "object", - "required": [ - "approvals", - "owner" - ], - "properties": { - "approvals": { - "description": "If set this address is approved to transfer/send the token as well", - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - }, - "owner": { - "description": "Owner of the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "all_operators": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OperatorsResponse", - "type": "object", - "required": [ - "operators" - ], - "properties": { - "operators": { - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - } - }, - "additionalProperties": false, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "all_tokens": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "TokensResponse", - "type": "object", - "required": [ - "tokens" - ], - "properties": { - "tokens": { - "description": "Contains all token_ids in lexicographical ordering If there are more than `limit`, use `start_from` in future queries to achieve pagination.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - }, - "approval": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovalResponse", - "type": "object", - "required": [ - "approval" - ], - "properties": { - "approval": { - "$ref": "#/definitions/Approval" - } - }, - "additionalProperties": false, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "approvals": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovalsResponse", - "type": "object", - "required": [ - "approvals" - ], - "properties": { - "approvals": { - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - } - }, - "additionalProperties": false, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "contract_info": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ContractInfoResponse", - "type": "object", - "required": [ - "name", - "symbol" - ], - "properties": { - "name": { - "type": "string" - }, - "symbol": { - "type": "string" - } - }, - "additionalProperties": false - }, - "extension": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Null", - "type": "null" - }, - "minter": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "MinterResponse", - "description": "Shows who can mint these tokens", - "type": "object", - "properties": { - "minter": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, - "nft_info": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NftInfoResponse_for_Empty", - "type": "object", - "required": [ - "extension" - ], - "properties": { - "extension": { - "description": "You can add any custom metadata here when you extend cw721-base", - "allOf": [ - { - "$ref": "#/definitions/Empty" - } - ] - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false, - "definitions": { - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - } - } - }, - "num_tokens": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NumTokensResponse", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - "operator": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OperatorResponse", - "type": "object", - "required": [ - "approval" - ], - "properties": { - "approval": { - "$ref": "#/definitions/Approval" - } - }, - "additionalProperties": false, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "owner_of": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OwnerOfResponse", - "type": "object", - "required": [ - "approvals", - "owner" - ], - "properties": { - "approvals": { - "description": "If set this address is approved to transfer/send the token as well", - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - }, - "owner": { - "description": "Owner of the token", - "type": "string" - } - }, - "additionalProperties": false, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - }, - "additionalProperties": false - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "ownership": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Ownership_for_String", - "description": "The contract's ownership info", - "type": "object", - "properties": { - "owner": { - "description": "The contract's current owner. `None` if the ownership has been renounced.", - "type": [ - "string", - "null" - ] - }, - "pending_expiry": { - "description": "The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline.", - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "pending_owner": { - "description": "The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer.", - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false, - "definitions": { - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } - }, - "tokens": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "TokensResponse", - "type": "object", - "required": [ - "tokens" - ], - "properties": { - "tokens": { - "description": "Contains all token_ids in lexicographical ordering If there are more than `limit`, use `start_from` in future queries to achieve pagination.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - } - } -} diff --git a/contracts/cw721-template/.cargo/config b/templates/cw721-template/.cargo/config similarity index 100% rename from contracts/cw721-template/.cargo/config rename to templates/cw721-template/.cargo/config diff --git a/contracts/cw721-template/.github/workflows/basic.yml b/templates/cw721-template/.github/workflows/basic.yml similarity index 100% rename from contracts/cw721-template/.github/workflows/basic.yml rename to templates/cw721-template/.github/workflows/basic.yml diff --git a/contracts/cw721-template/.gitignore b/templates/cw721-template/.gitignore similarity index 100% rename from contracts/cw721-template/.gitignore rename to templates/cw721-template/.gitignore diff --git a/contracts/cw721-template/Cargo.toml b/templates/cw721-template/Cargo.toml similarity index 100% rename from contracts/cw721-template/Cargo.toml rename to templates/cw721-template/Cargo.toml diff --git a/contracts/cw721-template/NOTICE b/templates/cw721-template/NOTICE similarity index 100% rename from contracts/cw721-template/NOTICE rename to templates/cw721-template/NOTICE diff --git a/contracts/cw721-template/README.md b/templates/cw721-template/README.md similarity index 100% rename from contracts/cw721-template/README.md rename to templates/cw721-template/README.md diff --git a/contracts/cw721-template/cargo-generate.toml b/templates/cw721-template/cargo-generate.toml similarity index 100% rename from contracts/cw721-template/cargo-generate.toml rename to templates/cw721-template/cargo-generate.toml diff --git a/contracts/cw721-template/examples/schema.rs b/templates/cw721-template/examples/schema.rs similarity index 100% rename from contracts/cw721-template/examples/schema.rs rename to templates/cw721-template/examples/schema.rs diff --git a/contracts/cw721-template/src/lib.rs b/templates/cw721-template/src/lib.rs similarity index 100% rename from contracts/cw721-template/src/lib.rs rename to templates/cw721-template/src/lib.rs diff --git a/contracts/cw721-template/test_generate.sh b/templates/cw721-template/test_generate.sh similarity index 100% rename from contracts/cw721-template/test_generate.sh rename to templates/cw721-template/test_generate.sh From f949dedd3aa700c8188ea1161921363da271d448 Mon Sep 17 00:00:00 2001 From: Art3mix Date: Sat, 10 Jun 2023 09:59:30 +0300 Subject: [PATCH 11/12] multiple files template --- templates/cw721-template/examples/schema.rs | 3 +- templates/cw721-template/src/contract.rs | 67 +++++++++ templates/cw721-template/src/error.rs | 13 ++ templates/cw721-template/src/lib.rs | 146 +------------------- templates/cw721-template/src/msg.rs | 36 +++++ templates/cw721-template/src/tests.rs | 29 ++++ templates/cw721-template/test_generate.sh | 0 7 files changed, 151 insertions(+), 143 deletions(-) create mode 100644 templates/cw721-template/src/contract.rs create mode 100644 templates/cw721-template/src/error.rs create mode 100644 templates/cw721-template/src/msg.rs create mode 100644 templates/cw721-template/src/tests.rs mode change 100644 => 100755 templates/cw721-template/test_generate.sh diff --git a/templates/cw721-template/examples/schema.rs b/templates/cw721-template/examples/schema.rs index c713a8bb4..1c2e79b22 100644 --- a/templates/cw721-template/examples/schema.rs +++ b/templates/cw721-template/examples/schema.rs @@ -1,6 +1,7 @@ use cosmwasm_schema::write_api; -use {{crate_name}}::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use cw721_base::InstantiateMsg; +use {{crate_name}}::msg::{ExecuteMsg, QueryMsg}; fn main() { write_api! { diff --git a/templates/cw721-template/src/contract.rs b/templates/cw721-template/src/contract.rs new file mode 100644 index 000000000..4f0e1c4d7 --- /dev/null +++ b/templates/cw721-template/src/contract.rs @@ -0,0 +1,67 @@ +// Version info for migration +pub const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; +pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg(not(feature = "library"))] +pub mod entry { + use crate::error::ContractError; + use crate::msg::{Cw721Contract, ExecuteMsg, QueryMsg}; + + use super::*; + + use cosmwasm_std::entry_point; + use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; + use cw721_base::InstantiateMsg; + + // This makes a conscious choice on the various generics used by the contract + #[cfg_attr(not(feature = "library"), entry_point)] + pub fn instantiate( + mut deps: DepsMut, + env: Env, + info: MessageInfo, + msg: InstantiateMsg, + ) -> StdResult { + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + // Instantiate the base contract + Cw721Contract::default().instantiate(deps.branch(), env, info, msg) + } + + #[cfg_attr(not(feature = "library"), entry_point)] + pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, + ) -> Result { + match msg { + // Optionally override the default cw721-base behavior + // ExecuteMsg::Burn { token_id } => unimplemented!(), + + // Implment extension messages here, remove if you don't wish to use + // An ExecuteExt extension + ExecuteMsg::Extension { msg } => match msg { + _ => unimplemented!(), + }, + + // Use the default cw721-base implementation + _ => Cw721Contract::default() + .execute(deps, env, info, msg) + .map_err(Into::into), + } + } + + #[cfg_attr(not(feature = "library"), entry_point)] + pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { + match msg { + // Optionally override a default cw721-base query + // QueryMsg::Minter {} => unimplemented!(), + QueryMsg::Extension { msg } => match msg { + _ => unimplemented!(), + }, + + // Use default cw721-base query implementation + _ => Cw721Contract::default().query(deps, env, msg), + } + } +} diff --git a/templates/cw721-template/src/error.rs b/templates/cw721-template/src/error.rs new file mode 100644 index 000000000..3d8761ec7 --- /dev/null +++ b/templates/cw721-template/src/error.rs @@ -0,0 +1,13 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +/// Custom errors for this contract, add additional errors here. +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + /// This inherits from cw721-base::ContractError to handle the base contract errors + #[error("{0}")] + Cw721Error(#[from] cw721_base::ContractError), +} diff --git a/templates/cw721-template/src/lib.rs b/templates/cw721-template/src/lib.rs index 06633406d..25caf5a33 100644 --- a/templates/cw721-template/src/lib.rs +++ b/templates/cw721-template/src/lib.rs @@ -1,143 +1,5 @@ -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{CustomMsg, Empty, StdError}; -pub use cw721_base::{InstantiateMsg, MinterResponse}; -use thiserror::Error; - -// Version info for migration -const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; -const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); - -// Implements extended on-chain metadata, by default cw721 NFTs only store a -// token_uri, which is a URL to off-chain metadata (same as ERC721). -#[cw_serde] -#[derive(Default)] -pub struct MetadataExt {} - -// This is the custom Execute message extension for this contract. -// Use it to implement custom functionality. -#[cw_serde] -pub enum ExecuteExt {} -impl CustomMsg for ExecuteExt {} - -// This is the custom Query message type for this contract. -// Use it to implement custom query messages. -#[cw_serde] -pub enum QueryExt {} -impl CustomMsg for QueryExt {} - -// This contrains default cw721 logic with extensions. -// If you don't need a particular extension, replace it with an -// `Empty` type. -pub type Cw721Contract<'a> = - cw721_base::Cw721Contract<'a, MetadataExt, Empty, ExecuteExt, QueryExt>; - -// The execute message type for this contract. -// If you don't need the Metadata and Execute extensions, you can use the -// `Empty` type. -pub type ExecuteMsg = cw721_base::ExecuteMsg; - -// The query message type for this contract. -// If you don't need the QueryExt extension, you can use the -// `Empty` type. -pub type QueryMsg = cw721_base::QueryMsg; - -/// Custom errors for this contract, add additional errors here. -#[derive(Error, Debug, PartialEq)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - /// This inherits from cw721-base::ContractError to handle the base contract errors - #[error("{0}")] - Cw721Error(#[from] cw721_base::ContractError), -} - -#[cfg(not(feature = "library"))] -pub mod entry { - use super::*; - - use cosmwasm_std::entry_point; - use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; - - // This makes a conscious choice on the various generics used by the contract - #[entry_point] - pub fn instantiate( - mut deps: DepsMut, - env: Env, - info: MessageInfo, - msg: InstantiateMsg, - ) -> StdResult { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - // Instantiate the base contract - Cw721Contract::default().instantiate(deps.branch(), env, info, msg) - } - - #[entry_point] - pub fn execute( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, - ) -> Result { - match msg { - // Optionally override the default cw721-base behavior - // ExecuteMsg::Burn { token_id } => unimplemented!(), - - // Implment extension messages here, remove if you don't wish to use - // An ExecuteExt extension - ExecuteMsg::Extension { msg } => match msg { - _ => unimplemented!(), - }, - - // Use the default cw721-base implementation - _ => Cw721Contract::default() - .execute(deps, env, info, msg) - .map_err(Into::into), - } - } - - #[entry_point] - pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { - match msg { - // Optionally override a default cw721-base query - // QueryMsg::Minter {} => unimplemented!(), - QueryMsg::Extension { msg } => match msg { - _ => unimplemented!(), - }, - - // Use default cw721-base query implementation - _ => Cw721Contract::default().query(deps, env, msg), - } - } -} - +mod contract; +mod error; +pub mod msg; #[cfg(test)] -mod tests { - use super::*; - - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - - /// Make sure cw2 version info is properly initialized during instantiation, - /// and NOT overwritten by the base contract. - #[test] - fn proper_cw2_initialization() { - let mut deps = mock_dependencies(); - - entry::instantiate( - deps.as_mut(), - mock_env(), - mock_info("larry", &[]), - InstantiateMsg { - name: "".into(), - symbol: "".into(), - minter: "larry".into(), - }, - ) - .unwrap(); - - let version = cw2::get_contract_version(deps.as_ref().storage).unwrap(); - assert_eq!(version.contract, CONTRACT_NAME); - assert_ne!(version.contract, cw721_base::CONTRACT_NAME); - } -} +mod tests; diff --git a/templates/cw721-template/src/msg.rs b/templates/cw721-template/src/msg.rs new file mode 100644 index 000000000..3d6981f43 --- /dev/null +++ b/templates/cw721-template/src/msg.rs @@ -0,0 +1,36 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{CustomMsg, Empty}; + +// Implements extended on-chain metadata, by default cw721 NFTs only store a +// token_uri, which is a URL to off-chain metadata (same as ERC721). +#[cw_serde] +#[derive(Default)] +pub struct MetadataExt {} + +// This is the custom Execute message extension for this contract. +// Use it to implement custom functionality. +#[cw_serde] +pub enum ExecuteExt {} +impl CustomMsg for ExecuteExt {} + +// This is the custom Query message type for this contract. +// Use it to implement custom query messages. +#[cw_serde] +pub enum QueryExt {} +impl CustomMsg for QueryExt {} + +// This contrains default cw721 logic with extensions. +// If you don't need a particular extension, replace it with an +// `Empty` type. +pub type Cw721Contract<'a> = + cw721_base::Cw721Contract<'a, MetadataExt, Empty, ExecuteExt, QueryExt>; + +// The execute message type for this contract. +// If you don't need the Metadata and Execute extensions, you can use the +// `Empty` type. +pub type ExecuteMsg = cw721_base::ExecuteMsg; + +// The query message type for this contract. +// If you don't need the QueryExt extension, you can use the +// `Empty` type. +pub type QueryMsg = cw721_base::QueryMsg; diff --git a/templates/cw721-template/src/tests.rs b/templates/cw721-template/src/tests.rs new file mode 100644 index 000000000..0c292539b --- /dev/null +++ b/templates/cw721-template/src/tests.rs @@ -0,0 +1,29 @@ +mod tests { + use crate::contract::{entry, CONTRACT_NAME}; + + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cw721_base::InstantiateMsg; + + /// Make sure cw2 version info is properly initialized during instantiation, + /// and NOT overwritten by the base contract. + #[test] + fn proper_cw2_initialization() { + let mut deps = mock_dependencies(); + + entry::instantiate( + deps.as_mut(), + mock_env(), + mock_info("larry", &[]), + InstantiateMsg { + name: "".into(), + symbol: "".into(), + minter: "larry".into(), + }, + ) + .unwrap(); + + let version = cw2::get_contract_version(deps.as_ref().storage).unwrap(); + assert_eq!(version.contract, CONTRACT_NAME); + assert_ne!(version.contract, cw721_base::CONTRACT_NAME); + } +} diff --git a/templates/cw721-template/test_generate.sh b/templates/cw721-template/test_generate.sh old mode 100644 new mode 100755 From 11a2eeffb82e99190b22d0d77a1bef5da6eb56d0 Mon Sep 17 00:00:00 2001 From: Art3mix Date: Sat, 10 Jun 2023 10:13:29 +0300 Subject: [PATCH 12/12] small fix --- templates/cw721-template/examples/schema.rs | 3 +- templates/cw721-template/src/contract.rs | 9 ++-- templates/cw721-template/src/msg.rs | 1 + templates/cw721-template/src/tests.rs | 46 ++++++++++----------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/templates/cw721-template/examples/schema.rs b/templates/cw721-template/examples/schema.rs index 1c2e79b22..b378cc219 100644 --- a/templates/cw721-template/examples/schema.rs +++ b/templates/cw721-template/examples/schema.rs @@ -1,7 +1,6 @@ use cosmwasm_schema::write_api; -use cw721_base::InstantiateMsg; -use {{crate_name}}::msg::{ExecuteMsg, QueryMsg}; +use {{crate_name}}::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { write_api! { diff --git a/templates/cw721-template/src/contract.rs b/templates/cw721-template/src/contract.rs index 4f0e1c4d7..e79178b9c 100644 --- a/templates/cw721-template/src/contract.rs +++ b/templates/cw721-template/src/contract.rs @@ -5,16 +5,15 @@ pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[cfg(not(feature = "library"))] pub mod entry { use crate::error::ContractError; - use crate::msg::{Cw721Contract, ExecuteMsg, QueryMsg}; + use crate::msg::{Cw721Contract, ExecuteMsg, InstantiateMsg, QueryMsg}; use super::*; use cosmwasm_std::entry_point; use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; - use cw721_base::InstantiateMsg; // This makes a conscious choice on the various generics used by the contract - #[cfg_attr(not(feature = "library"), entry_point)] + #[entry_point] pub fn instantiate( mut deps: DepsMut, env: Env, @@ -27,7 +26,7 @@ pub mod entry { Cw721Contract::default().instantiate(deps.branch(), env, info, msg) } - #[cfg_attr(not(feature = "library"), entry_point)] + #[entry_point] pub fn execute( deps: DepsMut, env: Env, @@ -51,7 +50,7 @@ pub mod entry { } } - #[cfg_attr(not(feature = "library"), entry_point)] + #[entry_point] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { // Optionally override a default cw721-base query diff --git a/templates/cw721-template/src/msg.rs b/templates/cw721-template/src/msg.rs index 3d6981f43..d6af97119 100644 --- a/templates/cw721-template/src/msg.rs +++ b/templates/cw721-template/src/msg.rs @@ -1,5 +1,6 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{CustomMsg, Empty}; +pub use cw721_base::msg::InstantiateMsg; // Implements extended on-chain metadata, by default cw721 NFTs only store a // token_uri, which is a URL to off-chain metadata (same as ERC721). diff --git a/templates/cw721-template/src/tests.rs b/templates/cw721-template/src/tests.rs index 0c292539b..1da9ca9f9 100644 --- a/templates/cw721-template/src/tests.rs +++ b/templates/cw721-template/src/tests.rs @@ -1,29 +1,27 @@ -mod tests { - use crate::contract::{entry, CONTRACT_NAME}; +use crate::contract::{entry, CONTRACT_NAME}; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cw721_base::InstantiateMsg; +use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; +use cw721_base::InstantiateMsg; - /// Make sure cw2 version info is properly initialized during instantiation, - /// and NOT overwritten by the base contract. - #[test] - fn proper_cw2_initialization() { - let mut deps = mock_dependencies(); +/// Make sure cw2 version info is properly initialized during instantiation, +/// and NOT overwritten by the base contract. +#[test] +fn proper_cw2_initialization() { + let mut deps = mock_dependencies(); - entry::instantiate( - deps.as_mut(), - mock_env(), - mock_info("larry", &[]), - InstantiateMsg { - name: "".into(), - symbol: "".into(), - minter: "larry".into(), - }, - ) - .unwrap(); + entry::instantiate( + deps.as_mut(), + mock_env(), + mock_info("larry", &[]), + InstantiateMsg { + name: "".into(), + symbol: "".into(), + minter: "larry".into(), + }, + ) + .unwrap(); - let version = cw2::get_contract_version(deps.as_ref().storage).unwrap(); - assert_eq!(version.contract, CONTRACT_NAME); - assert_ne!(version.contract, cw721_base::CONTRACT_NAME); - } + let version = cw2::get_contract_version(deps.as_ref().storage).unwrap(); + assert_eq!(version.contract, CONTRACT_NAME); + assert_ne!(version.contract, cw721_base::CONTRACT_NAME); }