diff --git a/.github/workflows/doc-test.yml b/.github/workflows/doc-test.yml index 6150371c..e6efc0bf 100644 --- a/.github/workflows/doc-test.yml +++ b/.github/workflows/doc-test.yml @@ -26,6 +26,7 @@ jobs: cargo update -p cosmwasm-schema-derive cargo update -p cosmwasm-schema cargo update -p cosmwasm-std + cargo update -p cw2 - uses: Swatinem/rust-cache@v2 with: workspaces: | diff --git a/docs-test-gen/Cargo.lock b/docs-test-gen/Cargo.lock index 1b46b31f..5ad2eace 100644 --- a/docs-test-gen/Cargo.lock +++ b/docs-test-gen/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "base16ct" @@ -93,9 +93,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b08e6670ab9e13a1a8a9cfad8fdad48bf0aaf88a6e81f39f2d9b2fc79b1890" +checksum = "6bf91c32ff87ffec3f1a36d03c96a528bc7447b9774c0616e5b092d7a3fd6503" dependencies = [ "digest 0.10.7", "ed25519-zebra", @@ -106,18 +106,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b0918fc1a24b2ee08142c8d99d03f4c8e6d74244bdb304dbb29c0dab8e77e9" +checksum = "9125094db6fdf355525d0968d5a2b3a23f82dfc9553efd64942a545ac086eed8" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26dbdb5800ca67f2f2f938d67db59a7c5434af133c3e508779a4df7a9b5d533b" +checksum = "d403dea1175a5b20fd2d29dda180fa9f1391dd46f354a8639391d1e549a99e5e" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ee47cf29f7688ebfa6ade8ddabcf51fc153f1157a3b46f5b4b1ce7a0316fdf" +checksum = "e3c3153038e91080ded2e2554689e802be2a34a24c6e49c039ae94810c99a680" dependencies = [ "proc-macro2", "quote", @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88191bd0d4743613eb7a2f086acb0838404cb531bf658382effafc7ba91e8320" +checksum = "eae364adb252732194283cd06dea3de2a1ed1e97d5033cdfd0fb651daa5a0100" dependencies = [ "base64", "bech32", @@ -203,6 +203,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cw-storage-plus" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f13360e9007f51998d42b1bc6b7fa0141f74feae61ed5fd1e5b0a89eec7b5de1" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "semver", + "serde", + "thiserror", +] + [[package]] name = "der" version = "0.7.9" @@ -252,6 +278,7 @@ dependencies = [ "anyhow", "cosmwasm-schema", "cosmwasm-std", + "cw2", "glob", "phf", "pulldown-cmark", @@ -341,9 +368,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -419,9 +446,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "memchr" @@ -471,7 +498,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -495,18 +522,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0" dependencies = [ "bitflags", "memchr", @@ -558,21 +585,21 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schemars" -version = "0.8.17" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309" +checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29" dependencies = [ "dyn-clone", "schemars_derive", @@ -582,14 +609,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.17" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108" +checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -606,11 +633,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" -version = "1.0.199" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -626,31 +659,31 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -732,7 +765,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -754,9 +787,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ "proc-macro2", "quote", @@ -765,22 +798,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] diff --git a/docs-test-gen/Cargo.toml b/docs-test-gen/Cargo.toml index 1c99253b..60a134d9 100644 --- a/docs-test-gen/Cargo.toml +++ b/docs-test-gen/Cargo.toml @@ -8,9 +8,10 @@ edition = "2021" anyhow = "1.0.82" glob = "0.3.1" phf = { version = "0.11.2", features = ["macros"] } -pulldown-cmark = { version = "0.10.3", default-features = false } +pulldown-cmark = { version = "0.11.0", default-features = false } strum = { version = "0.26.2", features = ["derive"] } [dev-dependencies] +cw2 = "*" cosmwasm-schema = "*" cosmwasm-std = { version = "*", features = ["stargate", "staking", "cosmwasm_2_0"] } diff --git a/docs-test-gen/templates/core.tpl b/docs-test-gen/templates/core.tpl index f3fe96f0..e6703496 100644 --- a/docs-test-gen/templates/core.tpl +++ b/docs-test-gen/templates/core.tpl @@ -1,6 +1,11 @@ use cosmwasm_std::*; use cosmwasm_schema::cw_serde; +#[cw_serde] +enum OtherContractMsg { + DoSomething {} +} + #[cw_serde] struct InstantiateMsg {} @@ -10,6 +15,20 @@ struct QueryMsg {} #[cw_serde] struct ExecuteMsg {} +#[cw_serde] +struct MigrateMsg {} + +#[cw_serde] +struct SudoMsg {} + +fn transform(_old_data: OldData) -> () { + () +} + +#[cw_serde] +#[derive(Default)] +struct OldData {} + #[test] fn doctest() { {{code}} diff --git a/src/pages/core/entrypoints.mdx b/src/pages/core/entrypoints.mdx index d338b1b8..211138d3 100644 --- a/src/pages/core/entrypoints.mdx +++ b/src/pages/core/entrypoints.mdx @@ -14,7 +14,7 @@ these entrypoints, each one different from the last. In this section we want to give you a quick overview over all the entrypoints and when they are called. -## Define entrypoints +## Defining entrypoints While you will learn all about entrypoints in the next sections, we want to give you an idea on how to define an entrypoint in the first place. @@ -31,6 +31,14 @@ VM: "Hey! This is an entrypoint, please use it when needed!" including the correct function signature. + + Even though the sections will show you to use `#[entry_point]`, it is + recommended to define your endpoints as `#[cfg_attr(not(feature = "library"), + entry_point)]`. +
The reason behind that is that it allows you to reuse your contract as a + library. +
+ ```rust template="core" #[entry_point] pub fn instantiate( @@ -38,7 +46,7 @@ pub fn instantiate( env: Env, info: MessageInfo, msg: InstantiateMsg, -) -> Result { +) -> StdResult { // Do some logic here Ok(Response::default()) } diff --git a/src/pages/core/entrypoints/execute.mdx b/src/pages/core/entrypoints/execute.mdx index b29096a1..e26d1cba 100644 --- a/src/pages/core/entrypoints/execute.mdx +++ b/src/pages/core/entrypoints/execute.mdx @@ -5,3 +5,26 @@ tags: ["core", "entrypoints"] import { Callout } from "nextra/components"; # Execute + +Execute pretty much does what it says on the tin: It executes some routine in +your contract after a remote (either another contract or some client) sent a +message. + +This function is called when some wants you to, for example, increment a counter +or add a user to a lottery. Anything that might modify the state of the +contract. + +## Definition + +```rust filename="contract.rs" template="core" +#[entry_point] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> StdResult { + // Increment some counter, register a user, spread liberty for super earth! + Ok(Response::new()) +} +``` diff --git a/src/pages/core/entrypoints/instantiate.mdx b/src/pages/core/entrypoints/instantiate.mdx index 29de9412..fec549fb 100644 --- a/src/pages/core/entrypoints/instantiate.mdx +++ b/src/pages/core/entrypoints/instantiate.mdx @@ -5,3 +5,37 @@ tags: ["core", "entrypoints"] import { Callout } from "nextra/components"; # Instantiate + +This is one of the most fundamental entrypoints. This entrypoint is called once +during the contract lifecycle. +It essentially is there to initialise the state of your contract (for example, +initialising a counter in storage, etc.). + +You can imagine it as the constructor of your contract. + + + Note that this function is called for *each instance* of your contract + that you decide to create, not one time ever. + + To equate it to OOP, your contract is a *class*, and this is the *constructor*, + and you can have *multiple instances* of the same class, and the constructor + is called once for every one of these instances. + + It is **not** a singleton. + + + +## Definition + +```rust filename="contract.rs" template="core" +#[entry_point] +pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InstantiateMsg, +) -> StdResult { + // TODO: Initialise storage, send out metrics, do mischief + Ok(Response::new()) +} +``` diff --git a/src/pages/core/entrypoints/migrate.mdx b/src/pages/core/entrypoints/migrate.mdx index 8d252b78..152ec54a 100644 --- a/src/pages/core/entrypoints/migrate.mdx +++ b/src/pages/core/entrypoints/migrate.mdx @@ -5,3 +5,81 @@ tags: ["core", "entrypoints"] import { Callout } from "nextra/components"; # Migrate + +This is another special endpoint. It is, just like `instantiate`, not called +frequently. + +`migrate` is only called once you upload a new version to the chain and lets you +run all the required changes to the storage. + +Let's say your storage has the following layout, expressed as JSON for +simplicity's sake: + +```json filename="structure.json" +{ + "user_count": 205, + "call_count": 543, + "balance": 43 +} +``` + +But then you notice "Hey! Why don't I nest all the counts into an own object? +That way I don't have that redundant postfix, making the keys smaller". + +So you go ahead and rework your logic to query the data from the following +structure: + +```json filename="structure.json" +{ + "count": { + "user": 205, + "call": 543 + }, + "balance": 43 +} +``` + +But your storage on-chain still stores the old format. You need to somehow +transform it. + +That's what you do in the `migrate` entrypoint. You transform the structure of +the storage in there. + +## Example + +```rust filename="contract.rs" template="core" +const CONTRACT_NAME: &str = "my_contract"; +const STATE_VERSION: &str = "v2"; + +#[entry_point] +pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult { + // Check if the state version is older than the current one and update it + cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, STATE_VERSION)?; + + // Load the old data + let Some(old_data) = deps.storage.get(b"persisted_data") else { + return Err(StdError::generic_err("Data not found")); + }; + // Deserialize it from the old format + let old_data: OldData = cosmwasm_std::from_json(&old_data)?; + + // Transform it + let new_data = transform(old_data); + + // Serialize the new data + let new_data = cosmwasm_std::to_json_vec(&new_data)?; + // Store the new data + deps.storage.set(b"persisted_data", &new_data); + + Ok(Response::default()) +} +``` + +## Definition + +```rust filename="contract.rs" template="core" +#[entry_point] +pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult { + Ok(Response::default()) +} +``` diff --git a/src/pages/core/entrypoints/query.mdx b/src/pages/core/entrypoints/query.mdx index bd04eaa3..37fdbaee 100644 --- a/src/pages/core/entrypoints/query.mdx +++ b/src/pages/core/entrypoints/query.mdx @@ -5,3 +5,22 @@ tags: ["core", "entrypoints"] import { Callout } from "nextra/components"; # Query + +In the previous section we talked about the [`execute` endpoint](./execute.mdx). +The `query` endpoint is actually pretty similar to its sibling `execute`, but +with one key difference: The storage is only accessible immutably. + +This means you can only _read_ from the storage but not _write_ to it. + +## Definition + +```rust filename="contract.rs" template="core" +#[entry_point] +pub fn query( + _deps: Deps, + _env: Env, + _msg: QueryMsg, +) -> StdResult { + Ok(QueryResponse::default()) +} +``` diff --git a/src/pages/core/entrypoints/reply.mdx b/src/pages/core/entrypoints/reply.mdx new file mode 100644 index 00000000..a659ffbc --- /dev/null +++ b/src/pages/core/entrypoints/reply.mdx @@ -0,0 +1,64 @@ +--- +tags: ["core", "entrypoints"] +--- + +import { Callout } from "nextra/components"; + +# Reply + +The `reply` endpoint is another special one. + +It relates to CosmWasm's actor model which dictates how you call other contracts +and interact with them. + +TODO: Link to the actor model section once we have one + +This endpoint gets invoked when you receive a response to a message you sent out +over the chain. The reply parameter then allows you to inspect and work with the +response that was produced. + +## Request a reply + +To request a reply, you need to use the `reply_on` field in the message you send +and set it to one of the following values: + +- `ReplyOn::Always` +- `ReplyOn::Error` +- `ReplyOn::Success` + +```rust filename="contract.rs" template="core" +const CONTRACT_ADDR: &str = "other_contract"; +const SUBMSG_ID: u64 = 1; // This is a unique identifier so we can associate a reply with a specific submessage. It can be any numeric value. + +#[entry_point] +pub fn reply(deps: DepsMut, env: Env, msg: cosmwasm_std::Reply) -> StdResult { + if msg.id != SUBMSG_ID { + return Err(StdError::generic_err("Invalid submsg id")); + } + + // We received a message! From the contract we invoked earlier. + + Ok(Response::default()) +} + +#[entry_point] +pub fn execute(deps: DepsMut, env: Env, msg: ExecuteMsg) -> StdResult { + let msg = WasmMsg::Execute { + contract_addr: CONTRACT_ADDR.into(), + msg: to_json_binary(&OtherContractMsg::DoSomething {}).unwrap(), + funds: vec![], + }; + + let submsg = SubMsg::reply_always(msg, SUBMSG_ID); + Ok(Response::new().add_submessage(submsg)) +} +``` + +## Definition + +```rust filename="contract.rs" template="core" +#[entry_point] +pub fn reply(deps: DepsMut, env: Env, msg: cosmwasm_std::Reply) -> StdResult { + Ok(Response::default()) +} +``` diff --git a/src/pages/core/entrypoints/sudo.mdx b/src/pages/core/entrypoints/sudo.mdx index 705585d6..bb7a805a 100644 --- a/src/pages/core/entrypoints/sudo.mdx +++ b/src/pages/core/entrypoints/sudo.mdx @@ -5,3 +5,21 @@ tags: ["core", "entrypoints"] import { Callout } from "nextra/components"; # Sudo + +`sudo` is a special endpoint that you will probably rarely use in practice. + +This is where you will receive messages issued _by the chain itself_ and it +won't be invoked by clients or other contracts. + +And since these are special messages you will only receive from the chain, the +messages you will receive are not defined by yourself, and instead usually +provided by some sort of chain SDK. + +## Definition + +```rust filename="contract.rs" template="core" +#[entry_point] +pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> StdResult { + Ok(Response::default()) +} +```