From f721945d9061df67c10bcf0a2ee63417464716d8 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 17 Mar 2021 16:05:28 +0800 Subject: [PATCH 01/11] Add cw1155 specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design decisions: - Fungible tokens and non-fungible tokens are treated equally, non-fungible tokens just have one max supply. - Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) - Metadata and token enumeration should be done by indexing events off-chain. - Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time. --- Cargo.lock | 12 + packages/cw0/src/event.rs | 5 + packages/cw0/src/lib.rs | 2 + packages/cw1155/Cargo.toml | 18 ++ packages/cw1155/README.md | 63 +++++ packages/cw1155/examples/schema.rs | 21 ++ packages/cw1155/schema/balance_response.json | 18 ++ .../cw1155/schema/batch_balance_response.json | 21 ++ .../schema/cw1155_batch_receive_msg.json | 63 +++++ packages/cw1155/schema/cw1155_handle_msg.json | 226 ++++++++++++++++++ packages/cw1155/schema/cw1155_query_msg.json | 86 +++++++ .../cw1155/schema/cw1155_receive_msg.json | 54 +++++ packages/cw1155/src/event.rs | 42 ++++ packages/cw1155/src/lib.rs | 9 + packages/cw1155/src/msg.rs | 48 ++++ packages/cw1155/src/query.rs | 41 ++++ packages/cw1155/src/receiver.rs | 73 ++++++ 17 files changed, 802 insertions(+) create mode 100644 packages/cw0/src/event.rs create mode 100644 packages/cw1155/Cargo.toml create mode 100644 packages/cw1155/README.md create mode 100644 packages/cw1155/examples/schema.rs create mode 100644 packages/cw1155/schema/balance_response.json create mode 100644 packages/cw1155/schema/batch_balance_response.json create mode 100644 packages/cw1155/schema/cw1155_batch_receive_msg.json create mode 100644 packages/cw1155/schema/cw1155_handle_msg.json create mode 100644 packages/cw1155/schema/cw1155_query_msg.json create mode 100644 packages/cw1155/schema/cw1155_receive_msg.json create mode 100644 packages/cw1155/src/event.rs create mode 100644 packages/cw1155/src/lib.rs create mode 100644 packages/cw1155/src/msg.rs create mode 100644 packages/cw1155/src/query.rs create mode 100644 packages/cw1155/src/receiver.rs diff --git a/Cargo.lock b/Cargo.lock index 37c757d6e..ea7427230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "arrayvec" version = "0.5.2" @@ -241,6 +243,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cw1155" +version = "0.6.0-alpha1" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "schemars", + "serde", +] + [[package]] name = "cw2" version = "0.6.0-alpha1" diff --git a/packages/cw0/src/event.rs b/packages/cw0/src/event.rs new file mode 100644 index 000000000..dad2b87c1 --- /dev/null +++ b/packages/cw0/src/event.rs @@ -0,0 +1,5 @@ +use cosmwasm_std::Attribute; + +pub trait Event { + fn write_attributes(&self, attributes: &mut Vec); +} diff --git a/packages/cw0/src/lib.rs b/packages/cw0/src/lib.rs index 96278b8ef..5fac7f7f6 100644 --- a/packages/cw0/src/lib.rs +++ b/packages/cw0/src/lib.rs @@ -1,4 +1,5 @@ mod balance; +mod event; mod expiration; mod pagination; mod payment; @@ -9,4 +10,5 @@ pub use pagination::{ pub use payment::{may_pay, must_pay, nonpayable, one_coin, PaymentError}; pub use crate::balance::NativeBalance; +pub use crate::event::Event; pub use crate::expiration::{Duration, Expiration, DAY, HOUR, WEEK}; diff --git a/packages/cw1155/Cargo.toml b/packages/cw1155/Cargo.toml new file mode 100644 index 000000000..bde54e112 --- /dev/null +++ b/packages/cw1155/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "cw1155" +version = "0.6.0-alpha1" +authors = ["Huang Yi "] +edition = "2018" +description = "Definition and types for the CosmWasm-1155 interface" +license = "Apache-2.0" +repository = "https://github.com/CosmWasm/cosmwasm-plus" +homepage = "https://cosmwasm.com" +documentation = "https://docs.cosmwasm.com" + +[dependencies] +cosmwasm-std = { version = "0.14.0-beta1" } +schemars = "0.7" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } + +[dev-dependencies] +cosmwasm-schema = { version = "0.14.0-alpha2" } diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md new file mode 100644 index 000000000..bcd129212 --- /dev/null +++ b/packages/cw1155/README.md @@ -0,0 +1,63 @@ +# CW1155 Spec: Multiple Tokens + +CW1155 is a specification for managing multiple tokens based on CosmWasm. +The name and design is based on Ethereum's ERC1155 standard. + +Design decisions: + +- Fungible tokens and non-fungible tokens are treated equally, non-fungible tokens just have one max supply. + +- Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) + +- Metadata and token enumeration should be done by indexing events off-chain. + +- Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. + + In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time. + +## Base + +### Messages + +`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator should have approval from the source account. + +`SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. `to` +must be an address controlled by a smart contract, which implements +the `CW1155Receiver` interface. The operator should have approval from the source account. The `msg` will be passed to the recipient contract, along with the other fields. + +`BatchTransferFrom{from, to, batch}` - Batched version of `TransferFrom` which can handle multiple types of tokens at once. + +`BatchSendFrom{from, contract, batch, msg}` - Batched version of `SendFrom` which can handle multiple types of tokens at once. + +`SetApprovalForAll { operator, approved }` - Grant or revoke `operator` the permission to transfer or send all tokens owned by `msg.sender`. This approval is tied to the owner, not the +tokens and applies to any future token that the owner receives as well. + +### Queries + +`Balance { owner, token_id }` - Query the balance of `owner` on perticular type of token, default to `0` when record not exist. + +`BatchBalance { owner, token_ids }` - Query the balance of `owner` on multiple types of tokens, batched version of `Balance` + +`ApprovedForAll{ owner, spender }` - Query if `spender` has the permission to transfer or send tokens owned by `msg.sender`. + +### Receiver + +Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and `Cw1155BatchReceiveMsg`. + +`Cw1155ReceiveMsg { operator, from, token_id, amount, msg}` - + +`Cw1155BatchReceiveMsg { operator, from, batch, msg}` - + +### Events + +- `transfer(from, to, token_id, value)` + + `from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning. + +- `metadata(url, token_id)` + + Metadata url of `token_id` is changed, `url` should point to a json file. + +## Metadata and Enumerable + +[TODO] ERC1155 suggests that metadata and enumerable should be indexed from events log, to save some on-chain storage. Should we define standard events like ERC1155? \ No newline at end of file diff --git a/packages/cw1155/examples/schema.rs b/packages/cw1155/examples/schema.rs new file mode 100644 index 000000000..e32488031 --- /dev/null +++ b/packages/cw1155/examples/schema.rs @@ -0,0 +1,21 @@ +use std::env::current_dir; +use std::fs::create_dir_all; + +use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; + +use cw1155; + +fn main() { + let mut out_dir = current_dir().unwrap(); + out_dir.push("schema"); + create_dir_all(&out_dir).unwrap(); + remove_schemas(&out_dir).unwrap(); + + export_schema(&schema_for!(cw1155::Cw1155HandleMsg), &out_dir); + export_schema(&schema_for!(cw1155::Cw1155QueryMsg), &out_dir); + export_schema(&schema_for!(cw1155::Cw1155ReceiveMsg), &out_dir); + export_schema(&schema_for!(cw1155::Cw1155BatchReceiveMsg), &out_dir); + export_schema(&schema_for!(cw1155::BalanceResponse), &out_dir); + export_schema(&schema_for!(cw1155::BatchBalanceResponse), &out_dir); + export_schema(&schema_for!(cw1155::ApprovedForAllResponse), &out_dir); +} diff --git a/packages/cw1155/schema/balance_response.json b/packages/cw1155/schema/balance_response.json new file mode 100644 index 000000000..efa5d6ce0 --- /dev/null +++ b/packages/cw1155/schema/balance_response.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "BalanceResponse", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "$ref": "#/definitions/Uint128" + } + }, + "definitions": { + "Uint128": { + "type": "string" + } + } +} diff --git a/packages/cw1155/schema/batch_balance_response.json b/packages/cw1155/schema/batch_balance_response.json new file mode 100644 index 000000000..138cc4a43 --- /dev/null +++ b/packages/cw1155/schema/batch_balance_response.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "BatchBalanceResponse", + "type": "object", + "required": [ + "balances" + ], + "properties": { + "balances": { + "type": "array", + "items": { + "$ref": "#/definitions/Uint128" + } + } + }, + "definitions": { + "Uint128": { + "type": "string" + } + } +} diff --git a/packages/cw1155/schema/cw1155_batch_receive_msg.json b/packages/cw1155/schema/cw1155_batch_receive_msg.json new file mode 100644 index 000000000..c87676573 --- /dev/null +++ b/packages/cw1155/schema/cw1155_batch_receive_msg.json @@ -0,0 +1,63 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155BatchReceiveMsg", + "description": "Cw1155BatchReceiveMsg should be de/serialized under `BatchReceive()` variant in a HandleMsg", + "type": "object", + "required": [ + "batch", + "operator" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "from": { + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] + }, + "msg": { + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "operator": { + "$ref": "#/definitions/HumanAddr" + } + }, + "definitions": { + "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", + "type": "string" + }, + "HumanAddr": { + "type": "string" + }, + "Uint128": { + "type": "string" + } + } +} diff --git a/packages/cw1155/schema/cw1155_handle_msg.json b/packages/cw1155/schema/cw1155_handle_msg.json new file mode 100644 index 000000000..d12c568fd --- /dev/null +++ b/packages/cw1155/schema/cw1155_handle_msg.json @@ -0,0 +1,226 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155HandleMsg", + "anyOf": [ + { + "description": "TransferFrom is a base message to move tokens if `env.sender` has sufficient pre-approval.", + "type": "object", + "required": [ + "transfer_from" + ], + "properties": { + "transfer_from": { + "type": "object", + "required": [ + "token_id", + "value" + ], + "properties": { + "from": { + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] + }, + "to": { + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] + }, + "token_id": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Uint128" + } + } + } + } + }, + { + "description": "SendFrom is a base message to move tokens to contract if `env.sender` has sufficient pre-approval.", + "type": "object", + "required": [ + "send_from" + ], + "properties": { + "send_from": { + "type": "object", + "required": [ + "contract", + "token_id", + "value" + ], + "properties": { + "contract": { + "$ref": "#/definitions/HumanAddr" + }, + "from": { + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] + }, + "msg": { + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "token_id": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Uint128" + } + } + } + } + }, + { + "description": "BatchTransferFrom is a base message to move tokens to another account without triggering actions", + "type": "object", + "required": [ + "batch_transfer_from" + ], + "properties": { + "batch_transfer_from": { + "type": "object", + "required": [ + "batch", + "from", + "to" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + }, + { + "description": "BatchSendFrom is a base message to move tokens to another to without triggering actions", + "type": "object", + "required": [ + "batch_send_from" + ], + "properties": { + "batch_send_from": { + "type": "object", + "required": [ + "batch", + "contract", + "from" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "contract": { + "$ref": "#/definitions/HumanAddr" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "msg": { + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + } + } + } + } + }, + { + "description": "Enable or disable approval for a third party (\"operator\") to manage all of the caller's tokens.", + "type": "object", + "required": [ + "set_approval_for_all" + ], + "properties": { + "set_approval_for_all": { + "type": "object", + "required": [ + "approved", + "operator" + ], + "properties": { + "approved": { + "type": "boolean" + }, + "operator": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + } + ], + "definitions": { + "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", + "type": "string" + }, + "HumanAddr": { + "type": "string" + }, + "Uint128": { + "type": "string" + } + } +} diff --git a/packages/cw1155/schema/cw1155_query_msg.json b/packages/cw1155/schema/cw1155_query_msg.json new file mode 100644 index 000000000..5b6a039fb --- /dev/null +++ b/packages/cw1155/schema/cw1155_query_msg.json @@ -0,0 +1,86 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155QueryMsg", + "anyOf": [ + { + "description": "Returns the current balance of the given address, 0 if unset. Return type: BalanceResponse.", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "type": "object", + "required": [ + "owner", + "token_id" + ], + "properties": { + "owner": { + "$ref": "#/definitions/HumanAddr" + }, + "token_id": { + "type": "string" + } + } + } + } + }, + { + "description": "Returns the current balance of the given address for a batch of tokens, 0 if unset. Return type: BatchBalanceResponse.", + "type": "object", + "required": [ + "batch_balance" + ], + "properties": { + "batch_balance": { + "type": "object", + "required": [ + "owner", + "token_ids" + ], + "properties": { + "owner": { + "$ref": "#/definitions/HumanAddr" + }, + "token_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + { + "description": "Queries the approval status of an operator for a given owner Return type: ApprovedForAllResponse.", + "type": "object", + "required": [ + "approved_for_all" + ], + "properties": { + "approved_for_all": { + "type": "object", + "required": [ + "owner", + "spender" + ], + "properties": { + "owner": { + "$ref": "#/definitions/HumanAddr" + }, + "spender": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + } + ], + "definitions": { + "HumanAddr": { + "type": "string" + } + } +} diff --git a/packages/cw1155/schema/cw1155_receive_msg.json b/packages/cw1155/schema/cw1155_receive_msg.json new file mode 100644 index 000000000..27ae7c648 --- /dev/null +++ b/packages/cw1155/schema/cw1155_receive_msg.json @@ -0,0 +1,54 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155ReceiveMsg", + "description": "Cw1155ReceiveMsg should be de/serialized under `Receive()` variant in a HandleMsg", + "type": "object", + "required": [ + "amount", + "operator", + "token_id" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "from": { + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] + }, + "msg": { + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "operator": { + "$ref": "#/definitions/HumanAddr" + }, + "token_id": { + "type": "string" + } + }, + "definitions": { + "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", + "type": "string" + }, + "HumanAddr": { + "type": "string" + }, + "Uint128": { + "type": "string" + } + } +} diff --git a/packages/cw1155/src/event.rs b/packages/cw1155/src/event.rs new file mode 100644 index 000000000..b6439c5b0 --- /dev/null +++ b/packages/cw1155/src/event.rs @@ -0,0 +1,42 @@ +use cosmwasm_std::{attr, Attribute, HumanAddr, Uint128}; +use cw0::Event; + +use crate::msg::TokenId; + +pub struct TransferEvent<'a> { + pub from: Option<&'a HumanAddr>, + pub to: Option<&'a HumanAddr>, + pub token_id: TokenId, + pub amount: Uint128, +} + +impl Event for TransferEvent { + fn write_attributes(&self, attributes: &mut Vec) { + attributes.extend_from_slice(&[ + attr("action", "transfer"), + attr("token_id", self.token_id), + attr("amount", self.amount), + ]); + if let Some(from) = from { + attributes.push(attr("from", from)); + } + if let Some(to) = to { + attributes.push(attr("to", to)); + } + } +} + +pub struct MetadataEvent<'a> { + pub url: &'a str, + pub token_id: TokenId, +} + +impl Event for URLEvent { + fn write_attributes(&self, attributes: &mut Vec) { + attributes.extend_from_slice(&[ + attr("action", "set_metadata"), + attr("url", self.url), + attr("token_id", self.token_id), + ]); + } +} diff --git a/packages/cw1155/src/lib.rs b/packages/cw1155/src/lib.rs new file mode 100644 index 000000000..84583d914 --- /dev/null +++ b/packages/cw1155/src/lib.rs @@ -0,0 +1,9 @@ +pub use crate::msg::{Cw1155HandleMsg, TokenId}; +pub use crate::query::{ + ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, +}; +pub use crate::receiver::{Cw1155BatchReceiveMsg, Cw1155ReceiveMsg}; + +mod msg; +mod query; +mod receiver; diff --git a/packages/cw1155/src/msg.rs b/packages/cw1155/src/msg.rs new file mode 100644 index 000000000..9b566386e --- /dev/null +++ b/packages/cw1155/src/msg.rs @@ -0,0 +1,48 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::{Binary, HumanAddr, Uint128}; + +pub type TokenId = String; + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub enum Cw1155HandleMsg { + /// TransferFrom is a base message to move tokens, if `env.sender` has sufficient pre-approval. + TransferFrom { + // `None` means minting + from: Option, + // `None` means burning + to: Option, + token_id: TokenId, + value: Uint128, + }, + /// SendFrom is a base message to move tokens to contract + /// if `env.sender` has sufficient pre-approval. + SendFrom { + // `None` means minting + from: Option, + contract: HumanAddr, + token_id: TokenId, + value: Uint128, + msg: Option, + }, + /// BatchTransferFrom is a base message to move tokens to another account without triggering actions + BatchTransferFrom { + // `None` means minting + from: Option, + // `None` means burning + to: Option, + batch: Vec<(TokenId, Uint128)>, + }, + /// BatchSendFrom is a base message to move tokens to another to without triggering actions + BatchSendFrom { + // `None` means minting + from: Option, + contract: HumanAddr, + batch: Vec<(TokenId, Uint128)>, + msg: Option, + }, + /// Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + SetApprovalForAll { operator: HumanAddr, approved: bool }, +} diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs new file mode 100644 index 000000000..d2e08d8fa --- /dev/null +++ b/packages/cw1155/src/query.rs @@ -0,0 +1,41 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::{HumanAddr, Uint128}; + +use crate::msg::TokenId; + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub enum Cw1155QueryMsg { + /// Returns the current balance of the given address, 0 if unset. + /// Return type: BalanceResponse. + Balance { owner: HumanAddr, token_id: TokenId }, + /// Returns the current balance of the given address for a batch of tokens, 0 if unset. + /// Return type: BatchBalanceResponse. + BatchBalance { + owner: HumanAddr, + token_ids: Vec, + }, + /// Queries the approval status of an operator for a given owner + /// Return type: ApprovedForAllResponse. + ApprovedForAll { + owner: HumanAddr, + spender: HumanAddr, + }, +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct BalanceResponse { + pub balance: Uint128, +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct BatchBalanceResponse { + pub balances: Vec, +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct ApprovedForAllResponse { + pub approved: bool, +} diff --git a/packages/cw1155/src/receiver.rs b/packages/cw1155/src/receiver.rs new file mode 100644 index 000000000..0e9cb27e8 --- /dev/null +++ b/packages/cw1155/src/receiver.rs @@ -0,0 +1,73 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::{to_binary, Binary, CosmosMsg, HumanAddr, StdResult, Uint128, WasmMsg}; + +use crate::msg::TokenId; + +/// Cw1155ReceiveMsg should be de/serialized under `Receive()` variant in a HandleMsg +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub struct Cw1155ReceiveMsg { + pub operator: HumanAddr, + pub from: Option, + pub token_id: TokenId, + pub amount: Uint128, + pub msg: Option, +} + +impl Cw1155ReceiveMsg { + /// serializes the message + pub fn into_binary(self) -> StdResult { + let msg = ReceiverHandleMsg::Receive(self); + to_binary(&msg) + } + + /// creates a cosmos_msg sending this struct to the named contract + pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + let msg = self.into_binary()?; + let execute = WasmMsg::Execute { + contract_addr, + msg, + send: vec![], + }; + Ok(execute.into()) + } +} + +/// Cw1155BatchReceiveMsg should be de/serialized under `BatchReceive()` variant in a HandleMsg +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub struct Cw1155BatchReceiveMsg { + pub operator: HumanAddr, + pub from: Option, + pub batch: Vec<(TokenId, Uint128)>, + pub msg: Option, +} + +impl Cw1155BatchReceiveMsg { + /// serializes the message + pub fn into_binary(self) -> StdResult { + let msg = ReceiverHandleMsg::BatchReceive(self); + to_binary(&msg) + } + + /// creates a cosmos_msg sending this struct to the named contract + pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + let msg = self.into_binary()?; + let execute = WasmMsg::Execute { + contract_addr, + msg, + send: vec![], + }; + Ok(execute.into()) + } +} + +// This is just a helper to properly serialize the above message +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +enum ReceiverHandleMsg { + Receive(Cw1155ReceiveMsg), + BatchReceive(Cw1155BatchReceiveMsg), +} From 3fd5e709d171725ed69da857f149eaf8b6a03cd3 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 17 Mar 2021 16:29:45 +0800 Subject: [PATCH 02/11] update schema --- .../schema/approved_for_all_response.json | 13 +++++++ packages/cw1155/schema/cw1155_handle_msg.json | 36 ++++++++++++++----- 2 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 packages/cw1155/schema/approved_for_all_response.json diff --git a/packages/cw1155/schema/approved_for_all_response.json b/packages/cw1155/schema/approved_for_all_response.json new file mode 100644 index 000000000..67d916a3d --- /dev/null +++ b/packages/cw1155/schema/approved_for_all_response.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovedForAllResponse", + "type": "object", + "required": [ + "approved" + ], + "properties": { + "approved": { + "type": "boolean" + } + } +} diff --git a/packages/cw1155/schema/cw1155_handle_msg.json b/packages/cw1155/schema/cw1155_handle_msg.json index d12c568fd..95b8ca077 100644 --- a/packages/cw1155/schema/cw1155_handle_msg.json +++ b/packages/cw1155/schema/cw1155_handle_msg.json @@ -3,7 +3,7 @@ "title": "Cw1155HandleMsg", "anyOf": [ { - "description": "TransferFrom is a base message to move tokens if `env.sender` has sufficient pre-approval.", + "description": "TransferFrom is a base message to move tokens, if `env.sender` has sufficient pre-approval.", "type": "object", "required": [ "transfer_from" @@ -104,9 +104,7 @@ "batch_transfer_from": { "type": "object", "required": [ - "batch", - "from", - "to" + "batch" ], "properties": { "batch": { @@ -126,10 +124,24 @@ } }, "from": { - "$ref": "#/definitions/HumanAddr" + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] }, "to": { - "$ref": "#/definitions/HumanAddr" + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] } } } @@ -146,8 +158,7 @@ "type": "object", "required": [ "batch", - "contract", - "from" + "contract" ], "properties": { "batch": { @@ -170,7 +181,14 @@ "$ref": "#/definitions/HumanAddr" }, "from": { - "$ref": "#/definitions/HumanAddr" + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] }, "msg": { "anyOf": [ From d9d54d3bd5ee0fec036e2f8bb6ca22addb244458 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 18 Mar 2021 14:47:47 +0800 Subject: [PATCH 03/11] add TokenInfo query api --- packages/cw0/src/event.rs | 6 ++++-- packages/cw1155/Cargo.toml | 2 +- packages/cw1155/README.md | 14 +++++++------- packages/cw1155/examples/schema.rs | 1 + packages/cw1155/src/lib.rs | 1 + packages/cw1155/src/query.rs | 11 ++++++++++- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/cw0/src/event.rs b/packages/cw0/src/event.rs index dad2b87c1..79abed5a5 100644 --- a/packages/cw0/src/event.rs +++ b/packages/cw0/src/event.rs @@ -1,5 +1,7 @@ -use cosmwasm_std::Attribute; +use cosmwasm_std::Response; +/// This defines a set of attributes which should be added to `Response`. pub trait Event { - fn write_attributes(&self, attributes: &mut Vec); + /// Append attributes to response + fn add_attributes(&self, response: &mut Response); } diff --git a/packages/cw1155/Cargo.toml b/packages/cw1155/Cargo.toml index bde54e112..807803d23 100644 --- a/packages/cw1155/Cargo.toml +++ b/packages/cw1155/Cargo.toml @@ -15,4 +15,4 @@ schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-alpha2" } +cosmwasm-schema = { version = "0.14.0-beta1" } diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md index bcd129212..13f7d7688 100644 --- a/packages/cw1155/README.md +++ b/packages/cw1155/README.md @@ -7,13 +7,11 @@ Design decisions: - Fungible tokens and non-fungible tokens are treated equally, non-fungible tokens just have one max supply. -- Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) - -- Metadata and token enumeration should be done by indexing events off-chain. +- Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) - Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. - In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time. + In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time. ## Base @@ -40,6 +38,8 @@ tokens and applies to any future token that the owner receives as well. `ApprovedForAll{ owner, spender }` - Query if `spender` has the permission to transfer or send tokens owned by `msg.sender`. +`TokenInfo{ token_id }` - Query metadata url of `token_id`. + ### Receiver Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and `Cw1155BatchReceiveMsg`. @@ -54,10 +54,10 @@ Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and `from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning. -- `metadata(url, token_id)` +- `token_info(url, token_id)` - Metadata url of `token_id` is changed, `url` should point to a json file. + Metadata url of `token_id` is changed, `url` should point to a json file. ## Metadata and Enumerable -[TODO] ERC1155 suggests that metadata and enumerable should be indexed from events log, to save some on-chain storage. Should we define standard events like ERC1155? \ No newline at end of file +[TODO] ERC1155 suggests that metadata and enumerable should be indexed from events log, to save some on-chain storage. Should we define standard events like ERC1155? diff --git a/packages/cw1155/examples/schema.rs b/packages/cw1155/examples/schema.rs index e32488031..07cd56ee6 100644 --- a/packages/cw1155/examples/schema.rs +++ b/packages/cw1155/examples/schema.rs @@ -18,4 +18,5 @@ fn main() { export_schema(&schema_for!(cw1155::BalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::BatchBalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::ApprovedForAllResponse), &out_dir); + export_schema(&schema_for!(cw1155::TokenInfoResponse), &out_dir); } diff --git a/packages/cw1155/src/lib.rs b/packages/cw1155/src/lib.rs index 84583d914..d9060eddb 100644 --- a/packages/cw1155/src/lib.rs +++ b/packages/cw1155/src/lib.rs @@ -1,6 +1,7 @@ pub use crate::msg::{Cw1155HandleMsg, TokenId}; pub use crate::query::{ ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, + TokenInfoResponse, }; pub use crate::receiver::{Cw1155BatchReceiveMsg, Cw1155ReceiveMsg}; diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs index d2e08d8fa..e6be4c32a 100644 --- a/packages/cw1155/src/query.rs +++ b/packages/cw1155/src/query.rs @@ -17,12 +17,15 @@ pub enum Cw1155QueryMsg { owner: HumanAddr, token_ids: Vec, }, - /// Queries the approval status of an operator for a given owner + /// Query the approval status of an operator for a given owner /// Return type: ApprovedForAllResponse. ApprovedForAll { owner: HumanAddr, spender: HumanAddr, }, + /// Query metadata of token + /// Return type: TokenInfoResponse. + TokenInfo { token_id: TokenId }, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -39,3 +42,9 @@ pub struct BatchBalanceResponse { pub struct ApprovedForAllResponse { pub approved: bool, } + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct TokenInfoResponse { + /// Should be a url point to a json file + pub url: String, +} From 7354e365876bb218401d2b3b899be1e4f875d7c6 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 18 Mar 2021 15:05:08 +0800 Subject: [PATCH 04/11] Add Enumerable query apis similar to CW721 --- packages/cw1155/README.md | 46 ++++++++-- packages/cw1155/examples/schema.rs | 1 + packages/cw1155/schema/cw1155_query_msg.json | 84 ++++++++++++++++++- .../cw1155/schema/token_info_response.json | 14 ++++ packages/cw1155/schema/tokens_response.json | 17 ++++ packages/cw1155/src/lib.rs | 2 +- packages/cw1155/src/query.rs | 26 ++++++ 7 files changed, 179 insertions(+), 11 deletions(-) create mode 100644 packages/cw1155/schema/token_info_response.json create mode 100644 packages/cw1155/schema/tokens_response.json diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md index 13f7d7688..c0c454117 100644 --- a/packages/cw1155/README.md +++ b/packages/cw1155/README.md @@ -3,6 +3,9 @@ CW1155 is a specification for managing multiple tokens based on CosmWasm. The name and design is based on Ethereum's ERC1155 standard. +The specification is split into multiple sections, a contract may only +implement some of this functionality, but must implement the base. + Design decisions: - Fungible tokens and non-fungible tokens are treated equally, non-fungible tokens just have one max supply. @@ -17,11 +20,11 @@ Design decisions: ### Messages -`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator should have approval from the source account. +`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator should either be the `from` account or have approval from it. `SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. `to` must be an address controlled by a smart contract, which implements -the `CW1155Receiver` interface. The operator should have approval from the source account. The `msg` will be passed to the recipient contract, along with the other fields. +the `CW1155Receiver` interface. The operator should eitherbe the `from` account or have approval from it. The `msg` will be passed to the recipient contract, along with the other fields. `BatchTransferFrom{from, to, batch}` - Batched version of `TransferFrom` which can handle multiple types of tokens at once. @@ -38,8 +41,6 @@ tokens and applies to any future token that the owner receives as well. `ApprovedForAll{ owner, spender }` - Query if `spender` has the permission to transfer or send tokens owned by `msg.sender`. -`TokenInfo{ token_id }` - Query metadata url of `token_id`. - ### Receiver Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and `Cw1155BatchReceiveMsg`. @@ -52,12 +53,39 @@ Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and - `transfer(from, to, token_id, value)` - `from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning. + `from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning, but they mustn't be neglected at the same time. + + +## Metadata + +### Queries + +`TokenInfo{ token_id }` - Query metadata url of `token_id`. + +### Events + +`token_info(url, token_id)` + +Metadata url of `token_id` is changed, `url` should point to a json file. + +## Enumerable + +### Queries -- `token_info(url, token_id)` +Pagination is acheived via `start_after` and `limit`. Limit is a request +set by the client, if unset, the contract will automatically set it to +`DefaultLimit` (suggested 10). If set, it will be used up to a `MaxLimit` +value (suggested 30). Contracts can define other `DefaultLimit` and `MaxLimit` +values without violating the CW1155 spec, and clients should not rely on +any particular values. - Metadata url of `token_id` is changed, `url` should point to a json file. +If `start_after` is unset, the query returns the first results, ordered by +lexogaphically by `token_id`. If `start_after` is set, then it returns the +first `limit` tokens *after* the given one. This allows straight-forward +pagination by taking the last result returned (a `token_id`) and using it +as the `start_after` value in a future query. -## Metadata and Enumerable +`Tokens{owner, start_after, limit}` - List all token_ids that belong to a given owner. +Return type is `TokensResponse{tokens: Vec}`. -[TODO] ERC1155 suggests that metadata and enumerable should be indexed from events log, to save some on-chain storage. Should we define standard events like ERC1155? +`AllTokens{start_after, limit}` - Requires pagination. Lists all token_ids controlled by the contract. \ No newline at end of file diff --git a/packages/cw1155/examples/schema.rs b/packages/cw1155/examples/schema.rs index 07cd56ee6..40f3fb35c 100644 --- a/packages/cw1155/examples/schema.rs +++ b/packages/cw1155/examples/schema.rs @@ -19,4 +19,5 @@ fn main() { export_schema(&schema_for!(cw1155::BatchBalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::ApprovedForAllResponse), &out_dir); export_schema(&schema_for!(cw1155::TokenInfoResponse), &out_dir); + export_schema(&schema_for!(cw1155::TokensResponse), &out_dir); } diff --git a/packages/cw1155/schema/cw1155_query_msg.json b/packages/cw1155/schema/cw1155_query_msg.json index 5b6a039fb..3159534df 100644 --- a/packages/cw1155/schema/cw1155_query_msg.json +++ b/packages/cw1155/schema/cw1155_query_msg.json @@ -54,7 +54,7 @@ } }, { - "description": "Queries the approval status of an operator for a given owner Return type: ApprovedForAllResponse.", + "description": "Query the approval status of an operator for a given owner Return type: ApprovedForAllResponse.", "type": "object", "required": [ "approved_for_all" @@ -76,6 +76,88 @@ } } } + }, + { + "description": "With MetaData Extension. Query metadata of token Return type: TokenInfoResponse.", + "type": "object", + "required": [ + "token_info" + ], + "properties": { + "token_info": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "token_id": { + "type": "string" + } + } + } + } + }, + { + "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset. Return type: TokensResponse.", + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "owner": { + "$ref": "#/definitions/HumanAddr" + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + } + } + } + }, + { + "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract. Return type: TokensResponse.", + "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" + ] + } + } + } + } } ], "definitions": { diff --git a/packages/cw1155/schema/token_info_response.json b/packages/cw1155/schema/token_info_response.json new file mode 100644 index 000000000..a94af98e3 --- /dev/null +++ b/packages/cw1155/schema/token_info_response.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TokenInfoResponse", + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "description": "Should be a url point to a json file", + "type": "string" + } + } +} diff --git a/packages/cw1155/schema/tokens_response.json b/packages/cw1155/schema/tokens_response.json new file mode 100644 index 000000000..b8e3d75b5 --- /dev/null +++ b/packages/cw1155/schema/tokens_response.json @@ -0,0 +1,17 @@ +{ + "$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" + } + } + } +} diff --git a/packages/cw1155/src/lib.rs b/packages/cw1155/src/lib.rs index d9060eddb..719b75493 100644 --- a/packages/cw1155/src/lib.rs +++ b/packages/cw1155/src/lib.rs @@ -1,7 +1,7 @@ pub use crate::msg::{Cw1155HandleMsg, TokenId}; pub use crate::query::{ ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, - TokenInfoResponse, + TokenInfoResponse, TokensResponse, }; pub use crate::receiver::{Cw1155BatchReceiveMsg, Cw1155ReceiveMsg}; diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs index e6be4c32a..08a6e6313 100644 --- a/packages/cw1155/src/query.rs +++ b/packages/cw1155/src/query.rs @@ -23,9 +23,27 @@ pub enum Cw1155QueryMsg { owner: HumanAddr, spender: HumanAddr, }, + + /// With MetaData Extension. /// Query metadata of token /// Return type: TokenInfoResponse. TokenInfo { token_id: TokenId }, + + /// With Enumerable extension. + /// Returns all tokens owned by the given address, [] if unset. + /// Return type: TokensResponse. + Tokens { + owner: HumanAddr, + start_after: Option, + limit: Option, + }, + /// With Enumerable extension. + /// Requires pagination. Lists all token_ids controlled by the contract. + /// Return type: TokensResponse. + AllTokens { + start_after: Option, + limit: Option, + }, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -48,3 +66,11 @@ pub struct TokenInfoResponse { /// Should be a url point to a json file pub url: String, } + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct TokensResponse { + /// Contains all token_ids in lexicographical ordering + /// If there are more than `limit`, use `start_from` in future queries + /// to achieve pagination. + pub tokens: Vec, +} From 242a9f697ea21bd84f09712fed8b9c8e20ac766a Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 18 Mar 2021 15:25:49 +0800 Subject: [PATCH 05/11] Change approval apis similar to CW721 --- Cargo.lock | 1 + packages/cw1155/Cargo.toml | 1 + packages/cw1155/README.md | 12 ++++++++---- packages/cw1155/src/lib.rs | 2 +- packages/cw1155/src/msg.rs | 24 +++++++++++++++++------- packages/cw1155/src/query.rs | 18 +++++++++++++++--- 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea7427230..6b0a91b31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -249,6 +249,7 @@ version = "0.6.0-alpha1" dependencies = [ "cosmwasm-schema", "cosmwasm-std", + "cw0", "schemars", "serde", ] diff --git a/packages/cw1155/Cargo.toml b/packages/cw1155/Cargo.toml index 807803d23..8e81cfc23 100644 --- a/packages/cw1155/Cargo.toml +++ b/packages/cw1155/Cargo.toml @@ -10,6 +10,7 @@ homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" [dependencies] +cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha1" } cosmwasm-std = { version = "0.14.0-beta1" } schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md index c0c454117..8de8bc42b 100644 --- a/packages/cw1155/README.md +++ b/packages/cw1155/README.md @@ -30,16 +30,20 @@ the `CW1155Receiver` interface. The operator should eitherbe the `from` account `BatchSendFrom{from, contract, batch, msg}` - Batched version of `SendFrom` which can handle multiple types of tokens at once. -`SetApprovalForAll { operator, approved }` - Grant or revoke `operator` the permission to transfer or send all tokens owned by `msg.sender`. This approval is tied to the owner, not the -tokens and applies to any future token that the owner receives as well. +`ApproveAll{ operator, expires }` - Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit. + +`RevokeAll { operator }` - Remove previously granted ApproveAll permission ### Queries `Balance { owner, token_id }` - Query the balance of `owner` on perticular type of token, default to `0` when record not exist. -`BatchBalance { owner, token_ids }` - Query the balance of `owner` on multiple types of tokens, batched version of `Balance` +`BatchBalance { owner, token_ids }` - Query the balance of `owner` on multiple types of tokens, batched version of `Balance`. -`ApprovedForAll{ owner, spender }` - Query if `spender` has the permission to transfer or send tokens owned by `msg.sender`. +`ApprovedForAll{owner, include_expired, start_after, limit}` - List all operators that can +access all of the owner's tokens. Return type is `ApprovedForAllResponse`. +If `include_expired` is set, show expired owners in the results, otherwise, +ignore them. If query for some specific operator, set `start_after` to the operator, and set limit to 1. ### Receiver diff --git a/packages/cw1155/src/lib.rs b/packages/cw1155/src/lib.rs index 719b75493..2ef82fbf2 100644 --- a/packages/cw1155/src/lib.rs +++ b/packages/cw1155/src/lib.rs @@ -1,6 +1,6 @@ pub use crate::msg::{Cw1155HandleMsg, TokenId}; pub use crate::query::{ - ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, + Approval, ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, TokenInfoResponse, TokensResponse, }; pub use crate::receiver::{Cw1155BatchReceiveMsg, Cw1155ReceiveMsg}; diff --git a/packages/cw1155/src/msg.rs b/packages/cw1155/src/msg.rs index 9b566386e..34ab1d4ea 100644 --- a/packages/cw1155/src/msg.rs +++ b/packages/cw1155/src/msg.rs @@ -2,13 +2,15 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use cosmwasm_std::{Binary, HumanAddr, Uint128}; +use cw0::Expiration; pub type TokenId = String; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum Cw1155HandleMsg { - /// TransferFrom is a base message to move tokens, if `env.sender` has sufficient pre-approval. + /// TransferFrom is a base message to move tokens. + /// if `env.sender` is the owner or has sufficient pre-approval. TransferFrom { // `None` means minting from: Option, @@ -17,8 +19,8 @@ pub enum Cw1155HandleMsg { token_id: TokenId, value: Uint128, }, - /// SendFrom is a base message to move tokens to contract - /// if `env.sender` has sufficient pre-approval. + /// SendFrom is a base message to move tokens to contract. + /// if `env.sender` is the owner or has sufficient pre-approval. SendFrom { // `None` means minting from: Option, @@ -27,7 +29,8 @@ pub enum Cw1155HandleMsg { value: Uint128, msg: Option, }, - /// BatchTransferFrom is a base message to move tokens to another account without triggering actions + /// BatchTransferFrom is a base message to move tokens to another account without triggering actions. + /// if `env.sender` is the owner or has sufficient pre-approval. BatchTransferFrom { // `None` means minting from: Option, @@ -35,7 +38,8 @@ pub enum Cw1155HandleMsg { to: Option, batch: Vec<(TokenId, Uint128)>, }, - /// BatchSendFrom is a base message to move tokens to another to without triggering actions + /// BatchSendFrom is a base message to move tokens to another to without triggering actions. + /// if `env.sender` is the owner or has sufficient pre-approval. BatchSendFrom { // `None` means minting from: Option, @@ -43,6 +47,12 @@ pub enum Cw1155HandleMsg { batch: Vec<(TokenId, Uint128)>, msg: Option, }, - /// Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. - SetApprovalForAll { operator: HumanAddr, approved: bool }, + /// Allows operator to transfer / send any token from the owner's account. + /// If expiration is set, then this allowance has a time/height limit + ApproveAll { + operator: HumanAddr, + expires: Option, + }, + /// Remove previously granted ApproveAll permission + RevokeAll { operator: HumanAddr }, } diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs index 08a6e6313..394e94b13 100644 --- a/packages/cw1155/src/query.rs +++ b/packages/cw1155/src/query.rs @@ -2,6 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use cosmwasm_std::{HumanAddr, Uint128}; +use cw0::Expiration; use crate::msg::TokenId; @@ -17,11 +18,14 @@ pub enum Cw1155QueryMsg { owner: HumanAddr, token_ids: Vec, }, - /// Query the approval status of an operator for a given owner + /// List all operators that can access all of the owner's tokens. /// Return type: ApprovedForAllResponse. ApprovedForAll { owner: HumanAddr, - spender: HumanAddr, + /// unset or false will filter out expired approvals, you must set to true to see them + include_expired: Option, + start_after: Option, + limit: Option, }, /// With MetaData Extension. @@ -56,9 +60,17 @@ pub struct BatchBalanceResponse { pub balances: Vec, } +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct Approval { + /// Account that can transfer/send the token + pub spender: HumanAddr, + /// When the Approval expires (maybe Expiration::never) + pub expires: Expiration, +} + #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct ApprovedForAllResponse { - pub approved: bool, + pub operators: Vec, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] From e750e9325699c7934afa5355e00d29dbf9574583 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 18 Mar 2021 15:30:12 +0800 Subject: [PATCH 06/11] Add comments to Cw1155ReceiveMsg --- packages/cw1155/src/receiver.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/cw1155/src/receiver.rs b/packages/cw1155/src/receiver.rs index 0e9cb27e8..7e14e6441 100644 --- a/packages/cw1155/src/receiver.rs +++ b/packages/cw1155/src/receiver.rs @@ -9,7 +9,9 @@ use crate::msg::TokenId; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub struct Cw1155ReceiveMsg { + /// The account that executed the send message pub operator: HumanAddr, + /// The account that the token transfered from pub from: Option, pub token_id: TokenId, pub amount: Uint128, From 3bc9208b9229acf9e05852818284e60346338034 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 18 Mar 2021 16:17:23 +0800 Subject: [PATCH 07/11] update schema --- .../schema/approved_for_all_response.json | 84 ++++++++++++++++- packages/cw1155/schema/cw1155_handle_msg.json | 91 +++++++++++++++++-- packages/cw1155/schema/cw1155_query_msg.json | 31 ++++++- .../cw1155/schema/cw1155_receive_msg.json | 8 +- 4 files changed, 195 insertions(+), 19 deletions(-) diff --git a/packages/cw1155/schema/approved_for_all_response.json b/packages/cw1155/schema/approved_for_all_response.json index 67d916a3d..5b013ee49 100644 --- a/packages/cw1155/schema/approved_for_all_response.json +++ b/packages/cw1155/schema/approved_for_all_response.json @@ -3,11 +3,89 @@ "title": "ApprovedForAllResponse", "type": "object", "required": [ - "approved" + "operators" ], "properties": { - "approved": { - "type": "boolean" + "operators": { + "type": "array", + "items": { + "$ref": "#/definitions/Approval" + } + } + }, + "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", + "allOf": [ + { + "$ref": "#/definitions/HumanAddr" + } + ] + } + } + }, + "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)", + "anyOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + } + } + ] + }, + "HumanAddr": { + "type": "string" } } } diff --git a/packages/cw1155/schema/cw1155_handle_msg.json b/packages/cw1155/schema/cw1155_handle_msg.json index 95b8ca077..200c53be8 100644 --- a/packages/cw1155/schema/cw1155_handle_msg.json +++ b/packages/cw1155/schema/cw1155_handle_msg.json @@ -3,7 +3,7 @@ "title": "Cw1155HandleMsg", "anyOf": [ { - "description": "TransferFrom is a base message to move tokens, if `env.sender` has sufficient pre-approval.", + "description": "TransferFrom is a base message to move tokens. if `env.sender` is the owner or has sufficient pre-approval.", "type": "object", "required": [ "transfer_from" @@ -47,7 +47,7 @@ } }, { - "description": "SendFrom is a base message to move tokens to contract if `env.sender` has sufficient pre-approval.", + "description": "SendFrom is a base message to move tokens to contract. if `env.sender` is the owner or has sufficient pre-approval.", "type": "object", "required": [ "send_from" @@ -95,7 +95,7 @@ } }, { - "description": "BatchTransferFrom is a base message to move tokens to another account without triggering actions", + "description": "BatchTransferFrom is a base message to move tokens to another account without triggering actions. if `env.sender` is the owner or has sufficient pre-approval.", "type": "object", "required": [ "batch_transfer_from" @@ -148,7 +148,7 @@ } }, { - "description": "BatchSendFrom is a base message to move tokens to another to without triggering actions", + "description": "BatchSendFrom is a base message to move tokens to another to without triggering actions. if `env.sender` is the owner or has sufficient pre-approval.", "type": "object", "required": [ "batch_send_from" @@ -205,21 +205,27 @@ } }, { - "description": "Enable or disable approval for a third party (\"operator\") to manage all of the caller's tokens.", + "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": [ - "set_approval_for_all" + "approve_all" ], "properties": { - "set_approval_for_all": { + "approve_all": { "type": "object", "required": [ - "approved", "operator" ], "properties": { - "approved": { - "type": "boolean" + "expires": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] }, "operator": { "$ref": "#/definitions/HumanAddr" @@ -227,6 +233,26 @@ } } } + }, + { + "description": "Remove previously granted ApproveAll permission", + "type": "object", + "required": [ + "revoke_all" + ], + "properties": { + "revoke_all": { + "type": "object", + "required": [ + "operator" + ], + "properties": { + "operator": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } } ], "definitions": { @@ -234,6 +260,51 @@ "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", "type": "string" }, + "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)", + "anyOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + } + } + ] + }, "HumanAddr": { "type": "string" }, diff --git a/packages/cw1155/schema/cw1155_query_msg.json b/packages/cw1155/schema/cw1155_query_msg.json index 3159534df..35c336f34 100644 --- a/packages/cw1155/schema/cw1155_query_msg.json +++ b/packages/cw1155/schema/cw1155_query_msg.json @@ -54,7 +54,7 @@ } }, { - "description": "Query the approval status of an operator for a given owner Return type: ApprovedForAllResponse.", + "description": "List all operators that can access all of the owner's tokens. Return type: ApprovedForAllResponse.", "type": "object", "required": [ "approved_for_all" @@ -63,15 +63,36 @@ "approved_for_all": { "type": "object", "required": [ - "owner", - "spender" + "owner" ], "properties": { + "include_expired": { + "description": "unset or false will filter out expired approvals, you must set to true to see them", + "type": [ + "boolean", + "null" + ] + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, "owner": { "$ref": "#/definitions/HumanAddr" }, - "spender": { - "$ref": "#/definitions/HumanAddr" + "start_after": { + "anyOf": [ + { + "$ref": "#/definitions/HumanAddr" + }, + { + "type": "null" + } + ] } } } diff --git a/packages/cw1155/schema/cw1155_receive_msg.json b/packages/cw1155/schema/cw1155_receive_msg.json index 27ae7c648..17f03fd38 100644 --- a/packages/cw1155/schema/cw1155_receive_msg.json +++ b/packages/cw1155/schema/cw1155_receive_msg.json @@ -13,6 +13,7 @@ "$ref": "#/definitions/Uint128" }, "from": { + "description": "The account that the token transfered from", "anyOf": [ { "$ref": "#/definitions/HumanAddr" @@ -33,7 +34,12 @@ ] }, "operator": { - "$ref": "#/definitions/HumanAddr" + "description": "The account that executed the send message", + "allOf": [ + { + "$ref": "#/definitions/HumanAddr" + } + ] }, "token_id": { "type": "string" From c6d0ab5aafaa5c6bb606a89a5dac3915d776912a Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 18 Mar 2021 19:16:42 +0800 Subject: [PATCH 08/11] Add ApprovedForAllItem to query approved status for one operator --- packages/cw1155/README.md | 4 +++- packages/cw1155/examples/schema.rs | 1 + .../approved_for_all_item_response.json | 13 ++++++++++ packages/cw1155/schema/cw1155_query_msg.json | 24 +++++++++++++++++++ packages/cw1155/src/lib.rs | 4 ++-- packages/cw1155/src/query.rs | 11 +++++++++ 6 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 packages/cw1155/schema/approved_for_all_item_response.json diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md index 8de8bc42b..86510a9f2 100644 --- a/packages/cw1155/README.md +++ b/packages/cw1155/README.md @@ -43,7 +43,9 @@ the `CW1155Receiver` interface. The operator should eitherbe the `from` account `ApprovedForAll{owner, include_expired, start_after, limit}` - List all operators that can access all of the owner's tokens. Return type is `ApprovedForAllResponse`. If `include_expired` is set, show expired owners in the results, otherwise, -ignore them. If query for some specific operator, set `start_after` to the operator, and set limit to 1. +ignore them. + +`ApprovedForAllItem{owner, operator}` - Query approved status `owner` granted to `operator`. Return type is `ApprovedForAllItemResponse`. ### Receiver diff --git a/packages/cw1155/examples/schema.rs b/packages/cw1155/examples/schema.rs index 40f3fb35c..7b7f739c0 100644 --- a/packages/cw1155/examples/schema.rs +++ b/packages/cw1155/examples/schema.rs @@ -18,6 +18,7 @@ fn main() { export_schema(&schema_for!(cw1155::BalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::BatchBalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::ApprovedForAllResponse), &out_dir); + export_schema(&schema_for!(cw1155::ApprovedForAllItemResponse), &out_dir); export_schema(&schema_for!(cw1155::TokenInfoResponse), &out_dir); export_schema(&schema_for!(cw1155::TokensResponse), &out_dir); } diff --git a/packages/cw1155/schema/approved_for_all_item_response.json b/packages/cw1155/schema/approved_for_all_item_response.json new file mode 100644 index 000000000..f43382094 --- /dev/null +++ b/packages/cw1155/schema/approved_for_all_item_response.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovedForAllItemResponse", + "type": "object", + "required": [ + "approved" + ], + "properties": { + "approved": { + "type": "boolean" + } + } +} diff --git a/packages/cw1155/schema/cw1155_query_msg.json b/packages/cw1155/schema/cw1155_query_msg.json index 35c336f34..f7c2d6c15 100644 --- a/packages/cw1155/schema/cw1155_query_msg.json +++ b/packages/cw1155/schema/cw1155_query_msg.json @@ -98,6 +98,30 @@ } } }, + { + "description": "Query approved status `owner` granted to `operator`. Return type: ApprovedForAllItemResponse", + "type": "object", + "required": [ + "approved_for_all_item" + ], + "properties": { + "approved_for_all_item": { + "type": "object", + "required": [ + "operator", + "owner" + ], + "properties": { + "operator": { + "$ref": "#/definitions/HumanAddr" + }, + "owner": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + }, { "description": "With MetaData Extension. Query metadata of token Return type: TokenInfoResponse.", "type": "object", diff --git a/packages/cw1155/src/lib.rs b/packages/cw1155/src/lib.rs index 2ef82fbf2..8532f1e94 100644 --- a/packages/cw1155/src/lib.rs +++ b/packages/cw1155/src/lib.rs @@ -1,7 +1,7 @@ pub use crate::msg::{Cw1155HandleMsg, TokenId}; pub use crate::query::{ - Approval, ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, - TokenInfoResponse, TokensResponse, + Approval, ApprovedForAllItemResponse, ApprovedForAllResponse, BalanceResponse, + BatchBalanceResponse, Cw1155QueryMsg, TokenInfoResponse, TokensResponse, }; pub use crate::receiver::{Cw1155BatchReceiveMsg, Cw1155ReceiveMsg}; diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs index 394e94b13..947c524d7 100644 --- a/packages/cw1155/src/query.rs +++ b/packages/cw1155/src/query.rs @@ -27,6 +27,12 @@ pub enum Cw1155QueryMsg { start_after: Option, limit: Option, }, + /// Query approved status `owner` granted to `operator`. + /// Return type: ApprovedForAllItemResponse + ApprovedForAllItem { + owner: HumanAddr, + operator: HumanAddr, + }, /// With MetaData Extension. /// Query metadata of token @@ -73,6 +79,11 @@ pub struct ApprovedForAllResponse { pub operators: Vec, } +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct ApprovedForAllItemResponse { + pub approved: bool, +} + #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct TokenInfoResponse { /// Should be a url point to a json file From 028349992cf373a27fbc350e6fb3b1bef655f008 Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 19 Mar 2021 10:09:31 +0800 Subject: [PATCH 09/11] rename query nanme ApprovedForAllItem to IsApprovedForAll --- packages/cw1155/examples/schema.rs | 2 +- packages/cw1155/schema/cw1155_query_msg.json | 6 +++--- ...item_response.json => is_approved_for_all_response.json} | 2 +- packages/cw1155/src/lib.rs | 4 ++-- packages/cw1155/src/query.rs | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) rename packages/cw1155/schema/{approved_for_all_item_response.json => is_approved_for_all_response.json} (81%) diff --git a/packages/cw1155/examples/schema.rs b/packages/cw1155/examples/schema.rs index 7b7f739c0..c4ea357f9 100644 --- a/packages/cw1155/examples/schema.rs +++ b/packages/cw1155/examples/schema.rs @@ -18,7 +18,7 @@ fn main() { export_schema(&schema_for!(cw1155::BalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::BatchBalanceResponse), &out_dir); export_schema(&schema_for!(cw1155::ApprovedForAllResponse), &out_dir); - export_schema(&schema_for!(cw1155::ApprovedForAllItemResponse), &out_dir); + export_schema(&schema_for!(cw1155::IsApprovedForAllResponse), &out_dir); export_schema(&schema_for!(cw1155::TokenInfoResponse), &out_dir); export_schema(&schema_for!(cw1155::TokensResponse), &out_dir); } diff --git a/packages/cw1155/schema/cw1155_query_msg.json b/packages/cw1155/schema/cw1155_query_msg.json index f7c2d6c15..6e97a5f94 100644 --- a/packages/cw1155/schema/cw1155_query_msg.json +++ b/packages/cw1155/schema/cw1155_query_msg.json @@ -99,13 +99,13 @@ } }, { - "description": "Query approved status `owner` granted to `operator`. Return type: ApprovedForAllItemResponse", + "description": "Query approved status `owner` granted to `operator`. Return type: IsApprovedForAllResponse", "type": "object", "required": [ - "approved_for_all_item" + "is_approved_for_all" ], "properties": { - "approved_for_all_item": { + "is_approved_for_all": { "type": "object", "required": [ "operator", diff --git a/packages/cw1155/schema/approved_for_all_item_response.json b/packages/cw1155/schema/is_approved_for_all_response.json similarity index 81% rename from packages/cw1155/schema/approved_for_all_item_response.json rename to packages/cw1155/schema/is_approved_for_all_response.json index f43382094..e3af7a983 100644 --- a/packages/cw1155/schema/approved_for_all_item_response.json +++ b/packages/cw1155/schema/is_approved_for_all_response.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovedForAllItemResponse", + "title": "IsApprovedForAllResponse", "type": "object", "required": [ "approved" diff --git a/packages/cw1155/src/lib.rs b/packages/cw1155/src/lib.rs index 8532f1e94..7adbb6e51 100644 --- a/packages/cw1155/src/lib.rs +++ b/packages/cw1155/src/lib.rs @@ -1,7 +1,7 @@ pub use crate::msg::{Cw1155HandleMsg, TokenId}; pub use crate::query::{ - Approval, ApprovedForAllItemResponse, ApprovedForAllResponse, BalanceResponse, - BatchBalanceResponse, Cw1155QueryMsg, TokenInfoResponse, TokensResponse, + Approval, ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155QueryMsg, + IsApprovedForAllResponse, TokenInfoResponse, TokensResponse, }; pub use crate::receiver::{Cw1155BatchReceiveMsg, Cw1155ReceiveMsg}; diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs index 947c524d7..379c3a4bd 100644 --- a/packages/cw1155/src/query.rs +++ b/packages/cw1155/src/query.rs @@ -28,8 +28,8 @@ pub enum Cw1155QueryMsg { limit: Option, }, /// Query approved status `owner` granted to `operator`. - /// Return type: ApprovedForAllItemResponse - ApprovedForAllItem { + /// Return type: IsApprovedForAllResponse + IsApprovedForAll { owner: HumanAddr, operator: HumanAddr, }, @@ -80,7 +80,7 @@ pub struct ApprovedForAllResponse { } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct ApprovedForAllItemResponse { +pub struct IsApprovedForAllResponse { pub approved: bool, } From 16d0158e62f788ac9fcf92e897168060c8cdf133 Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 19 Mar 2021 10:11:50 +0800 Subject: [PATCH 10/11] format readme, breaking long lines --- packages/cw1155/README.md | 44 ++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md index 86510a9f2..c7b71d0e9 100644 --- a/packages/cw1155/README.md +++ b/packages/cw1155/README.md @@ -10,42 +10,51 @@ Design decisions: - Fungible tokens and non-fungible tokens are treated equally, non-fungible tokens just have one max supply. -- Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) +- Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in + [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) -- Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. +- Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. + `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. - In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time. + In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they +must not both be `None` at the same time. ## Base ### Messages -`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator should either be the `from` account or have approval from it. +`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator +should either be the `from` account or have approval from it. `SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. `to` -must be an address controlled by a smart contract, which implements -the `CW1155Receiver` interface. The operator should eitherbe the `from` account or have approval from it. The `msg` will be passed to the recipient contract, along with the other fields. +must be an address controlled by a smart contract, which implements the `CW1155Receiver` interface. The operator should +either be the `from` account or have approval from it. The `msg` will be passed to the recipient contract, along with +the other fields. `BatchTransferFrom{from, to, batch}` - Batched version of `TransferFrom` which can handle multiple types of tokens at once. -`BatchSendFrom{from, contract, batch, msg}` - Batched version of `SendFrom` which can handle multiple types of tokens at once. +`BatchSendFrom{from, contract, batch, msg}` - Batched version of `SendFrom` which can handle multiple types of tokens at +once. -`ApproveAll{ operator, expires }` - Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit. +`ApproveAll{ operator, expires }` - Allows operator to transfer / send any token from the owner's account. If expiration +is set, then this allowance has a time/height limit. `RevokeAll { operator }` - Remove previously granted ApproveAll permission ### Queries -`Balance { owner, token_id }` - Query the balance of `owner` on perticular type of token, default to `0` when record not exist. +`Balance { owner, token_id }` - Query the balance of `owner` on perticular type of token, default to `0` when record not +exist. -`BatchBalance { owner, token_ids }` - Query the balance of `owner` on multiple types of tokens, batched version of `Balance`. +`BatchBalance { owner, token_ids }` - Query the balance of `owner` on multiple types of tokens, batched version of +`Balance`. -`ApprovedForAll{owner, include_expired, start_after, limit}` - List all operators that can -access all of the owner's tokens. Return type is `ApprovedForAllResponse`. -If `include_expired` is set, show expired owners in the results, otherwise, -ignore them. +`ApprovedForAll{owner, include_expired, start_after, limit}` - List all operators that can access all of the owner's +tokens. Return type is `ApprovedForAllResponse`. If `include_expired` is set, show expired owners in the results, +otherwise, ignore them. -`ApprovedForAllItem{owner, operator}` - Query approved status `owner` granted to `operator`. Return type is `ApprovedForAllItemResponse`. +`ApprovedForAllItem{owner, operator}` - Query approved status `owner` granted to `operator`. Return type is +`ApprovedForAllItemResponse`. ### Receiver @@ -59,7 +68,8 @@ Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and - `transfer(from, to, token_id, value)` - `from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning, but they mustn't be neglected at the same time. + `from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning, but they mustn't be +neglected at the same time. ## Metadata @@ -94,4 +104,4 @@ as the `start_after` value in a future query. `Tokens{owner, start_after, limit}` - List all token_ids that belong to a given owner. Return type is `TokensResponse{tokens: Vec}`. -`AllTokens{start_after, limit}` - Requires pagination. Lists all token_ids controlled by the contract. \ No newline at end of file +`AllTokens{start_after, limit}` - Requires pagination. Lists all token_ids controlled by the contract. From 8581364135612cd6f5a7219389e13de00a5aa3bf Mon Sep 17 00:00:00 2001 From: yihuang Date: Sat, 20 Mar 2021 01:50:38 +0800 Subject: [PATCH 11/11] Restructure message types - Seperate Mint/Burn/BatchMint/BatchBurn - Merge TransferFrom and SendFrom --- packages/cw1155/README.md | 25 +-- .../schema/cw1155_batch_receive_msg.json | 10 +- packages/cw1155/schema/cw1155_handle_msg.json | 169 ++++++++++++------ .../cw1155/schema/cw1155_receive_msg.json | 10 +- packages/cw1155/src/msg.rs | 61 ++++--- packages/cw1155/src/receiver.rs | 4 +- 6 files changed, 174 insertions(+), 105 deletions(-) diff --git a/packages/cw1155/README.md b/packages/cw1155/README.md index c7b71d0e9..c49402cfa 100644 --- a/packages/cw1155/README.md +++ b/packages/cw1155/README.md @@ -23,18 +23,23 @@ must not both be `None` at the same time. ### Messages -`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator -should either be the `from` account or have approval from it. +`SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. If `to` is an +address controlled by a smart contract, it must implement the `CW1155Receiver` interface, `msg` will be passed to it +along with other fields, otherwise, `msg` should be `None`. The operator should either be the `from` account or have +approval from it. -`SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. `to` -must be an address controlled by a smart contract, which implements the `CW1155Receiver` interface. The operator should -either be the `from` account or have approval from it. The `msg` will be passed to the recipient contract, along with -the other fields. +`BatchSendFrom{from, to, batch: Vec<(token_id, value)>, msg}` - Batched version of `SendFrom` which can handle multiple +types of tokens at once. -`BatchTransferFrom{from, to, batch}` - Batched version of `TransferFrom` which can handle multiple types of tokens at once. +`Mint {to, token_id, value, msg}` - This mints some tokens to `to` account, If `to` is controlled by a smart contract, +it should implement `CW1155Receiver` interface, `msg` will be passed to it along with other fields, otherwise, `msg` +should be `None`. -`BatchSendFrom{from, contract, batch, msg}` - Batched version of `SendFrom` which can handle multiple types of tokens at -once. +`BatchMint {to, batch: Vec<(token_id, value)>, msg}` - Batched version of `Mint`. + +`Burn {from, token_id, value}` - This burns some tokens from `from` account. + +`BatchBurn {from, batch: Vec<(token_id, value)>}` - Batched version of `Burn`. `ApproveAll{ operator, expires }` - Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit. @@ -53,7 +58,7 @@ exist. tokens. Return type is `ApprovedForAllResponse`. If `include_expired` is set, show expired owners in the results, otherwise, ignore them. -`ApprovedForAllItem{owner, operator}` - Query approved status `owner` granted to `operator`. Return type is +`ApprovedForAllItem{owner, operator}` - Query approved status `owner` granted to `operator`. Return type is `ApprovedForAllItemResponse`. ### Receiver diff --git a/packages/cw1155/schema/cw1155_batch_receive_msg.json b/packages/cw1155/schema/cw1155_batch_receive_msg.json index c87676573..9756a3bd4 100644 --- a/packages/cw1155/schema/cw1155_batch_receive_msg.json +++ b/packages/cw1155/schema/cw1155_batch_receive_msg.json @@ -5,6 +5,7 @@ "type": "object", "required": [ "batch", + "msg", "operator" ], "properties": { @@ -35,14 +36,7 @@ ] }, "msg": { - "anyOf": [ - { - "$ref": "#/definitions/Binary" - }, - { - "type": "null" - } - ] + "$ref": "#/definitions/Binary" }, "operator": { "$ref": "#/definitions/HumanAddr" diff --git a/packages/cw1155/schema/cw1155_handle_msg.json b/packages/cw1155/schema/cw1155_handle_msg.json index 200c53be8..27b56a372 100644 --- a/packages/cw1155/schema/cw1155_handle_msg.json +++ b/packages/cw1155/schema/cw1155_handle_msg.json @@ -3,23 +3,29 @@ "title": "Cw1155HandleMsg", "anyOf": [ { - "description": "TransferFrom is a base message to move tokens. if `env.sender` is the owner or has sufficient pre-approval.", + "description": "SendFrom is a base message to move tokens, if `env.sender` is the owner or has sufficient pre-approval.", "type": "object", "required": [ - "transfer_from" + "send_from" ], "properties": { - "transfer_from": { + "send_from": { "type": "object", "required": [ + "from", + "to", "token_id", "value" ], "properties": { "from": { + "$ref": "#/definitions/HumanAddr" + }, + "msg": { + "description": "`None` means don't call the receiver interface", "anyOf": [ { - "$ref": "#/definitions/HumanAddr" + "$ref": "#/definitions/Binary" }, { "type": "null" @@ -27,12 +33,10 @@ ] }, "to": { - "anyOf": [ + "description": "If `to` is not contract, `msg` should be `None`", + "allOf": [ { "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" } ] }, @@ -47,34 +51,79 @@ } }, { - "description": "SendFrom is a base message to move tokens to contract. if `env.sender` is the owner or has sufficient pre-approval.", + "description": "BatchSendFrom is a base message to move multiple types of tokens in batch, if `env.sender` is the owner or has sufficient pre-approval.", "type": "object", "required": [ - "send_from" + "batch_send_from" ], "properties": { - "send_from": { + "batch_send_from": { "type": "object", "required": [ - "contract", - "token_id", - "value" + "batch", + "from", + "to" ], "properties": { - "contract": { - "$ref": "#/definitions/HumanAddr" + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } }, "from": { + "$ref": "#/definitions/HumanAddr" + }, + "msg": { + "description": "`None` means don't call the receiver interface", "anyOf": [ { - "$ref": "#/definitions/HumanAddr" + "$ref": "#/definitions/Binary" }, { "type": "null" } ] }, + "to": { + "description": "if `to` is not contract, `msg` should be `None`", + "allOf": [ + { + "$ref": "#/definitions/HumanAddr" + } + ] + } + } + } + } + }, + { + "description": "Mint is a base message to mint tokens.", + "type": "object", + "required": [ + "mint" + ], + "properties": { + "mint": { + "type": "object", + "required": [ + "to", + "token_id", + "value" + ], + "properties": { "msg": { + "description": "`None` means don't call the receiver interface", "anyOf": [ { "$ref": "#/definitions/Binary" @@ -84,6 +133,14 @@ } ] }, + "to": { + "description": "If `to` is not contract, `msg` should be `None`", + "allOf": [ + { + "$ref": "#/definitions/HumanAddr" + } + ] + }, "token_id": { "type": "string" }, @@ -95,16 +152,17 @@ } }, { - "description": "BatchTransferFrom is a base message to move tokens to another account without triggering actions. if `env.sender` is the owner or has sufficient pre-approval.", + "description": "BatchMint is a base message to mint multiple types of tokens in batch.", "type": "object", "required": [ - "batch_transfer_from" + "batch_mint" ], "properties": { - "batch_transfer_from": { + "batch_mint": { "type": "object", "required": [ - "batch" + "batch", + "to" ], "properties": { "batch": { @@ -123,10 +181,11 @@ "minItems": 2 } }, - "from": { + "msg": { + "description": "`None` means don't call the receiver interface", "anyOf": [ { - "$ref": "#/definitions/HumanAddr" + "$ref": "#/definitions/Binary" }, { "type": "null" @@ -134,12 +193,10 @@ ] }, "to": { - "anyOf": [ + "description": "If `to` is not contract, `msg` should be `None`", + "allOf": [ { "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" } ] } @@ -148,17 +205,45 @@ } }, { - "description": "BatchSendFrom is a base message to move tokens to another to without triggering actions. if `env.sender` is the owner or has sufficient pre-approval.", + "description": "Burn is a base message to burn tokens.", "type": "object", "required": [ - "batch_send_from" + "burn" ], "properties": { - "batch_send_from": { + "burn": { + "type": "object", + "required": [ + "from", + "token_id", + "value" + ], + "properties": { + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "token_id": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Uint128" + } + } + } + } + }, + { + "description": "BatchBurn is a base message to burn multiple types of tokens in batch.", + "type": "object", + "required": [ + "batch_burn" + ], + "properties": { + "batch_burn": { "type": "object", "required": [ "batch", - "contract" + "from" ], "properties": { "batch": { @@ -177,28 +262,8 @@ "minItems": 2 } }, - "contract": { - "$ref": "#/definitions/HumanAddr" - }, "from": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } - ] - }, - "msg": { - "anyOf": [ - { - "$ref": "#/definitions/Binary" - }, - { - "type": "null" - } - ] + "$ref": "#/definitions/HumanAddr" } } } diff --git a/packages/cw1155/schema/cw1155_receive_msg.json b/packages/cw1155/schema/cw1155_receive_msg.json index 17f03fd38..67ee6d6d8 100644 --- a/packages/cw1155/schema/cw1155_receive_msg.json +++ b/packages/cw1155/schema/cw1155_receive_msg.json @@ -5,6 +5,7 @@ "type": "object", "required": [ "amount", + "msg", "operator", "token_id" ], @@ -24,14 +25,7 @@ ] }, "msg": { - "anyOf": [ - { - "$ref": "#/definitions/Binary" - }, - { - "type": "null" - } - ] + "$ref": "#/definitions/Binary" }, "operator": { "description": "The account that executed the send message", diff --git a/packages/cw1155/src/msg.rs b/packages/cw1155/src/msg.rs index 34ab1d4ea..102ebbb3a 100644 --- a/packages/cw1155/src/msg.rs +++ b/packages/cw1155/src/msg.rs @@ -9,43 +9,54 @@ pub type TokenId = String; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum Cw1155HandleMsg { - /// TransferFrom is a base message to move tokens. + /// SendFrom is a base message to move tokens, /// if `env.sender` is the owner or has sufficient pre-approval. - TransferFrom { - // `None` means minting - from: Option, - // `None` means burning - to: Option, + SendFrom { + from: HumanAddr, + /// If `to` is not contract, `msg` should be `None` + to: HumanAddr, token_id: TokenId, value: Uint128, + /// `None` means don't call the receiver interface + msg: Option, }, - /// SendFrom is a base message to move tokens to contract. + /// BatchSendFrom is a base message to move multiple types of tokens in batch, /// if `env.sender` is the owner or has sufficient pre-approval. - SendFrom { - // `None` means minting - from: Option, - contract: HumanAddr, + BatchSendFrom { + from: HumanAddr, + /// if `to` is not contract, `msg` should be `None` + to: HumanAddr, + batch: Vec<(TokenId, Uint128)>, + /// `None` means don't call the receiver interface + msg: Option, + }, + /// Mint is a base message to mint tokens. + Mint { + /// If `to` is not contract, `msg` should be `None` + to: HumanAddr, token_id: TokenId, value: Uint128, + /// `None` means don't call the receiver interface msg: Option, }, - /// BatchTransferFrom is a base message to move tokens to another account without triggering actions. - /// if `env.sender` is the owner or has sufficient pre-approval. - BatchTransferFrom { - // `None` means minting - from: Option, - // `None` means burning - to: Option, + /// BatchMint is a base message to mint multiple types of tokens in batch. + BatchMint { + /// If `to` is not contract, `msg` should be `None` + to: HumanAddr, batch: Vec<(TokenId, Uint128)>, + /// `None` means don't call the receiver interface + msg: Option, }, - /// BatchSendFrom is a base message to move tokens to another to without triggering actions. - /// if `env.sender` is the owner or has sufficient pre-approval. - BatchSendFrom { - // `None` means minting - from: Option, - contract: HumanAddr, + /// Burn is a base message to burn tokens. + Burn { + from: HumanAddr, + token_id: TokenId, + value: Uint128, + }, + /// BatchBurn is a base message to burn multiple types of tokens in batch. + BatchBurn { + from: HumanAddr, batch: Vec<(TokenId, Uint128)>, - msg: Option, }, /// Allows operator to transfer / send any token from the owner's account. /// If expiration is set, then this allowance has a time/height limit diff --git a/packages/cw1155/src/receiver.rs b/packages/cw1155/src/receiver.rs index 7e14e6441..9fccec2fd 100644 --- a/packages/cw1155/src/receiver.rs +++ b/packages/cw1155/src/receiver.rs @@ -15,7 +15,7 @@ pub struct Cw1155ReceiveMsg { pub from: Option, pub token_id: TokenId, pub amount: Uint128, - pub msg: Option, + pub msg: Binary, } impl Cw1155ReceiveMsg { @@ -44,7 +44,7 @@ pub struct Cw1155BatchReceiveMsg { pub operator: HumanAddr, pub from: Option, pub batch: Vec<(TokenId, Uint128)>, - pub msg: Option, + pub msg: Binary, } impl Cw1155BatchReceiveMsg {