Skip to content

Commit 0f19bc0

Browse files
committed
Complete docs for current state (pre-762)
1 parent 874f8bf commit 0f19bc0

File tree

1 file changed

+80
-23
lines changed

1 file changed

+80
-23
lines changed

IBC.md

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,16 @@ pub struct IbcEndpoint {
126126

127127
Note that neither `counterparty_version` nor `counterparty_endpoint` is set in
128128
`ibc_channel_open` for chain A. Chain B should enforce any
129-
`counterparty_version` constraints in `ibc_channel_open`. (So test if the field
130-
is `None` before enforcing any logic).
129+
`counterparty_version` constraints in `ibc_channel_open`. Chain A must enforce
130+
`counterparty_version` or `counterparty_endpoint` restrictions in
131+
`ibc_channel_connect`.
131132

132-
You should save any state related to `counterparty_endpoint` only in
133-
`ibc_channel_connect` when it is fixed.
133+
(Just test if the `counterparty_version` field is `Some(x)` in both calls and
134+
then enforce the counterparty restrictions if set. That will check these once at
135+
the proper place for both chain A and chain B).
136+
137+
You should save any state only in `ibc_channel_connect` once the channel has
138+
been approved by the remote side.
134139

135140
#### Channel Connect
136141

@@ -150,7 +155,10 @@ pub fn ibc_channel_connect(
150155

151156
At this point, it is expected that the contract updates its internal state and
152157
may return `CosmosMsg` in the `Reponse` to interact with other contracts, just
153-
like in `execute`.
158+
like in `execute`. In particular, you will most likely want to store the local
159+
channel_id (`channel.endpoint.channel_id`) in the contract's storage, so it
160+
knows what open channels it has (and can expose those via queries or maintain
161+
state for each one).
154162

155163
Once this has been called, you may expect to send and receive any number of
156164
packets with the contract. The packets will only stop once the channel is closed
@@ -169,9 +177,9 @@ pub enum IbcMsg {
169177
}
170178
```
171179

172-
Once a channel is closed, due to error, our request, or request of the other
173-
side, the following callback is made on the contract, which allows it to take
174-
appropriate cleanup action:
180+
Once a channel is closed, whether due to an IBC error, at our request, or at the
181+
request of the other side, the following callback is made on the contract, which
182+
allows it to take appropriate cleanup action:
175183

176184
```rust
177185
#[entry_point]
@@ -229,6 +237,13 @@ pub enum IbcMsg {
229237
}
230238
```
231239

240+
For the content of the `data` field, we recommend that you model it on the
241+
format of `ExecuteMsg` (an enum with serde) and encode it via
242+
`cosmwasm_std::to_binary(&packet_msg)?`. This is the approach for a new protocol
243+
you develop with cosmwasm contracts. If you are working with an existing
244+
protocol, please read their spec and create the proper type along with JSON or
245+
Protobuf encoders for it as the protocol requires.
246+
232247
#### Receiving a Packet
233248

234249
After a contract on chain A sends a packet, it is generally processed by the
@@ -237,9 +252,6 @@ the following callback on chain B:
237252

238253
```rust
239254
#[entry_point]
240-
/// we look for a the proper reflect contract to relay to and send the message
241-
/// We cannot return any meaningful response value as we do not know the response value
242-
/// of execution. We just return ok if we dispatched, error if we failed to dispatch
243255
pub fn ibc_packet_receive(
244256
deps: DepsMut,
245257
env: Env,
@@ -251,16 +263,20 @@ Note the different return response here (`IbcReceiveResponse` rather than
251263
`IbcBasicResponse`)? This is because it has an extra field
252264
`acknowledgement: Binary`, which must be filled out. That is the response bytes
253265
that will be returned to the original contract, informing it of failure or
254-
success.
266+
success. (Note: this is vague as it will be refined in the next PR)
255267

256268
Here is the
257269
[`IbcPacket` structure](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta4/packages/std/src/ibc.rs#L129-L146)
258270
that contains all information needed to process the receipt. You can generally
259271
ignore timeout (this is only called if it hasn't yet timed out) and sequence
260272
(which is used by the IBC framework to avoid duplicates). I generally use
261273
`dest.channel_id` like `info.sender` to authenticate the packet, and parse
262-
`data` into a `PacketMsg` structure. After that you can process this more or
263-
less like in `execute`.
274+
`data` into a `PacketMsg` structure, using the same encoding rules as we
275+
discussed in the last section.
276+
277+
After that you can process `PacketMsg` more or less like an `ExecuteMsg`,
278+
including calling into other contracts. The only major difference is that you
279+
must return Acknowledgement bytes in the protocol-specified format
264280

265281
```rust
266282
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -283,13 +299,38 @@ pub struct IbcPacket {
283299
}
284300
```
285301

286-
TODO: explain how to handle this
287-
288-
TODO: document the default JSON encoding used in ICS20
289-
290302
TODO: explain how to handle/parse errors (As part of
291303
https://github.com/CosmWasm/cosmwasm/issues/762)
292304

305+
##### Standard Acknowledgement Format
306+
307+
Although the ICS spec leave the actual acknowledgement as opaque bytes, it does
308+
provide a recommendation for the format you can use, allowing contracts to
309+
easily differentiate between success and error (and allow IBC explorers to label
310+
such packets without knowing every protocol).
311+
312+
It is defined as part of the
313+
[ICS4 - Channel Spec](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/ibc/core/channel/v1/channel.proto#L134-L147).
314+
315+
```proto
316+
message Acknowledgement {
317+
// response contains either a result or an error and must be non-empty
318+
oneof response {
319+
bytes result = 21;
320+
string error = 22;
321+
}
322+
}
323+
```
324+
325+
Although it suggests this is a Protobuf object, the ICS spec doesn't define
326+
whether to encode it as JSON or Protobuf. In the ICS20 implementation, this is
327+
JSON encoded when returned from a contract. Given that, we will consider this
328+
structure, JSON-encoded, to be the "standard" acknowledgement format.
329+
330+
You can find a
331+
[CosmWasm-compatible definition of this format](https://github.com/CosmWasm/cosmwasm-plus/blob/v0.6.0-beta1/contracts/cw20-ics20/src/ibc.rs#L52-L72)
332+
as part of the `cw20-ics20` contract.
333+
293334
#### Receiving an Acknowledgement
294335

295336
If chain B successfully received the packet (even if the contract returned an
@@ -309,8 +350,10 @@ The
309350
[`IbcAcknowledgement` structure](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta4/packages/std/src/ibc.rs#L148-L152)
310351
contains both the original packet that was sent as well as the acknowledgement
311352
bytes returned from executing the remote contract. You can use the
312-
`original_packet` to map it the proper handler, and parse the `acknowledgement`
313-
there:
353+
`original_packet` to
354+
[map it the proper handler](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta4/contracts/ibc-reflect-send/src/ibc.rs#L114-L138)
355+
(after parsing your custom data format), and parse the `acknowledgement` there,
356+
to determine how to respond:
314357

315358
```rust
316359
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -320,7 +363,18 @@ pub struct IbcAcknowledgement {
320363
}
321364
```
322365

323-
TODO: explain how to handle this
366+
On success, you will want to commit the pending state. For some contracts like
367+
`cw20-ics20`, you accept the tokens before sending the packet, so no need to
368+
commit any more state. On other contracts, you may want to store the data
369+
returned as part of the acknowledgement (like
370+
[storing the remote address after calling "WhoAmI"](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta4/contracts/ibc-reflect-send/src/ibc.rs#L157-L192)
371+
in our simple `ibc-reflect` example.
372+
373+
On error, you will want to revert any state that was pending based on the
374+
packet. For example, in ics20, if the
375+
[remote chain rejects the packet](https://github.com/CosmWasm/cosmwasm-plus/blob/v0.6.0-beta1/contracts/cw20-ics20/src/ibc.rs#L246),
376+
we must
377+
[return the funds to the original sender](https://github.com/CosmWasm/cosmwasm-plus/blob/v0.6.0-beta1/contracts/cw20-ics20/src/ibc.rs#L291-L317).
324378

325379
#### Handling Timeouts
326380

@@ -346,8 +400,11 @@ pub fn ibc_packet_timeout(
346400

347401
It is generally handled just like the error case in `ibc_packet_ack`, reverting
348402
the state change from sending the packet (eg. if we send tokens over ICS20, both
349-
an ack failure as well as a timeout will return those tokens to the original
350-
sender).
403+
[an ack failure](https://github.com/CosmWasm/cosmwasm-plus/blob/v0.6.0-beta1/contracts/cw20-ics20/src/ibc.rs#L246)
404+
as well as
405+
[a timeout](https://github.com/CosmWasm/cosmwasm-plus/blob/v0.6.0-beta1/contracts/cw20-ics20/src/ibc.rs#L258)
406+
will return those tokens to the original sender. In fact they both dispatch to
407+
the same `on_packet_failure` function).
351408

352409
Note that like `ibc_packet_ack`, we get the original packet we sent, which must
353410
contain all information needed to revert itself. Thus the ICS20 packet contains

0 commit comments

Comments
 (0)