Skip to content

Commit 81acc6e

Browse files
committed
improve ibc transfer script building and parsing
1 parent fe9c8e7 commit 81acc6e

1 file changed

Lines changed: 53 additions & 7 deletions

File tree

x/btcbridge/types/ibc.go

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
package types
22

33
import (
4+
"encoding/binary"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
49
"github.com/btcsuite/btcd/txscript"
510
"github.com/btcsuite/btcd/wire"
11+
12+
errorsmod "cosmossdk.io/errors"
13+
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
614
)
715

816
const (
@@ -21,22 +29,29 @@ const (
2129

2230
// BuildIBCTransferScript builds the script for IBC transfer with the given channel and recipient address
2331
func BuildIBCTransferScript(channelId string, recipient string) ([]byte, error) {
32+
// unprefix channel id
33+
unprefixedChannelId, err := GetUnprefixedChannelId(channelId)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
// build OP_RETURN script
2439
scriptBuilder := txscript.NewScriptBuilder()
2540
scriptBuilder.AddOp(txscript.OP_RETURN)
2641

2742
// add magic number
2843
scriptBuilder.AddOp(IBCTransferMagicNumber)
2944

3045
// add payload
31-
scriptBuilder.AddData([]byte(channelId)).AddData([]byte(recipient))
46+
scriptBuilder.AddData(unprefixedChannelId).AddData([]byte(recipient))
3247

3348
return scriptBuilder.Script()
3449
}
3550

3651
// GetIBCTransferScript gets the IBC transfer script from the given deposit tx
3752
func GetIBCTransferScript(depositTx *wire.MsgTx) []byte {
3853
for _, out := range depositTx.TxOut {
39-
if IsOpReturnOutput(out) && out.PkScript[1] == IBCTransferMagicNumber {
54+
if IsOpReturnOutput(out) && len(out.PkScript) > 1 && out.PkScript[1] == IBCTransferMagicNumber {
4055
return out.PkScript
4156
}
4257
}
@@ -48,21 +63,25 @@ func GetIBCTransferScript(depositTx *wire.MsgTx) []byte {
4863
func ParseIBCTransferScript(script []byte) (channelId string, recipient string, err error) {
4964
tokenizer := txscript.MakeScriptTokenizer(0, script)
5065
if !tokenizer.Next() || tokenizer.Err() != nil || tokenizer.Opcode() != txscript.OP_RETURN {
51-
return "", "", ErrInvalidIBCTransferScript
66+
return "", "", errorsmod.Wrap(ErrInvalidIBCTransferScript, "non OP_RETURN script")
5267
}
5368

5469
if !tokenizer.Next() || tokenizer.Err() != nil || tokenizer.Opcode() != IBCTransferMagicNumber {
55-
return "", "", ErrInvalidIBCTransferScript
70+
return "", "", errorsmod.Wrap(ErrInvalidIBCTransferScript, "failed to parse magic number")
5671
}
5772

5873
if !tokenizer.Next() || tokenizer.Err() != nil {
59-
return "", "", ErrInvalidIBCTransferScript
74+
return "", "", errorsmod.Wrap(ErrInvalidIBCTransferScript, "failed to parse channel id")
75+
}
76+
77+
if len(tokenizer.Data()) != 4 {
78+
return "", "", errorsmod.Wrap(ErrInvalidIBCTransferScript, "invalid channel id")
6079
}
6180

62-
channelId = string(tokenizer.Data())
81+
channelId = NormalizeChannelId(tokenizer.Data())
6382

6483
if !tokenizer.Next() || tokenizer.Err() != nil {
65-
return "", "", ErrInvalidIBCTransferScript
84+
return "", "", errorsmod.Wrap(ErrInvalidIBCTransferScript, "failed to parse recipient address")
6685
}
6786

6887
recipient = string(tokenizer.Data())
@@ -73,3 +92,30 @@ func ParseIBCTransferScript(script []byte) (channelId string, recipient string,
7392

7493
return
7594
}
95+
96+
// GetUnprefixedChannelId gets the channel id without prefix
97+
func GetUnprefixedChannelId(channelId string) ([]byte, error) {
98+
unprefixedChannelId, found := strings.CutPrefix(channelId, channeltypes.ChannelPrefix)
99+
if !found {
100+
return nil, channeltypes.ErrInvalidChannelIdentifier
101+
}
102+
103+
id, err := strconv.ParseUint(unprefixedChannelId, 10, 32)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
bz := make([]byte, 4)
109+
binary.BigEndian.PutUint32(bz, uint32(id))
110+
111+
return bz, nil
112+
}
113+
114+
// NormalizeChannelId normalizes the given channel id
115+
func NormalizeChannelId(unprefixedChannelId []byte) string {
116+
if len(unprefixedChannelId) != 4 {
117+
return ""
118+
}
119+
120+
return fmt.Sprintf("%s%d", channeltypes.ChannelPrefix, binary.BigEndian.Uint32(unprefixedChannelId))
121+
}

0 commit comments

Comments
 (0)