Skip to content

Commit d1bff6f

Browse files
authored
Merge pull request #675 from CosmWasm/co/ibc-callbacks-funds
Add `Transfer` handling to `IBCDestinationCallbackMsg`
2 parents 0119e24 + 0b45ff7 commit d1bff6f

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed

types/ibc.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,21 @@ type IBCTimeoutCallbackMsg struct {
187187
type IBCDestinationCallbackMsg struct {
188188
Ack IBCAcknowledgement `json:"ack"`
189189
Packet IBCPacket `json:"packet"`
190+
// When the underlying packet is a successful transfer message, this field contains information about the transfer. Otherwise it is empty.
191+
//
192+
// This is always empty on chains using CosmWasm < 3.0
193+
Transfer *IBCTransferCallback `json:"transfer,omitempty"`
194+
}
195+
196+
type IBCTransferCallback struct {
197+
// The funds that were transferred.
198+
//
199+
// When the callback is executed, the transfer is completed already and the coins are now owned by the receiver.
200+
Funds Array[Coin] `json:"funds"`
201+
// Address of the receiver of the transfer. Since this is on the destination chain, this is a valid address.
202+
Receiver string `json:"receiver"`
203+
// Address of the sender of the transfer. Note that this is *not* a valid address on the destination chain.
204+
Sender string `json:"sender"`
190205
}
191206

192207
// TODO: test what the sdk Order.String() represents and how to parse back

types/json_size.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,37 @@ const (
108108
null int = 4 // null
109109
)
110110

111+
// ExpectedJSONSize returns the expected JSON size in bytes when using
112+
// json.Marshal with the given value.
113+
// Since JSON marshalling does not have a guaranteed output format,
114+
// this should be understood as a best guess and correct in most cases.
115+
// Do not use it when a precise value is required.
116+
func (c Coin) ExpectedJSONSize() int {
117+
// Denom string `json:"denom"`
118+
// Amount string `json:"amount"`
119+
return brackets +
120+
7 + colon + ExpectedJSONSizeString(c.Denom) + comma +
121+
8 + colon + ExpectedJSONSizeString(c.Amount)
122+
}
123+
124+
// ExpectedJSONSize returns the expected JSON size in bytes when using
125+
// json.Marshal with the given value.
126+
// Since JSON marshalling does not have a guaranteed output format,
127+
// this should be understood as a best guess and correct in most cases.
128+
// Do not use it when a precise value is required.
129+
//
130+
// This is a free-standing function because methods don't support constraining the generic type.
131+
func ExpectedJSONSizeArray[T ExpectedJSONSize](a Array[T]) int {
132+
out := brackets
133+
for i, v := range a {
134+
if i > 0 {
135+
out += comma
136+
}
137+
out += v.ExpectedJSONSize()
138+
}
139+
return out
140+
}
141+
111142
// ExpectedJSONSize returns the expected JSON size in bytes when using
112143
// json.Marshal with the given value.
113144
// Since JSON marshalling does not have a guaranteed output format,
@@ -440,7 +471,29 @@ func (t IBCSourceCallbackMsg) ExpectedJSONSize() int {
440471
func (t IBCDestinationCallbackMsg) ExpectedJSONSize() int {
441472
// Ack IBCAcknowledgement `json:"ack"`
442473
// Packet IBCPacket `json:"packet"`
443-
return brackets +
474+
// Transfer *IBCTransfer `json:"transfer,omitempty"`
475+
out := brackets +
444476
5 + colon + t.Ack.ExpectedJSONSize() + comma +
445477
8 + colon + t.Packet.ExpectedJSONSize()
478+
479+
if t.Transfer != nil {
480+
out += comma + 10 + colon + t.Transfer.ExpectedJSONSize()
481+
}
482+
483+
return out
484+
}
485+
486+
// ExpectedJSONSize returns the expected JSON size in bytes when using
487+
// json.Marshal with the given value.
488+
// Since JSON marshalling does not have a guaranteed output format,
489+
// this should be understood as a best guess and correct in most cases.
490+
// Do not use it when a precise value is required.
491+
func (t IBCTransferCallback) ExpectedJSONSize() int {
492+
// Funds Array[Coin] `json:"funds"`
493+
// Receiver string `json:"receiver"`
494+
// Sender string `json:"sender"`
495+
return brackets +
496+
7 + colon + ExpectedJSONSizeArray(t.Funds) + comma +
497+
10 + colon + ExpectedJSONSizeString(t.Receiver) + comma +
498+
8 + colon + ExpectedJSONSizeString(t.Sender)
446499
}

types/json_size_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,61 @@ func TestExpectedJSONSizeBool(t *testing.T) {
309309
})
310310
}
311311
}
312+
313+
func TestExpectedJSONSizeCoin(t *testing.T) {
314+
specs := map[string]struct {
315+
input Coin
316+
}{
317+
"zero": {
318+
input: NewCoin(0, "untrn"),
319+
},
320+
"three": {
321+
input: NewCoin(3, "uatom"),
322+
},
323+
"max": {
324+
input: Coin{
325+
// 2^256 - 1
326+
Amount: "115792089237316195423570985008687907853269984665640564039457584007913129639935",
327+
Denom: "untrn",
328+
},
329+
},
330+
}
331+
332+
for name, spec := range specs {
333+
t.Run(name, func(t *testing.T) {
334+
serialized, err := json.Marshal(spec.input)
335+
if err != nil {
336+
panic("Could not marshal input")
337+
}
338+
require.Equal(t, len(serialized), spec.input.ExpectedJSONSize())
339+
})
340+
}
341+
}
342+
343+
func TestExpectedJSONSizeArray(t *testing.T) {
344+
specs := map[string]struct {
345+
input Array[Coin]
346+
}{
347+
"empty": {
348+
input: Array[Coin]{},
349+
},
350+
"zero": {
351+
input: Array[Coin]{NewCoin(0, "untrn")},
352+
},
353+
"one": {
354+
input: Array[Coin]{NewCoin(1, "uatom")},
355+
},
356+
"big": {
357+
input: Array[Coin]{NewCoin(10000000, "untrn"), NewCoin(2000000, "uatom")},
358+
},
359+
}
360+
for name, spec := range specs {
361+
t.Run(name, func(t *testing.T) {
362+
serialized, err := json.Marshal(spec.input)
363+
if err != nil {
364+
panic("Could not marshal input")
365+
}
366+
require.Equal(t, len(serialized), ExpectedJSONSizeArray(spec.input))
367+
})
368+
}
369+
}

0 commit comments

Comments
 (0)