packet.gno
3.49 Kb · 139 lines
1package transfer
2
3import (
4 "strings"
5
6 "gno.land/p/aib/encoding/proto"
7 "gno.land/p/nt/ufmt/v0"
8 "gno.land/p/onbloc/int256"
9)
10
11// FungibleTokenPacketData defines a struct for the packet payload
12// See FungibleTokenPacketData spec:
13// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures
14type FungibleTokenPacketData struct {
15 // the token denomination to be transferred
16 Denom string
17 // the token amount to be transferred
18 Amount string
19 // the sender address
20 Sender string
21 // the recipient address on the destination chain
22 Receiver string
23 // optional memo
24 Memo string
25}
26
27// NewFungibleTokenPacketData constructs a new FungibleTokenPacketData instance
28func NewFungibleTokenPacketData(
29 denom string, amount string,
30 sender, receiver string,
31 memo string,
32) FungibleTokenPacketData {
33 return FungibleTokenPacketData{
34 Denom: denom,
35 Amount: amount,
36 Sender: sender,
37 Receiver: receiver,
38 Memo: memo,
39 }
40}
41
42// ProtoMarshal returns the protobuf encoding of f.
43//
44// message FungibleTokenPacketData {
45// string denom = 1;
46// string amount = 2;
47// string sender = 3;
48// string receiver = 4;
49// string memo = 5;
50// }
51func (f *FungibleTokenPacketData) ProtoMarshal() (buf []byte) {
52 // Field 1: denom (length-delimited)
53 buf = proto.AppendLengthDelimited(buf, 1, []byte(f.Denom))
54
55 // Field 2: amount (length-delimited)
56 buf = proto.AppendLengthDelimited(buf, 2, []byte(f.Amount))
57
58 // Field 3: sender (length-delimited)
59 buf = proto.AppendLengthDelimited(buf, 3, []byte(f.Sender))
60
61 // Field 4: receiver (length-delimited)
62 buf = proto.AppendLengthDelimited(buf, 4, []byte(f.Receiver))
63
64 // Field 5: memo (length-delimited)
65 buf = proto.AppendLengthDelimited(buf, 5, []byte(f.Memo))
66
67 return
68}
69
70// ProtoUnmarshal reads the protobuf encoded bz into f.
71//
72// message FungibleTokenPacketData {
73// string denom = 1;
74// string amount = 2;
75// string sender = 3;
76// string receiver = 4;
77// string memo = 5;
78// }
79func (f *FungibleTokenPacketData) ProtoUnmarshal(bz []byte) error {
80 var pos int
81 for pos < len(bz) {
82 // Read field tag (key)
83 key, newPos, err := proto.DecodeVarint(bz, pos)
84 if err != nil {
85 return ufmt.Errorf("error reading field tag: %v", err)
86 }
87 pos = newPos
88
89 fieldNum := key >> 3
90 wireType := key & 0x07
91
92 if wireType != 2 { // All fields are strings (wire type 2)
93 return ufmt.Errorf("unexpected wire type %d for field %d", wireType, fieldNum)
94 }
95
96 // Read string value
97 value, newPos, err := proto.DecodeString(bz, pos)
98 if err != nil {
99 return ufmt.Errorf("error reading string value: %v", err)
100 }
101 pos = newPos
102
103 // Assign to appropriate field
104 switch fieldNum {
105 case 1:
106 f.Denom = value
107 case 2:
108 f.Amount = value
109 case 3:
110 f.Sender = value
111 case 4:
112 f.Receiver = value
113 case 5:
114 f.Memo = value
115 default:
116 return ufmt.Errorf("unknown field aren't authorized in FungibleTokenPacketData")
117 }
118 }
119 return nil
120}
121
122// ValidateBasic is used for validating the token transfer.
123func (f FungibleTokenPacketData) ValidateBasic() error {
124 amount, err := int256.FromDecimal(f.Amount)
125 if err != nil {
126 return ufmt.Errorf("unable to parse transfer amount %q: %v", f.Amount, err)
127 }
128 if amount.Sign() != 1 {
129 return ufmt.Errorf("amount must be strictly positive: got %s", amount)
130 }
131 if strings.TrimSpace(f.Sender) == "" {
132 return ufmt.Errorf("sender address cannot be blank")
133 }
134 if strings.TrimSpace(f.Receiver) == "" {
135 return ufmt.Errorf("receiver address cannot be blank")
136 }
137 denom := ExtractDenomFromPath(f.Denom)
138 return denom.ValidateBasic()
139}