From d40125b0a26bc3e70f4e904479928a7c196c62b4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 30 Jul 2024 15:51:10 +0200 Subject: [PATCH 1/2] Use prettier-plugin-tailwindcss for js files only --- .prettierrc | 9 ++++++++- scripts/format.sh | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.prettierrc b/.prettierrc index 14853fc2..3ab74d37 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,11 @@ { "proseWrap": "always", - "plugins": ["prettier-plugin-tailwindcss"] + "overrides": [ + { + "files": "*.js", + "options": { + "plugins": ["prettier-plugin-tailwindcss"] + } + } + ] } diff --git a/scripts/format.sh b/scripts/format.sh index 94d12316..3184af4c 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -11,4 +11,4 @@ while getopts c option; do esac done -npx prettier@3.3.3 --$op --no-config "./src/**/*.md" "./src/**/*.mdx" +npx prettier@3.3.3 --$op "./src/**/*.md" "./src/**/*.mdx" From ad7ac79a2bfbf9062ac787564c4f31630591d506 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 30 Jul 2024 16:26:43 +0200 Subject: [PATCH 2/2] Reformat with config file --- src/pages/core.mdx | 24 +- src/pages/core/advanced.mdx | 11 +- src/pages/core/advanced/measuring-time.mdx | 22 +- src/pages/core/architecture/actor-model.mdx | 65 +++--- src/pages/core/architecture/events.mdx | 18 +- src/pages/core/architecture/gas.mdx | 84 ++++--- src/pages/core/architecture/pinning.mdx | 80 +++---- src/pages/core/architecture/transactions.mdx | 25 +-- src/pages/core/conventions.mdx | 11 +- src/pages/core/conventions/enum-dispatch.mdx | 10 +- .../core/conventions/library-feature.mdx | 25 +-- src/pages/core/entrypoints.mdx | 85 ++++--- src/pages/core/entrypoints/execute.mdx | 10 +- src/pages/core/entrypoints/instantiate.mdx | 8 +- src/pages/core/entrypoints/migrate.mdx | 23 +- src/pages/core/entrypoints/query.mdx | 14 +- src/pages/core/entrypoints/reply.mdx | 20 +- src/pages/core/entrypoints/sudo.mdx | 9 +- src/pages/core/installation.mdx | 33 ++- src/pages/core/specification.mdx | 5 +- .../core/specification/instantiate2-algo.mdx | 19 +- src/pages/core/standard-library.mdx | 9 +- .../core/standard-library/cryptography.mdx | 48 ++-- .../cryptography/bls12-381.mdx | 20 +- .../standard-library/cryptography/ed25519.mdx | 14 +- .../standard-library/cryptography/k256.mdx | 4 +- .../standard-library/cryptography/p256.mdx | 5 +- src/pages/core/standard-library/math.mdx | 6 +- .../core/standard-library/math/decimals.mdx | 10 +- .../core/standard-library/math/integers.mdx | 27 +-- src/pages/cw-multi-test.mdx | 46 ++-- src/pages/cw-multi-test/installation.mdx | 20 +- src/pages/cw-storage-plus.mdx | 44 ++-- src/pages/cw-storage-plus/basics.mdx | 83 +++---- .../cw-storage-plus/containers/deque.mdx | 67 +++--- .../containers/indexed-map.mdx | 130 +++++------ src/pages/cw-storage-plus/containers/item.mdx | 29 ++- src/pages/cw-storage-plus/containers/map.mdx | 45 ++-- src/pages/how-to-doc.md | 9 +- src/pages/how-to-doc/callout.mdx | 21 +- src/pages/how-to-doc/mdx.mdx | 27 +-- src/pages/how-to-doc/tags.mdx | 7 +- src/pages/ibc.mdx | 17 +- src/pages/ibc/basic-concepts.mdx | 30 ++- src/pages/ibc/diy-protocol.mdx | 17 +- .../ibc/diy-protocol/channel-lifecycle.mdx | 139 ++++++------ .../ibc/diy-protocol/packet-lifecycle.mdx | 184 +++++++-------- src/pages/ibc/existing-protocols.mdx | 211 +++++++++--------- src/pages/ibc/getting-started.mdx | 5 +- src/pages/index.md | 6 +- src/pages/storey.mdx | 23 +- src/pages/storey/basics.mdx | 49 ++-- src/pages/storey/containers.mdx | 60 +++-- src/pages/sylvia.mdx | 43 ++-- src/pages/sylvia/attributes.mdx | 3 +- src/pages/sylvia/attributes/custom.mdx | 10 +- src/pages/sylvia/attributes/error.mdx | 7 +- src/pages/sylvia/attributes/message.mdx | 28 +-- src/pages/sylvia/attributes/msg.mdx | 17 +- .../attributes/override-entry-point.mdx | 30 ++- src/pages/sylvia/basics.mdx | 4 +- .../sylvia/basics/contract-structure.mdx | 100 ++++----- src/pages/sylvia/basics/generate-contract.mdx | 77 +++---- src/pages/sylvia/basics/getting-started.mdx | 33 ++- src/pages/sylvia/basics/ibc.mdx | 17 +- src/pages/sylvia/basics/interoperability.mdx | 77 +++---- src/pages/sylvia/macros/contract.mdx | 45 ++-- src/pages/sylvia/macros/entry-points.mdx | 29 ++- src/pages/sylvia/macros/generated-types.mdx | 4 +- .../macros/generated-types/communication.mdx | 32 ++- .../macros/generated-types/message-types.mdx | 75 +++---- .../macros/generated-types/multitest.mdx | 50 ++--- src/pages/sylvia/macros/interface.mdx | 39 ++-- src/pages/sylvia/types/communication.mdx | 77 +++---- src/pages/sylvia/types/context.mdx | 8 +- src/pages/sylvia/types/multitest.mdx | 85 +++---- src/pages/wasmd.mdx | 11 +- src/pages/wasmd/getting-started.mdx | 4 +- src/pages/wasmd/getting-started/cli.mdx | 117 +++++----- src/pages/wasmd/getting-started/run-node.mdx | 10 +- src/pages/wasmd/getting-started/setup.mdx | 9 +- 81 files changed, 1362 insertions(+), 1692 deletions(-) diff --git a/src/pages/core.mdx b/src/pages/core.mdx index 61c7d431..706b353f 100644 --- a/src/pages/core.mdx +++ b/src/pages/core.mdx @@ -6,26 +6,21 @@ import { Callout } from "nextra/components"; # Introduction -This chapter will give you an overview over CosmWasm from a contract developer -perspective, its capabilities, and guide you through initializing your first -smart contract. +This chapter will give you an overview over CosmWasm from a contract developer perspective, its +capabilities, and guide you through initializing your first smart contract. - - We assume you have basic knowledge of Rust and Cargo (its standard build - system) - +We assume you have basic knowledge of Rust and Cargo (its standard build system) ## What is CosmWasm? -CosmWasm is a platform for writing smart contracts for Cosmos chains using Rust -and WebAssembly. -Meaning CosmWasm is your one-stop shop for developing, testing, and running -smart contracts on enabled chains. +CosmWasm is a platform for writing smart contracts for Cosmos chains using Rust and WebAssembly. +Meaning CosmWasm is your one-stop shop for developing, testing, and running smart contracts on +enabled chains. ## What does CosmWasm provide? -For you, a contract developer, CosmWasm provides a set of high-quality -primitives through our standard library. These primitives include: +For you, a contract developer, CosmWasm provides a set of high-quality primitives through our +standard library. These primitives include: - extended precision arithmetic (128, 256, 512-bit integers) - cryptographic primitives (for example, secp256k1 verification) @@ -33,6 +28,5 @@ primitives through our standard library. These primitives include: ## What does CosmWasm _not_ provide? -- Abstractions to simplify contract development (for this, check out - [Sylvia](/sylvia)) +- Abstractions to simplify contract development (for this, check out [Sylvia](/sylvia)) - Storage abstractions (for this, check out [Storey](/storey)) diff --git a/src/pages/core/advanced.mdx b/src/pages/core/advanced.mdx index 444dd1fe..a8f4f3d1 100644 --- a/src/pages/core/advanced.mdx +++ b/src/pages/core/advanced.mdx @@ -6,12 +6,11 @@ import { Callout } from "nextra/components"; # Advanced topics -In this part of the documentation, we go over some more "advanced" things you -can do with the functionality CosmWasm core offers. +In this part of the documentation, we go over some more "advanced" things you can do with the +functionality CosmWasm core offers. - While the name of this section is "advanced", this doesn't mean that we want - to imply that you only need these functions in advanced contexts. The wording - "advanced" moreso refers to the fact that you should be familiar with - endpoints, the structs that are passed to the endpoints, etc. + While the name of this section is "advanced", this doesn't mean that we want to imply that you + only need these functions in advanced contexts. The wording "advanced" moreso refers to the fact + that you should be familiar with endpoints, the structs that are passed to the endpoints, etc. diff --git a/src/pages/core/advanced/measuring-time.mdx b/src/pages/core/advanced/measuring-time.mdx index 66cf370f..b402d686 100644 --- a/src/pages/core/advanced/measuring-time.mdx +++ b/src/pages/core/advanced/measuring-time.mdx @@ -6,23 +6,21 @@ import { Callout } from "nextra/components"; # Measuring time -Accessing the current time is useful in a lot of different contexts but time is -hard. It is hard to coordinate, hard to keep in sync, and this gets worse in -distributed settings such as blockchains. +Accessing the current time is useful in a lot of different contexts but time is hard. It is hard to +coordinate, hard to keep in sync, and this gets worse in distributed settings such as blockchains. -In CosmWasm, we solve this by passing you some information about the blockchain -you are running on whenever an entrypoint is invoked. +In CosmWasm, we solve this by passing you some information about the blockchain you are running on +whenever an entrypoint is invoked. -In each of the entrypoints, you get a parameter of the type `Env` and this -struct contains the field `block`. The struct contained in this field has a -bunch of different information about the current state of the blockchain you are -running on. +In each of the entrypoints, you get a parameter of the type `Env` and this struct contains the field +`block`. The struct contained in this field has a bunch of different information about the current +state of the blockchain you are running on. > The documentation about the `BlockInfo` struct can be [found here] -The timestamp contained in this struct can be safely used in your program as the -source of the current time. Well, kinda. It won't be 100% matching the current -time, as it is the timestamp of the block we are currently operating on. +The timestamp contained in this struct can be safely used in your program as the source of the +current time. Well, kinda. It won't be 100% matching the current time, as it is the timestamp of the +block we are currently operating on. But you can rely on this timestamp to have the following properties: diff --git a/src/pages/core/architecture/actor-model.mdx b/src/pages/core/architecture/actor-model.mdx index 700412fb..c9814fe7 100644 --- a/src/pages/core/architecture/actor-model.mdx +++ b/src/pages/core/architecture/actor-model.mdx @@ -7,36 +7,32 @@ import { Callout } from "nextra/components"; # Actor Model -CosmWasm, at its core, is built around the actor model. This prevents some -common pitfalls which, for example, Ethereum smart contracts had to fix over the -years. The issues mostly revolved around [reentrancy issues] where we could, for -example, call out to another contract before finishing the current execution. +CosmWasm, at its core, is built around the actor model. This prevents some common pitfalls which, +for example, Ethereum smart contracts had to fix over the years. The issues mostly revolved around +[reentrancy issues] where we could, for example, call out to another contract before finishing the current +execution. - If you are already familiar with the actor model through, for example, - programming in languages such as Erlang or Elixir, you can skip this page. + If you are already familiar with the actor model through, for example, programming in languages + such as Erlang or Elixir, you can skip this page. -While the term "actor model" sounds fancy, it is actually quite simple. Each -contract is an "actor" and _plays_ a role in the system (pun intended). +While the term "actor model" sounds fancy, it is actually quite simple. Each contract is an "actor" +and _plays_ a role in the system (pun intended). -Each actor has its own state and can only be interacted with via messages. This -means a contract can only interact with the outside world via messages and only -manipulate its own state. +Each actor has its own state and can only be interacted with via messages. This means a contract can +only interact with the outside world via messages and only manipulate its own state. -Picture two people living in two houses, each house has a mailbox. If person A -wants to talk to person B, they write a letter, address it to person B, and send -it off. The mailman (or in this case, the chain) will put the letter in person -B's mailbox. +Picture two people living in two houses, each house has a mailbox. If person A wants to talk to +person B, they write a letter, address it to person B, and send it off. The mailman (or in this +case, the chain) will put the letter in person B's mailbox. -Person B will then read the letter and can choose to write a response, address -it to person A with a note indicating that this is a reply, and send it off once -again. +Person B will then read the letter and can choose to write a response, address it to person A with a +note indicating that this is a reply, and send it off once again. -No direct interaction is happening here, nobody visits each other's house which -would allow them to rummage around in their belongings (state). They simply -exchange messages and put everything the other side needs to know into a -message. +No direct interaction is happening here, nobody visits each other's house which would allow them to +rummage around in their belongings (state). They simply exchange messages and put everything the +other side needs to know into a message. -As you can see in the simple graphic above, they simply exchange messages -addressed to each other, and the messages reference previous messages if need -be. +As you can see in the simple graphic above, they simply exchange messages addressed to each other, +and the messages reference previous messages if need be. - In CosmWasm you can only pass a single message type to a contract endpoint. If - you are wondering how to handle multiple message types, check out the [enum - dispatch] page. + In CosmWasm you can only pass a single message type to a contract endpoint. If you are wondering + how to handle multiple message types, check out the [enum dispatch] page. -But how does that fix reentrancy? In CosmWasm, you can only send out messages at -the end of a contract execution as part of the response. This ensures you have -already written everything to the state, meaning the state can't suddenly change -mid-execution and make your contract exhibit buggy behaviour. +But how does that fix reentrancy? In CosmWasm, you can only send out messages at the end of a +contract execution as part of the response. This ensures you have already written everything to the +state, meaning the state can't suddenly change mid-execution and make your contract exhibit buggy +behaviour. -CosmWasm effectively forces you to follow the [CEI pattern (Checks, Effects, -Interactions)] while other similar systems only have this as a "best practice". +CosmWasm effectively forces you to follow the [CEI pattern (Checks, Effects, Interactions)] while +other similar systems only have this as a "best practice". [reentrancy issues]: https://ethereum.org/en/developers/docs/smart-contracts/security/#reentrancy [enum dispatch]: ../conventions/enum-dispatch -[CEI pattern (Checks, Effects, Interactions)]: https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html +[CEI pattern (Checks, Effects, Interactions)]: + https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html diff --git a/src/pages/core/architecture/events.mdx b/src/pages/core/architecture/events.mdx index 9652cb66..be41a9c3 100644 --- a/src/pages/core/architecture/events.mdx +++ b/src/pages/core/architecture/events.mdx @@ -6,9 +6,8 @@ import { Callout } from "nextra/components"; # Events -CosmWasm can emit [Cosmos Events]. These events are stored in the block as -metadata, allowing the contract to attach metadata to what exactly happened -during execution. +CosmWasm can emit [Cosmos Events]. These events are stored in the block as metadata, allowing the contract +to attach metadata to what exactly happened during execution. @@ -16,8 +15,7 @@ Some important details about the keys: - Whitespaces will be trimmed (i.e. removed from the begin and end) - Empty keys (that includes keys only consisting of whitespaces) are not allowed -- Keys _cannot_ start with an underscore (`_`). These types of keys are reserved - for `wasmd` +- Keys _cannot_ start with an underscore (`_`). These types of keys are reserved for `wasmd` @@ -30,13 +28,11 @@ let response: Response = Response::new() ## Custom events -As mentioned above, CosmWasm only emits the event `wasm` by default. If you want -to emit other events, such as domain-specific events like `user_added`, you can -construct a fully custom event and attach it to the response. +As mentioned above, CosmWasm only emits the event `wasm` by default. If you want to emit other +events, such as domain-specific events like `user_added`, you can construct a fully custom event and +attach it to the response. - - Note that those custom events will be prefixed with `wasm-` by the runtime. - +Note that those custom events will be prefixed with `wasm-` by the runtime. ```rust filename="custom_event.rs" template="core" let event = Event::new("custom_event") diff --git a/src/pages/core/architecture/gas.mdx b/src/pages/core/architecture/gas.mdx index 889fe85d..3afc7679 100644 --- a/src/pages/core/architecture/gas.mdx +++ b/src/pages/core/architecture/gas.mdx @@ -4,40 +4,36 @@ tags: ["core", "architecture"] # Gas -Gas is a way to measure computational expense of a smart contract execution, -including CPU time and storage cost. Its unit is 1, i.e. you can think of it as -countable points. Gas consumption is deterministic, so executing the same thing -costs the same amount of gas across all hardware and operating systems. +Gas is a way to measure computational expense of a smart contract execution, including CPU time and +storage cost. Its unit is 1, i.e. you can think of it as countable points. Gas consumption is +deterministic, so executing the same thing costs the same amount of gas across all hardware and +operating systems. ## CosmWasm gas vs. Cosmos SDK gas -CosmWasm charges gas for Wasm operations, calls to host functions and calls to -the Cosmos SDK. _CosmWasm gas_ is different from _Cosmos SDK gas_ as the numbers -here are much larger. Since we charge gas for arbitrary user defined operations, -we need to charge each Wasm operation individually and cannot group larger tasks -together. As a result, the gas values become much larger than in Cosmos SDK even -for very fast executions. There is a [multiplier][defaultgasmultiplier] to -translate between CosmWasm gas and Cosmos SDK. It was measured and set to 100 a -while ago and can be adjusted when necessary. +CosmWasm charges gas for Wasm operations, calls to host functions and calls to the Cosmos SDK. +_CosmWasm gas_ is different from _Cosmos SDK gas_ as the numbers here are much larger. Since we +charge gas for arbitrary user defined operations, we need to charge each Wasm operation individually +and cannot group larger tasks together. As a result, the gas values become much larger than in +Cosmos SDK even for very fast executions. There is a [multiplier][defaultgasmultiplier] to translate +between CosmWasm gas and Cosmos SDK. It was measured and set to 100 a while ago and can be adjusted +when necessary. ## CosmWasm gas pricing -For CosmWasm gas, the target gas consumption is 1 Teragas (10^12 gas) per -second. This idea is [inspired by NEAR][neargas] and we encourage you to read -their excellent docs on that topic. +For CosmWasm gas, the target gas consumption is 1 Teragas (10^12 gas) per second. This idea is +[inspired by NEAR][neargas] and we encourage you to read their excellent docs on that topic. -In order to meet this target, we execute Argon2 in a test contract ([#1120]). -This is a CPU and memory intense job that does not call out into the host. At a -constant gas cost per operation of 1 (pre CosmWasm 1.0), this consumed 96837752 -gas and took 15ms on our CI system. The ideal cost per operation for this system -is `10^12 / (96837752 / (15 / 1000))`: 154. This is rounded to 150 for +In order to meet this target, we execute Argon2 in a test contract ([#1120]). This is a CPU and +memory intense job that does not call out into the host. At a constant gas cost per operation of 1 +(pre CosmWasm 1.0), this consumed 96837752 gas and took 15ms on our CI system. The ideal cost per +operation for this system is `10^12 / (96837752 / (15 / 1000))`: 154. This is rounded to 150 for simplicity. -CosmWasm 2.1 update: All gas values were re-evaluated and adjusted to meet the 1 -Teragas/second target mentioned above. A rerun of the Argon2 test contract -consumed 5270718300 gas with the previous cost of 150, so the operation count -was `5270718300 / 150 = 35138122`. This took 6ms on our benchmark server, so the -new cost per operation is `10^12 / (35138122 / (6 / 1000))`: 171. This is +CosmWasm 2.1 update: All gas values were re-evaluated and adjusted to meet the 1 Teragas/second +target mentioned above. A rerun of the Argon2 test contract consumed 5270718300 gas with the +previous cost of 150, so the operation count was `5270718300 / 150 = 35138122`. This took 6ms on our +benchmark server, so the new cost per operation is `10^12 / (35138122 / (6 / 1000))`: 171. This is rounded to 170 for simplicity. Benchmarking system: @@ -45,34 +41,29 @@ Benchmarking system: - CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz (4 cores, 8 threads) - RAM: 32GB DDR4 2133 MHz -Each machine is different, we know that. But the above target helps us in -multiple ways: +Each machine is different, we know that. But the above target helps us in multiple ways: -1. Develop an intuition what it means to burn X gas or how much gas can be used - if a block should be executable in e.g. 1 second -2. Have a target for adjustments, e.g. when the Wasm runtime becomes faster or - slower +1. Develop an intuition what it means to burn X gas or how much gas can be used if a block should be + executable in e.g. 1 second +2. Have a target for adjustments, e.g. when the Wasm runtime becomes faster or slower 3. Allow pricing of calls that are not executed in Wasm, such as crypto APIs 4. Find significant over or underpricing ## Gas overflow potential -CosmWasm gas aims for 1 Teragas/second, i.e. the uint64 range exceeds after 18 -million seconds (5000 hours)1. Assuming a max supported block -execution time of 30 seconds, the gas price has to be over-priced by a factor of -614891 (614891 Teragas/second) in order to exceed the uint64 range2. -Since serious over or underpricing is considered a bug, using uint64 for gas +CosmWasm gas aims for 1 Teragas/second, i.e. the uint64 range exceeds after 18 million seconds (5000 +hours)1. Assuming a max supported block execution time of 30 seconds, the gas price has +to be over-priced by a factor of 614891 (614891 Teragas/second) in order to exceed the uint64 +range2. Since serious over or underpricing is considered a bug, using uint64 for gas measurements is considered safe. -Cosmos SDK gas uses values that are smaller by a factor of 150, so those don't -overflow as well. Since no Cosmos SDK gas values are processed inside of this -repository, this is not our main concern. However, it's good to know that we can -safely pass them in uint64 fields, as long as the full range is supported. This -is the case for the C API as well as [JSON numbers] as long as both sides -support integers in their JSON implementation. Go and Rust do that while many -other implementations don't support integers, and convert them to IEEE-754 -doubles, which has a safe integer range up to about 53 bit (e.g. JavaScript and -jq). +Cosmos SDK gas uses values that are smaller by a factor of 150, so those don't overflow as well. +Since no Cosmos SDK gas values are processed inside of this repository, this is not our main +concern. However, it's good to know that we can safely pass them in uint64 fields, as long as the +full range is supported. This is the case for the C API as well as [JSON numbers] as long as both sides +support integers in their JSON implementation. Go and Rust do that while many other implementations don't +support integers, and convert them to IEEE-754 doubles, which has a safe integer range up to about 53 +bit (e.g. JavaScript and jq). 1 `(2^64-1) / 10^12` @@ -98,6 +89,7 @@ jq). [#1599]: https://github.com/CosmWasm/cosmwasm/pull/1599 [JSON numbers]: https://www.json.org/ -[defaultgasmultiplier]: https://github.com/CosmWasm/wasmd/blob/v0.19.0/x/wasm/keeper/gas_register.go#L18 +[defaultgasmultiplier]: + https://github.com/CosmWasm/wasmd/blob/v0.19.0/x/wasm/keeper/gas_register.go#L18 [neargas]: https://docs.near.org/docs/concepts/gas [#1120]: https://github.com/CosmWasm/cosmwasm/pull/1120 diff --git a/src/pages/core/architecture/pinning.mdx b/src/pages/core/architecture/pinning.mdx index 7fa433db..7fd571c4 100644 --- a/src/pages/core/architecture/pinning.mdx +++ b/src/pages/core/architecture/pinning.mdx @@ -6,70 +6,61 @@ import { Callout } from "nextra/components"; # Contract pinning -Contract pinning is a feature of the CosmWasm virtual machine which ensures that -a previously stored compiled contract code (module) is started from a dedicated -in-memory cache. Starting a module from memory takes ~45µs compared to 1.5ms -when loaded from disk (33x faster). +Contract pinning is a feature of the CosmWasm virtual machine which ensures that a previously stored +compiled contract code (module) is started from a dedicated in-memory cache. Starting a module from +memory takes ~45µs compared to 1.5ms when loaded from disk (33x faster). -In contrast to the node-specific Least recently used (LRU) memory cache, pinning -**guarantees** this performance boost across the network. As a consequence wasmd -can charge discounted gas cost[^1]. +In contrast to the node-specific Least recently used (LRU) memory cache, pinning **guarantees** this +performance boost across the network. As a consequence wasmd can charge discounted gas cost[^1]. - Pinning is an incredibly valuable tool for chains to optimize gas costs. - According to a [case study][neutron-case-study] by one of our subscribers, - Neutron, pinning improved the gas cost of their contracts somewhere between 15 - and 50%! + Pinning is an incredibly valuable tool for chains to optimize gas costs. According to a [case + study][neutron-case-study] by one of our subscribers, Neutron, pinning improved the gas cost of + their contracts somewhere between 15 and 50%! ## The caches CosmWasm has 3 different caches for modules: -1. `FileSystemCache` the `.module` files stored in the cache directory of the - node +1. `FileSystemCache` the `.module` files stored in the cache directory of the node 2. `InMemoryCache` the LRU cache 3. `PinnedMemoryCache` a separate cache -Both memory caches (2./3.) work the same in terms of performance but their -elements are tracked separately. A pinned contract is never added to the -standard `InMemoryCache` and the size of pinned contracts is not counted towards -its cache size limit. +Both memory caches (2./3.) work the same in terms of performance but their elements are tracked +separately. A pinned contract is never added to the standard `InMemoryCache` and the size of pinned +contracts is not counted towards its cache size limit. ## Pinning and Unpinning -In order to add a contract to the `PinnedMemoryCache`, you need to call -[`Cache::pin`] in Rust or `func (vm *VM) Pin(checksum Checksum) error` in -wasmvm. To remove a contract from the cache use [`Cache::unpin`] / -`func (vm *VM) Unpin(checksum Checksum) error`. In both cases a contract is +In order to add a contract to the `PinnedMemoryCache`, you need to call [`Cache::pin`] in Rust or +`func (vm *VM) Pin(checksum Checksum) error` in wasmvm. To remove a contract from the cache use +[`Cache::unpin`] / `func (vm *VM) Unpin(checksum Checksum) error`. In both cases a contract is identified by its checksum (sha256 hash of the Wasm blob). -The VM does not persist pinned memory entries. I.e. you need to call `Pin` every -time you start the process. This is implemented in [`InitializePinnedCodes` in -wasmd][initializepinnedcodes]. +The VM does not persist pinned memory entries. I.e. you need to call `Pin` every time you start the +process. This is implemented in [`InitializePinnedCodes` in wasmd][initializepinnedcodes]. At the chain level pinning and unpinning are done via governance proposals. See `MsgPinCodes`/`MsgUnpinCodes` in wasmd. -When contracts are migrated from one code to another, there is no automatic -pinning or unpinning. This is primarily since the migration of a single instance -does not mean all instances of the same code become unused. In the future we -want to provide hit stats for each checksum in order to easily find unused codes -in the pinned memory cache[^2]. +When contracts are migrated from one code to another, there is no automatic pinning or unpinning. +This is primarily since the migration of a single instance does not mean all instances of the same +code become unused. In the future we want to provide hit stats for each checksum in order to easily +find unused codes in the pinned memory cache[^2]. ## Best practices -Pinning contracts is a balance between increasing memory usage and boosting -execution speed. Contracts that are known to be heavily used should be pinned. -This can include contracts that are executed as part of begin/end block or the -IBC light client implementations of the Wasm Light Client ([08-wasm]). If a -chain is permissioned and runs on a small number of well known contracts, they -can all be pinned. A permissionless chain might select certain contracts of -strategic importance and pin them. +Pinning contracts is a balance between increasing memory usage and boosting execution speed. +Contracts that are known to be heavily used should be pinned. This can include contracts that are +executed as part of begin/end block or the IBC light client implementations of the Wasm Light Client +([08-wasm]). If a chain is permissioned and runs on a small number of well known contracts, they can +all be pinned. A permissionless chain might select certain contracts of strategic importance and pin +them. -The estimated size of the pinned contracts is visible in the [Metrics] struct -you can access through [Prometheus]. In order to better estimate which contracts -are worth pinning, CosmWasm also exports metrics per pinned contract. +The estimated size of the pinned contracts is visible in the [Metrics] struct you can access through +[Prometheus]. In order to better estimate which contracts are worth pinning, CosmWasm also exports +metrics per pinned contract. These metrics are: @@ -80,17 +71,18 @@ That way you can better estimate which contracts are worth keeping pinned. ## History -Pinning was developed in 2021 (CosmWasm 0.14) for the Proof of Engagement -consensus system of Tgrade which required certain contracts to be executed in -every block. +Pinning was developed in 2021 (CosmWasm 0.14) for the Proof of Engagement consensus system of Tgrade +which required certain contracts to be executed in every block. [metrics]: https://github.com/CosmWasm/wasmvm/blob/v2.0.0-rc.2/types/types.go#L174-L185 [`cache::pin`]: https://docs.rs/cosmwasm-vm/latest/cosmwasm_vm/struct.Cache.html#method.pin [`cache::unpin`]: https://docs.rs/cosmwasm-vm/latest/cosmwasm_vm/struct.Cache.html#method.unpin [08-wasm]: https://github.com/cosmos/ibc-go/tree/main/modules/light-clients/08-wasm -[initializepinnedcodes]: https://github.com/CosmWasm/wasmd/blob/v0.50.0/x/wasm/keeper/keeper.go#L1011-L1028 +[initializepinnedcodes]: + https://github.com/CosmWasm/wasmd/blob/v0.50.0/x/wasm/keeper/keeper.go#L1011-L1028 [Prometheus]: https://prometheus.io/ -[neutron-case-study]: https://medium.com/confio/neutron-case-study-optimizing-gas-usage-with-contract-pinning-5970a109c706 +[neutron-case-study]: + https://medium.com/confio/neutron-case-study-optimizing-gas-usage-with-contract-pinning-5970a109c706 [^1]: https://github.com/CosmWasm/wasmd/pull/1799 diff --git a/src/pages/core/architecture/transactions.mdx b/src/pages/core/architecture/transactions.mdx index 80aed7d5..b51f9a57 100644 --- a/src/pages/core/architecture/transactions.mdx +++ b/src/pages/core/architecture/transactions.mdx @@ -4,25 +4,22 @@ tags: ["core", "architecture"] # Transactions -Every contract invocation is wrapped into a transaction. If you know about -transactions in SQL databases, you can consider them as the same basic concept. -You execute multiple operations in a single transaction, and if one of them -fails, the whole transaction is rolled back. +Every contract invocation is wrapped into a transaction. If you know about transactions in SQL +databases, you can consider them as the same basic concept. You execute multiple operations in a +single transaction, and if one of them fails, the whole transaction is rolled back. -In our case, these operations are invocations of contract entrypoints. If one of -the invocations in the chain fails, the whole transaction is usually rolled -back. Failing in this context means that the contract entrypoint returns an -error or panics. +In our case, these operations are invocations of contract entrypoints. If one of the invocations in +the chain fails, the whole transaction is usually rolled back. Failing in this context means that +the contract entrypoint returns an error or panics. ## Preventing rollbacks in case of failure -If you don't want your entire transaction to be rolled back in case of a -failure, you can use the `reply_on` field in the message you send. Set the field -to one of the following values and instead of rolling back the transaction, you -will receive a message containing the error: +If you don't want your entire transaction to be rolled back in case of a failure, you can use the +`reply_on` field in the message you send. Set the field to one of the following values and instead +of rolling back the transaction, you will receive a message containing the error: - `ReplyOn::Always` - `ReplyOn::Error` -That way you can handle the error and decide what to do next, whether you want -to propagate the error, retry the operation, ignore it, etc. +That way you can handle the error and decide what to do next, whether you want to propagate the +error, retry the operation, ignore it, etc. diff --git a/src/pages/core/conventions.mdx b/src/pages/core/conventions.mdx index 750747b9..2a8c4405 100644 --- a/src/pages/core/conventions.mdx +++ b/src/pages/core/conventions.mdx @@ -6,10 +6,9 @@ import { Callout } from "nextra/components"; # Conventions -Just like with any platform, there are certain conventions on how to write -contracts for CosmWasm. This section will give you a quick overview over the -different conventions set in the CosmWasm ecosystem. +Just like with any platform, there are certain conventions on how to write contracts for CosmWasm. +This section will give you a quick overview over the different conventions set in the CosmWasm +ecosystem. -These conventions are about recommended programming patterns, and -recommendations on how you should structure your contract to make it fit into -the existing CosmWasm ecosystem better. +These conventions are about recommended programming patterns, and recommendations on how you should +structure your contract to make it fit into the existing CosmWasm ecosystem better. diff --git a/src/pages/core/conventions/enum-dispatch.mdx b/src/pages/core/conventions/enum-dispatch.mdx index 04303fd1..7536b268 100644 --- a/src/pages/core/conventions/enum-dispatch.mdx +++ b/src/pages/core/conventions/enum-dispatch.mdx @@ -6,12 +6,12 @@ import { Callout } from "nextra/components"; # Enum dispatch -In most production contracts you want to handle multiple message types in a -single contract. Unfortunately you can't create multiple endpoints of the same -type in a single contract, so you need to dispatch based on the message type. +In most production contracts you want to handle multiple message types in a single contract. +Unfortunately you can't create multiple endpoints of the same type in a single contract, so you need +to dispatch based on the message type. -The most common way to do this is to use an enum to represent the different -message types and then match on that enum in the endpoint. +The most common way to do this is to use an enum to represent the different message types and then +match on that enum in the endpoint. If this sounds like something you don't want to do manually, we got you covered! diff --git a/src/pages/core/conventions/library-feature.mdx b/src/pages/core/conventions/library-feature.mdx index 9ce55347..91102ad6 100644 --- a/src/pages/core/conventions/library-feature.mdx +++ b/src/pages/core/conventions/library-feature.mdx @@ -6,9 +6,8 @@ import { Callout } from "nextra/components"; # Library feature -In the ecosystem, there is the convention to gate the entrypoints of your -contract behind a compile-time feature. The feature is conventionally called -`library`. +In the ecosystem, there is the convention to gate the entrypoints of your contract behind a +compile-time feature. The feature is conventionally called `library`. So instead of doing this: @@ -39,19 +38,19 @@ pub fn instantiate( ``` - You can see this in action in the [`cw-plus` contracts]. Here is an example in - the [`cw4-stake` contract]. + You can see this in action in the [`cw-plus` contracts]. Here is an example in the [`cw4-stake` + contract]. -The rationale behind this is that currently using `#[entry_point]` exports -special symbols from the binary, and these symbols **must** be unique. +The rationale behind this is that currently using `#[entry_point]` exports special symbols from the +binary, and these symbols **must** be unique. -That means if you have two `instantiate` endpoints annotated with -`#[entry_point]` _somewhere_ in your project (that includes all your -dependencies!), your contract will fail to compile. +That means if you have two `instantiate` endpoints annotated with `#[entry_point]` _somewhere_ in +your project (that includes all your dependencies!), your contract will fail to compile. -Using this library feature will enable developers to use your contract as a -dependency and reuse your code. +Using this library feature will enable developers to use your contract as a dependency and reuse +your code. [`cw-plus` contracts]: https://github.com/CosmWasm/cw-plus -[`cw4-stake` contract]: https://github.com/CosmWasm/cw-plus/blob/48bec694521655d5b3e688c51e4185f740ea4640/contracts/cw4-stake/Cargo.toml#L22-L24 +[`cw4-stake` contract]: + https://github.com/CosmWasm/cw-plus/blob/48bec694521655d5b3e688c51e4185f740ea4640/contracts/cw4-stake/Cargo.toml#L22-L24 diff --git a/src/pages/core/entrypoints.mdx b/src/pages/core/entrypoints.mdx index 27ab8ebc..d986be9e 100644 --- a/src/pages/core/entrypoints.mdx +++ b/src/pages/core/entrypoints.mdx @@ -6,47 +6,44 @@ import { Callout } from "nextra/components"; # Entrypoints -Entrypoints are where your contract can be called from the outside world. You -can equate that to your `main` function in C, Rust, Java, etc. -However, there is one _small_ difference: In CosmWasm, you have multiple of -these entrypoints, each one different from the last. +Entrypoints are where your contract can be called from the outside world. You can equate that to +your `main` function in C, Rust, Java, etc. +However, there is one _small_ difference: In CosmWasm, you have multiple of 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. +In this section we want to give you a quick overview over all the entrypoints and when they are +called. In our examples, we will always refer to `StdResult` as the return type (and therefore `StdError` as the error type). This is just for convenience since every type that implements the `ToString` type can be used as an error type! -Meaning, as long as it implements `ToString`, nothing is stopping you from -defining `Result`. This can reduce your code complexity, -especially if you want to use the try operator. +Meaning, as long as it implements `ToString`, nothing is stopping you from defining +`Result`. This can reduce your code complexity, especially if you want to use the +try operator. ## 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. +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. -CosmWasm defines the handy `#[entry_point]` attribute macro. You simply annotate -a function with it, and it automatically generates code that communicates to the -VM: "Hey! This is an entrypoint, please use it when needed!" +CosmWasm defines the handy `#[entry_point]` attribute macro. You simply annotate a function with it, +and it automatically generates code that communicates to the VM: "Hey! This is an entrypoint, please +use it when needed!" - When defining an entrypoint, it is important to use the correct types for the - parameters and return type. Incorrect types will cause errors when trying to - call the contract. -
In the following sections we will take a look at all possible - entrypoints, including the correct function signature. + When defining an entrypoint, it is important to use the correct types for the parameters and + return type. Incorrect types will cause errors when trying to call the contract. +
In the following sections we will take a look at all possible entrypoints, 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. + 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" @@ -64,11 +61,11 @@ pub fn instantiate( ## Entrypoint parameters -Entrypoints have a few parameters (as you can see above), some of them are -predefined by `cosmwasm-std`, others are defined by the user themselves. +Entrypoints have a few parameters (as you can see above), some of them are predefined by +`cosmwasm-std`, others are defined by the user themselves. -Here we go over the different predefined types the standard library provides, -and how you can define your own types. +Here we go over the different predefined types the standard library provides, and how you can define +your own types. ### Predefined types @@ -80,37 +77,33 @@ These structs provide you access to the: - VM API - Querier -The big difference is that `DepsMut` gives you _mutable_ access to the storage. -This design is deliberate since you, for example, can't mutate the state in the -`query` endpoint. Instead of relying on runtime errors, this is made -_irrepresentable_ through Rust's type system. +The big difference is that `DepsMut` gives you _mutable_ access to the storage. This design is +deliberate since you, for example, can't mutate the state in the `query` endpoint. Instead of +relying on runtime errors, this is made _irrepresentable_ through Rust's type system. #### `Env` -This struct provides you with some information of the current state of the -environment your contract is executed in. +This struct provides you with some information of the current state of the environment your contract +is executed in. -The information provided is, for example, the block height, chain ID, -transaction info, etc. Basically anything you'd ever want to know about the -current state of the execution environment! +The information provided is, for example, the block height, chain ID, transaction info, etc. +Basically anything you'd ever want to know about the current state of the execution environment! #### `MessageInfo` This struct isn't provided to every endpoint, only to a select few. -It provides you with some information that might be crucial to you, depending on -the operation you want to perform. It contains the sender of the message you -just received, and the funds that were transferred along with it to your -contract. +It provides you with some information that might be crucial to you, depending on the operation you +want to perform. It contains the sender of the message you just received, and the funds that were +transferred along with it to your contract. ### Defining your own messages -In our examples, you might have seen messages such as `InstantiateMsg`. These -messages are actually _user-defined_, meaning each contract developer has to -define them themselves. +In our examples, you might have seen messages such as `InstantiateMsg`. These messages are actually +_user-defined_, meaning each contract developer has to define them themselves. -To make this easier our `cosmwasm-schema` crate provides the `cw_serde` -attribute macro, to define an instantiate message, you simply write this: +To make this easier our `cosmwasm-schema` crate provides the `cw_serde` attribute macro, to define +an instantiate message, you simply write this: ```rust filename="instantiate.rs" template="core" #[cw_serde] diff --git a/src/pages/core/entrypoints/execute.mdx b/src/pages/core/entrypoints/execute.mdx index dc0ce0d6..93b54f0c 100644 --- a/src/pages/core/entrypoints/execute.mdx +++ b/src/pages/core/entrypoints/execute.mdx @@ -6,13 +6,11 @@ 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. +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. +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 diff --git a/src/pages/core/entrypoints/instantiate.mdx b/src/pages/core/entrypoints/instantiate.mdx index 20f3eb20..df8382c9 100644 --- a/src/pages/core/entrypoints/instantiate.mdx +++ b/src/pages/core/entrypoints/instantiate.mdx @@ -6,10 +6,10 @@ 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.). +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. diff --git a/src/pages/core/entrypoints/migrate.mdx b/src/pages/core/entrypoints/migrate.mdx index 5817de54..2ee63dd0 100644 --- a/src/pages/core/entrypoints/migrate.mdx +++ b/src/pages/core/entrypoints/migrate.mdx @@ -6,14 +6,12 @@ import { Callout } from "nextra/components"; # Migrate -This is another special endpoint. It is, just like `instantiate`, not called -frequently. +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. +`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: +Let's say your storage has the following layout, expressed as JSON for simplicity's sake: ```json filename="structure.json" { @@ -23,11 +21,10 @@ simplicity's sake: } ``` -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". +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: +So you go ahead and rework your logic to query the data from the following structure: ```json filename="structure.json" { @@ -39,11 +36,9 @@ structure: } ``` -But your storage on-chain still stores the old format. You need to somehow -transform it. +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. +That's what you do in the `migrate` entrypoint. You transform the structure of the storage in there. ## Example diff --git a/src/pages/core/entrypoints/query.mdx b/src/pages/core/entrypoints/query.mdx index 1df2639e..81907ab8 100644 --- a/src/pages/core/entrypoints/query.mdx +++ b/src/pages/core/entrypoints/query.mdx @@ -6,16 +6,15 @@ import { Callout } from "nextra/components"; # Query -In the previous section we talked about the [`execute` endpoint]. The `query` endpoint -is actually pretty similar to its sibling `execute`, but with one key difference: -The storage is only accessible immutably. +In the previous section we talked about the [`execute` endpoint]. 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. ## Properly defining a message -When defining a message for queries, you always return some value. To properly -document these return values, you'll want to define them in your schema. +When defining a message for queries, you always return some value. To properly document these return +values, you'll want to define them in your schema. This is where the `cosmwasm_schema::QueryResponses` derive macro comes in. @@ -40,9 +39,8 @@ enum CustomQueryMsg { } ``` -The macro then defines the required code to document the responses in your code -properly so you can easily generate, for example, TypeScript types for your -contract clients. +The macro then defines the required code to document the responses in your code properly so you can +easily generate, for example, TypeScript types for your contract clients. ## Definition diff --git a/src/pages/core/entrypoints/reply.mdx b/src/pages/core/entrypoints/reply.mdx index 61d453e5..ce5347b0 100644 --- a/src/pages/core/entrypoints/reply.mdx +++ b/src/pages/core/entrypoints/reply.mdx @@ -8,30 +8,28 @@ import { Callout } from "nextra/components"; 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. +It relates to CosmWasm's actor model which dictates how you call other contracts and interact with +them. - If you are not familiar with the actor model, you can find out more about it - on [its own page]. + If you are not familiar with the actor model, you can find out more about it on [its own page]. -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. +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: +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` - The `reply_on` value has an impact on when a transaction is cancelled. For - more info, check the page about [transactions]. + The `reply_on` value has an impact on when a transaction is cancelled. For more info, check the + page about [transactions]. ```rust filename="contract.rs" template="core" diff --git a/src/pages/core/entrypoints/sudo.mdx b/src/pages/core/entrypoints/sudo.mdx index 64af65a6..57c8b26c 100644 --- a/src/pages/core/entrypoints/sudo.mdx +++ b/src/pages/core/entrypoints/sudo.mdx @@ -8,12 +8,11 @@ import { Callout } from "nextra/components"; `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. +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. +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 diff --git a/src/pages/core/installation.mdx b/src/pages/core/installation.mdx index d787934a..42422315 100644 --- a/src/pages/core/installation.mdx +++ b/src/pages/core/installation.mdx @@ -8,16 +8,14 @@ import { Callout } from "nextra/components"; ## Setting up the environment -Before diving right into writing code, you need to install some tooling in order -to compile your contract. CosmWasm is luckily rather self-contained and -therefore needs little external tooling to compile. -Our only external dependency is Rust, which you need to install for your -platform. +Before diving right into writing code, you need to install some tooling in order to compile your +contract. CosmWasm is luckily rather self-contained and therefore needs little external tooling to +compile. +Our only external dependency is Rust, which you need to install for your platform. - We recommend installing Rust using the official [rustup installer]. This makes - it easy to stay on the most recent Rust version and to install compiler - targets. + We recommend installing Rust using the official [rustup installer]. This makes it easy to stay on + the most recent Rust version and to install compiler targets. @@ -54,8 +52,8 @@ platform. -After installing Rust, you need to add the WebAssembly target. This is needed so -Rust knows how to build your code to WebAssembly. +After installing Rust, you need to add the WebAssembly target. This is needed so Rust knows how to +build your code to WebAssembly. To install the target using `rustup`, run the following command: @@ -67,8 +65,7 @@ Perfect! Now that we set up the foundation we just need two more tools: 1. `cargo-generate` -2. `cargo-run-script` (this is required to later optimize your contract for - production) +2. `cargo-run-script` (this is required to later optimize your contract for production) To install those, run the following commands: @@ -81,21 +78,19 @@ cargo install cargo-run-script Now that the environment is all done, let's create the project! -Luckily you don't need to start from scratch, we already took care of the most -tedious parts of setting up a new project in form of a template! +Luckily you don't need to start from scratch, we already took care of the most tedious parts of +setting up a new project in form of a template! In order to generate a fresh project, run this command and off we go: - - Make sure to change `PROJECT_NAME` to the name of your contract! - +Make sure to change `PROJECT_NAME` to the name of your contract! ```sh cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME ``` -Now you should have a ready contract project in a new folder called -`PROJECT_NAME` (or whatever you changed it to). +Now you should have a ready contract project in a new folder called `PROJECT_NAME` (or whatever you +changed it to). [rustup installer]: https://rustup.rs [Docker]: https://www.docker.com/ diff --git a/src/pages/core/specification.mdx b/src/pages/core/specification.mdx index 24f14e3c..ab5c5d78 100644 --- a/src/pages/core/specification.mdx +++ b/src/pages/core/specification.mdx @@ -6,6 +6,5 @@ tags: ["core", "specification"] This section contains specifications of CosmWasm-specific algorithms. -Whenever you want to port one of those algorithms into a different programming -language, you can refer to their pages and treat them as their canonical -specifications. +Whenever you want to port one of those algorithms into a different programming language, you can +refer to their pages and treat them as their canonical specifications. diff --git a/src/pages/core/specification/instantiate2-algo.mdx b/src/pages/core/specification/instantiate2-algo.mdx index 44e0e933..ea537deb 100644 --- a/src/pages/core/specification/instantiate2-algo.mdx +++ b/src/pages/core/specification/instantiate2-algo.mdx @@ -6,25 +6,22 @@ import { Callout } from "nextra/components"; # Instantiate2 algorithm -With the instantiate2 algorithm you can create a contract address in a -predictable and deterministic way. The underlying algorithm is rather simple. +With the instantiate2 algorithm you can create a contract address in a predictable and deterministic +way. The underlying algorithm is rather simple. We use SHA-256 as the underlying hashing algorithm. You need to provide the following inputs: -- Checksum: This is the checksum of the contract code (the Wasm module, for - example). This _has_ to be a SHA-256 hash -- Creator: This is the canonicalized address of the user instantiating the - contract -- Salt: This is some byte string allowing you to distinguish multiple - instantiations of the same contract by the same creator; this parameter has to - be under 64 bytes in length +- Checksum: This is the checksum of the contract code (the Wasm module, for example). This _has_ to + be a SHA-256 hash +- Creator: This is the canonicalized address of the user instantiating the contract +- Salt: This is some byte string allowing you to distinguish multiple instantiations of the same + contract by the same creator; this parameter has to be under 64 bytes in length - Message: This is usually unused. CosmWasm sets this to an empty byte string - Make sure you convert all the integers into their *big-endian* byte - representation! + Make sure you convert all the integers into their *big-endian* byte representation! ```rust filename="instantiate2.rs" template="instantiate-spec" diff --git a/src/pages/core/standard-library.mdx b/src/pages/core/standard-library.mdx index 46ddf38f..78dc0a6e 100644 --- a/src/pages/core/standard-library.mdx +++ b/src/pages/core/standard-library.mdx @@ -6,11 +6,10 @@ import { Callout } from "nextra/components"; # Standard Library -CosmWasm offers a standard library providing a bunch of different components to -write smart contracts. In this section we will go over some components and -functionality the standard library offers. +CosmWasm offers a standard library providing a bunch of different components to write smart +contracts. In this section we will go over some components and functionality the standard library +offers. -A full list of all components along with documentation can be found [on -docs.rs]. +A full list of all components along with documentation can be found [on docs.rs]. [on docs.rs]: https://docs.rs/cosmwasm-std diff --git a/src/pages/core/standard-library/cryptography.mdx b/src/pages/core/standard-library/cryptography.mdx index 85c5aa3e..b91c19b4 100644 --- a/src/pages/core/standard-library/cryptography.mdx +++ b/src/pages/core/standard-library/cryptography.mdx @@ -6,22 +6,20 @@ import { Callout } from "nextra/components"; # Cryptography -CosmWasm offers cryptographic primitives that are implemented as VM intrinsics. -This means that they are more efficient than implementations in contract code -could be, saving you gas and code size. In some cases they are also _impossible_ -to implement in contract code, since some of them require a random intermediate -value and randomness is generally not exposed to contracts to ensure +CosmWasm offers cryptographic primitives that are implemented as VM intrinsics. This means that they +are more efficient than implementations in contract code could be, saving you gas and code size. In +some cases they are also _impossible_ to implement in contract code, since some of them require a +random intermediate value and randomness is generally not exposed to contracts to ensure deterministic execution. -In the sidebar, you can find all the supported algorithms/curves along with -documentation about them. +In the sidebar, you can find all the supported algorithms/curves along with documentation about +them. ## Gas costs - Note that these values are in CosmWasm Gas (which is not equivalent to Cosmos - SDK Gas; rather, CosmWasm Gas is eventually converted to Cosmos SDK Gas). For - more info on gas, [check this page]. + Note that these values are in CosmWasm Gas (which is not equivalent to Cosmos SDK Gas; rather, + CosmWasm Gas is eventually converted to Cosmos SDK Gas). For more info on gas, [check this page]. ### secp256k1 @@ -62,23 +60,21 @@ You can also check these numbers in the [source code]. ## Note on hash functions -You'll notice that CosmWasm does not implement any hash functions as native -functions, and we intend to keep it that way. The reasoning for that is: - -- Hash functions are pretty much always cheap in terms of execution cost _and_ - code size -- There are way too many hash functions out there, adding one would open the - floodgates where we would have to add more - - SHA-3 family, Keccak256, cSHAKE256, BLAKE2, BLAKE3, SHA-2 family, - KangarooTwelve, etc. (and this is just a small sample set to drive the point - home) -- Benchmarking and pricing functions (and keeping those up-to-date) correctly is - a lot of work +You'll notice that CosmWasm does not implement any hash functions as native functions, and we intend +to keep it that way. The reasoning for that is: + +- Hash functions are pretty much always cheap in terms of execution cost _and_ code size +- There are way too many hash functions out there, adding one would open the floodgates where we + would have to add more + - SHA-3 family, Keccak256, cSHAKE256, BLAKE2, BLAKE3, SHA-2 family, KangarooTwelve, etc. (and this + is just a small sample set to drive the point home) +- Benchmarking and pricing functions (and keeping those up-to-date) correctly is a lot of work - We want to keep the API surface as small as possible for ease of maintainance -Keep in mind that, thanks to Wasm being our execution environment, contract -execution is quite fast. In most cases the perceived need to move hashing into a -host function is premature optimization and not actually needed. +Keep in mind that, thanks to Wasm being our execution environment, contract execution is quite fast. +In most cases the perceived need to move hashing into a host function is premature optimization and +not actually needed. [check this page]: ../architecture/gas -[source code]: https://github.com/CosmWasm/cosmwasm/blob/main/packages/vm/src/environment.rs#L62-L101 +[source code]: + https://github.com/CosmWasm/cosmwasm/blob/main/packages/vm/src/environment.rs#L62-L101 diff --git a/src/pages/core/standard-library/cryptography/bls12-381.mdx b/src/pages/core/standard-library/cryptography/bls12-381.mdx index a8e669b1..2180fc93 100644 --- a/src/pages/core/standard-library/cryptography/bls12-381.mdx +++ b/src/pages/core/standard-library/cryptography/bls12-381.mdx @@ -6,19 +6,17 @@ import { Callout } from "nextra/components"; # BLS12-381 -BLS12-381 is a bit of a special curve. It is a pairing-friendly curve, allowing -for fun things such as aggregated signatures. At the moment, CosmWasm only -supports signature verifications. In the future we might add support for -zero-knowledge proofs on this curve. +BLS12-381 is a bit of a special curve. It is a pairing-friendly curve, allowing for fun things such +as aggregated signatures. At the moment, CosmWasm only supports signature verifications. In the +future we might add support for zero-knowledge proofs on this curve. -Common examples where this curve is used are Ethereum block-headers and [drand] -randomness beacons. +Common examples where this curve is used are Ethereum block-headers and [drand] randomness beacons. ## Example -CosmWasm offers a byte-oriented API for signature verification. This API also -doesn't care whether the public key is part of the G1 or G2 group (same for the -other components). They just have to somehow fit together. +CosmWasm offers a byte-oriented API for signature verification. This API also doesn't care whether +the public key is part of the G1 or G2 group (same for the other components). They just have to +somehow fit together. ## Verify on G1 @@ -44,7 +42,9 @@ pub fn query( ## Verify on G2 -Signature verification with public key in G2 (See https://hackmd.io/@benjaminion/bls12-381#Verification in combination with https://hackmd.io/@benjaminion/bls12-381#Swapping-G1-and-G2): +Signature verification with public key in G2 (See +https://hackmd.io/@benjaminion/bls12-381#Verification in combination with +https://hackmd.io/@benjaminion/bls12-381#Swapping-G1-and-G2): ```rust filename="contract.rs" template="core" #[cfg_attr(not(feature = "library"), entry_point)] diff --git a/src/pages/core/standard-library/cryptography/ed25519.mdx b/src/pages/core/standard-library/cryptography/ed25519.mdx index e2065657..f4d49499 100644 --- a/src/pages/core/standard-library/cryptography/ed25519.mdx +++ b/src/pages/core/standard-library/cryptography/ed25519.mdx @@ -6,13 +6,12 @@ import { Callout } from "nextra/components"; # Ed25519 -CosmWasm offers an API to verify and batch verify Ed25519 signatures. This is -powerful, especially since batch verifications require a random component which -is impossible to implement in contract code. +CosmWasm offers an API to verify and batch verify Ed25519 signatures. This is powerful, especially +since batch verifications require a random component which is impossible to implement in contract +code. -Ed25519 is known to [have issues with inconsistent validation criteria], the API -we offer follows [ZIP215]. This means you will have no issues with signatures -being valid in one place and invalid in another. +Ed25519 is known to [have issues with inconsistent validation criteria], the API we offer follows [ZIP215]. +This means you will have no issues with signatures being valid in one place and invalid in another. ## Example @@ -37,5 +36,6 @@ pub fn query( } ``` -[have issues with inconsistent validation criteria]: https://hdevalence.ca/blog/2020-10-04-its-25519am +[have issues with inconsistent validation criteria]: + https://hdevalence.ca/blog/2020-10-04-its-25519am [ZIP215]: https://zips.z.cash/zip-0215 diff --git a/src/pages/core/standard-library/cryptography/k256.mdx b/src/pages/core/standard-library/cryptography/k256.mdx index 78d41816..d23d0459 100644 --- a/src/pages/core/standard-library/cryptography/k256.mdx +++ b/src/pages/core/standard-library/cryptography/k256.mdx @@ -6,8 +6,8 @@ import { Callout } from "nextra/components"; # K256 (secp256k1) -K256 is a Koblitz curve that is widely used in the blockchain space (e.g. -Bitcoin and Ethereum). CosmWasm offers the following APIs: +K256 is a Koblitz curve that is widely used in the blockchain space (e.g. Bitcoin and Ethereum). +CosmWasm offers the following APIs: - Signature verification - Public key recovery diff --git a/src/pages/core/standard-library/cryptography/p256.mdx b/src/pages/core/standard-library/cryptography/p256.mdx index 096375eb..fa3a7cea 100644 --- a/src/pages/core/standard-library/cryptography/p256.mdx +++ b/src/pages/core/standard-library/cryptography/p256.mdx @@ -6,9 +6,8 @@ import { Callout } from "nextra/components"; # P256 (secp256r1) -P256 is one of NIST's prime-order elliptic curves. You may need this curve to -implement protocols such as WebAuthn. This is the main reason this curve was -added to CosmWasm. +P256 is one of NIST's prime-order elliptic curves. You may need this curve to implement protocols +such as WebAuthn. This is the main reason this curve was added to CosmWasm. ## Example diff --git a/src/pages/core/standard-library/math.mdx b/src/pages/core/standard-library/math.mdx index 15c7d595..11cdd732 100644 --- a/src/pages/core/standard-library/math.mdx +++ b/src/pages/core/standard-library/math.mdx @@ -6,6 +6,6 @@ import { Callout } from "nextra/components"; # Math -CosmWasm offers mathematical primitives for, you guessed it, mathematical -operations. In contrast to the Rust standard library, which is limited to 128 -bit integers, we offer integers that exceed that precision. +CosmWasm offers mathematical primitives for, you guessed it, mathematical operations. In contrast to +the Rust standard library, which is limited to 128 bit integers, we offer integers that exceed that +precision. diff --git a/src/pages/core/standard-library/math/decimals.mdx b/src/pages/core/standard-library/math/decimals.mdx index 92cb15ce..fa350bb6 100644 --- a/src/pages/core/standard-library/math/decimals.mdx +++ b/src/pages/core/standard-library/math/decimals.mdx @@ -8,13 +8,11 @@ import { Callout } from "nextra/components"; CosmWasm offers decimal types for handling fractional numbers. -In contrast to floating point numbers, these datatypes do not suffer from the -same precision issues. This means that these decimal types are safe for use in -financial calculations. +In contrast to floating point numbers, these datatypes do not suffer from the same precision issues. +This means that these decimal types are safe for use in financial calculations. -Instead of storing numbers in the floating point format, which gives it a -_floating_ amount of decimal places, these decimal types have a fixed precision -of 18 decimal places. +Instead of storing numbers in the floating point format, which gives it a _floating_ amount of +decimal places, these decimal types have a fixed precision of 18 decimal places. Note that, due to how the decimal types are structured, the value ranges can seem a little weird. diff --git a/src/pages/core/standard-library/math/integers.mdx b/src/pages/core/standard-library/math/integers.mdx index b3755b07..94f74be9 100644 --- a/src/pages/core/standard-library/math/integers.mdx +++ b/src/pages/core/standard-library/math/integers.mdx @@ -6,27 +6,24 @@ import { Callout } from "nextra/components"; # Integers -CosmWasm offers integer types starting at 64 bit precision, all the way up to -512 bits. +CosmWasm offers integer types starting at 64 bit precision, all the way up to 512 bits. -Reasoning behind wrapping the primitive 64 bit type is the interaction with, for -example, JavaScript (same goes for parsers like `jq` or any parser that parses -numbers into double precision floats). A `u64` would normally serialize into a -regular integer field in JSON. The issue here is that, due to representing -integers in form of double precision floats, JavaScript can only handle up to -~53 bit numbers without potentially losing information. +Reasoning behind wrapping the primitive 64 bit type is the interaction with, for example, JavaScript +(same goes for parsers like `jq` or any parser that parses numbers into double precision floats). A +`u64` would normally serialize into a regular integer field in JSON. The issue here is that, due to +representing integers in form of double precision floats, JavaScript can only handle up to ~53 bit +numbers without potentially losing information. - There is nothing wrong with using the primitive 64- and 128-bit types in your - contract for calculations. The issues mentioned here can only happen when you - de-/serialize these values. + There is nothing wrong with using the primitive 64- and 128-bit types in your contract for + calculations. The issues mentioned here can only happen when you de-/serialize these values. -Our wrapper fixes this by serializing numbers as strings, letting JavaScript -clients deserialize these numbers into their respective BigInteger types. +Our wrapper fixes this by serializing numbers as strings, letting JavaScript clients deserialize +these numbers into their respective BigInteger types. -The other integer types, which reach even higher amounts of precision, are -serialized in the same way. +The other integer types, which reach even higher amounts of precision, are serialized in the same +way. Integers come in the following variants: diff --git a/src/pages/cw-multi-test.mdx b/src/pages/cw-multi-test.mdx index 51d1ed59..edde3f42 100644 --- a/src/pages/cw-multi-test.mdx +++ b/src/pages/cw-multi-test.mdx @@ -6,32 +6,28 @@ import { Callout } from "nextra/components"; # Introduction -**`MultiTest`** is a suite of testing tools designed for facilitating -multi-contract interactions within the CosmWasm ecosystem. Its primary focus is -on providing developers with a robust framework for testing complex contract -interactions and several Cosmos modules operations. +**`MultiTest`** is a suite of testing tools designed for facilitating multi-contract interactions +within the CosmWasm ecosystem. Its primary focus is on providing developers with a robust framework +for testing complex contract interactions and several Cosmos modules operations. - MultiTest is a **simulator** of the blockchain, allowing tested smart - contracts to interact as if they were operating on the real-life blockchain. + MultiTest is a **simulator** of the blockchain, allowing tested smart contracts to interact as if + they were operating on the real-life blockchain. -The most valuable advantage of using **`MultiTest`** is that it allows you to -test and debug smart contracts with access to Rust source code, eliminating the -need to run a complete blockchain node to begin designing smart contract -functionality. - -The disadvantage is that **`MultiTest`** is a blockchain simulator, and it is -possible that the behavior of the real-life blockchain may slightly differ in -edge cases from the simulated model. In such cases, we strongly encourage you to -[file an issue](https://github.com/CosmWasm/cw-multi-test/issues) with a -detailed description of the use case to help us improve **`MultiTest`**. - -In the upcoming chapters, we will provide detailed instructions on installing -and getting started with **`MultiTest`**, writing unit tests for smart -contracts, testing complex interactions between smart contracts and testing -smart contract interactions with Cosmos modules. - -By the end of these chapters, you will have a comprehensive understanding of -using **`MultiTest`** for testing and debugging smart contracts in various -scenarios. +The most valuable advantage of using **`MultiTest`** is that it allows you to test and debug smart +contracts with access to Rust source code, eliminating the need to run a complete blockchain node to +begin designing smart contract functionality. + +The disadvantage is that **`MultiTest`** is a blockchain simulator, and it is possible that the +behavior of the real-life blockchain may slightly differ in edge cases from the simulated model. In +such cases, we strongly encourage you to +[file an issue](https://github.com/CosmWasm/cw-multi-test/issues) with a detailed description of the +use case to help us improve **`MultiTest`**. + +In the upcoming chapters, we will provide detailed instructions on installing and getting started +with **`MultiTest`**, writing unit tests for smart contracts, testing complex interactions between +smart contracts and testing smart contract interactions with Cosmos modules. + +By the end of these chapters, you will have a comprehensive understanding of using **`MultiTest`** +for testing and debugging smart contracts in various scenarios. diff --git a/src/pages/cw-multi-test/installation.mdx b/src/pages/cw-multi-test/installation.mdx index 12c6163a..08bb2516 100644 --- a/src/pages/cw-multi-test/installation.mdx +++ b/src/pages/cw-multi-test/installation.mdx @@ -9,8 +9,8 @@ import { Callout } from "nextra/components"; **`MultiTest`** ships as a Rust library named [cw-multi-test](https://crates.io/crates/cw-multi-test). -To use **`MultiTest`** for building and testing smart contracts, add it as a -**development dependency** to your project: +To use **`MultiTest`** for building and testing smart contracts, add it as a **development +dependency** to your project: ```toml filename="Cargo.toml" [dev-dependencies] @@ -18,20 +18,18 @@ cw-multi-test = "2" ``` - **`MultiTest`** is a _**testing**_ library and should always be added to your - project as **DEVELOPMENT DEPENDENCY** in section **`[dev-dependencies]`** of - the **Cargo.toml** file. + **`MultiTest`** is a _**testing**_ library and should always be added to your project as + **DEVELOPMENT DEPENDENCY** in section **`[dev-dependencies]`** of the **Cargo.toml** file. ### Prerequisities -The only prerequisite to build and test smart contracts using **`MultiTest`** is -having [Rust and Cargo](https://www.rust-lang.org/tools/install) installed. +The only prerequisite to build and test smart contracts using **`MultiTest`** is having +[Rust and Cargo](https://www.rust-lang.org/tools/install) installed. -Optionally, you may want to install -[Tarpaulin](https://github.com/xd009642/tarpaulin) for measuring code coverage -and [Nextest](https://nexte.st) for running tests faster, with clean and -beautiful user interface. +Optionally, you may want to install [Tarpaulin](https://github.com/xd009642/tarpaulin) for measuring +code coverage and [Nextest](https://nexte.st) for running tests faster, with clean and beautiful +user interface. Installing **Tarpaulin**: diff --git a/src/pages/cw-storage-plus.mdx b/src/pages/cw-storage-plus.mdx index d96a93e5..764eafcd 100644 --- a/src/pages/cw-storage-plus.mdx +++ b/src/pages/cw-storage-plus.mdx @@ -4,42 +4,36 @@ tags: ["storage-plus"] # Introduction -Not being able to persist data across calls would limit the utility of smart -contracts. Think of these problems: +Not being able to persist data across calls would limit the utility of smart contracts. Think of +these problems: -- How could a smart contract implement a token if it could not keep track of - balances? -- How could a smart contract implement a voting system if it could not keep - track of votes? -- How could a smart contract implement a game if it could not keep track of - scores? +- How could a smart contract implement a token if it could not keep track of balances? +- How could a smart contract implement a voting system if it could not keep track of votes? +- How could a smart contract implement a game if it could not keep track of scores? -This is why a _CosmWasm_ smart contract has access to the storage facilities -offered by the [_Cosmos SDK_](https://docs.cosmos.network/). These facilities -are essentially a binary key-value store, with records stored on-chain. +This is why a _CosmWasm_ smart contract has access to the storage facilities offered by the +[_Cosmos SDK_](https://docs.cosmos.network/). These facilities are essentially a binary key-value +store, with records stored on-chain. ## Storage limits -While developing smart contracts, it's important to remember on-chain storage -is, as always, pricey. Conventionally, developers often draw the line at a -"small logo image" (think a few KBs). If you need to store bigger things, it's -likely time to consider off-chain storage (like IPFS or some centralized -storage). Techniques for securely and reliably storing large data off-chain are -beyond the scope of this document. +While developing smart contracts, it's important to remember on-chain storage is, as always, pricey. +Conventionally, developers often draw the line at a "small logo image" (think a few KBs). If you +need to store bigger things, it's likely time to consider off-chain storage (like IPFS or some +centralized storage). Techniques for securely and reliably storing large data off-chain are beyond +the scope of this document. -Trying to minimize bloat is always good practice when it comes to on-chain -storage. +Trying to minimize bloat is always good practice when it comes to on-chain storage. ## What _cw-storage-plus_ builds on -The smart contract framework itself (`cosmwasm-std`) provides a simple API for -storing and retrieving data. If you're curious, you can check it out right +The smart contract framework itself (`cosmwasm-std`) provides a simple API for storing and +retrieving data. If you're curious, you can check it out right [here](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/trait.Storage.html). -This API is raw in that it exposes the **binary** key-value store. While you're -free to use it directly, you're likely to find that finicky and error-prone. -`cw-storage-plus` is a library that builds on top of this API to do the -following: +This API is raw in that it exposes the **binary** key-value store. While you're free to use it +directly, you're likely to find that finicky and error-prone. `cw-storage-plus` is a library that +builds on top of this API to do the following: - eliminate the need to manually serialize and deserialize data - provide a type-safe interface for storing and retrieving data diff --git a/src/pages/cw-storage-plus/basics.mdx b/src/pages/cw-storage-plus/basics.mdx index 6126ede8..29650f7b 100644 --- a/src/pages/cw-storage-plus/basics.mdx +++ b/src/pages/cw-storage-plus/basics.mdx @@ -8,81 +8,70 @@ import { Callout } from "nextra/components"; ## Containers -`cw-storage-plus`` provides several storage containers that can be used to store -data on the blockchain. The fundamental ones are: +`cw-storage-plus`` provides several storage containers that can be used to store data on the +blockchain. The fundamental ones are: - [`Item`](containers/item) - [`Map`](containers/map) - [`Deque`](containers/deque) -An [`Item`](containers/item) is a simple container that stores a single value. -The other two are a little more involved - they are collections capable of -storing multiple values, and provide several methods to interact with them. +An [`Item`](containers/item) is a simple container that stores a single value. The other two are a +little more involved - they are collections capable of storing multiple values, and provide several +methods to interact with them. ## Keys and prefixes -One task of a storage library like `cw-storage-plus` is to manage the namespace -of keys provided by the blockchain. +One task of a storage library like `cw-storage-plus` is to manage the namespace of keys provided by +the blockchain. -When constructing a container, you must provide a key of type `&'static str` (or -use +When constructing a container, you must provide a key of type `&'static str` (or use [`new_dyn`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Item.html#method.new_dyn)). This usually means you'll be providing a string literal or some constant. -In the case of an [`Item`](containers/item), the provided string is the exact -key (a standard UTF-8 string) under which the value will be saved. In the case -of collections, the provided string is a prefix (sometimes called `namespace` in -the code); the collection will use this prefix to generate keys (by appending to -it) for the individual values it stores. +In the case of an [`Item`](containers/item), the provided string is the exact key (a standard UTF-8 +string) under which the value will be saved. In the case of collections, the provided string is a +prefix (sometimes called `namespace` in the code); the collection will use this prefix to generate +keys (by appending to it) for the individual values it stores. -As a contract dev, it is your responsibility to ensure that the keys you provide -are unique and do not conflict with keys used by other parts of the contract. +As a contract dev, it is your responsibility to ensure that the keys you provide are unique and do +not conflict with keys used by other parts of the contract. - Over time, we've learned that using long keys hurts storage performance. If - you _gotta go fast_, a good approach might be to only provide single-character - ASCII prefixes for your containers, like _"a"_, _"b"_, _"c"_, etc. + Over time, we've learned that using long keys hurts storage performance. If you _gotta go fast_, a + good approach might be to only provide single-character ASCII prefixes for your containers, like + _"a"_, _"b"_, _"c"_, etc. -Generally speaking, we tried to make it so that as long as you use a unique -prefix for each container, you shouldn't have to worry about key conflicts. +Generally speaking, we tried to make it so that as long as you use a unique prefix for each +container, you shouldn't have to worry about key conflicts. -TODO: Research the key collisions in the warning below more! Then we can provide -better advice. +TODO: Research the key collisions in the warning below more! Then we can provide better advice. - ...yet there's a small _but_. A `Map`'s prefix is length-prefixed. An `Item` - is saved without any sort of length-prefixing of the key. It is, in theory, - possible for an `Item`'s key to conflict with one of the keys generated by a - `Map` or `Deque`. In practice, this is unlikely unless you use very long - prefixes or start your `Item`'s key with the null byte. Probably don't do - that! + ...yet there's a small _but_. A `Map`'s prefix is length-prefixed. An `Item` is saved without any + sort of length-prefixing of the key. It is, in theory, possible for an `Item`'s key to conflict + with one of the keys generated by a `Map` or `Deque`. In practice, this is unlikely unless you use + very long prefixes or start your `Item`'s key with the null byte. Probably don't do that! ## Values -In `cw-storage-plus`, every value is saved using JSON serialization. For that to -be possible, only types that implement -[`serde::Serialize`](https://docs.rs/serde/1.0.201/serde/trait.Serialize.html) -and -[`serde::Deserialize`](https://docs.rs/serde/1.0.201/serde/trait.Deserialize.html) -are allowed. +In `cw-storage-plus`, every value is saved using JSON serialization. For that to be possible, only +types that implement [`serde::Serialize`](https://docs.rs/serde/1.0.201/serde/trait.Serialize.html) +and [`serde::Deserialize`](https://docs.rs/serde/1.0.201/serde/trait.Deserialize.html) are allowed. -Most of the Rust standard library types already implement these traits. -Additionally, types you'll find in `cosmwasm_std` (like +Most of the Rust standard library types already implement these traits. Additionally, types you'll +find in `cosmwasm_std` (like [`Addr`](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/struct.Addr.html), [`Decimal`](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/struct.Decimal.html), -[`Binary`](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/struct.Binary.html) -or [`Coin`](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/struct.Coin.html)) -often do as well. +[`Binary`](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/struct.Binary.html) or +[`Coin`](https://docs.rs/cosmwasm-std/2.0.3/cosmwasm_std/struct.Coin.html)) often do as well. -If you're writing a custom type and wish to send it across call or put it in -storage, you'll have to derive these traits. +If you're writing a custom type and wish to send it across call or put it in storage, you'll have to +derive these traits. - *cw-storage-plus* uses - [*serde-json-wasm*](https://github.com/CosmWasm/serde-json-wasm) under the - hood. This provides determinism in some corners - - [*serde_json*](https://github.com/serde-rs/json) would not be suited for the - blockchain world! On top of that, `serde-json-wasm` is just smaller. + *cw-storage-plus* uses [*serde-json-wasm*](https://github.com/CosmWasm/serde-json-wasm) under the + hood. This provides determinism in some corners - [*serde_json*](https://github.com/serde-rs/json) + would not be suited for the blockchain world! On top of that, `serde-json-wasm` is just smaller. diff --git a/src/pages/cw-storage-plus/containers/deque.mdx b/src/pages/cw-storage-plus/containers/deque.mdx index ac281dd1..8c5d551e 100644 --- a/src/pages/cw-storage-plus/containers/deque.mdx +++ b/src/pages/cw-storage-plus/containers/deque.mdx @@ -6,57 +6,58 @@ import { Callout } from "nextra/components"; # `Deque` -A `Deque` is a container that imitates a traditional double-ended queue. It's -designed for efficient pushes and pops from either the beginning or end, making -it suitable for use as a queue or stack. However, it's not optimized for -insertions or deletions from the middle. +A `Deque` is a container that imitates a traditional double-ended queue. It's designed for efficient +pushes and pops from either the beginning or end, making it suitable for use as a queue or stack. +However, it's not optimized for insertions or deletions from the middle. More information can be found in the [API docs]. ## Deque operations -The main operations available for a `Deque` are [`push_back`], [`push_front`], -[`pop_back`], and [`pop_front`]. It is also possible to check the [`len`]gth of -the deque, [`get`] an element by index, and [`iter`]ate over the elements. - -[`push_back`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_back -[`push_front`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_front -[`pop_back`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_back -[`pop_front`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_front +The main operations available for a `Deque` are [`push_back`], [`push_front`], [`pop_back`], and +[`pop_front`]. It is also possible to check the [`len`]gth of the deque, [`get`] an element by +index, and [`iter`]ate over the elements. + +[`push_back`]: + https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_back +[`push_front`]: + https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_front +[`pop_back`]: + https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_back +[`pop_front`]: + https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_front [`len`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.len [`get`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.get [`iter`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.iter - `push_back`: Adds an element to the end of the deque. O(1) time complexity. -- `push_front`: Adds an element to the beginning of the deque. O(1) time +- `push_front`: Adds an element to the beginning of the deque. O(1) time complexity. +- `pop_back`: Removes and returns the last element. Returns `None` if the deque is empty. O(1) time complexity. -- `pop_back`: Removes and returns the last element. Returns `None` if the deque - is empty. O(1) time complexity. -- `pop_front`: Removes and returns the first element. Returns `None` if the - deque is empty. O(1) time complexity. +- `pop_front`: Removes and returns the first element. Returns `None` if the deque is empty. O(1) + time complexity. - `len`: Returns the number of elements in the deque. O(1) time complexity. -- `is_empty`: Returns `true` if the deque contains no elements. O(1) time +- `is_empty`: Returns `true` if the deque contains no elements. O(1) time complexity. +- `get`: Retrieves an element by index. Returns `None` if the index is out of bounds. O(1) time complexity. -- `get`: Retrieves an element by index. Returns `None` if the index is out of - bounds. O(1) time complexity. -- `front`: Returns a reference to the first element without removing it. Returns - `None` if the deque is empty. -- `back`: Returns a reference to the last element without removing it. Returns - `None` if the deque is empty. +- `front`: Returns a reference to the first element without removing it. Returns `None` if the deque + is empty. +- `back`: Returns a reference to the last element without removing it. Returns `None` if the deque + is empty. - `iter`: Returns an iterator over the elements of the deque. - The maximum capacity of a `Deque` is `u32::MAX - 1` elements. Attempting to - push more elements is considered Undefined Behavior. + The maximum capacity of a `Deque` is `u32::MAX - 1` elements. Attempting to push more elements is + considered Undefined Behavior. ## Deque lifecycle -Creating a `Deque` doesn't immediately commit anything to storage. To add -elements to the deque, you need to use the `push_back` or `push_front` methods. +Creating a `Deque` doesn't immediately commit anything to storage. To add elements to the deque, you +need to use the `push_back` or `push_front` methods. -Values in a `Deque` must implement the `Serialize` and `Deserialize` traits from -the [`serde`] crate to be stored. +Values in a `Deque` must implement the `Serialize` and `Deserialize` traits from the [`serde`] crate +to be stored. ### Lifecycle example @@ -139,9 +140,9 @@ assert_eq!(sum, 6); ### Maintaining a log store -It is possible to use a `Deque` to maintain a store of log events or transaction -records. This is useful when you want to keep a history of production level -events to ease in debugging a deployed instance of a contract. +It is possible to use a `Deque` to maintain a store of log events or transaction records. This is +useful when you want to keep a history of production level events to ease in debugging a deployed +instance of a contract. ```rust template="storage" use cw_storage_plus::Deque; diff --git a/src/pages/cw-storage-plus/containers/indexed-map.mdx b/src/pages/cw-storage-plus/containers/indexed-map.mdx index c9c0e256..f609c71b 100644 --- a/src/pages/cw-storage-plus/containers/indexed-map.mdx +++ b/src/pages/cw-storage-plus/containers/indexed-map.mdx @@ -6,33 +6,29 @@ import { Callout } from "nextra/components"; # IndexedMap -An -[`IndexedMap`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.IndexedMap.html) -is a map that, apart from the usual map key `K` has some secondary indexes `I` -that can be used to look up values. +An [`IndexedMap`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.IndexedMap.html) is +a map that, apart from the usual map key `K` has some secondary indexes `I` that can be used to look +up values. - There's no limit to how many indexes you can have, but be careful. Using many - indexes can increase the complexity of storage writes - with every write, the - list of indexes is iterated over since they might need to be updated. + There's no limit to how many indexes you can have, but be careful. Using many indexes can increase + the complexity of storage writes - with every write, the list of indexes is iterated over since + they might need to be updated. As always, we encourage you to explore the -[`API reference`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.IndexedMap.html) -for a full list of available methods and more rigid definitions of the types -involved. +[`API reference`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.IndexedMap.html) for +a full list of available methods and more rigid definitions of the types involved. ## Case study: User lookup -Imagine we have a list of users. Every user is uniquely identified by their -address, so it makes sense to use that as the primary key. We'll need to look up -users by their address - if Alice calls the contract, we should be able to look -up her user data by the address with which she called. +Imagine we have a list of users. Every user is uniquely identified by their address, so it makes +sense to use that as the primary key. We'll need to look up users by their address - if Alice calls +the contract, we should be able to look up her user data by the address with which she called. - Every snippet on this page builds on the previous ones. Make sure you've - understood the previous snippet before moving on to the next one, and feel - free to go back and forth as needed. + Every snippet on this page builds on the previous ones. Make sure you've understood the previous + snippet before moving on to the next one, and feel free to go back and forth as needed. This is easy to model with a normal `Map`. @@ -51,9 +47,9 @@ struct User { let _users = Map::::new("u"); ``` -Great! But what if we want to look up users by their handles? Our only real -option here is to iterate over all users and check if the handle matches. With a -big enough user base, this could be slow and expensive. +Great! But what if we want to look up users by their handles? Our only real option here is to +iterate over all users and check if the handle matches. With a big enough user base, this could be +slow and expensive. ### Setting up an `IndexedMap` with a `UniqueIndex` @@ -77,24 +73,22 @@ let _users = IndexedMap::::new("u", user_indexes); ``` - The `index_list` macro is used to define a list of indexes for a given struct. - This is a helper macro that generates an implementation of the - [`IndexList`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/trait.IndexList.html) - trait, with all the fields of the struct as indexes. + The `index_list` macro is used to define a list of indexes for a given struct. This is a helper + macro that generates an implementation of the + [`IndexList`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/trait.IndexList.html) trait, + with all the fields of the struct as indexes. Here's what happens step-by-step -- We define a struct `UserIndexes` that holds all the indexes we want to use. In - this case, we only have one index - `handle`, indexing the `handle` field. -- We construct our `UserIndexes`. Notice the `UniqueIndex` constructor takes two - parameters: - - A function pointer (here we provide an anonymous function). This function is - supposed to take the value of an entry and produce the secondary key. - Without this, the `IndexedMap` would not know how to create the index. - - A prefix. The index needs its own storage namespace. Note the index prefix - has to be distinct from the `IndexedMap` prefix (or any other prefix used - with this contract's storage). +- We define a struct `UserIndexes` that holds all the indexes we want to use. In this case, we only + have one index - `handle`, indexing the `handle` field. +- We construct our `UserIndexes`. Notice the `UniqueIndex` constructor takes two parameters: + - A function pointer (here we provide an anonymous function). This function is supposed to take + the value of an entry and produce the secondary key. Without this, the `IndexedMap` would not + know how to create the index. + - A prefix. The index needs its own storage namespace. Note the index prefix has to be distinct + from the `IndexedMap` prefix (or any other prefix used with this contract's storage). - We construct an `IndexedMap` with that list of indexes. @@ -110,20 +104,19 @@ Here's what happens step-by-step If you're using [`UniqueIndex`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.UniqueIndex.html), - it's your responsibility to ensure that the index you've built has unique - keys. If you have two users with the same handle, the index will be - overwritten and only contain the last user. Be careful! If you need to store a - key that is not unique, you'll want to use a - [`MultiIndex`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.MultiIndex.html) - - see [*Lookup by country*](#lookup-by-country). + it's your responsibility to ensure that the index you've built has unique keys. If you have two + users with the same handle, the index will be overwritten and only contain the last user. Be + careful! If you need to store a key that is not unique, you'll want to use a + [`MultiIndex`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.MultiIndex.html) - + see [*Lookup by country*](#lookup-by-country). Under the hood, the `IndexedMap` will store the data using a regular `Map` for the primary key, and then another `Map` for each secondary index. This is how efficient lookups are achieved. -Again, every update to this storage structure will have to update all the -indexes - that's the price we pay for efficient lookups. +Again, every update to this storage structure will have to update all the indexes - that's the price +we pay for efficient lookups. @@ -204,8 +197,8 @@ assert_eq!( ); ``` -We can also iterate over records using bounds based on the secondary index. -Here's how we can find all user handles starting with "a" or "b". +We can also iterate over records using bounds based on the secondary index. Here's how we can find +all user handles starting with "a" or "b". ```rust template="storage" use cw_storage_plus::{Bound, IndexedMap}; @@ -242,18 +235,16 @@ assert_eq!(found_users[1].1.handle, "bob"); Note when iterating like this, the items yielded are of type `(PK::Output, V)`, where `PK` is the primary key type of the `IndexedMap` and `V` is the value. -The `PK::Output` associated type is generally just the owned version of the `PK` -type. For example, if `PK` is `Addr`, `PK::Output` will be `Addr`. If it's a -`String` or a `&str`, `PK::Output` will be a `String`. +The `PK::Output` associated type is generally just the owned version of the `PK` type. For example, +if `PK` is `Addr`, `PK::Output` will be `Addr`. If it's a `String` or a `&str`, `PK::Output` will be +a `String`. -What's important and possibly surprising is we **don't** get back the secondary -index. Because of that, it's sadly hard to implement anything like pagination -with secondary key iteration. +What's important and possibly surprising is we **don't** get back the secondary index. Because of +that, it's sadly hard to implement anything like pagination with secondary key iteration. -If we're only interested in the addresses (primary keys in our case), we can use -the `keys` method. +If we're only interested in the addresses (primary keys in our case), we can use the `keys` method. ```rust template="storage" use cw_storage_plus::{Bound, IndexedMap}; @@ -276,9 +267,8 @@ assert_eq!(found_keys, [ ### Lookup by country -Let's say we want to look up users by their country. This time, we'll use a -`MultiIndex` instead of a `UniqueIndex`. This is because multiple users can be -from the same country. +Let's say we want to look up users by their country. This time, we'll use a `MultiIndex` instead of +a `UniqueIndex`. This is because multiple users can be from the same country. ```rust template="storage" showLineNumbers use cw_storage_plus::{index_list, IndexedMap, MultiIndex, UniqueIndex}; @@ -301,16 +291,15 @@ let _users = IndexedMap::::new("u", user_indexes); Note that the `MultiIndex` constructor (line 13) takes three parameters: -- A closure that produces the secondary key. This is similar to the - `UniqueIndex` constructor's first parameter. -- A namespace for the map. This is supposed to be the same value as the prefix - used for the `IndexedMap`. -- A prefix for the index. This is supposed to be distinct from the prefix used - for the `IndexedMap`, and is similar to the `UniqueIndex` constructor's second - parameter. +- A closure that produces the secondary key. This is similar to the `UniqueIndex` constructor's + first parameter. +- A namespace for the map. This is supposed to be the same value as the prefix used for the + `IndexedMap`. +- A prefix for the index. This is supposed to be distinct from the prefix used for the `IndexedMap`, + and is similar to the `UniqueIndex` constructor's second parameter. -Let's take advantage of the new index. We'll find all users from the USA. The -call chain is a bit different here, so hang on tight. +Let's take advantage of the new index. We'll find all users from the USA. The call chain is a bit +different here, so hang on tight. ```rust template="storage" use cw_storage_plus::{Bound, IndexedMap}; @@ -343,11 +332,10 @@ assert_eq!(us_users, [ ]); ``` -Due to technical limitations, the `MultiIndex` does not support **bounded** -iteration over the secondary key for dynamically sized types (like `Addr` or -`String`). For example, this means we can't find out all the entries for -countries starting with "U". If your secondary index is something with a fixed -size (like `u32` or `[u8; 32]`), bounds should work just fine. +Due to technical limitations, the `MultiIndex` does not support **bounded** iteration over the +secondary key for dynamically sized types (like `Addr` or `String`). For example, this means we +can't find out all the entries for countries starting with "U". If your secondary index is something +with a fixed size (like `u32` or `[u8; 32]`), bounds should work just fine. The technical reason for this is that the `MultiIndex` is implemented as a @@ -355,7 +343,7 @@ The technical reason for this is that the `MultiIndex` is implemented as a the primary key. This means it's subject to the same limitations as compound keys in general. -If you're interested in iterating over all the entries in a `MultiIndex`, you -can use the `range` method without bounds. As before, there's also the +If you're interested in iterating over all the entries in a `MultiIndex`, you can use the `range` +method without bounds. As before, there's also the [`keys`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.MultiIndex.html#method.keys) method for when values don't matter to you. diff --git a/src/pages/cw-storage-plus/containers/item.mdx b/src/pages/cw-storage-plus/containers/item.mdx index 6443b666..0a6482ec 100644 --- a/src/pages/cw-storage-plus/containers/item.mdx +++ b/src/pages/cw-storage-plus/containers/item.mdx @@ -6,33 +6,31 @@ import { Callout } from "nextra/components"; # `Item` -An `Item` is a container that contains a single value that is potentially stored -in some storage identified by a unique key. +An `Item` is a container that contains a single value that is potentially stored in some storage +identified by a unique key. More information can be found in the [API docs]. ## Item lifecycle -Just creating an `Item` does not commit anything to storage yet. In order to -actually store a value into a storage, you need to call the `save` method. +Just creating an `Item` does not commit anything to storage yet. In order to actually store a value +into a storage, you need to call the `save` method. -At the moment, values are serialized to the underlying storage in the JSON -format. Your value must implement the `Serialize` and `Deserialize` traits from -the [`serde`] crate in order to be stored. +At the moment, values are serialized to the underlying storage in the JSON format. Your value must +implement the `Serialize` and `Deserialize` traits from the [`serde`] crate in order to be stored. - This is an implementation detail that may change in the future. You should - always use the provided API methods to interact with the storage. + This is an implementation detail that may change in the future. You should always use the provided + API methods to interact with the storage. ### Loading existing values `cw-storage-plus` provides you with two functions for loading an `Item`: -- `load` - which will return an error if the `Item` is empty or if - deserialization fails. -- `may_load` - which will return `Ok(None)` if the `Item` is empty, and an error - if deserialization fails. +- `load` - which will return an error if the `Item` is empty or if deserialization fails. +- `may_load` - which will return `Ok(None)` if the `Item` is empty, and an error if deserialization + fails. ### Lifecycle example @@ -102,9 +100,8 @@ assert_eq!(cfg_storage.load(&storage).unwrap(), cfg); ### Default values -Sometimes you might like to read a value, but if it may have never been set, you -want to provide a default. This is a common pattern for counters or other -numeric values. +Sometimes you might like to read a value, but if it may have never been set, you want to provide a +default. This is a common pattern for counters or other numeric values. ```rust template="storage" use cw_storage_plus::Item; diff --git a/src/pages/cw-storage-plus/containers/map.mdx b/src/pages/cw-storage-plus/containers/map.mdx index a75a3bbe..5da04629 100644 --- a/src/pages/cw-storage-plus/containers/map.mdx +++ b/src/pages/cw-storage-plus/containers/map.mdx @@ -6,22 +6,21 @@ import { Callout } from "nextra/components"; # `Map` -A `Map` is a key-value store. Unlike the raw storage backend, the keys and -values of a map are typed. +A `Map` is a key-value store. Unlike the raw storage backend, the keys and values of a map are +typed. ## Keys The key type has to implement the -[`PrimaryKey`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/trait.PrimaryKey.html) -trait. Most commonly, the key is simply a `String` or -[`Addr`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Addr.html). -Other types include binary strings (`Vec`, `[u8; N]`, `&[u8]`), numerical -types, or even tuples, which can be used to create composite keys. +[`PrimaryKey`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/trait.PrimaryKey.html) trait. +Most commonly, the key is simply a `String` or +[`Addr`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Addr.html). Other types include +binary strings (`Vec`, `[u8; N]`, `&[u8]`), numerical types, or even tuples, which can be used +to create composite keys. - Unlike values, keys do **not** need to implement anything like - `serde::Serialize` or `serde::Deserialize`. Key encoding is handled by the - `PrimaryKey` trait. + Unlike values, keys do **not** need to implement anything like `serde::Serialize` or + `serde::Deserialize`. Key encoding is handled by the `PrimaryKey` trait. ## Values @@ -32,13 +31,12 @@ The values, as usual, are serialized as JSON and must implement the ## Operations -Similar to an [`Item`](./item), a `Map` defines methods like `load`, `save`, and -`may_load`. The difference is that `Map`'s methods take a key as an argument. +Similar to an [`Item`](./item), a `Map` defines methods like `load`, `save`, and `may_load`. The +difference is that `Map`'s methods take a key as an argument. -Most _CosmWasm_-enabled chains will enable iteration. If they do, it is possible -to iterate over the entries in a map using methods like -[`keys`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Map.html#method.keys) -or +Most _CosmWasm_-enabled chains will enable iteration. If they do, it is possible to iterate over the +entries in a map using methods like +[`keys`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Map.html#method.keys) or [`range`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Map.html#method.range). @@ -153,14 +151,13 @@ assert_eq!(alices_balances, vec![("osmo".to_string(), 200), ("uusd".to_string(), As seen here, the order of keys isn't always lexicographic. -If you need to rely on iteration order in maps with composite keys, here's how -things work: under the hood, every component of a composite key is -length-prefixed except for the last one. If you're only iterating over the last -component, you can expect things to be ordered lexicographically. For non-final -components, shorter strings will always come before longer ones. +If you need to rely on iteration order in maps with composite keys, here's how things work: under +the hood, every component of a composite key is length-prefixed except for the last one. If you're +only iterating over the last component, you can expect things to be ordered lexicographically. For +non-final components, shorter strings will always come before longer ones. -In the example, note how `"bob"` (a non-last component) comes before `"alice"`. -Also note how once we lock the first component to `"alice"`, entries are ordered -lexicographically by the second component. +In the example, note how `"bob"` (a non-last component) comes before `"alice"`. Also note how once +we lock the first component to `"alice"`, entries are ordered lexicographically by the second +component. diff --git a/src/pages/how-to-doc.md b/src/pages/how-to-doc.md index 655e07a3..9e77776a 100644 --- a/src/pages/how-to-doc.md +++ b/src/pages/how-to-doc.md @@ -9,10 +9,7 @@ The next articles will teach you the basics for writing documentation using - [MDX](/how-to-doc/mdx): general MDX syntax and how to use it in Nextra. - [Tags](/how-to-doc/tags): how to assign tags per file for extra grouping. -- [Callout](/how-to-doc/callout): how to use the Callout component for - attracting attention. -- [Tabs](/how-to-doc/tabs): a Tabs component for switching between related - content. +- [Callout](/how-to-doc/callout): how to use the Callout component for attracting attention. +- [Tabs](/how-to-doc/tabs): a Tabs component for switching between related content. -You can also check out Nextra's [official docs](https://nextra.site/docs) for -more information. +You can also check out Nextra's [official docs](https://nextra.site/docs) for more information. diff --git a/src/pages/how-to-doc/callout.mdx b/src/pages/how-to-doc/callout.mdx index 838d78e3..01470422 100644 --- a/src/pages/how-to-doc/callout.mdx +++ b/src/pages/how-to-doc/callout.mdx @@ -10,23 +10,19 @@ A built-in component provided by `nextra/components`. import { Callout } from "nextra/components"; - - A **callout** is a short piece of text intended to attract attention. - +A **callout** is a short piece of text intended to attract attention. ## Usage ### Default - **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro - Nishikado. + **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro Nishikado. ```mdx - **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro - Nishikado. + **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro Nishikado. ``` @@ -40,14 +36,10 @@ import { Callout } from "nextra/components"; ### Error - - This is a dangerous feature that can cause everything to explode. - +This is a dangerous feature that can cause everything to explode. ```mdx - - This is a dangerous feature that can cause everything to explode. - +This is a dangerous feature that can cause everything to explode. ``` ### React Component @@ -58,8 +50,7 @@ import { Callout } from "nextra/components"; const Component = () => { return ( - **Space Invaders** is a 1978 shoot 'em up arcade game developed by - Tomohiro Nishikado. + **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro Nishikado. ); }; diff --git a/src/pages/how-to-doc/mdx.mdx b/src/pages/how-to-doc/mdx.mdx index 7563dfc1..cc982c3b 100644 --- a/src/pages/how-to-doc/mdx.mdx +++ b/src/pages/how-to-doc/mdx.mdx @@ -4,12 +4,10 @@ tags: ["tutorial"] # MDX -With Nextra, all your `.md` and `.mdx` files under the pages directory will be -rendered with [MDX](https://mdxjs.com/about), it's an advanced Markdown format -with React component support. +With Nextra, all your `.md` and `.mdx` files under the pages directory will be rendered with +[MDX](https://mdxjs.com/about), it's an advanced Markdown format with React component support. -You can use import and use React components inside your Markdown files like -this: +You can use import and use React components inside your Markdown files like this: ```mdx filename="example.mdx" import { Callout } from "nextra/components"; @@ -17,10 +15,9 @@ import { Callout } from "nextra/components"; **Markdown With React Components** - **MDX** (the library), at its core, transforms MDX (the syntax) to JSX. It - receives an MDX string and outputs a _JSX string_. It does this by parsing the - MDX document to a syntax tree and then generates a JSX document from that - tree. + **MDX** (the library), at its core, transforms MDX (the syntax) to JSX. It receives an MDX string + and outputs a _JSX string_. It does this by parsing the MDX document to a syntax tree and then + generates a JSX document from that tree. ``` @@ -130,15 +127,15 @@ You can use \`content\` to wrap inline code content like: `let x = 1`. ## Blockquote -> Where some people measure progress in answers-right per test or tests-passed -> per year, we are more interested in Sistine-Chapel-Ceilings per Lifetime. +> Where some people measure progress in answers-right per test or tests-passed per year, we are more +> interested in Sistine-Chapel-Ceilings per Lifetime. > > — Alan Kay, A Personal Computer for Children of All Ages Nested quotes: -> > Where some people measure progress in answers-right per test or tests-passed -> > per year, we are more interested in Sistine-Chapel-Ceilings per Lifetime. +> > Where some people measure progress in answers-right per test or tests-passed per year, we are +> > more interested in Sistine-Chapel-Ceilings per Lifetime. > > > > — Alan Kay, A Personal Computer for Children of All Ages > @@ -164,6 +161,4 @@ React components and Markdown can be **mixed together**, for instance: Renders: -> -> Give [**Nextra**](https://github.com/shuding/nextra) a star! -> +> Give [**Nextra**](https://github.com/shuding/nextra) a star! diff --git a/src/pages/how-to-doc/tags.mdx b/src/pages/how-to-doc/tags.mdx index ef195351..cd4123cd 100644 --- a/src/pages/how-to-doc/tags.mdx +++ b/src/pages/how-to-doc/tags.mdx @@ -4,8 +4,7 @@ tags: ["tutorial", "component"] # Tags -A [front matter](https://github.com/jxson/front-matter) attribute allows us to -define tags per file. +A [front matter](https://github.com/jxson/front-matter) attribute allows us to define tags per file. ## Example @@ -15,8 +14,8 @@ import TagPills from "@/components/TagPills"; ## Usage -You can use any valid front matter format for the tags attribute, but please -follow these conventions for consistency: +You can use any valid front matter format for the tags attribute, but please follow these +conventions for consistency: import { Tabs } from "nextra/components"; diff --git a/src/pages/ibc.mdx b/src/pages/ibc.mdx index 7704c55a..110afd29 100644 --- a/src/pages/ibc.mdx +++ b/src/pages/ibc.mdx @@ -4,14 +4,13 @@ tags: ["ibc"] # Introduction -IBC is a protocol that allows different blockchains to communicate with each -other. It is a standard that defines how blockchains can send and receive -messages to each other. This allows for the creation of a network of blockchains -that can interact with each other. +IBC is a protocol that allows different blockchains to communicate with each other. It is a standard +that defines how blockchains can send and receive messages to each other. This allows for the +creation of a network of blockchains that can interact with each other. -You can use the IBC protocol as a building block to create your own custom -protocols on top of it, but you can also use existing protocols like the [ICS-20 -token transfer protocol]. In the following sections, we will explain how both of -these work. +You can use the IBC protocol as a building block to create your own custom protocols on top of it, +but you can also use existing protocols like the [ICS-20 token transfer protocol]. In the following sections, +we will explain how both of these work. -[ICS-20 token transfer protocol]: https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md +[ICS-20 token transfer protocol]: + https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md diff --git a/src/pages/ibc/basic-concepts.mdx b/src/pages/ibc/basic-concepts.mdx index ea8cfb37..b640fb5e 100644 --- a/src/pages/ibc/basic-concepts.mdx +++ b/src/pages/ibc/basic-concepts.mdx @@ -4,25 +4,21 @@ tags: ["ibc"] ## Basic Concepts -In order to understand how IBC works, it is important to understand some basic -concepts: +In order to understand how IBC works, it is important to understand some basic concepts: -- **Port**: An identifier that corresponds to a single module on a chain. One - module can have multiple ports. Each contract has its own unique port. -- **Channel**: A connection between two ports on different blockchains that - allows them to send packets to each other. Each port can have multiple - channels. -- **Relayer**: A service that is responsible for passing packets between - blockchains. The relayer watches for new packet commitments on one chain and - submits them to the other chain. This is the way in which your packets - actually reach the other chain. Anyone can run a relayer. -- **Packet**: A piece of binary data that is sent through a channel. It can time - out if it is not delivered within a certain time frame. +- **Port**: An identifier that corresponds to a single module on a chain. One module can have + multiple ports. Each contract has its own unique port. +- **Channel**: A connection between two ports on different blockchains that allows them to send + packets to each other. Each port can have multiple channels. +- **Relayer**: A service that is responsible for passing packets between blockchains. The relayer + watches for new packet commitments on one chain and submits them to the other chain. This is the + way in which your packets actually reach the other chain. Anyone can run a relayer. +- **Packet**: A piece of binary data that is sent through a channel. It can time out if it is not + delivered within a certain time frame. -We will go into more detail on how these concepts are related to CosmWasm in the -later sections, but this should give you some basic terminology to start with. -If you want to learn more about IBC, you can read the [IBC specification] or -check out the [IBC documentation]. +We will go into more detail on how these concepts are related to CosmWasm in the later sections, but +this should give you some basic terminology to start with. If you want to learn more about IBC, you +can read the [IBC specification] or check out the [IBC documentation]. [IBC specification]: https://github.com/cosmos/ibc [IBC documentation]: https://ibc.cosmos.network/main diff --git a/src/pages/ibc/diy-protocol.mdx b/src/pages/ibc/diy-protocol.mdx index 3e8a3cb2..ccae3f12 100644 --- a/src/pages/ibc/diy-protocol.mdx +++ b/src/pages/ibc/diy-protocol.mdx @@ -4,15 +4,13 @@ tags: ["ibc", "entrypoints"] # Build your own protocol -In the following sections, we will guide you through the process of building -your own IBC protocol. We will cover how to establish a channel between two -chains, send and receive packets and how to handle timeouts and -acknowledgements. +In the following sections, we will guide you through the process of building your own IBC protocol. +We will cover how to establish a channel between two chains, send and receive packets and how to +handle timeouts and acknowledgements. ## Entrypoints -To get an IBC-enabled contract, you need to implement a few IBC-specific -entrypoints. +To get an IBC-enabled contract, you need to implement a few IBC-specific entrypoints. Three for the channel lifecycle: @@ -76,7 +74,6 @@ pub fn ibc_packet_timeout( } ``` -We will explain what these are for in the next sections, but it is important to -understand that you need to implement **all** of these entrypoints to get a -working IBC contract. You can always return errors in some of them if that makes -sense for your protocol, but you need to have them all. +We will explain what these are for in the next sections, but it is important to understand that you +need to implement **all** of these entrypoints to get a working IBC contract. You can always return +errors in some of them if that makes sense for your protocol, but you need to have them all. diff --git a/src/pages/ibc/diy-protocol/channel-lifecycle.mdx b/src/pages/ibc/diy-protocol/channel-lifecycle.mdx index 1a2614ff..79d12147 100644 --- a/src/pages/ibc/diy-protocol/channel-lifecycle.mdx +++ b/src/pages/ibc/diy-protocol/channel-lifecycle.mdx @@ -6,55 +6,54 @@ import { Callout, Tabs } from "nextra/components"; # Channel lifecycle -A channel is a connection between two IBC ports that allows them to send packets -to each other. In this section, we will cover how to establish a channel and how -to close it. Since a channel is a connection between two ports, it can connect -two chain modules, two contracts, or a module and a contract. +A channel is a connection between two IBC ports that allows them to send packets to each other. In +this section, we will cover how to establish a channel and how to close it. Since a channel is a +connection between two ports, it can connect two chain modules, two contracts, or a module and a +contract. - For the sake of readability, we will assume that both ends of the channel are - *contracts* in the following explanation. For more general information about - the channel lifecycle, see the [ICS 004 specification] or [IBC channel docs]. + For the sake of readability, we will assume that both ends of the channel are *contracts* in the + following explanation. For more general information about the channel lifecycle, see the [ICS 004 + specification] or [IBC channel docs]. -Each channel also has an order that can be either `Ordered` or `Unordered`. This -is encoded in the [`IbcOrder`] enum. In an ordered channel, packets must be -processed by the receiving chain in the order in which they were sent. In an -unordered channel, packets are processed in the order they arrive. +Each channel also has an order that can be either `Ordered` or `Unordered`. This is encoded in the +[`IbcOrder`] enum. In an ordered channel, packets must be processed by the receiving chain in the +order in which they were sent. In an unordered channel, packets are processed in the order they +arrive. [`IbcOrder`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcOrder.html -[ICS 004 specification]: https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management +[ICS 004 specification]: + https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management [IBC channel docs]: https://ibc.cosmos.network/main/ibc/overview#channels ## Establishing a channel -To send packets between two chains, you need to establish a channel between -them. This process involves two calls per chain. Once the channel is -established, you can start sending packets through it, which we will cover in -the next section. To initiate the channel creation, you can use a relayer binary -such as [hermes] to perform the handshake between the two endpoints. Returning -an error from one of the calls will cause the channel handshake to fail. +To send packets between two chains, you need to establish a channel between them. This process +involves two calls per chain. Once the channel is established, you can start sending packets through +it, which we will cover in the next section. To initiate the channel creation, you can use a relayer +binary such as [hermes] to perform the handshake between the two endpoints. Returning an error from +one of the calls will cause the channel handshake to fail. -In the following, we will refer to the two chains we want to connect as chain A -and B. The handshake starts on chain A. +In the following, we will refer to the two chains we want to connect as chain A and B. The handshake +starts on chain A. -We will take a closer look at the handshake process, but here is a brief summary -of the steps: +We will take a closer look at the handshake process, but here is a brief summary of the steps: 1. `ibc_channel_open` on chain A with `IbcChannelOpenMsg::OpenInit` 2. `ibc_channel_open` on chain B with `IbcChannelOpenMsg::OpenTry` 3. `ibc_channel_connect` on chain A with `IbcChannelConnectMsg::OpenAck` 4. `ibc_channel_connect` on chain B with `IbcChannelConnectMsg::OpenConfirm` -[hermes]: https://hermes.informal.systems/tutorials/local-chains/add-a-new-relay-path.html#3-channel-identifiers +[hermes]: + https://hermes.informal.systems/tutorials/local-chains/add-a-new-relay-path.html#3-channel-identifiers ### Channel open -When the channel creation is started by the relayer, the first call to the -contract is made on chain A. This call is made to the `ibc_channel_open` -entrypoint with the `IbcChannelOpenMsg::OpenInit` variant. Then the same -entrypoint is called on chain B with the `IbcChannelOpenMsg::OpenTry` variant. -See the following example and the [`IbcChannelOpenMsg`] documentation. +When the channel creation is started by the relayer, the first call to the contract is made on chain +A. This call is made to the `ibc_channel_open` entrypoint with the `IbcChannelOpenMsg::OpenInit` +variant. Then the same entrypoint is called on chain B with the `IbcChannelOpenMsg::OpenTry` +variant. See the following example and the [`IbcChannelOpenMsg`] documentation. @@ -180,34 +179,29 @@ const IBC_APP_VERSION: &str = "my-protocol-v1"; -In the example above, we return the same version we expect from the -counterparty, but you can return a different version if the counterparty accepts -it. The version is used to ensure that both chains are running the protocol that -the other one expects. You can also return `None` if you just want to accept the -counterparty version. +In the example above, we return the same version we expect from the counterparty, but you can return +a different version if the counterparty accepts it. The version is used to ensure that both chains +are running the protocol that the other one expects. You can also return `None` if you just want to +accept the counterparty version. [`IbcChannelOpenMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcChannelOpenMsg.html #### Permissions -Opening a channel is generally a permissionless process, so make sure to keep -that in mind when implementing the entrypoints. In the examples above, we only -allow a single channel per contract instance and always make sure not to -overwrite an existing channel. Note that we already save the channel in -`ibc_channel_open`. This causes overlapping channel openings to fail the channel -handshake. The drawback is that the contract can only connect to that one -channel, so if the handshake fails, the contract cannot connect to another -channel. - -You can add additional checks to ensure that the channel is connecting to the -correct counterparty or use a map to keep track of multiple channels connecting -to different counterparties. - -You can also be more restrictive and only allow the contract itself to initiate -the channel creation handshake. This can be done by adding a state item to the -contract that is only set to true before the contract sends the message to -initiate the handshake and immediately set to false in the `ibc_channel_open` -entrypoint. +Opening a channel is generally a permissionless process, so make sure to keep that in mind when +implementing the entrypoints. In the examples above, we only allow a single channel per contract +instance and always make sure not to overwrite an existing channel. Note that we already save the +channel in `ibc_channel_open`. This causes overlapping channel openings to fail the channel +handshake. The drawback is that the contract can only connect to that one channel, so if the +handshake fails, the contract cannot connect to another channel. + +You can add additional checks to ensure that the channel is connecting to the correct counterparty +or use a map to keep track of multiple channels connecting to different counterparties. + +You can also be more restrictive and only allow the contract itself to initiate the channel creation +handshake. This can be done by adding a state item to the contract that is only set to true before +the contract sends the message to initiate the handshake and immediately set to false in the +`ibc_channel_open` entrypoint.
Advanced example: Contract initiating the handshake on its own @@ -312,19 +306,17 @@ pub const ALLOW_CHANNEL_OPENING: Item = Item::new("allow_opening"); const IBC_APP_VERSION: &str = "my-protocol-v1"; ``` -As you can see, the contract itself sends the message to initialize the channel -handshake in this example. Please note that the rest of the handshake still -needs to be done by a relayer. +As you can see, the contract itself sends the message to initialize the channel handshake in this +example. Please note that the rest of the handshake still needs to be done by a relayer.
### Channel connect -After the `OpenTry` variant is called on chain B, the relayer calls the -`ibc_channel_connect` entrypoint, first with the `IbcChannelConnectMsg::OpenAck` -variant on chain A, then the `IbcChannelConnectMsg::OpenConfirm` variant on -chain B. The full data this entrypoint receives can be seen in the -[`IbcChannelConnectMsg`] documentation. Here is more example code: +After the `OpenTry` variant is called on chain B, the relayer calls the `ibc_channel_connect` +entrypoint, first with the `IbcChannelConnectMsg::OpenAck` variant on chain A, then the +`IbcChannelConnectMsg::OpenConfirm` variant on chain B. The full data this entrypoint receives can +be seen in the [`IbcChannelConnectMsg`] documentation. Here is more example code: @@ -414,16 +406,16 @@ const CHANNEL: Item = Item::new(0); -[`IbcChannelConnectMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcChannelConnectMsg.html +[`IbcChannelConnectMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcChannelConnectMsg.html ## Closing a channel -Similarly to opening a channel, closing a channel involves a handshake process. -However, this time the process only involves one call per chain. The relayer -initiates the process by calling the `ibc_channel_close` entrypoint with the -`IbcChannelCloseMsg::CloseInit` variant on chain A, followed by the same -entrypoint with the `IbcChannelCloseMsg::CloseConfirm` on chain B. The full data -can be seen in the [`IbcChannelCloseMsg`] documentation. Here is an example: +Similarly to opening a channel, closing a channel involves a handshake process. However, this time +the process only involves one call per chain. The relayer initiates the process by calling the +`ibc_channel_close` entrypoint with the `IbcChannelCloseMsg::CloseInit` variant on chain A, followed +by the same entrypoint with the `IbcChannelCloseMsg::CloseConfirm` on chain B. The full data can be +seen in the [`IbcChannelCloseMsg`] documentation. Here is an example: ```rust filename="ibc.rs" template="core" #[cfg_attr(not(feature = "library"), entry_point)] @@ -437,14 +429,13 @@ pub fn ibc_channel_close( ``` - While closing channels is something that is possible in IBC, you should think - carefully about whether you want to allow it in your protocol. In many cases, - it might be better to keep the channel open and return an error when someone - tries to close it. + While closing channels is something that is possible in IBC, you should think carefully about + whether you want to allow it in your protocol. In many cases, it might be better to keep the + channel open and return an error when someone tries to close it. -In this entrypoint, you can handle the closing process as you see fit. This can -involve cleaning up any storage related to the channel or simply returning an -error to prevent the channel from closing. +In this entrypoint, you can handle the closing process as you see fit. This can involve cleaning up +any storage related to the channel or simply returning an error to prevent the channel from closing. -[`IbcChannelCloseMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcChannelCloseMsg.html +[`IbcChannelCloseMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcChannelCloseMsg.html diff --git a/src/pages/ibc/diy-protocol/packet-lifecycle.mdx b/src/pages/ibc/diy-protocol/packet-lifecycle.mdx index a7a0a9be..544b4a35 100644 --- a/src/pages/ibc/diy-protocol/packet-lifecycle.mdx +++ b/src/pages/ibc/diy-protocol/packet-lifecycle.mdx @@ -6,33 +6,28 @@ import { Callout, Tabs } from "nextra/components"; # Packet lifecycle -In this section, we will cover the lifecycle of a packet in the IBC protocol. -Sending and receiving packets is the core functionality of IBC, and it is -important to understand how packets are processed and what implications this has -for your protocol. +In this section, we will cover the lifecycle of a packet in the IBC protocol. Sending and receiving +packets is the core functionality of IBC, and it is important to understand how packets are +processed and what implications this has for your protocol. -There are two flows that a packet can take during its lifecycle. Both start with -a packet being sent on chain A. The first flow is the successful delivery of the -packet to chain B: +There are two flows that a packet can take during its lifecycle. Both start with a packet being sent +on chain A. The first flow is the successful delivery of the packet to chain B: 1. **Sending a packet**: A packet is sent from chain A through a channel. 2. **Receiving a packet**: The packet is received and acknowledged by chain B. 3. **Receiving a packet acknowledgement**: Chain A receives the acknowledgement. -The second flow is when the packet is not relayed to chain B within the -specified time frame: +The second flow is when the packet is not relayed to chain B within the specified time frame: 1. **Sending a packet**: A packet is sent from chain A through a channel. -2. **Receiving a packet timeout**: The packet is not received within the - specified time frame. +2. **Receiving a packet timeout**: The packet is not received within the specified time frame. A visual representation of these flows can be found in the [IBC specification](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#packet-flow--handling). ## Sending a packet -In order to send a packet, you need to send the `IbcMsg::SendPacket` message. It -looks like this: +In order to send a packet, you need to send the `IbcMsg::SendPacket` message. It looks like this: @@ -90,12 +85,12 @@ The `channel_id` is the identifier of the channel you want to use for the packet. This must be a channel that was previously established, as described in the [previous section], so you probably want to load this from contract state. -The `data` field is of type `Binary` and contains the actual packet data. This -is the information that you want to send to chain B. +The `data` field is of type `Binary` and contains the actual packet data. This is the information +that you want to send to chain B. -The `timeout` field can either be a timestamp or a block height, as measured on -the destination chain. It is used to prevent the packet from being stuck in -limbo if the destination chain does not receive it. +The `timeout` field can either be a timestamp or a block height, as measured on the destination +chain. It is used to prevent the packet from being stuck in limbo if the destination chain does not +receive it. [previous section]: ./channel-lifecycle @@ -126,40 +121,35 @@ enum PacketMsg { } ``` -As you can see, this looks quite similar to the [`execute`] entrypoint. The main -difference is that you need to parse the packet data yourself, because it is not -necessarily in JSON format. What is also different, is the return type. Instead -of returning a `Response`, you need to return an [`IbcReceiveResponse`] with an -optional acknowledgement (see [next section](#async-acknowledgement) for more -details about not providing an acknowledgement). +As you can see, this looks quite similar to the [`execute`] entrypoint. The main difference is that +you need to parse the packet data yourself, because it is not necessarily in JSON format. What is +also different, is the return type. Instead of returning a `Response`, you need to return an +[`IbcReceiveResponse`] with an optional acknowledgement (see [next section](#async-acknowledgement) +for more details about not providing an acknowledgement). -In this example, we used the [`StdAck`] type for our acknowledgement. It encodes -the acknowledgement as a JSON object which can either be -`{"result":"BASE64 OF DATA"}` in the success case, or `{"error":"error string"}` -in the error case. This is the same format that is used in some existing IBC -protocols, like e.g. [ICS-20]. However, using this format is not a requirement. -You can use any type you like, as long as it can be converted to `Binary`. +In this example, we used the [`StdAck`] type for our acknowledgement. It encodes the acknowledgement +as a JSON object which can either be `{"result":"BASE64 OF DATA"}` in the success case, or +`{"error":"error string"}` in the error case. This is the same format that is used in some existing +IBC protocols, like e.g. [ICS-20]. However, using this format is not a requirement. You can use any +type you like, as long as it can be converted to `Binary`. ### Error handling -Using a different acknowledgement format comes with a caveat, though: The error -handling for `ibc_packet_receive` works differently than for other entrypoints. +Using a different acknowledgement format comes with a caveat, though: The error handling for +`ibc_packet_receive` works differently than for other entrypoints. -If you return an error from `ibc_packet_receive`, it will revert your contract -state changes, but will not fail the transaction. Instead, it will cause an -`StdAck::error` acknowledgement to be written. So, if you want to return errors -in `ibc_packet_receive`, you might want to also use the [`StdAck`] type for your -successful acknowledgements to keep the format consistent for the sender. +If you return an error from `ibc_packet_receive`, it will revert your contract state changes, but +will not fail the transaction. Instead, it will cause an `StdAck::error` acknowledgement to be +written. So, if you want to return errors in `ibc_packet_receive`, you might want to also use the +[`StdAck`] type for your successful acknowledgements to keep the format consistent for the sender. -Alternatively, you can also handle all errors within the `ibc_packet_receive` -entrypoint, always returning an `Ok(...)` result. In that case, **state changes -will be committed**, the transaction will succeed and you can use whatever -acknowledgement format you prefer. +Alternatively, you can also handle all errors within the `ibc_packet_receive` entrypoint, always +returning an `Ok(...)` result. In that case, **state changes will be committed**, the transaction +will succeed and you can use whatever acknowledgement format you prefer. -Panicking in `ibc_packet_receive` works the same as in other entrypoints: it -will revert all state changes and **fail** the transaction. One use case for -this is implementing a relayer allowlist because the failed receive can then be -picked up by another relayer. +Panicking in `ibc_packet_receive` works the same as in other entrypoints: it will revert all state +changes and **fail** the transaction. One use case for this is implementing a relayer allowlist +because the failed receive can then be picked up by another relayer. [`IbcReceiveResponse`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html [`execute`]: ../../core/entrypoints/execute @@ -169,23 +159,19 @@ picked up by another relayer. ### Async acknowledgement - This feature is currently under development and will be available in a future - version of CosmWasm. + This feature is currently under development and will be available in a future version of CosmWasm. -In some cases, you might want to acknowledge a packet asynchronously. This means -that you receive the packet, but you don't immediately return an -acknowledgement. One case where this is useful is if you need to perform some -other action that requires more than one transaction to complete before you can -acknowledge. To do that, you can return a `IbcReceiveResponse::without_ack()` -response, save the destination channel ID and packet sequence in contract state, -and then acknowledge the packet later using the `IbcMsg::WriteAcknowledgement` -message. +In some cases, you might want to acknowledge a packet asynchronously. This means that you receive +the packet, but you don't immediately return an acknowledgement. One case where this is useful is if +you need to perform some other action that requires more than one transaction to complete before you +can acknowledge. To do that, you can return a `IbcReceiveResponse::without_ack()` response, save the +destination channel ID and packet sequence in contract state, and then acknowledge the packet later +using the `IbcMsg::WriteAcknowledgement` message. - It is your responsibility to ensure that a received packet is always - acknowledged at some point. Not acknowledging can lead to problems for the - sender of the packet. + It is your responsibility to ensure that a received packet is always acknowledged at some point. + Not acknowledging can lead to problems for the sender of the packet. ```rust filename="ibc.rs" template="core" @@ -234,9 +220,9 @@ const ACK_LATER: Map<&(u64, String), String> = Map::new("ack_later"); ## Receiving a packet acknowledgement -After the packet has been received and acknowledged by chain B, the relayer will -pass the acknowledgement back to chain A, resulting in the `ibc_packet_ack` -entrypoint being called. This is where you can handle the acknowledgement: +After the packet has been received and acknowledged by chain B, the relayer will pass the +acknowledgement back to chain A, resulting in the `ibc_packet_ack` entrypoint being called. This is +where you can handle the acknowledgement: ```rust filename="ibc.rs" template="core" #[cfg_attr(not(feature = "library"), entry_point)] @@ -254,26 +240,23 @@ pub fn ibc_packet_ack( } ``` -The [`IbcPacketAckMsg`] struct contains the acknowledgement and original packet -data, as well as the address of the relayer that sent the acknowledgement. +The [`IbcPacketAckMsg`] struct contains the acknowledgement and original packet data, as well as the +address of the relayer that sent the acknowledgement. -When this entrypoint is called, it means that the packet has been successfully -delivered to chain B and has been processed by the counterparty. This is the -happy path of the packet lifecycle. +When this entrypoint is called, it means that the packet has been successfully delivered to chain B +and has been processed by the counterparty. This is the happy path of the packet lifecycle. [`IbcPacketAckMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcPacketAckMsg.html ## Receiving a packet timeout -If the packet is not relayed to chain B within the specified time frame (e.g. -because the chain is stopped or no relayer is picking the packet up), a relayer -can call the `ibc_packet_timeout` entrypoint with a [`IbcPacketTimeoutMsg`]. -This is where you can handle the timeout. +If the packet is not relayed to chain B within the specified time frame (e.g. because the chain is +stopped or no relayer is picking the packet up), a relayer can call the `ibc_packet_timeout` +entrypoint with a [`IbcPacketTimeoutMsg`]. This is where you can handle the timeout. - Please note that a timeout happening on an ordered channel automatically - closes the channel, since after a timeout the order of packets can no longer - be guaranteed. + Please note that a timeout happening on an ordered channel automatically closes the channel, since + after a timeout the order of packets can no longer be guaranteed. ```rust filename="ibc.rs" template="core" @@ -287,40 +270,37 @@ pub fn ibc_packet_timeout( } ``` -When this entrypoint is called, it means that the packet has not been delivered -until the timeout specified when sending the packet. This is the unhappy path of -the packet lifecycle. +When this entrypoint is called, it means that the packet has not been delivered until the timeout +specified when sending the packet. This is the unhappy path of the packet lifecycle. -Note that the timeout is based on when the packet is _received_ on chain B, -_not_ on when it is _acknowledged_. This means that a packet that is received, -but not acknowledged will **not** trigger a timeout. +Note that the timeout is based on when the packet is _received_ on chain B, _not_ on when it is +_acknowledged_. This means that a packet that is received, but not acknowledged will **not** trigger +a timeout. -[`IbcPacketTimeoutMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcPacketTimeoutMsg.html +[`IbcPacketTimeoutMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcPacketTimeoutMsg.html ## State rewinding -As you can see, IBC is inherently non-atomic. In a single atomic transaction, -you can do all the changes you want and later return an error, which reverts the -whole transaction. In IBC, you send a packet in one transaction and receive the -acknowledgement or timeout in another transaction. This means that you have to -take care of undoing the changes yourself. This includes any state changes you -made when sending the packet, as well as any funds sent to you. You also need to -make sure that when you send the packet, you don't do anything that shouldn't -happen until the packet is acknowledged (like sending funds to someone else). +As you can see, IBC is inherently non-atomic. In a single atomic transaction, you can do all the +changes you want and later return an error, which reverts the whole transaction. In IBC, you send a +packet in one transaction and receive the acknowledgement or timeout in another transaction. This +means that you have to take care of undoing the changes yourself. This includes any state changes +you made when sending the packet, as well as any funds sent to you. You also need to make sure that +when you send the packet, you don't do anything that shouldn't happen until the packet is +acknowledged (like sending funds to someone else). For state changes there are two main strategies: -- **Temporary state**: You can save the state changes you want to make in a - special temporary storage container. If the packet is acknowledged, you can - move them to the main storage to finalize them. If the packet times out, you - can discard them. -- **Undoing state changes**: You can do the state changes when sending the - packet and later undo them if the packet times out. It is important to make - sure that you can actually undo the changes you made and that you cannot get - into an inconsistent state by doing this. For example, if you give tokens to - someone in exchange for sending an IBC packet, you must lock those tokens - until the packet is acknowledged. Otherwise, the user could spend them before - the packet is acknowledged and you would not be able to undo the transfer. - -You can mix and match these strategies as needed, but be especially careful with -the second one. It is easy to make logical errors that can lead to problems. +- **Temporary state**: You can save the state changes you want to make in a special temporary + storage container. If the packet is acknowledged, you can move them to the main storage to + finalize them. If the packet times out, you can discard them. +- **Undoing state changes**: You can do the state changes when sending the packet and later undo + them if the packet times out. It is important to make sure that you can actually undo the changes + you made and that you cannot get into an inconsistent state by doing this. For example, if you + give tokens to someone in exchange for sending an IBC packet, you must lock those tokens until the + packet is acknowledged. Otherwise, the user could spend them before the packet is acknowledged and + you would not be able to undo the transfer. + +You can mix and match these strategies as needed, but be especially careful with the second one. It +is easy to make logical errors that can lead to problems. diff --git a/src/pages/ibc/existing-protocols.mdx b/src/pages/ibc/existing-protocols.mdx index 1d182270..7ab8ef89 100644 --- a/src/pages/ibc/existing-protocols.mdx +++ b/src/pages/ibc/existing-protocols.mdx @@ -6,24 +6,23 @@ import { Callout, Tabs } from "nextra/components"; # Using existing protocols -The easiest way to use IBC is to use an already existing protocol. These -protocols can either be implemented by the chain itself or by another contract. +The easiest way to use IBC is to use an already existing protocol. These protocols can either be +implemented by the chain itself or by another contract. -One example for the former is the `IbcMsg::Transfer` message, which causes an -[ICS20] transfer. This message is included in the CosmWasm standard library. It -causes the chain's IBC transfer module to send tokens to another chain. +One example for the former is the `IbcMsg::Transfer` message, which causes an [ICS20] transfer. This +message is included in the CosmWasm standard library. It causes the chain's IBC transfer module to +send tokens to another chain. -An example for the latter is the [Nois protocol]. It provides a proxy contract -that handles all the IBC logic for you. We will later cover how to implement -your own IBC protocol. +An example for the latter is the [Nois protocol]. It provides a proxy contract that handles all the IBC +logic for you. We will later cover how to implement your own IBC protocol. [ICS20]: https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md [Nois protocol]: https://docs.nois.network/dapp_devs/use_nois_randomness.html ## Example: `IbcMsg::Transfer` -To initiate an ICS20 transfer, you need to attach an `IbcMsg::Transfer` message -to your contract response like this: +To initiate an ICS20 transfer, you need to attach an `IbcMsg::Transfer` message to your contract +response like this: ```rust template="execute" // construct the transfer message @@ -39,42 +38,39 @@ let msg = IbcMsg::Transfer { Ok(Response::new().add_message(msg)) ``` -Sending this message causes an IBC transfer of the given `amount` from your -contract to the destination chain at the other end of the given channel. +Sending this message causes an IBC transfer of the given `amount` from your contract to the +destination chain at the other end of the given channel. -The `channel_id` is the identifier of the channel you want to use for the -transfer. Which channel that should be depends on the source and destination -chain. You can find out the correct channel ID using a -[block explorer](https://www.mintscan.io/cosmos/relayers). +The `channel_id` is the identifier of the channel you want to use for the transfer. Which channel +that should be depends on the source and destination chain. You can find out the correct channel ID +using a [block explorer](https://www.mintscan.io/cosmos/relayers). -The `to_address` is the address on the _destination chain_ that should receive -the tokens. +The `to_address` is the address on the _destination chain_ that should receive the tokens. -The `amount` is the number and denomination of tokens to send. On the -destination chain, the same amount will be received, but the denomination will -be of the form `ibc/HASH`, where `HASH` is a SHA256 hash uniquely identifying -the channel and the source chain denomination. To learn more about this, take a -look at the [Cosmos Developer Portal]. +The `amount` is the number and denomination of tokens to send. On the destination chain, the same +amount will be received, but the denomination will be of the form `ibc/HASH`, where `HASH` is a +SHA256 hash uniquely identifying the channel and the source chain denomination. To learn more about +this, take a look at the [Cosmos Developer Portal]. -The `timeout` can either be a timestamp or a block height, as measured on the -destination chain. It is used to prevent the transfer from being stuck in limbo -if the destination chain does not receive the packet. +The `timeout` can either be a timestamp or a block height, as measured on the destination chain. It +is used to prevent the transfer from being stuck in limbo if the destination chain does not receive +the packet. -The `memo` is an optional field that can be used to attach a message to the -transfer. It is often used for additional functionality like -[packet-forward-middleware] or IBC Callbacks. +The `memo` is an optional field that can be used to attach a message to the transfer. It is often +used for additional functionality like [packet-forward-middleware] or IBC Callbacks. -[packet-forward-middleware]: https://github.com/cosmos/ibc-apps/tree/main/middleware/packet-forward-middleware -[Cosmos Developer Portal]: https://tutorials.cosmos.network/tutorials/6-ibc-dev/#understand-ibc-denoms +[packet-forward-middleware]: + https://github.com/cosmos/ibc-apps/tree/main/middleware/packet-forward-middleware +[Cosmos Developer Portal]: + https://tutorials.cosmos.network/tutorials/6-ibc-dev/#understand-ibc-denoms ## ADR-8: IBC Callbacks -When you send an ICS20 transfer as described above, you do not get any feedback -on whether the transfer was successful or not and the destination does not get -informed of its newfound wealth. To solve this problem, the [ADR-8 -specification][adr-8] was created. On the source chain, it provides callbacks -when an IBC packet was acknowledged or timed out. On the destination chain, it -triggers callbacks when a packet is received. +When you send an ICS20 transfer as described above, you do not get any feedback on whether the +transfer was successful or not and the destination does not get informed of its newfound wealth. To +solve this problem, the [ADR-8 specification][adr-8] was created. On the source chain, it provides +callbacks when an IBC packet was acknowledged or timed out. On the destination chain, it triggers +callbacks when a packet is received. IBC Callbacks is a generalized successor of [IBC Hooks][ibc-hooks]. @@ -82,28 +78,26 @@ IBC Callbacks is a generalized successor of [IBC Hooks][ibc-hooks]. [ibc-hooks]: https://github.com/cosmos/ibc-apps/blob/main/modules/ibc-hooks/README.md - To receive callbacks, the chain needs to support IBC Callbacks for the message - type. + To receive callbacks, the chain needs to support IBC Callbacks for the message type. ### Enabling IBC Callbacks for a message -You need to explicitly opt-in to IBC Callbacks for each message. In order to do -this, you need to add some metadata to the message, including who should receive -the callbacks. +You need to explicitly opt-in to IBC Callbacks for each message. In order to do this, you need to +add some metadata to the message, including who should receive the callbacks. - The exact data format and how to add it to the message can vary, but for the - `IbcMsg::Transfer` message, this data is in JSON format and needs to be added - to the `memo` field. + The exact data format and how to add it to the message can vary, but for the `IbcMsg::Transfer` + message, this data is in JSON format and needs to be added to the `memo` field. -To make this as easy as possible, we provide two ways to generate the correct -JSON. One is a builder type for the `IbcMsg::Transfer` type which provides a -type-safe way to generate the complete `IbcMsg::Transfer`, the other is a helper -type [`IbcCallbackRequest`] that just generates the JSON for the `memo` field: +To make this as easy as possible, we provide two ways to generate the correct JSON. One is a builder +type for the `IbcMsg::Transfer` type which provides a type-safe way to generate the complete +`IbcMsg::Transfer`, the other is a helper type [`IbcCallbackRequest`] that just generates the JSON +for the `memo` field: -[`IbcCallbackRequest`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcCallbackRequest.html +[`IbcCallbackRequest`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcCallbackRequest.html @@ -154,43 +148,43 @@ Ok(Response::new().add_message(msg)) -As you can see, you can request callbacks for both the source and destination -chain. However, you can also request callbacks for only one of them. For this, -you need to provide the address that should receive the callback and you can -optionally set a gas limit for the callback execution. Please take a look at the -`IbcCallbackRequest` docs for more information. +As you can see, you can request callbacks for both the source and destination chain. However, you +can also request callbacks for only one of them. For this, you need to provide the address that +should receive the callback and you can optionally set a gas limit for the callback execution. +Please take a look at the `IbcCallbackRequest` docs for more information. - The `address` of the source callback always needs to be the contract address - that sends the message (`env.contract.address`). Otherwise, the callback will - error and the contract will not be called. + The `address` of the source callback always needs to be the contract address that sends the + message (`env.contract.address`). Otherwise, the callback will error and the contract will not be + called. ### Receiving IBC Callbacks -To receive callbacks, you need to implement two new entrypoints in your -contract: +To receive callbacks, you need to implement two new entrypoints in your contract: -- `ibc_source_callback`, receiving an [`IbcSourceCallbackMsg`] enum which can be - one of two types: +- `ibc_source_callback`, receiving an [`IbcSourceCallbackMsg`] enum which can be one of two types: - [`IbcAckCallbackMsg`] if the packet was acknowledged - [`IbcTimeoutCallbackMsg`] if the packet timed out - `ibc_destination_callback`, receiving an [`IbcDestinationCallbackMsg`] -[`IbcSourceCallbackMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcSourceCallbackMsg.html -[`IbcAckCallbackMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcAckCallbackMsg.html -[`IbcTimeoutCallbackMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcTimeoutCallbackMsg.html -[`IbcDestinationCallbackMsg`]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcDestinationCallbackMsg.html +[`IbcSourceCallbackMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.IbcSourceCallbackMsg.html +[`IbcAckCallbackMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcAckCallbackMsg.html +[`IbcTimeoutCallbackMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcTimeoutCallbackMsg.html +[`IbcDestinationCallbackMsg`]: + https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.IbcDestinationCallbackMsg.html #### Source Callback -The `ibc_source_callback` entrypoint is called when the packet was either -acknowledged or timed out. You can use this to update your contract state, -release locked funds or trigger other actions. +The `ibc_source_callback` entrypoint is called when the packet was either acknowledged or timed out. +You can use this to update your contract state, release locked funds or trigger other actions. -As mentioned above, the receiver of this callback is always the contract that -sent the message. This means you don't need to assume that an attacker might be -sending you fake callbacks, reducing the need for validation. +As mentioned above, the receiver of this callback is always the contract that sent the message. This +means you don't need to assume that an attacker might be sending you fake callbacks, reducing the +need for validation. This is how you can implement the `ibc_source_callback` entrypoint: @@ -225,43 +219,40 @@ pub fn ibc_source_callback( ##### Acknowledgement -When the packet was acknowledged, you will receive the -`Acknowledgement(IbcAckCallbackMsg)` variant of `IbcSourceCallbackMsg`. This -means that the packet was successfully received and processed by the application -on the destination chain. The message contains the original packet data, the +When the packet was acknowledged, you will receive the `Acknowledgement(IbcAckCallbackMsg)` variant +of `IbcSourceCallbackMsg`. This means that the packet was successfully received and processed by the +application on the destination chain. The message contains the original packet data, the acknowledgement and the address of the relayer. ##### Timeout -When the packet timed out, you will receive the `Timeout(IbcTimeoutCallbackMsg)` -variant of `IbcSourceCallbackMsg`. This means that the packet was not delivered -to the destination chain in time (e.g. because no relayer picked it up or the -chain is stopped). The message contains the original packet data and the address -of the relayer who told you about the timeout. +When the packet timed out, you will receive the `Timeout(IbcTimeoutCallbackMsg)` variant of +`IbcSourceCallbackMsg`. This means that the packet was not delivered to the destination chain in +time (e.g. because no relayer picked it up or the chain is stopped). The message contains the +original packet data and the address of the relayer who told you about the timeout. #### Destination Callback -The `ibc_destination_callback` entrypoint is called when a packet was -acknowledged on the destination chain. The shape of an acknowledgement is -protocol specific and usually contains both success and error cases. +The `ibc_destination_callback` entrypoint is called when a packet was acknowledged on the +destination chain. The shape of an acknowledgement is protocol specific and usually contains both +success and error cases. -For the `IbcMsg::Transfer` message, a success acknowledgement means that the -tokens were successfully transferred to the destination chain. It allows you to -use the received tokens immediately, update the contract state to reflect the -new tokens or trigger other actions. +For the `IbcMsg::Transfer` message, a success acknowledgement means that the tokens were +successfully transferred to the destination chain. It allows you to use the received tokens +immediately, update the contract state to reflect the new tokens or trigger other actions. - It is important to validate that the packet and acknowledgement are what you - expect them to be. For example for a transfer message, the receiver of the - funds is not necessarily the contract that receives the callbacks. + It is important to validate that the packet and acknowledgement are what you expect them to be. + For example for a transfer message, the receiver of the funds is not necessarily the contract that + receives the callbacks. This is how you can implement the `ibc_destination_callback` entrypoint: - This example uses the `ibc` crate with the `serde` feature, which provides a - data type for the transfer packet format to avoid defining that ourselves. You - can add it to your `Cargo.toml` by running `cargo add ibc --features serde`. + This example uses the `ibc` crate with the `serde` feature, which provides a data type for the + transfer packet format to avoid defining that ourselves. You can add it to your `Cargo.toml` by + running `cargo add ibc --features serde`. ```rust template="core" @@ -328,28 +319,26 @@ pub fn ibc_destination_callback( ``` - Please note that this example assumes an ICS20 v1 channel. At the time of - writing, the specification and implementation have just been extended with a - v2 which changes the [packet format]. If you want to use this in production - code, you should make sure to support both formats, such that a channel - upgrade does not break your contract. + Please note that this example assumes an ICS20 v1 channel. At the time of writing, the + specification and implementation have just been extended with a v2 which changes the [packet + format]. If you want to use this in production code, you should make sure to support both formats, + such that a channel upgrade does not break your contract. -As mentioned above, anyone can send you a destination callback for a packet. -This means you need to make sure that the packet and acknowledgement are what -you expect them to be. For example, for a transfer message, you need to make -sure that the transfer was successful, that the receiver of the funds is your -contract and the denomination is what you want to receive. This requires some +As mentioned above, anyone can send you a destination callback for a packet. This means you need to +make sure that the packet and acknowledgement are what you expect them to be. For example, for a +transfer message, you need to make sure that the transfer was successful, that the receiver of the +funds is your contract and the denomination is what you want to receive. This requires some knowledge about the [packet format]. -[packet format]: https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md#data-structures +[packet format]: + https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md#data-structures #### Error handling -Returning an error or panicking from a callback will **not** influence the IBC -packet lifecycle. The packet will still be acknowledged or timed out. This means -that you can safely return errors from your callbacks if you want to ignore the -packet. +Returning an error or panicking from a callback will **not** influence the IBC packet lifecycle. The +packet will still be acknowledged or timed out. This means that you can safely return errors from +your callbacks if you want to ignore the packet. -It will, however, undo any state changes that you made in the callback, just -like most other entrypoints. +It will, however, undo any state changes that you made in the callback, just like most other +entrypoints. diff --git a/src/pages/ibc/getting-started.mdx b/src/pages/ibc/getting-started.mdx index 884777bc..b6967f4d 100644 --- a/src/pages/ibc/getting-started.mdx +++ b/src/pages/ibc/getting-started.mdx @@ -4,9 +4,8 @@ tags: ["ibc"] # Getting started -To get started, you need to enable the `stargate` feature of the `cosmwasm-std` -crate. This will enable additional functionality that is not available on all -chains, including IBC support. +To get started, you need to enable the `stargate` feature of the `cosmwasm-std` crate. This will +enable additional functionality that is not available on all chains, including IBC support. ```toml cosmwasm-std = { version = "2.0.3", features = ["stargate"] } diff --git a/src/pages/index.md b/src/pages/index.md index ddebb3d7..6bf9f1f3 100644 --- a/src/pages/index.md +++ b/src/pages/index.md @@ -2,8 +2,8 @@ tags: ["intro"] --- -CosmWasm is a smart contract platform focusing on security, performance, and -interoperability. It is the only smart contracting platform for public -blockchains with heavy adoption outside of the EVM world. +CosmWasm is a smart contract platform focusing on security, performance, and interoperability. It is +the only smart contracting platform for public blockchains with heavy adoption outside of the EVM +world. Here you can find its documentation. diff --git a/src/pages/storey.mdx b/src/pages/storey.mdx index be1ef934..809f1b73 100644 --- a/src/pages/storey.mdx +++ b/src/pages/storey.mdx @@ -8,23 +8,20 @@ import { Callout } from "nextra/components"; [Storey](https://docs.rs/cw-storey/latest/cw_storey/) is an alternative to [StoragePlus](cw-storage-plus) and fulfills the same purpose. The -[StoragePlus introduction](cw-storage-plus) could very well be transplanted -here, verbatim - feel free to give it a read if you're not sure what this -software does. +[StoragePlus introduction](cw-storage-plus) could very well be transplanted here, verbatim - feel +free to give it a read if you're not sure what this software does. -While StoragePlus has been around for years and is the established way of -storing your data on-chain, Storey is the new kid on the block. +While StoragePlus has been around for years and is the established way of storing your data +on-chain, Storey is the new kid on the block. - Storey is currently **prototype software**, meaning the API might change - rapidly, **storage layout might break between versions**, and you might - stumble into bugs and missing features. It's probably a good idea not to use - it for serious production software just yet. If you do, please keep in mind - the increased maintenance burden and be careful! + Storey is currently **prototype software**, meaning the API might change rapidly, **storage layout + might break between versions**, and you might stumble into bugs and missing features. It's + probably a good idea not to use it for serious production software just yet. If you do, please + keep in mind the increased maintenance burden and be careful! -On the other hand, it is a solution we want to move toward - we appreciate -anyone willing to help us test it. We also appreciate feedback, feature -requests, and bug reports. +On the other hand, it is a solution we want to move toward - we appreciate anyone willing to help us +test it. We also appreciate feedback, feature requests, and bug reports. If you decide to give this a try, kudos to you! diff --git a/src/pages/storey/basics.mdx b/src/pages/storey/basics.mdx index e2851e25..29df9ce9 100644 --- a/src/pages/storey/basics.mdx +++ b/src/pages/storey/basics.mdx @@ -6,47 +6,42 @@ import { Callout } from "nextra/components"; # Basics -Storey is an abstraction layer that can be adapted to a binary KV store, -providing a typed API with a number of conveniences. This abstraction layer -lives in the [`storey`](https://docs.rs/storey/latest/storey/) crate. +Storey is an abstraction layer that can be adapted to a binary KV store, providing a typed API with +a number of conveniences. This abstraction layer lives in the +[`storey`](https://docs.rs/storey/latest/storey/) crate. -There's also the integration of `storey` with the Cosmos/CosmWasm storage API. -This integration lives in the -[`cw-storey`](https://docs.rs/cw-storey/latest/cw_storey/) crate. Since you -likely came here wanting to build CosmWasm contracts, this is the crate you'll -be interacting with for fundamental things. +There's also the integration of `storey` with the Cosmos/CosmWasm storage API. This integration +lives in the [`cw-storey`](https://docs.rs/cw-storey/latest/cw_storey/) crate. Since you likely came +here wanting to build CosmWasm contracts, this is the crate you'll be interacting with for +fundamental things. ## Containers -Storey provides some tools to build and compose "containers". The -[_Containers_](containers) section is probably the most relevant for practical -contract development; it describes storey's built-in containers. +Storey provides some tools to build and compose "containers". The [_Containers_](containers) section +is probably the most relevant for practical contract development; it describes storey's built-in +containers. ## Keys encoding -`storey` does a lot of key management for you, and doesn't use any particular -encoding scheme for that. The defacto encoding scheme is a combination of: +`storey` does a lot of key management for you, and doesn't use any particular encoding scheme for +that. The defacto encoding scheme is a combination of: - One-byte keys provided to `storey` containers -- The particular way a given container decides to use that key - it might save - something under that key directly, and/or it might append to it. In a way, a - container has a whole namespace of keys carved out for it to manage. +- The particular way a given container decides to use that key - it might save something under that + key directly, and/or it might append to it. In a way, a container has a whole namespace of keys + carved out for it to manage. ## Value encoding -Storey provides the `Encoding` trait, which describes how to serialize and -deserialize values. While for CosmWasm contracts you'll likely be using the -default [MessagePack](https://msgpack.org) encoding, you can switch out for -another one if you want, and you can do that granularly for each container. If -you need to integrate some other encoding, see the +Storey provides the `Encoding` trait, which describes how to serialize and deserialize values. While +for CosmWasm contracts you'll likely be using the default [MessagePack](https://msgpack.org) +encoding, you can switch out for another one if you want, and you can do that granularly for each +container. If you need to integrate some other encoding, see the [_Alternative encodings_](encodings) section. ## Alternative backends -The `storey` crate can be integrated with other storage backends. This is done -via the -[`StorageBackend`](https://docs.rs/storey/latest/storey/storage/trait.StorageBackend.html) -and +The `storey` crate can be integrated with other storage backends. This is done via the +[`StorageBackend`](https://docs.rs/storey/latest/storey/storage/trait.StorageBackend.html) and [`StorageBackendMut`](https://docs.rs/storey/latest/storey/storage/trait.StorageBackendMut.html) -traits. The process is described in the [_Alternative backends_](backend) -section. +traits. The process is described in the [_Alternative backends_](backend) section. diff --git a/src/pages/storey/containers.mdx b/src/pages/storey/containers.mdx index 16c0c37e..aefc4497 100644 --- a/src/pages/storey/containers.mdx +++ b/src/pages/storey/containers.mdx @@ -6,24 +6,23 @@ import { Callout, Tabs } from "nextra/components"; # Containers -A container is an abstraction that manages how some data should be stored and -retrieved. Sometimes this is as simple as a single value -([`Item`](containers/item)), sometimes there's more to it than that. +A container is an abstraction that manages how some data should be stored and retrieved. Sometimes +this is as simple as a single value ([`Item`](containers/item)), sometimes there's more to it than +that. -For most of your needs, you can likely do what you need to with the built-in -containers: +For most of your needs, you can likely do what you need to with the built-in containers: - [`Item`](containers/item) - [`Map`](containers/map) - [`Column`](containers/column) -For more advanced use cases, you can build your own containers as described in -the [_Implementing new containers_](container-impl) section. +For more advanced use cases, you can build your own containers as described in the +[_Implementing new containers_](container-impl) section. # Namespace -To construct a container, you need to provide a single byte. This byte is used -to distinguish between different "root" containers in the same storage space. +To construct a container, you need to provide a single byte. This byte is used to distinguish +between different "root" containers in the same storage space. ```rust template="storage" use cw_storey::containers::{Item, Map}; @@ -32,28 +31,26 @@ let item: Item = Item::new(0); // byte 0 is used as the namespace let map: Map> = Map::new(1); // byte 1 is used as the namespace ``` -A container will assume it's free to save stuff under the given key (e.g. `A`), -and any key that starts with that same byte (e.g. `A28F`). In this way, a whole -namespace is reserved for the container. +A container will assume it's free to save stuff under the given key (e.g. `A`), and any key that +starts with that same byte (e.g. `A28F`). In this way, a whole namespace is reserved for the +container. - An item will simply store its value under the given byte, while a map will - store its values under keys that are prefixed with the given byte. How exactly - the namespace is managed is up to the container implementation. + An item will simply store its value under the given byte, while a map will store its values under + keys that are prefixed with the given byte. How exactly the namespace is managed is up to the + container implementation. To avoid key collisions, you must provide a different byte to each container. # Composition -Some containers can be composed together to create more complex data structures. -Right now, the only built-in container that supports composition is the `Map` -container. +Some containers can be composed together to create more complex data structures. Right now, the only +built-in container that supports composition is the `Map` container. -This is an alternative design largely used to achieve the same effect as -"composite keys" in `cw-storage-plus` (think tuple keys like `(String, u32)`), -but also make this more flexible - you can put a `Column` or any other container -inside a `Map`! +This is an alternative design largely used to achieve the same effect as "composite keys" in +`cw-storage-plus` (think tuple keys like `(String, u32)`), but also make this more flexible - you +can put a `Column` or any other container inside a `Map`! Let's compare the two approaches: @@ -99,18 +96,15 @@ assert_eq!( -It's possible to define custom containers that enable composition similar to -maps. If done properly, they can be mixed with any other containers, including -built-in ones. +It's possible to define custom containers that enable composition similar to maps. If done properly, +they can be mixed with any other containers, including built-in ones. # Encoding -Types like `Item` or `Column` need a way to encode values in a binary store. If -you're using the `Item` and `Column` types from `cw-storey`, the -[MessagePack](https://msgpack.org/) format is used. This is a binary encoding -that should generally be a storage performance improvement over JSON. +Types like `Item` or `Column` need a way to encode values in a binary store. If you're using the +`Item` and `Column` types from `cw-storey`, the [MessagePack](https://msgpack.org/) format is used. +This is a binary encoding that should generally be a storage performance improvement over JSON. -If you need to use a different encoding, you can instead import the -`Item`/`Column` type from the `storey` crate and specify an alternative -encoding. A guide to implementing your encoding can be found in the -[_Alternative encodings_](encodings) section. +If you need to use a different encoding, you can instead import the `Item`/`Column` type from the +`storey` crate and specify an alternative encoding. A guide to implementing your encoding can be +found in the [_Alternative encodings_](encodings) section. diff --git a/src/pages/sylvia.mdx b/src/pages/sylvia.mdx index 960b2cb7..4013e7df 100644 --- a/src/pages/sylvia.mdx +++ b/src/pages/sylvia.mdx @@ -6,38 +6,31 @@ import { Callout } from "nextra/components"; # Introduction to Sylvia -[`Sylvia`](https://github.com/cosmwasm/sylvia) is a framework for building -CosmWasm smart contracts with a high level of abstraction. +[`Sylvia`](https://github.com/cosmwasm/sylvia) is a framework for building CosmWasm smart contracts +with a high level of abstraction. -It's built on top of crates such as -[`cosmwasm-std`](https://crates.io/crates/cosmwasm-std) and +It's built on top of crates such as [`cosmwasm-std`](https://crates.io/crates/cosmwasm-std) and [`cw-multi-test`](https://crates.io/crates/cw-multi-test). - - Sylvia contracts are fully interoperable with regular CosmWasm contracts - +Sylvia contracts are fully interoperable with regular CosmWasm contracts -It allows the users to focus purely on business logic by generating message -structures, specifying how their API is (de)serialized, or how to handle message -dispatching. Instead, the API of your contract is a set of traits you implement -on your contract type. +It allows the users to focus purely on business logic by generating message structures, specifying +how their API is (de)serialized, or how to handle message dispatching. Instead, the API of your +contract is a set of traits you implement on your contract type. -The framework generates things like entry point structures, functions -dispatching the messages, or even helpers for [`MultiTest`](../cw-multi-test). -It allows for better control of interfaces, including validating their -completeness in compile time. +The framework generates things like entry point structures, functions dispatching the messages, or +even helpers for [`MultiTest`](../cw-multi-test). It allows for better control of interfaces, +including validating their completeness in compile time. Sylvia consists of two crates: -- [`sylvia`](https://crates.io/crates/sylvia) - Crate the users should use. - Exposes all of the macros from the `sylvia-derive` and provides some - additional utilities. -- [`sylvia-derive`](https://crates.io/crates/sylvia-derive) - Contains all of - the Sylvia macros. Do not add this as a dependency on your contract. +- [`sylvia`](https://crates.io/crates/sylvia) - Crate the users should use. Exposes all of the + macros from the `sylvia-derive` and provides some additional utilities. +- [`sylvia-derive`](https://crates.io/crates/sylvia-derive) - Contains all of the Sylvia macros. Do + not add this as a dependency on your contract. -While using Sylvia consider using reexported crates like `cosmwasm-std` and -`cw-multi-test` instead of adding those dependencies yourself as this would lead -you to smaller dependencies to maintain. +While using Sylvia consider using reexported crates like `cosmwasm-std` and `cw-multi-test` instead +of adding those dependencies yourself as this would lead you to smaller dependencies to maintain. -You can visit [`docs.rs`](https://docs.rs/sylvia/latest/sylvia/) to learn about -the types exposed in the Sylvia. +You can visit [`docs.rs`](https://docs.rs/sylvia/latest/sylvia/) to learn about the types exposed in +the Sylvia. diff --git a/src/pages/sylvia/attributes.mdx b/src/pages/sylvia/attributes.mdx index eb5a7cc5..ebfeac78 100644 --- a/src/pages/sylvia/attributes.mdx +++ b/src/pages/sylvia/attributes.mdx @@ -4,5 +4,4 @@ tags: ["sylvia", "attributes"] # Attributes -This part of the documentation will describe the attributes supported by the -Sylvia framework. +This part of the documentation will describe the attributes supported by the Sylvia framework. diff --git a/src/pages/sylvia/attributes/custom.mdx b/src/pages/sylvia/attributes/custom.mdx index de7018fd..e0f57a71 100644 --- a/src/pages/sylvia/attributes/custom.mdx +++ b/src/pages/sylvia/attributes/custom.mdx @@ -6,8 +6,7 @@ import { Callout } from "nextra/components"; # `sv::custom` attribute -Use `sv::custom` if you want to use a custom message and/or query in your -contract. +Use `sv::custom` if you want to use a custom message and/or query in your contract. ## Macros @@ -60,8 +59,7 @@ impl CounterContract { Types passed as parameters have to implement - [`CustomMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.CustomMsg.html) - and + [`CustomMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.CustomMsg.html) and [`CustomQuery`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.CustomQuery.html) respectively. @@ -99,6 +97,6 @@ pub trait SomeInterface { ``` - It's also possible to define custom types for the interface using associated - types. We cover it in the [`interface`](../macros/interface) macro section. + It's also possible to define custom types for the interface using associated types. We cover it in + the [`interface`](../macros/interface) macro section. diff --git a/src/pages/sylvia/attributes/error.mdx b/src/pages/sylvia/attributes/error.mdx index c0fa3093..311a5533 100644 --- a/src/pages/sylvia/attributes/error.mdx +++ b/src/pages/sylvia/attributes/error.mdx @@ -21,8 +21,7 @@ List of macros supporting the `sv::error` attribute: - [`entry_points`](../macros/entry-points) - The `interface` macro supports custom error types via the `Error` associated - type. + The `interface` macro supports custom error types via the `Error` associated type. ## Usage @@ -56,6 +55,4 @@ impl CounterContract { } ``` - - Each method has to use the error type defined in the `sv::error` attribute. - +Each method has to use the error type defined in the `sv::error` attribute. diff --git a/src/pages/sylvia/attributes/message.mdx b/src/pages/sylvia/attributes/message.mdx index 5f69bb3a..69ad87af 100644 --- a/src/pages/sylvia/attributes/message.mdx +++ b/src/pages/sylvia/attributes/message.mdx @@ -6,12 +6,10 @@ import { Callout } from "nextra/components"; # `sv::messages` attribute -Use `sv::messages` to expand your contract functionality with the Sylvia -interface. +Use `sv::messages` to expand your contract functionality with the Sylvia interface. - The `sv::messages` attribute expects that the trait is implemented on the - contract type. + The `sv::messages` attribute expects that the trait is implemented on the contract type. ## Macros @@ -84,16 +82,15 @@ pub mod contract { ``` - Single `sv::messages` attribute corresponds to a single interface implemented - on a contract. If multiple interfaces are implemented, add this attribute for - each of them. + Single `sv::messages` attribute corresponds to a single interface implemented on a contract. If + multiple interfaces are implemented, add this attribute for each of them. ### Module/Interface name mismatch -In most cases, the only parameter the `sv::messages` expects is a path to the -interface, in this case `crate::interface`. Sylvia macros can deduce the -interface's name if it is simply an UpperCamelCase version of the module name. +In most cases, the only parameter the `sv::messages` expects is a path to the interface, in this +case `crate::interface`. Sylvia macros can deduce the interface's name if it is simply an +UpperCamelCase version of the module name. If the interface name differs from the module name, use the syntax below: @@ -104,15 +101,14 @@ If the interface name differs from the module name, use the syntax below: ### Custom types It's possible to implement an interface using -[`Empty`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Empty.html) -instead of custom types used in the contract. +[`Empty`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Empty.html) instead of custom +types used in the contract. -In such a case, we must inform Sylvia to convert the types in the `dispatch` -methods. +In such a case, we must inform Sylvia to convert the types in the `dispatch` methods. ```rust #[sv::messages(crate::interface: custom(msg, query))] ``` -The order of `msg` and `query` doesn't matter, and the attribute accepts either -`msg`, `query` or both. +The order of `msg` and `query` doesn't matter, and the attribute accepts either `msg`, `query` or +both. diff --git a/src/pages/sylvia/attributes/msg.mdx b/src/pages/sylvia/attributes/msg.mdx index ffd7c81d..c70d4705 100644 --- a/src/pages/sylvia/attributes/msg.mdx +++ b/src/pages/sylvia/attributes/msg.mdx @@ -17,8 +17,8 @@ List of macros supporting the `sv::msg` attribute: - [`entry_points`](../macros/entry-points) - [`interface`](../macros/interface) macro supports the `sv::msg` attribute only - with `exec`, `query` or `sudo` value. + [`interface`](../macros/interface) macro supports the `sv::msg` attribute only with `exec`, + `query` or `sudo` value. ## Usage @@ -75,20 +75,19 @@ impl CounterContract { ``` Notice that each message type has its context type, like -[`InstantiateCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.InstantiateCtx.html). -You are required to use the appropriate type. Otherwise, the dispatch will fail -to compile. +[`InstantiateCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.InstantiateCtx.html). You are +required to use the appropriate type. Otherwise, the dispatch will fail to compile. Each message type except for `query` expects the result type generic over [`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html). ## Aliasing -It is possible to use aliases for types in message signatures. In case of -`query` return type it requires however additional action. Due to +It is possible to use aliases for types in message signatures. In case of `query` return type it +requires however additional action. Due to [`QueryResponses`](https://docs.rs/cosmwasm-schema/latest/cosmwasm_schema/derive.QueryResponses.html) -macro derive on generated `query` message, we have to explicitly provide the -return type, as the macro wouldn't be able to deduce that from the alias. +macro derive on generated `query` message, we have to explicitly provide the return type, as the +macro wouldn't be able to deduce that from the alias. ```rust #[sv::msg(query, resp=SomeResponse)] diff --git a/src/pages/sylvia/attributes/override-entry-point.mdx b/src/pages/sylvia/attributes/override-entry-point.mdx index e6bd26ad..383fb385 100644 --- a/src/pages/sylvia/attributes/override-entry-point.mdx +++ b/src/pages/sylvia/attributes/override-entry-point.mdx @@ -6,15 +6,15 @@ import { Callout } from "nextra/components"; # `sv::override_entry_point` attribute -Use `sv::override_entry_point` if you want to define an entry point of your -contract yourself. This way, the [`sv::entry_points`](../macros/entry-points) -macro won't generate it for you. The entry point will also be used as a dispatch -method in the `MultiTest` helpers generated by the `contract` macro. +Use `sv::override_entry_point` if you want to define an entry point of your contract yourself. This +way, the [`sv::entry_points`](../macros/entry-points) macro won't generate it for you. The entry +point will also be used as a dispatch method in the `MultiTest` helpers generated by the `contract` +macro. - Use this attribute if you provide some custom logic in the entry points. - Otherwise, the [`MultiTest`](../../cw-multi-test) helpers won't cover that - logic, and thus you will miss the coverage. + Use this attribute if you provide some custom logic in the entry points. Otherwise, the + [`MultiTest`](../../cw-multi-test) helpers won't cover that logic, and thus you will miss the + coverage. ## Macros @@ -70,8 +70,8 @@ impl CounterContract { } ``` -First, the `sv::override_entry_point` attribute expects the entry point type to -override. Supported types are: +First, the `sv::override_entry_point` attribute expects the entry point type to override. Supported +types are: - `instantiate` - `exec` @@ -80,14 +80,12 @@ override. Supported types are: - `migrate` - `reply` -Next, we have to provide the path to the new entry point method prefixed with -the `=` character. +Next, we have to provide the path to the new entry point method prefixed with the `=` character. -Lastly, this attribute expects the message type the entry point expects. This -allows customization of the message used by the contract. If, for example your -contract functionality would be extended by another contract stored as its -field, it would be possible to wrap both contract messages and use that in the -entry point. +Lastly, this attribute expects the message type the entry point expects. This allows customization +of the message used by the contract. If, for example your contract functionality would be extended +by another contract stored as its field, it would be possible to wrap both contract messages and use +that in the entry point. An example of such an approach: diff --git a/src/pages/sylvia/basics.mdx b/src/pages/sylvia/basics.mdx index 2b0e4772..0047390a 100644 --- a/src/pages/sylvia/basics.mdx +++ b/src/pages/sylvia/basics.mdx @@ -4,5 +4,5 @@ tags: ["sylvia", "basics"] # Basics -This part of the documentation will describe the tooling and basic concepts -around the Sylvia framework. +This part of the documentation will describe the tooling and basic concepts around the Sylvia +framework. diff --git a/src/pages/sylvia/basics/contract-structure.mdx b/src/pages/sylvia/basics/contract-structure.mdx index 6131a74f..7149b2fc 100644 --- a/src/pages/sylvia/basics/contract-structure.mdx +++ b/src/pages/sylvia/basics/contract-structure.mdx @@ -4,8 +4,8 @@ tags: ["sylvia"] # Contract structure -Sylvia contracts are designed using the actor model. An actor is a contract -struct that can store a state and define a behavior. +Sylvia contracts are designed using the actor model. An actor is a contract struct that can store a +state and define a behavior. ```rust use sylvia::cw_storage_plus::Item; @@ -15,8 +15,8 @@ pub struct CounterContract { } ``` -In Sylvia we keep the state accessors as part of the contract definition. The -accessors are [`cw_storage_plus`](../../cw-storage-plus) primitives. +In Sylvia we keep the state accessors as part of the contract definition. The accessors are +[`cw_storage_plus`](../../cw-storage-plus) primitives. Let's take a look at the behavior implementation. @@ -55,55 +55,47 @@ impl CounterContract { In the first two lines, we see the usage of two macros: -- [`entry_points`](https://docs.rs/sylvia/latest/sylvia/attr.entry_points.html) - - Generates entry points of the contract. By default it will generate - `instantiate`, `execute` and `query` entry points. The other ones, `migrate`, - `reply`, and `sudo`, are generated if a behavior related to them is defined in - the `impl` block. - - This macro is wrapped in `cfg_attr` statement to be compiled only if `library` - feature flag is not enabled. This way, other users who might want to use this - contract in theirs won't get an entry point collision. - -- [`contract`](../macros/contract) - Parses every method inside the `impl` block - marked with the `[sv::msg(...)]` attribute and create proper messages and - utilities like helpers for [`MultiTest`](../../cw-multi-test). - -This simple example also has the `sv::msg(...)` attributes. Sylvia macros -distinguish the if message should be generated from the marked method and of -what type. - -CosmWasm contract requires the `instantiate` message, and it is mandatory to -specify it for the `contract` macro. We have to provide it with the proper -context type: -[`InstantiateCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.InstantiateCtx.html). -Another mandatory method is the `new`, as contract fields are out of scope for -the `contract` macro, and otherwise we wouldn't be able to create the contract -object in message dispatching. - -Context gives us access to the blockchain state, information about our contract, -and the sender of the message. We return the -[`StdResult`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/type.StdResult.html) -which uses standard CosmWasm error -[`StdError`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.StdError.html). -It's generic over +- [`entry_points`](https://docs.rs/sylvia/latest/sylvia/attr.entry_points.html) - Generates entry + points of the contract. By default it will generate `instantiate`, `execute` and `query` entry + points. The other ones, `migrate`, `reply`, and `sudo`, are generated if a behavior related to + them is defined in the `impl` block. + + This macro is wrapped in `cfg_attr` statement to be compiled only if `library` feature flag is not + enabled. This way, other users who might want to use this contract in theirs won't get an entry + point collision. + +- [`contract`](../macros/contract) - Parses every method inside the `impl` block marked with the + `[sv::msg(...)]` attribute and create proper messages and utilities like helpers for + [`MultiTest`](../../cw-multi-test). + +This simple example also has the `sv::msg(...)` attributes. Sylvia macros distinguish the if message +should be generated from the marked method and of what type. + +CosmWasm contract requires the `instantiate` message, and it is mandatory to specify it for the +`contract` macro. We have to provide it with the proper context type: +[`InstantiateCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.InstantiateCtx.html). Another +mandatory method is the `new`, as contract fields are out of scope for the `contract` macro, and +otherwise we wouldn't be able to create the contract object in message dispatching. + +Context gives us access to the blockchain state, information about our contract, and the sender of +the message. We return the +[`StdResult`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/type.StdResult.html) which uses +standard CosmWasm error +[`StdError`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.StdError.html). It's generic over [`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html). -The template contract also contains a query and an exec messages. Each type of -message in CosmWasm supports different contexts. F.e. the -[`QueryCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.QueryCtx.html) -exposes to the user an immutable -[`Deps`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Deps.html) as -by design, queries should never mutate the state. This is not the case for the -[`ExecCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecCtx.html) and -`InstantiateCtx` which exposes the -[`DepsMut`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.DepsMut.html). - -Fell free expanding the macro now and seeing what Sylvia generates. It might be -overwhelming, as there will be a lot of things generated that seem not relevant -to our code, so for the bare minimum, check the `InstantiateMsg` and its `impl` -block. - -Sylvia doesn't generate anything magical, but regular CosmWasm contract types -customized based on the provided methods and attributes. This means that the -Sylvia contract is fully interoperational with the standard CosmWasm contract. +The template contract also contains a query and an exec messages. Each type of message in CosmWasm +supports different contexts. F.e. the +[`QueryCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.QueryCtx.html) exposes to the user an +immutable [`Deps`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Deps.html) as by design, +queries should never mutate the state. This is not the case for the +[`ExecCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecCtx.html) and `InstantiateCtx` +which exposes the [`DepsMut`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.DepsMut.html). + +Fell free expanding the macro now and seeing what Sylvia generates. It might be overwhelming, as +there will be a lot of things generated that seem not relevant to our code, so for the bare minimum, +check the `InstantiateMsg` and its `impl` block. + +Sylvia doesn't generate anything magical, but regular CosmWasm contract types customized based on +the provided methods and attributes. This means that the Sylvia contract is fully interoperational +with the standard CosmWasm contract. diff --git a/src/pages/sylvia/basics/generate-contract.mdx b/src/pages/sylvia/basics/generate-contract.mdx index d2519cfa..9c0c8188 100644 --- a/src/pages/sylvia/basics/generate-contract.mdx +++ b/src/pages/sylvia/basics/generate-contract.mdx @@ -4,13 +4,12 @@ tags: ["sylvia"] # Generate contract -With the environment setup in the `getting-started` section, we can dive into -setting up a simple contract. +With the environment setup in the `getting-started` section, we can dive into setting up a simple +contract. -Run the `cargo-generate` command and give your contract a name. For simplicity -in learning Sylvia framework we will name it `counter`. This way, we will avoid -getting into possibly convoluted business logic and focus mainly on learning the -tool. +Run the `cargo-generate` command and give your contract a name. For simplicity in learning Sylvia +framework we will name it `counter`. This way, we will avoid getting into possibly convoluted +business logic and focus mainly on learning the tool. ```shell $ cargo generate CosmWasm/sylvia-template @@ -52,56 +51,48 @@ cw-storage-plus = "2.0.0" sylvia = { version = "1.0.2", features = ["mt"] } ``` -The `sylvia-template` contains a `library` feature. Its goal is to hide the -entry points of our contract for other developers who might want to use it in -their contracts. Otherwise, there would be conflicting implementations. +The `sylvia-template` contains a `library` feature. Its goal is to hide the entry points of our +contract for other developers who might want to use it in their contracts. Otherwise, there would be +conflicting implementations. This template also setup `crate-type` with two values: - `cdylib` - Required to compile the contract into `wasm`, -- `rlib` - Required for the contract to be used as a dependency in another - contract. +- `rlib` - Required for the contract to be used as a dependency in another contract. The `sylvia-template` also defines some dependencies. -- [`cosmwasm-std`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/) - Crate - that is a standard library for smart contracts. It provides essential - utilities for communication with the outside world, helper functions, and - types. Every smart contract we will build will use this dependency. -- [`sylvia`](https://docs.rs/sylvia/latest/sylvia/) - Crate, this documentation - describes. It provides us with three procedural macros: `entry_points`, - `contract`, and `interface`. We will expand on them later in the book. -- [`schemars`](https://docs.rs/schemars/latest/schemars/index.html) - Crate used - to create `JSON` schema documents for our contracts. It is automatically - derived on types generated by Sylvia and will be later used to provide concise - API for blockchain users, who might not be Rust developers. -- [`cosmwasm-schema`](https://docs.rs/cosmwasm-schema/latest/cosmwasm_schema/) - - Similar to `schemars`. This crate expands on `schemars` and provides us with - trait +- [`cosmwasm-std`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/) - Crate that is a standard + library for smart contracts. It provides essential utilities for communication with the outside + world, helper functions, and types. Every smart contract we will build will use this dependency. +- [`sylvia`](https://docs.rs/sylvia/latest/sylvia/) - Crate, this documentation describes. It + provides us with three procedural macros: `entry_points`, `contract`, and `interface`. We will + expand on them later in the book. +- [`schemars`](https://docs.rs/schemars/latest/schemars/index.html) - Crate used to create `JSON` + schema documents for our contracts. It is automatically derived on types generated by Sylvia and + will be later used to provide concise API for blockchain users, who might not be Rust developers. +- [`cosmwasm-schema`](https://docs.rs/cosmwasm-schema/latest/cosmwasm_schema/) - Similar to + `schemars`. This crate expands on `schemars` and provides us with trait [`QueryResponses`](https://docs.rs/cosmwasm-schema/latest/cosmwasm_schema/trait.QueryResponses.html) which ties query variants to their responses. We will expand on that later. -- [`serde`](https://docs.rs/serde/latest/serde/) - Framework for serializing and - deserializing Rust data structures efficiently and generically. +- [`serde`](https://docs.rs/serde/latest/serde/) - Framework for serializing and deserializing Rust + data structures efficiently and generically. -In the case of `dev-dependencies`, we will also enable the `mt` flag in Sylvia -to generate `Multitest` helpers in the test environment. +In the case of `dev-dependencies`, we will also enable the `mt` flag in Sylvia to generate +`Multitest` helpers in the test environment. ## Project structure -The structure present in the `sylvia-template` is an example and you can set up -the project in any way you want. +The structure present in the `sylvia-template` is an example and you can set up the project in any +way you want. - `src/lib.rs` - exposes contract modules. - `src/contract.rs` - main module in which the contract is defined. -- `src/multitest/` - module in which we define our tests. It's a good practice - to separate the tests between files semantically. -- `src/bin/schema.rs` - builds into a binary which generates the contract - schema. -- `.cargo/config` - exposes some aliases to make working with the project - simpler. - - `cargo wasm` - run `cargo build` with additional options to compile a proper - _wasm_ binary. - - `cargo wasm-debug` - same as `cargo wasm`, but without `--release` profile - to provide more debugging symbols. - - `cargo schema` - builds and runs the `src/schema.rs` for simpler schema - generation. +- `src/multitest/` - module in which we define our tests. It's a good practice to separate the tests + between files semantically. +- `src/bin/schema.rs` - builds into a binary which generates the contract schema. +- `.cargo/config` - exposes some aliases to make working with the project simpler. + - `cargo wasm` - run `cargo build` with additional options to compile a proper _wasm_ binary. + - `cargo wasm-debug` - same as `cargo wasm`, but without `--release` profile to provide more + debugging symbols. + - `cargo schema` - builds and runs the `src/schema.rs` for simpler schema generation. diff --git a/src/pages/sylvia/basics/getting-started.mdx b/src/pages/sylvia/basics/getting-started.mdx index 7d301043..7d88d8af 100644 --- a/src/pages/sylvia/basics/getting-started.mdx +++ b/src/pages/sylvia/basics/getting-started.mdx @@ -6,14 +6,13 @@ import { Callout } from "nextra/components"; # Prerequisites -To use Sylvia follow the [`installation`](../../core/installation) process for -the `CosmWasm core`. +To use Sylvia follow the [`installation`](../../core/installation) process for the `CosmWasm core`. ## Verifying the installation -To guarantee you are ready to build your smart contracts, you must ensure you -can build examples. Checkout the [sylvia](https://github.com/CosmWasm/sylvia) -repository and run the testing command in its folder: +To guarantee you are ready to build your smart contracts, you must ensure you can build examples. +Checkout the [sylvia](https://github.com/CosmWasm/sylvia) repository and run the testing command in +its folder: ```shell $ git clone https://github.com/CosmWasm/sylvia.git @@ -21,24 +20,23 @@ $ cd sylvia sylvia $ cargo test ``` -You should see that everything in the repository gets compiled and all tests -pass. +You should see that everything in the repository gets compiled and all tests pass. -Sylvia framework contains some examples of contracts. To find them go to -`examples/contracts` directory. These contracts are maintained by CosmWasm -creators, so contracts in there should follow good practices. +Sylvia framework contains some examples of contracts. To find them go to `examples/contracts` +directory. These contracts are maintained by CosmWasm creators, so contracts in there should follow +good practices. ## Macro expansion -Sylvia generates a lot of code for us, which is not visible right away. To see -the generated code, go to `examples/contracts/cw1-whitelist/src/contract.rs`. +Sylvia generates a lot of code for us, which is not visible right away. To see the generated code, +go to `examples/contracts/cw1-whitelist/src/contract.rs`. In VSCode you can click on `#[contract]`, do `shift+p` and then type: -`rust analyzer: Expand macro recursively`. This will open a window with a fully -expanded macro, which you can browse. +`rust analyzer: Expand macro recursively`. This will open a window with a fully expanded macro, +which you can browse. -In Vim you can consider installing the -[rustaceanvim](https://github.com/mrcjkb/rustaceanvim) plugin. +In Vim you can consider installing the [rustaceanvim](https://github.com/mrcjkb/rustaceanvim) +plugin. You can also use `cargo expand` tool from CLI, like this: @@ -55,5 +53,4 @@ To make Sylvia contract easier to setup we created the cargo generate CosmWasm/sylvia-template ``` -You will be prompted to provide project name. Once you choose it you are ready -to go. +You will be prompted to provide project name. Once you choose it you are ready to go. diff --git a/src/pages/sylvia/basics/ibc.mdx b/src/pages/sylvia/basics/ibc.mdx index 19d3b367..0efbdd71 100644 --- a/src/pages/sylvia/basics/ibc.mdx +++ b/src/pages/sylvia/basics/ibc.mdx @@ -6,12 +6,11 @@ import { Callout } from "nextra/components"; # IBC -Sylvia doesn't generate any [IBC](../../ibc) related code, but you can define -your own [IBC entry points](../../ibc/diy-protocol#Entrypoints) like you would -in the case of a regular CosmWasm contract. +Sylvia doesn't generate any [IBC](../../ibc) related code, but you can define your own +[IBC entry points](../../ibc/diy-protocol#Entrypoints) like you would in the case of a regular +CosmWasm contract. -You can define the logic inside the contract and call the method from the entry -point. +You can define the logic inside the contract and call the method from the entry point. ```rust {14-21, 32, 30} pub struct IbcContract; @@ -47,8 +46,7 @@ pub fn ibc_channel_open( } ``` -You can also define a trait for the IBC methods and implement it for on the -contract. +You can also define a trait for the IBC methods and implement it for on the contract. ```rust {7, 10, 12-13, 21-22} #[cfg_attr(not(feature = "library"), entry_point)] @@ -83,6 +81,5 @@ impl Ibc for IbcContract { } ``` -Remember not to use the interface attribute for this trait. Sylvia does not -handle IBC entry points, and there is no point in generating helpers around -them. +Remember not to use the interface attribute for this trait. Sylvia does not handle IBC entry points, +and there is no point in generating helpers around them. diff --git a/src/pages/sylvia/basics/interoperability.mdx b/src/pages/sylvia/basics/interoperability.mdx index ee4c490b..0b55c7be 100644 --- a/src/pages/sylvia/basics/interoperability.mdx +++ b/src/pages/sylvia/basics/interoperability.mdx @@ -6,24 +6,21 @@ import { Callout, Tabs } from "nextra/components"; # Interoperability - - Sylvia contracts are fully interoperable with classical CosmWasm contracts. - +Sylvia contracts are fully interoperable with classical CosmWasm contracts. -Sylvia macros expand into a regular CosmWasm code. Because of that, we can test -and communicate with Sylvia contracts like we would with any CosmWasm contract. +Sylvia macros expand into a regular CosmWasm code. Because of that, we can test and communicate with +Sylvia contracts like we would with any CosmWasm contract. -Sylvia exposes, however additional QoL utilities like -[`Remote`](../types/communication#remote) and [`MultiTest`](../types/multitest) -helpers, which we recommend using alongside the Sylvia contracts. +Sylvia exposes, however additional QoL utilities like [`Remote`](../types/communication#remote) and +[`MultiTest`](../types/multitest) helpers, which we recommend using alongside the Sylvia contracts. ## Communication We can send messages from Sylvia as we would from any CosmWasm contract. Execute messages in Sylvia return the -[`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html) -on which we can call the +[`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html) on which we can +call the [`add_message`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html#method.add_message) or [`add_messages`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html#method.add_messages). @@ -42,14 +39,10 @@ fn external_increment(&self, ctx: ExecCtx) -> StdResult { ``` We can also use the generated -[`WasmMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.WasmMsg.html) -to construct the -[`SubMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.SubMsg.html) -and expect reply. +[`WasmMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.WasmMsg.html) to construct the +[`SubMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.SubMsg.html) and expect reply. - - Learn more about replies [here](../../core/entrypoints/reply). - +Learn more about replies [here](../../core/entrypoints/reply). ```rust {1, 24-33, 36-45} const SUBMSG_ID: u64 = 1; @@ -104,8 +97,8 @@ impl ReplyContract { Query messages can also be sent through the [`query_wasm_smart`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.QuerierWrapper.html#method.query_wasm_smart) method. We can access the -[`Deps`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Deps.html) -through the [`QueryCtx`](../types/context). +[`Deps`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Deps.html) through the +[`QueryCtx`](../types/context). ```rust {5-7} #[sv::msg(query)] @@ -118,30 +111,25 @@ fn external_count(&self, ctx: QueryCtx) -> StdResult { } ``` -As you see, we can send messages from the Sylvia contract as we would in case of -a CosmWasm contract. You can check generated messages -[here](../macros/generated-types/message-types). +As you see, we can send messages from the Sylvia contract as we would in case of a CosmWasm +contract. You can check generated messages [here](../macros/generated-types/message-types). -Although we could send messages to Sylvia contract in the same way, we recommend -using the [`ExecutorBuilder`](../types/communication#executorbuilder) and -[`BoundQuerier`](../types/communication#boundquerier) which wraps construction -of the messages. +Although we could send messages to Sylvia contract in the same way, we recommend using the +[`ExecutorBuilder`](../types/communication#executorbuilder) and +[`BoundQuerier`](../types/communication#boundquerier) which wraps construction of the messages. - You can learn more about these helpers in the - [`communication`](../types/communication) section. + You can learn more about these helpers in the [`communication`](../types/communication) section. ## Testing -We test Sylvia contract with MultiTest the same way we would test the classical -CosmWasm contracts, except we use the [`sylvia::App`](../types/multitest#app) in -place of -[`cw_multi_test::App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html). -This type provides all the API as the MultiTest counterpart, exposing the -underlying object but adding support for using the Sylvia-generated helpers. It -can also be used to simulate the execution of standard CosmWasm contracts as -well +We test Sylvia contract with MultiTest the same way we would test the classical CosmWasm contracts, +except we use the [`sylvia::App`](../types/multitest#app) in place of +[`cw_multi_test::App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html). This +type provides all the API as the MultiTest counterpart, exposing the underlying object but adding +support for using the Sylvia-generated helpers. It can also be used to simulate the execution of +standard CosmWasm contracts as well ```rust use sylvia::multitest::App; @@ -150,15 +138,13 @@ let app = App::>::default(); ``` - We must provide the full type for the [`App`](../types/multitest#app), as Rust - cannot deduce it here. + We must provide the full type for the [`App`](../types/multitest#app), as Rust cannot deduce it + here. We can access the underlying -[`cw_multi_test::App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html) -via -[`app_mut`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.App.html#method.app_mut) -to +[`cw_multi_test::App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html) via +[`app_mut`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.App.html#method.app_mut) to [`store_code`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.store_code) of the CosmWasm contract. @@ -185,7 +171,6 @@ let cosmwasm_contract = app .unwrap(); ``` -After that testing will be the same as with any CosmWasm and Sylvia contract. -Check out the documentation about testing Sylvia's contract -[`here`](../types/multitest) and about testing CosmWasm contracts -[`here`](../../cw-multi-test). +After that testing will be the same as with any CosmWasm and Sylvia contract. Check out the +documentation about testing Sylvia's contract [`here`](../types/multitest) and about testing +CosmWasm contracts [`here`](../../cw-multi-test). diff --git a/src/pages/sylvia/macros/contract.mdx b/src/pages/sylvia/macros/contract.mdx index 9393eb9a..9bff9ddf 100644 --- a/src/pages/sylvia/macros/contract.mdx +++ b/src/pages/sylvia/macros/contract.mdx @@ -75,8 +75,8 @@ impl CounterContract { We define our messages signatures by marking the appropriate methods with the [`sv::msg`](../attributes/msg) attribute. -The `impl` block must contain the attributeless `new` method for the generated -`dispatch` to work properly. +The `impl` block must contain the attributeless `new` method for the generated `dispatch` to work +properly. ## Custom types @@ -85,10 +85,10 @@ You can construct your contract to work with some specific custom types with the ## Generic types -Sylvia contracts can be reused as a state by other contracts. This way you could -expand functionality of one contract with another one. In such a case you might -want to present a possibility for the user to use it with types that suits their -purpose. You can do that by defining generics on your contract. +Sylvia contracts can be reused as a state by other contracts. This way you could expand +functionality of one contract with another one. In such a case you might want to present a +possibility for the user to use it with types that suits their purpose. You can do that by defining +generics on your contract. ```rust use std::marker::PhantomData; @@ -133,31 +133,26 @@ where } ``` -This is a standard way to create generic structs in Rust. Two important things -to mention are: +This is a standard way to create generic structs in Rust. Two important things to mention are: -- Rust will complain that generics used in method signatures are unused. You - have to create a `std::marker::PhantomData` field to silence this error. In - case a contract uses multiple generic types, simply wrap them in a tuple - `PhantomData<(T1, T2)>`. -- If generic types are used as part of the method signature, generated messages - will require them to fulfill their trait bounds. In most cases it's enough to - add the `sylvia::types::CustomMsg + \'static` bounds. +- Rust will complain that generics used in method signatures are unused. You have to create a + `std::marker::PhantomData` field to silence this error. In case a contract uses multiple generic + types, simply wrap them in a tuple `PhantomData<(T1, T2)>`. +- If generic types are used as part of the method signature, generated messages will require them to + fulfill their trait bounds. In most cases it's enough to add the + `sylvia::types::CustomMsg + \'static` bounds. ## Good practices ### Prefer generic custom types -The [`sv::custom`](../attributes/custom) attribute is not mandatory, as by -default contract macro will use -[`Empty`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Empty.html) -type in place of custom types. It has a downside that the contract always -expects the -[`Empty`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Empty.html) -custom messages, and it makes testing it in the [MultiTest](../../cw-multi-test) -environment with different custom messages tricky. We recommend that if your -contract is meant to be chain agnostic, define it with a generic custom message -and custom query. +The [`sv::custom`](../attributes/custom) attribute is not mandatory, as by default contract macro +will use [`Empty`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Empty.html) type in place +of custom types. It has a downside that the contract always expects the +[`Empty`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Empty.html) custom messages, and +it makes testing it in the [MultiTest](../../cw-multi-test) environment with different custom +messages tricky. We recommend that if your contract is meant to be chain agnostic, define it with a +generic custom message and custom query. ```rust pub struct Contract { diff --git a/src/pages/sylvia/macros/entry-points.mdx b/src/pages/sylvia/macros/entry-points.mdx index 87e1c4d8..cbb009ff 100644 --- a/src/pages/sylvia/macros/entry-points.mdx +++ b/src/pages/sylvia/macros/entry-points.mdx @@ -59,18 +59,18 @@ impl CounterContract { } ``` -The `entry_points` macro scans for [`sv::msg`](../attributes/msg) attributes. By -default it generates: instantiate, exec, and query entry points. +The `entry_points` macro scans for [`sv::msg`](../attributes/msg) attributes. By default it +generates: instantiate, exec, and query entry points. ## Custom types -You can construct your entry points to work with some specific custom types with -the [`sv::custom`](../attributes/custom). +You can construct your entry points to work with some specific custom types with the +[`sv::custom`](../attributes/custom). ## Generic types -CosmWasm entry points cannot be generic. We are thus forced to provide concrete -types to be used in place of generic types used in the contract. +CosmWasm entry points cannot be generic. We are thus forced to provide concrete types to be used in +place of generic types used in the contract. ```rust use std::marker::PhantomData; @@ -121,12 +121,11 @@ where } ``` -We do that by adding parantheses after the `entry_points` macro and passing -`generics` attribute with concrete types passed in brackets. +We do that by adding parantheses after the `entry_points` macro and passing `generics` attribute +with concrete types passed in brackets. - Remember to pass the types in the order reflecting the order of generics - defined on the contract. + Remember to pass the types in the order reflecting the order of generics defined on the contract. If the contract uses generic custom types we have to do some more work. @@ -135,9 +134,9 @@ If the contract uses generic custom types we have to do some more work. #[cfg_attr(not(feature = "library"), entry_points(generics, custom(msg=SvCustomMsg, query=SvCustomQuery)))] ``` -After coma we have to pass another parameter `custom`, and in the paranthesis -specify which types should be used in place of custom message and custom query. -The syntax reflects one used in the [`custom`](../attributes/custom). +After coma we have to pass another parameter `custom`, and in the paranthesis specify which types +should be used in place of custom message and custom query. The syntax reflects one used in the +[`custom`](../attributes/custom). -This is required as, for at least now, Sylvia is unable to determine which -concrete types are supposed to be used in place of generic custom types. +This is required as, for at least now, Sylvia is unable to determine which concrete types are +supposed to be used in place of generic custom types. diff --git a/src/pages/sylvia/macros/generated-types.mdx b/src/pages/sylvia/macros/generated-types.mdx index da64cc55..7225e0ff 100644 --- a/src/pages/sylvia/macros/generated-types.mdx +++ b/src/pages/sylvia/macros/generated-types.mdx @@ -6,5 +6,5 @@ tags: ["sylvia", "macro"] This part of the documentation describes types generated by Sylvia macros. -All of the generated code, except for the one generated by the -[`entry_points`](entry-points) macro is generated inside of the `sv` module. +All of the generated code, except for the one generated by the [`entry_points`](entry-points) macro +is generated inside of the `sv` module. diff --git a/src/pages/sylvia/macros/generated-types/communication.mdx b/src/pages/sylvia/macros/generated-types/communication.mdx index 2389d989..d73ea7cb 100644 --- a/src/pages/sylvia/macros/generated-types/communication.mdx +++ b/src/pages/sylvia/macros/generated-types/communication.mdx @@ -6,17 +6,13 @@ import { Callout, Tabs } from "nextra/components"; # Generated communication helpers -Sylvia exposes types to ease communication between contracts. Currently there -are two types: +Sylvia exposes types to ease communication between contracts. Currently there are two types: -- [`BoundQuerier`](../../types/communication#boundquerier) - for sending query - messages, -- [`ExecutorBuilder`](../../types/communication#executorbuilder) - for building - execute messages. +- [`BoundQuerier`](../../types/communication#boundquerier) - for sending query messages, +- [`ExecutorBuilder`](../../types/communication#executorbuilder) - for building execute messages. -The [`contract`](../contract) and [`interface`](../interface) expand these types -by generating and implementing traits with methods representing execute and -query methods +The [`contract`](../contract) and [`interface`](../interface) expand these types by generating and +implementing traits with methods representing execute and query methods Examples in the following paragraphs are generated from the below contract: @@ -46,11 +42,10 @@ impl CounterContract { ## Query helpers -Sylvia macros generate a `Querier` trait that mirrors all of the methods marked -with the [`sv::msg(query)`](../../attributes/msg.mdx) attribute. This trait is -then implemented on the [`BoundQuerier`](../../types/communication#boundquerier) -type. Implementation of each method constructs the appropriate message and sends -it to the contract. +Sylvia macros generate a `Querier` trait that mirrors all of the methods marked with the +[`sv::msg(query)`](../../attributes/msg.mdx) attribute. This trait is then implemented on the +[`BoundQuerier`](../../types/communication#boundquerier) type. Implementation of each method +constructs the appropriate message and sends it to the contract. ```rust pub trait Querier { @@ -68,11 +63,10 @@ impl<'a, C: sylvia::cw_std::CustomQuery> Querier ## Executor helpers -Sylvia macros generate an `Executor` trait that mirrors all of the methods -marked with the [`sv::msg(exec)`](../../attributes/msg.mdx) attribute. This -trait is then implemented on the -[`ExecutorBuilder`](../../types/communication#executorbuilder) type. -Implementation of each method constructs the appropriate message and returns the +Sylvia macros generate an `Executor` trait that mirrors all of the methods marked with the +[`sv::msg(exec)`](../../attributes/msg.mdx) attribute. This trait is then implemented on the +[`ExecutorBuilder`](../../types/communication#executorbuilder) type. Implementation of each method +constructs the appropriate message and returns the [`ExecutorBuilder`](../../types/communication#executorbuilder) generic over [`ReadyExecutorBuilderState`](https://docs.rs/sylvia/latest/sylvia/types/struct.ReadyExecutorBuilderState.html). diff --git a/src/pages/sylvia/macros/generated-types/message-types.mdx b/src/pages/sylvia/macros/generated-types/message-types.mdx index 733fbc89..a2e6bbb0 100644 --- a/src/pages/sylvia/macros/generated-types/message-types.mdx +++ b/src/pages/sylvia/macros/generated-types/message-types.mdx @@ -6,17 +6,16 @@ import { Callout, Tabs } from "nextra/components"; # Generated message types -Sylvia macros generate CosmWasm messages from methods marked with -[`sv::msg`](../../attributes/msg) attributes. +Sylvia macros generate CosmWasm messages from methods marked with [`sv::msg`](../../attributes/msg) +attributes. -Messages are generated either as struct, for instantiate and migrate, or enum in -case of the rest of the types. +Messages are generated either as struct, for instantiate and migrate, or enum in case of the rest of +the types. -Each message's implementation contains a `dispatch` method. Calling the -`msg.dispatch(...)` method on a struct message forwards the message's fields to -the single method as arguments, i.e. structure's fields become the method's -arguments. For the enum messages, the respective method will be called depending -on the enum variant. This is described in the example below +Each message's implementation contains a `dispatch` method. Calling the `msg.dispatch(...)` method +on a struct message forwards the message's fields to the single method as arguments, i.e. +structure's fields become the method's arguments. For the enum messages, the respective method will +be called depending on the enum variant. This is described in the example below ## Contract messages @@ -66,8 +65,7 @@ impl CounterContract { } ``` -generates the following messages for every respective -[entrypoint](../../../core/entrypoints): +generates the following messages for every respective [entrypoint](../../../core/entrypoints): @@ -265,20 +263,16 @@ generates the following messages for every respective - Notice that the method parameters are used as fields of appropriate messages - and their variants. + Notice that the method parameters are used as fields of appropriate messages and their variants. -The [`contract`](../contract) macro also generates wrapper messages for exec, -query and sudo. Their goal is to wrap respective messages, like `ExecMsg`, from -both the contract and interfaces implemented on it, which are used as the main -messages of the contract. +The [`contract`](../contract) macro also generates wrapper messages for exec, query and sudo. Their +goal is to wrap respective messages, like `ExecMsg`, from both the contract and interfaces +implemented on it, which are used as the main messages of the contract. - Use `ContractExecMsg`/`ContractQueryMsg`/`ContractSudoMsg` in hand made entry - points and in - [`write_api!`](https://docs.rs/cosmwasm-schema/latest/cosmwasm_schema/macro.write_api.html) - macro. + Use `ContractExecMsg`/`ContractQueryMsg`/`ContractSudoMsg` in hand made entry points and in + [`write_api!`](https://docs.rs/cosmwasm-schema/latest/cosmwasm_schema/macro.write_api.html) macro. @@ -394,22 +388,19 @@ messages of the contract. We mark the wrapper message with the -[`serde(untagged)`](https://serde.rs/enum-representations.html#untagged) -attribute to drop the wrapping variant names so that serialization matches one -done for the regular CosmWasm messages. +[`serde(untagged)`](https://serde.rs/enum-representations.html#untagged) attribute to drop the +wrapping variant names so that serialization matches one done for the regular CosmWasm messages. -The interface variants use -`::Sudo`, which is an -accessor meant to simplify the API while using generics in the -contract/interface. +The interface variants use `::Sudo`, which is an +accessor meant to simplify the API while using generics in the contract/interface. -Lastly, in dispatch, there is a const block. Its goal is to provide compile time -validation that none of the messages overlap between a contract and interfaces. +Lastly, in dispatch, there is a const block. Its goal is to provide compile time validation that +none of the messages overlap between a contract and interfaces. ## Interface messages -The generation done by [`interface`](../interface) macro is much simpler, as -Sylvia generates just three types of messages. +The generation done by [`interface`](../interface) macro is much simpler, as Sylvia generates just +three types of messages. We will use the below example interface to generate the messages: @@ -569,16 +560,14 @@ And the three generated messages: -Although interface messages are almost the same as contract ones, some slight -differences exist. +Although interface messages are almost the same as contract ones, some slight differences exist. -Notice that the messages are prefixed with the interfaces name: -`InterfaceSudoMsg`, while in case of the contract the name was just `SudoMsg`. -This prefix is required. Otherwise, `ContractSudoMsg` variants names would -overlap during the schema generation, and all but one would be lost. However, a -simplified alias is generated for them, so it's possible to access them like, -e.g., `SudoMsg`. The same rule applies to the exec and query messages. +Notice that the messages are prefixed with the interfaces name: `InterfaceSudoMsg`, while in case of +the contract the name was just `SudoMsg`. This prefix is required. Otherwise, `ContractSudoMsg` +variants names would overlap during the schema generation, and all but one would be lost. However, a +simplified alias is generated for them, so it's possible to access them like, e.g., `SudoMsg`. The +same rule applies to the exec and query messages. -Since multiple contracts might use these messages, the `dispatch` is generic -over the `ContractT` type implementing the interface. The error type returned in -the `dispatch` is the associated type defined on the interface. +Since multiple contracts might use these messages, the `dispatch` is generic over the `ContractT` +type implementing the interface. The error type returned in the `dispatch` is the associated type +defined on the interface. diff --git a/src/pages/sylvia/macros/generated-types/multitest.mdx b/src/pages/sylvia/macros/generated-types/multitest.mdx index 0155dfe3..30240ad1 100644 --- a/src/pages/sylvia/macros/generated-types/multitest.mdx +++ b/src/pages/sylvia/macros/generated-types/multitest.mdx @@ -7,26 +7,23 @@ import { Callout, Tabs } from "nextra/components"; # Generated MultiTest helpers - The macros generate MultiTest helpers only if the `mt` feature flag is - enabled. We recommend enabling it in the dev-dependencies. + The macros generate MultiTest helpers only if the `mt` feature flag is enabled. We recommend + enabling it in the dev-dependencies. -The [`contract`](../contract) and [`interface`](../interface) macros generate -QoL utilities to test your contract with the -[MultiTest](../../../cw-multi-test). +The [`contract`](../contract) and [`interface`](../interface) macros generate QoL utilities to test +your contract with the [MultiTest](../../../cw-multi-test). The MultiTest helpers are generated in the `sv::mt` module. ## Code generation -Most of the code is generated only by the [`contract`](../contract) macro. To -see the code generated by the [`interface`](../interface) macro skip to the -[proxy trait](#proxy-trait) section. +Most of the code is generated only by the [`contract`](../contract) macro. To see the code generated +by the [`interface`](../interface) macro skip to the [proxy trait](#proxy-trait) section. ### CodeId -The sole purpose of the `CodeId` is to act as a proxy for instantiating the -contract instance. +The sole purpose of the `CodeId` is to act as a proxy for instantiating the contract instance. ```rust pub struct CodeId<'app, MtApp> { @@ -121,11 +118,10 @@ where } ``` -The `CodeId` structure imitates the id of a contracts binary uploaded to the -actual blockchain. It links the code id with the -[`App`](../../types/multitest#app) on which the contract is stored. Call the -`instantiate` method and pass to it parameters you would pass to the -`InstantiateMsg` to get the `InstantiateProxy` instance. +The `CodeId` structure imitates the id of a contracts binary uploaded to the actual blockchain. It +links the code id with the [`App`](../../types/multitest#app) on which the contract is stored. Call +the `instantiate` method and pass to it parameters you would pass to the `InstantiateMsg` to get the +`InstantiateProxy` instance. ### InstantiateProxy @@ -200,8 +196,8 @@ where } ``` -At this stage of initializing the contract, we can set the funds, label, and -admins of our contract, as well as the salt for the +At this stage of initializing the contract, we can set the funds, label, and admins of our contract, +as well as the salt for the [`instantiate2`](https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.Executor.html#method.instantiate2_contract) call. @@ -211,14 +207,13 @@ call. enable the `cosmwasm_1_2` feature flag.
-The `call` method instantiates the contract on the -[`App`](../../types/multitest#app) and return the +The `call` method instantiates the contract on the [`App`](../../types/multitest#app) and return the [`Proxy`](../../types/multitest#proxy) to communicate with it. ### Proxy trait -By itself the [`Proxy`](../../types/multitest#proxy) stores the address of the -contract as well as the reference to the [`App`](../../types/multitest#app). +By itself the [`Proxy`](../../types/multitest#proxy) stores the address of the contract as well as +the reference to the [`App`](../../types/multitest#app). @@ -518,9 +513,8 @@ contract as well as the reference to the [`App`](../../types/multitest#app). The [`store_code`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.store_code) expects a type to implement the -[`Contract`](https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.Contract.html) -trait. The [`contract`](../contract) macro covers that by implementing this -trait on our contract type. +[`Contract`](https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.Contract.html) trait. The +[`contract`](../contract) macro covers that by implementing this trait on our contract type. ```rust impl sylvia::cw_multi_test::Contract @@ -601,8 +595,8 @@ impl sylvia::cw_multi_test::Contract - By default, the instantiate, exec and query methods will dispatch the message - to the proper methods in our contract. The sudo, reply, and migrate by default - calls [`bail!`](https://docs.rs/anyhow/latest/anyhow/macro.bail.html) unless - the respective method is specified in the contract impl block. + By default, the instantiate, exec and query methods will dispatch the message to the proper + methods in our contract. The sudo, reply, and migrate by default calls + [`bail!`](https://docs.rs/anyhow/latest/anyhow/macro.bail.html) unless the respective method is + specified in the contract impl block.
diff --git a/src/pages/sylvia/macros/interface.mdx b/src/pages/sylvia/macros/interface.mdx index 9973bea4..c5546d71 100644 --- a/src/pages/sylvia/macros/interface.mdx +++ b/src/pages/sylvia/macros/interface.mdx @@ -6,8 +6,8 @@ import { Callout } from "nextra/components"; # Interface -Use the [`interface`](https://docs.rs/sylvia/latest/sylvia/attr.interface.html) -macro to abstract semantical parts of your contracts. +Use the [`interface`](https://docs.rs/sylvia/latest/sylvia/attr.interface.html) macro to abstract +semantical parts of your contracts. Use `interface` macro only on Rust traits. @@ -39,27 +39,25 @@ pub trait Interface { As mentioned earlier `interface` macro is used attached to the Rust traits. -We define the `Error` associated type. Thanks to that, future contracts -implementing this interface will be able to assign their error type to it and -have wider range of errors than the `StdError`. +We define the `Error` associated type. Thanks to that, future contracts implementing this interface +will be able to assign their error type to it and have wider range of errors than the `StdError`. - `Error` associated type is the only mandatory thing to be defined for the - `interface` macro. + `Error` associated type is the only mandatory thing to be defined for the `interface` macro. -Then we can define our messages signatures. We do that by marking the methods -with the [`sv::msg`](../attributes/msg) attribute. +Then we can define our messages signatures. We do that by marking the methods with the +[`sv::msg`](../attributes/msg) attribute. ## Custom types -You can construct your interface to work with some specific custom types with -the [`sv::custom`](../attributes/custom) attribute. Use of `sv::custom` -restricts the interface to work with the predefined custom types. +You can construct your interface to work with some specific custom types with the +[`sv::custom`](../attributes/custom) attribute. Use of `sv::custom` restricts the interface to work +with the predefined custom types. -If you want to allow the users to use the interface with their own specified -custom types, you can declare `ExecC` and `QueryC` associated types, where -`ExecC` specifies the `CustomMsg` and `QueryC` the `CustomQuery`. +If you want to allow the users to use the interface with their own specified custom types, you can +declare `ExecC` and `QueryC` associated types, where `ExecC` specifies the `CustomMsg` and `QueryC` +the `CustomQuery`. ```rust use cosmwasm_schema::cw_serde; @@ -87,16 +85,13 @@ pub trait Interface { } ``` - - Remember to pass the associated types to context and `Response` types. - +Remember to pass the associated types to context and `Response` types. ## Generic types -The `interface` macro does not support generics. Instead, you can provide -generic functionality using the associated types. It's because Sylvia interfaces -can be implemented only once per contract, and in such a case, associated types -are semantically correct in Rust. +The `interface` macro does not support generics. Instead, you can provide generic functionality +using the associated types. It's because Sylvia interfaces can be implemented only once per +contract, and in such a case, associated types are semantically correct in Rust. ```rust #[interface] diff --git a/src/pages/sylvia/types/communication.mdx b/src/pages/sylvia/types/communication.mdx index ce9478bf..ad25bc58 100644 --- a/src/pages/sylvia/types/communication.mdx +++ b/src/pages/sylvia/types/communication.mdx @@ -6,23 +6,22 @@ import { Callout } from "nextra/components"; # Communication helpers -Sylvia defines few types to ease the communication between contracts. By design, -they are very limited in their functionality and serve as an infrastructure. All -of the message constructing methods are meant to be provided via traits. +Sylvia defines few types to ease the communication between contracts. By design, they are very +limited in their functionality and serve as an infrastructure. All of the message constructing +methods are meant to be provided via traits. -To gate these methods to be only accessible for the specific contracts, all of -these types are generic over a contract type. +To gate these methods to be only accessible for the specific contracts, all of these types are +generic over a contract type. - The goal of these helpers is to automate the message construction, making the - code more readable and reducing risk of an error. + The goal of these helpers is to automate the message construction, making the code more readable + and reducing risk of an error. ## Remote -The [`Remote`](https://docs.rs/sylvia/latest/sylvia/types/struct.Remote.html) -type is a gateway, that stores the remote contract address and expose methods -constructing the communication helpers. +The [`Remote`](https://docs.rs/sylvia/latest/sylvia/types/struct.Remote.html) type is a gateway, +that stores the remote contract address and expose methods constructing the communication helpers. These methods are: @@ -34,8 +33,8 @@ These methods are: [`ExecutorBuilder<(EmptyExecutorBuilderState, Contract)>`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecutorBuilder.html). - We recommend to store the `Remote` type as the contract state and access the - `BoundQuerier` and `ExecutorBuilder` via above methods. + We recommend to store the `Remote` type as the contract state and access the `BoundQuerier` and + `ExecutorBuilder` via above methods. The `Remote` can be stored as a represantation of a specific contract: @@ -63,12 +62,11 @@ pub struct Contract<'a> { ``` - Note that we have to use the dynamic dispatch here and also provide values for - every associated type defined in the interface. + Note that we have to use the dynamic dispatch here and also provide values for every associated + type defined in the interface. -The initialization of the `Remote` requires only the address of the external -contract: +The initialization of the `Remote` requires only the address of the external contract: ```rust self.remote @@ -91,20 +89,17 @@ let executor_builder = self ## BoundQuerier -The -[`BoundQuerier`](https://docs.rs/sylvia/latest/sylvia/types/struct.BoundQuerier.html) -is a wrapper over the +The [`BoundQuerier`](https://docs.rs/sylvia/latest/sylvia/types/struct.BoundQuerier.html) is a +wrapper over the [`QuerierWrapper`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.QuerierWrapper.html). -We provide the querying functionality via traits. The -[`contract`](../macros/contract) and [`interface`](../macros/interface) macros -generate these traits for us. You can learn about that in -[`this section`](../macros/generated-types/communication#query-helpers). If you -don't use Sylvia yet, you can create and implement those traits manually. Feel -free to get inspiration from above example. +We provide the querying functionality via traits. The [`contract`](../macros/contract) and +[`interface`](../macros/interface) macros generate these traits for us. You can learn about that in +[`this section`](../macros/generated-types/communication#query-helpers). If you don't use Sylvia +yet, you can create and implement those traits manually. Feel free to get inspiration from above +example. -With the traits implemented, a contract with a query method `some_query` can be -queried as follows: +With the traits implemented, a contract with a query method `some_query` can be queried as follows: ```rust let some_response = self @@ -116,13 +111,11 @@ let some_response = self ## ExecutorBuilder -The -[`ExecutorBuilder`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecutorBuilder.html) -is used to construct the +The [`ExecutorBuilder`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecutorBuilder.html) is +used to construct the [`WasmMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.WasmMsg.html). -It's generic over two states limiting it's functionality depending on the stage -it's in: +It's generic over two states limiting it's functionality depending on the stage it's in: - [`EmptyExecutorBuilderState`](https://docs.rs/sylvia/latest/sylvia/types/struct.EmptyExecutorBuilderState.html) - Setting funds for the transaction, @@ -130,17 +123,15 @@ it's in: [`Building`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecutorBuilder.html#method.build) the `WasmMsg`. -For the `ExecutorBuilder` generic over `EmptyExecutorBuilderState`, we also -provide the message constructing functionality. The -[`contract`](../macros/contract) and [`interface`](../macros/interface) macros -generate a trait with methods for every execute message. You can learn about -that in -[`this section`](../macros/generated-types/communication#execute-helpers). If -you don't use Sylvia yet, you can create and implement those traits manually. -Feel free to get inspiration from above example. - -With the traits implemented, we can create an execute method `some_exec` can be -queried as follows: +For the `ExecutorBuilder` generic over `EmptyExecutorBuilderState`, we also provide the message +constructing functionality. The [`contract`](../macros/contract) and +[`interface`](../macros/interface) macros generate a trait with methods for every execute message. +You can learn about that in +[`this section`](../macros/generated-types/communication#execute-helpers). If you don't use Sylvia +yet, you can create and implement those traits manually. Feel free to get inspiration from above +example. + +With the traits implemented, we can create an execute method `some_exec` can be queried as follows: ```rust let wasm_msg = self diff --git a/src/pages/sylvia/types/context.mdx b/src/pages/sylvia/types/context.mdx index fe67f4a4..031b3029 100644 --- a/src/pages/sylvia/types/context.mdx +++ b/src/pages/sylvia/types/context.mdx @@ -6,11 +6,9 @@ import { Callout } from "nextra/components"; # Context -Sylvia exposes context types to wrap the -[`Deps/DepsMut`](../../core/entrypoints.mdx#depsdepsmut), -[`Env`](../../core/entrypoints.mdx#env), and -[`MessageInfo`](../../core/entrypoints.mdx#messageinfo) types received in the -contract entrypoints. +Sylvia exposes context types to wrap the [`Deps/DepsMut`](../../core/entrypoints.mdx#depsdepsmut), +[`Env`](../../core/entrypoints.mdx#env), and [`MessageInfo`](../../core/entrypoints.mdx#messageinfo) +types received in the contract entrypoints. Those types are: diff --git a/src/pages/sylvia/types/multitest.mdx b/src/pages/sylvia/types/multitest.mdx index 73e7b008..57f20781 100644 --- a/src/pages/sylvia/types/multitest.mdx +++ b/src/pages/sylvia/types/multitest.mdx @@ -6,14 +6,13 @@ import { Callout } from "nextra/components"; # Multitest -Sylvia exposes several types that build on top of the -[`Multitest`](../../cw-multi-test). These types are supposed to be used next to -[`the types`](../macros/generated-types/multitest) generated by -[`contract`](../macros/contract) and [`interface`](../macros/interface) macros. +Sylvia exposes several types that build on top of the [`Multitest`](../../cw-multi-test). These +types are supposed to be used next to [`the types`](../macros/generated-types/multitest) generated +by [`contract`](../macros/contract) and [`interface`](../macros/interface) macros. - The types are hidden behind the `mt` feature flag. We recommend enabling it in - the dev-dependencies. + The types are hidden behind the `mt` feature flag. We recommend enabling it in the + dev-dependencies. Example usage of utilities described on this page as well as ones defined on the @@ -61,68 +60,54 @@ fn example_test() { ## App -The [`App`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.App.html) is a -wrapper around the -[`cw-multi-test::App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html), -stored inside the `RefCell`. It is done this way because the -[`App`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.App.html) has to -be passed by reference to multiple types, and we have to use the interior -mutability to affect it's state. +The [`App`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.App.html) is a wrapper around the +[`cw-multi-test::App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html), stored +inside the `RefCell`. It is done this way because the +[`App`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.App.html) has to be passed by +reference to multiple types, and we have to use the interior mutability to affect it's state. ## Proxy -The [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html) -represents a single, initialized contract. It is generic over it, and the `App` -on which it's installed. The `Proxy` is the structure through which you act on -behalf of the contract, sending messages and querying the state. +The [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html) represents a single, +initialized contract. It is generic over it, and the `App` on which it's installed. The `Proxy` is +the structure through which you act on behalf of the contract, sending messages and querying the +state. - The - [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html) - should not be constructed manually. Instead, create the contracts - [`CodeId`](../macros/generated-types/multitest#codeid) instance and call - `CodeId::instantiate`, which returns the - [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html). + The [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html) should not be + constructed manually. Instead, create the contracts + [`CodeId`](../macros/generated-types/multitest#codeid) instance and call `CodeId::instantiate`, + which returns the [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html). -The [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html) -by itself doesn't have the methods defined in your contract. They are instead -implemented via auto-generated traits by [`contract`](../macros/contract) and -[`interface`](../macros/interface) macros. Import the generated proxy trait into -your test scope to use these methods. If you want to learn more about the proxy -traits, you can go to -[`this section`](../macros/generated-types/multitest#proxy-trait). +The [`Proxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.Proxy.html) by itself doesn't +have the methods defined in your contract. They are instead implemented via auto-generated traits by +[`contract`](../macros/contract) and [`interface`](../macros/interface) macros. Import the generated +proxy trait into your test scope to use these methods. If you want to learn more about the proxy +traits, you can go to [`this section`](../macros/generated-types/multitest#proxy-trait). ## ExecProxy -The -[`ExecProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.ExecProxy.html) -is an intermediate type, for setting additional data for the execute messages. -It's main functionality is the -[`call`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.ExecProxy.html#method.call) +The [`ExecProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.ExecProxy.html) is an +intermediate type, for setting additional data for the execute messages. It's main functionality is +the [`call`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.ExecProxy.html#method.call) method, requiring the user to specify the caller of the message. - The - [`ExecProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.ExecProxy.html) - should not be constructed manually. Instead, it's supposed to be returned by - execute methods exposed in the [`proxy - traits`](../macros/generated-types/multitest#proxy-trait). + The [`ExecProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.ExecProxy.html) should not + be constructed manually. Instead, it's supposed to be returned by execute methods exposed in the + [`proxy traits`](../macros/generated-types/multitest#proxy-trait). ## MigrateProxy -The -[`MigrateProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.MigrateProxy.html) -is an intermediate type for setting additional data for the migrate messages. -It's main functionality is the -[`call`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.MigrateProxy.html#method.call) +The [`MigrateProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.MigrateProxy.html) is an +intermediate type for setting additional data for the migrate messages. It's main functionality is +the [`call`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.MigrateProxy.html#method.call) method, requiring the user to specify the caller of the message. - The - [`MigrateProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.MigrateProxy.html) - should not be constructed manually. Instead, it's supposed to be returned by - migrate methods exposed in the [`proxy - traits`](../macros/generated-types/multitest#proxy-trait). + The [`MigrateProxy`](https://docs.rs/sylvia/latest/sylvia/multitest/struct.MigrateProxy.html) + should not be constructed manually. Instead, it's supposed to be returned by migrate methods + exposed in the [`proxy traits`](../macros/generated-types/multitest#proxy-trait). diff --git a/src/pages/wasmd.mdx b/src/pages/wasmd.mdx index 4c6da1f9..f10f97b1 100644 --- a/src/pages/wasmd.mdx +++ b/src/pages/wasmd.mdx @@ -1,8 +1,7 @@ # Introduction -Wasmd is a Cosmos-SDK sample application that integrates the `x/wasm` module, -providing full support for Wasm smart contracts while maintaining the standard -features of a Cosmos-based blockchain. `x/wasm` is an essential module for -developers looking to build Cosmos SDK-based blockchains where they can deploy, -execute, and manage Wasm smart contracts. In this section you will learn how to -set up `wasmd` and integrate `x/wasm` in your blockchain. +Wasmd is a Cosmos-SDK sample application that integrates the `x/wasm` module, providing full support +for Wasm smart contracts while maintaining the standard features of a Cosmos-based blockchain. +`x/wasm` is an essential module for developers looking to build Cosmos SDK-based blockchains where +they can deploy, execute, and manage Wasm smart contracts. In this section you will learn how to set +up `wasmd` and integrate `x/wasm` in your blockchain. diff --git a/src/pages/wasmd/getting-started.mdx b/src/pages/wasmd/getting-started.mdx index 522020f2..7f6466b9 100644 --- a/src/pages/wasmd/getting-started.mdx +++ b/src/pages/wasmd/getting-started.mdx @@ -1,4 +1,4 @@ # Getting Started -This part of the documentation describes how to set up wasmd, start a node, and -interact with it using the CLI. +This part of the documentation describes how to set up wasmd, start a node, and interact with it +using the CLI. diff --git a/src/pages/wasmd/getting-started/cli.mdx b/src/pages/wasmd/getting-started/cli.mdx index 482160d5..bdd56a39 100644 --- a/src/pages/wasmd/getting-started/cli.mdx +++ b/src/pages/wasmd/getting-started/cli.mdx @@ -2,15 +2,14 @@ ## Upload -In this section, you will upload a WASM contract to the blockchain. This -involves using the `wasmd tx wasm store` command to upload the contract file, -and then querying the blockchain to obtain the unique code ID for the uploaded -contract. +In this section, you will upload a WASM contract to the blockchain. This involves using the +`wasmd tx wasm store` command to upload the contract file, and then querying the blockchain to +obtain the unique code ID for the uploaded contract. ### Upload code -You can upload your contract by running the command: `wasmd tx wasm store`. In -the following example, we upload the `hackatom.wasm` contract: +You can upload your contract by running the command: `wasmd tx wasm store`. In the following +example, we upload the `hackatom.wasm` contract: ```sh wasmd tx wasm store "./x/wasm/keeper/testdata/hackatom.wasm" \ @@ -22,8 +21,7 @@ wasmd tx wasm store "./x/wasm/keeper/testdata/hackatom.wasm" \ --keyring-backend=test ``` -- `./x/wasm/keeper/testdata/hackatom.wasm` is the path to the WASM file to - upload +- `./x/wasm/keeper/testdata/hackatom.wasm` is the path to the WASM file to upload - `--from alice` specifies the sender's account, in this case, `alice` - `--gas 1500000` sets the gas limit for the transaction - `-y` automatically accepts the transaction @@ -51,8 +49,8 @@ The output looks like: } ``` -From this output, we can get the transaction hash `txhash`. Using this hash, we -can fetch the code ID. +From this output, we can get the transaction hash `txhash`. Using this hash, we can fetch the code +ID. ```sh wasmd q tx 2C19314D369E7EF3C77CBD1B33E02DB0401619B5C8E1B1E5BD15AB46C3704E96 -o json @@ -89,8 +87,8 @@ Output: } ``` -Inside the `store_code` event, you can find the `code_id`. To extract it, you -can use the following command: +Inside the `store_code` event, you can find the `code_id`. To extract it, you can use the following +command: ```sh RESP=$(wasmd q tx 2C19314D369E7EF3C77CBD1B33E02DB0401619B5C8E1B1E5BD15AB46C3704E96 -o json) @@ -147,32 +145,31 @@ Output: - Code ID: This is the reference to the stored WASM code - Creator: This is the address of the account that uploaded the code - Data Hash: This is the checksum of the stored WASM code -- Instantiate Permission: This is the instantiate permission configuration. It - is optional, and the default value is `Everybody`, which means everybody can - create an instance of the uploaded WASM code +- Instantiate Permission: This is the instantiate permission configuration. It is optional, and the + default value is `Everybody`, which means everybody can create an instance of the uploaded WASM + code ### Download code -You can download the code associated with a specific code ID by running the -following command: +You can download the code associated with a specific code ID by running the following command: ```sh wasmd q wasm code $CODE_ID downloaded_code.wasm ``` -This command retrieves the WASM code from the blockchain and saves it to a file -named `downloaded_code.wasm`. +This command retrieves the WASM code from the blockchain and saves it to a file named +`downloaded_code.wasm`. ## Instantiation -In this section, you will create a new instance of the uploaded WASM contract. -This involves using the `wasmd tx wasm instantiate` command to instantiate the -contract, and then querying the blockchain to obtain the contract's address. +In this section, you will create a new instance of the uploaded WASM contract. This involves using +the `wasmd tx wasm instantiate` command to instantiate the contract, and then querying the +blockchain to obtain the contract's address. ### Create a new contract instance -First, set up the addresses for the accounts involved in the contract using -`wasmd keys show` command: +First, set up the addresses for the accounts involved in the contract using `wasmd keys show` +command: ```sh # Retrieve the address of Alice's account @@ -200,14 +197,12 @@ wasmd tx wasm instantiate "$CODE_ID" "$INIT" \ --keyring-backend=test ``` -- `wasmd tx wasm instantiate "$CODE_ID" "$INIT"` instantiates the contract using - the specified code ID and initial parameters -- `--admin="$ALICE_ADDR"` specifies Alice as the admin who can later update the - contract +- `wasmd tx wasm instantiate "$CODE_ID" "$INIT"` instantiates the contract using the specified code + ID and initial parameters +- `--admin="$ALICE_ADDR"` specifies Alice as the admin who can later update the contract - `--from alice` specifies Alice as the sender of the transaction - `--amount="100stake"`: Sends `100 stake` to the contract upon instantiation -- `--label "local0.1.0"` assigns a label to this contract instance for easy - identification +- `--label "local0.1.0"` assigns a label to this contract instance for easy identification - `--gas 1000000` sets the gas limit for the transaction - `-y` automatically accepts the transaction without prompting for confirmation - `--chain-id=docs-chain-1` specifies the chain ID of the blockchain @@ -227,9 +222,7 @@ The output lists all contracts instantiated from the specified code ID: ```json { - "contracts": [ - "wasm1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrss5maay" - ], + "contracts": ["wasm1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrss5maay"], "pagination": { "next_key": null, "total": "0" @@ -295,26 +288,24 @@ Output: } ``` -- Address: This is the address of the contract on the blockchain. It uniquely - identifies the contract and is used for interacting with it. -- Code ID: This is the reference to the stored WASM code from which the contract - was instantiated. -- Creator: This is the blockchain address of the account that initially - instantiated the contract. It indicates who created the contract instance. -- Admin: This is the address of the account that has administrative privileges - over the contract, such as the ability to execute migrations. This field is - optional and can be set during instantiation. -- Label: This is an optional field used to give a human-readable label to the - contract. It helps in identifying the contract instance, especially when - multiple instances of the same code are deployed. -- Created: This section provides details about the transaction in which the - contract was instantiated, including the block height at which the contract - was created and the index of the transaction within the block. -- IBC Port ID: This is the Port ID for Inter-Blockchain Communication - [IBC](../../ibc.mdx). If the contract is set up to interact with other - blockchains via IBC, this field will contain the relevant port ID. -- Extention: This is is an extension point to store custom metadata within the - persistence model +- Address: This is the address of the contract on the blockchain. It uniquely identifies the + contract and is used for interacting with it. +- Code ID: This is the reference to the stored WASM code from which the contract was instantiated. +- Creator: This is the blockchain address of the account that initially instantiated the contract. + It indicates who created the contract instance. +- Admin: This is the address of the account that has administrative privileges over the contract, + such as the ability to execute migrations. This field is optional and can be set during + instantiation. +- Label: This is an optional field used to give a human-readable label to the contract. It helps in + identifying the contract instance, especially when multiple instances of the same code are + deployed. +- Created: This section provides details about the transaction in which the contract was + instantiated, including the block height at which the contract was created and the index of the + transaction within the block. +- IBC Port ID: This is the Port ID for Inter-Blockchain Communication [IBC](../../ibc.mdx). If the + contract is set up to interact with other blockchains via IBC, this field will contain the + relevant port ID. +- Extention: This is is an extension point to store custom metadata within the persistence model ## Instantiation with Predictable Address @@ -344,8 +335,8 @@ echo "* Predictable contract address: $CONTRACT_PREDICTABLE" ### Query contracts by code id -You can get a list of contracts instantiated from a specific Code ID, by running -the following command: +You can get a list of contracts instantiated from a specific Code ID, by running the following +command: ```sh wasmd q wasm list-contract-by-code $CODE_ID @@ -353,8 +344,8 @@ wasmd q wasm list-contract-by-code $CODE_ID ### Query contracts by creator -You can get a list of contracts instantiated from a specific creator, by running -the following command: +You can get a list of contracts instantiated from a specific creator, by running the following +command: ```sh wasmd q wasm list-contracts-by-creator $ALICE_ADDR @@ -433,8 +424,7 @@ wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json | jq ### Query contract history -You can query the history entries for a contract by running the following -command: +You can query the history entries for a contract by running the following command: ```sh wasmd q wasm contract-history $CONTRACT -o json | jq @@ -478,9 +468,9 @@ Output: ### Set contract admin -The admin is the only address that can migrate a contract. The admin can be -updated by the current admin with the following command. In this case, the admin -is updated from Alice's address to Bob's address. +The admin is the only address that can migrate a contract. The admin can be updated by the current +admin with the following command. In this case, the admin is updated from Alice's address to Bob's +address. ```sh wasmd tx wasm set-contract-admin \ @@ -494,8 +484,7 @@ wasmd tx wasm set-contract-admin \ ### Clear contract admin -You can clear the admin address from a contract. This action prevents any -further migration. +You can clear the admin address from a contract. This action prevents any further migration. ```sh wasmd tx wasm clear-contract-admin \ diff --git a/src/pages/wasmd/getting-started/run-node.mdx b/src/pages/wasmd/getting-started/run-node.mdx index e2fd9c67..f0747c40 100644 --- a/src/pages/wasmd/getting-started/run-node.mdx +++ b/src/pages/wasmd/getting-started/run-node.mdx @@ -3,13 +3,13 @@ import { Callout } from "nextra/components"; # Run A Node For detailed instructions on running a node, please refer to -[this tutorial](https://tutorials.cosmos.network/tutorials/3-run-node/). Below, -we provide a quick setup script to get your node up and running. +[this tutorial](https://tutorials.cosmos.network/tutorials/3-run-node/). Below, we provide a quick +setup script to get your node up and running. - Make sure to remove the `.wasmd` folder before starting this setup. The - `.wasmd` folder is usually located in your home directory and contains all the - data related to the chain. Leaving it might cause conflicts or errors. + Make sure to remove the `.wasmd` folder before starting this setup. The `.wasmd` folder is usually + located in your home directory and contains all the data related to the chain. Leaving it might + cause conflicts or errors. ## Setup Node diff --git a/src/pages/wasmd/getting-started/setup.mdx b/src/pages/wasmd/getting-started/setup.mdx index 8df02942..57e96517 100644 --- a/src/pages/wasmd/getting-started/setup.mdx +++ b/src/pages/wasmd/getting-started/setup.mdx @@ -4,9 +4,8 @@ import { Callout } from "nextra/components"; ## Install Go -To build and install Wasmd, Go is required. If you haven't installed Go yet, you -can set it up by visiting the -[Go download and install page](https://go.dev/doc/install). +To build and install Wasmd, Go is required. If you haven't installed Go yet, you can set it up by +visiting the [Go download and install page](https://go.dev/doc/install). The latest version of wasmd requires `go version v1.21`. @@ -37,6 +36,6 @@ wasmd version ``` - Running a node on Windows OS is not supported yet. You can build a wasmd - client for Windows using `make build-windows-client`. + Running a node on Windows OS is not supported yet. You can build a wasmd client for Windows using + `make build-windows-client`.