Skip to content

Commit

Permalink
make receiver address optional
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Oct 11, 2024
1 parent b3fabbd commit dd80da8
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 94 deletions.
6 changes: 4 additions & 2 deletions pkg/memo/codec_compact.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,10 @@ func (c *CodecCompact) unpackBytes(data []byte, output interface{}) (int, error)
}

// make a copy of the data
*pSlice = make([]byte, dataLen)
copy(*pSlice, data[c.lenBytes:c.lenBytes+dataLen])
if dataLen > 0 {
*pSlice = make([]byte, dataLen)
copy(*pSlice, data[c.lenBytes:c.lenBytes+dataLen])
}

return c.lenBytes + dataLen, nil
}
Expand Down
7 changes: 5 additions & 2 deletions pkg/memo/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package memo
// Fields is the interface for memo fields
type Fields interface {
// Pack encodes the memo fields
Pack(opCode, encodingFormat uint8) (byte, []byte, error)
Pack(opCode, encodingFormat, dataFlags uint8) ([]byte, error)

// Unpack decodes the memo fields
Unpack(opCode, encodingFormat, dataFlags uint8, data []byte) error

// Validate checks if the fields are valid
Validate(opCode uint8) error
Validate(opCode, dataFlags uint8) error

// DataFlags build the data flags for the fields
DataFlags() uint8
}
97 changes: 66 additions & 31 deletions pkg/memo/fields_v0.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import (

// Enum of the bit position of each memo fields
const (
bitPosPayload uint8 = 0 // payload
bitPosRevertAddress uint8 = 1 // revertAddress
bitPosAbortAddress uint8 = 2 // abortAddress
bitPosRevertMessage uint8 = 3 // revertMessage
bitPosReceiver uint8 = 0 // receiver
bitPosPayload uint8 = 1 // payload
bitPosRevertAddress uint8 = 2 // revertAddress
bitPosAbortAddress uint8 = 3 // abortAddress
bitPosRevertMessage uint8 = 4 // revertMessage
)

const (
// MaskFlagsReserved is the mask for reserved data flags
MaskFlagsReserved = 0b11110000
MaskFlagsReserved = 0b11100000
)

var _ Fields = (*FieldsV0)(nil)
Expand All @@ -37,23 +38,23 @@ type FieldsV0 struct {
}

// Pack encodes the memo fields
func (f *FieldsV0) Pack(opCode uint8, encodingFormat uint8) (byte, []byte, error) {
func (f *FieldsV0) Pack(opCode uint8, encodingFormat uint8, dataFlags uint8) ([]byte, error) {
// validate fields
err := f.Validate(opCode)
err := f.Validate(opCode, dataFlags)
if err != nil {
return 0, nil, err
return nil, err
}

codec, err := GetCodec(encodingFormat)
if err != nil {
return 0, nil, errors.Wrap(err, "unable to get codec")
return nil, errors.Wrap(err, "unable to get codec")
}

return f.packFields(codec)
return f.packFields(codec, dataFlags)
}

// Unpack decodes the memo fields
func (f *FieldsV0) Unpack(opCode uint8, encodingFormat uint8, dataFlags byte, data []byte) error {
func (f *FieldsV0) Unpack(opCode uint8, encodingFormat uint8, dataFlags uint8, data []byte) error {
codec, err := GetCodec(encodingFormat)
if err != nil {
return errors.Wrap(err, "unable to get codec")
Expand All @@ -64,13 +65,13 @@ func (f *FieldsV0) Unpack(opCode uint8, encodingFormat uint8, dataFlags byte, da
return err
}

return f.Validate(opCode)
return f.Validate(opCode, dataFlags)
}

// Validate checks if the fields are valid
func (f *FieldsV0) Validate(opCode uint8) error {
// check if receiver is empty
if crypto.IsEmptyAddress(f.Receiver) {
func (f *FieldsV0) Validate(opCode uint8, dataFlags uint8) error {
// receiver address must be a valid address
if zetamath.IsBitSet(dataFlags, bitPosReceiver) && crypto.IsEmptyAddress(f.Receiver) {
return errors.New("receiver address is empty")
}

Expand All @@ -79,6 +80,11 @@ func (f *FieldsV0) Validate(opCode uint8) error {
return errors.New("payload is not allowed for deposit operation")
}

// abort address must be a valid address
if zetamath.IsBitSet(dataFlags, bitPosAbortAddress) && !common.IsHexAddress(f.RevertOptions.AbortAddress) {
return errors.New("invalid abort address")
}

// revert message is not allowed when CallOnRevert is false
// 1. it's a good-to-have check to make the fields semantically correct.
// 2. unpacking won't hit this error as the codec will catch it earlier.
Expand All @@ -89,52 +95,81 @@ func (f *FieldsV0) Validate(opCode uint8) error {
return nil
}

// packFieldsV0 packs the memo fields for version 0
func (f *FieldsV0) packFields(codec Codec) (byte, []byte, error) {
// create data flags byte
var dataFlags byte
// DataFlags build the data flags from actual fields
func (f *FieldsV0) DataFlags() uint8 {
var dataFlags uint8

// add 'receiver' as the first argument
codec.AddArguments(ArgReceiver(f.Receiver))
// set 'receiver' flag if provided
if !crypto.IsEmptyAddress(f.Receiver) {
zetamath.SetBit(&dataFlags, bitPosReceiver)
}

// add 'payload' argument optionally
// set 'payload' flag if provided
if len(f.Payload) > 0 {
zetamath.SetBit(&dataFlags, bitPosPayload)
codec.AddArguments(ArgPayload(f.Payload))
}

// add 'revertAddress' argument optionally
// set 'revertAddress' flag if provided
if f.RevertOptions.RevertAddress != "" {
zetamath.SetBit(&dataFlags, bitPosRevertAddress)
}

// set 'abortAddress' flag if provided
if f.RevertOptions.AbortAddress != "" {
zetamath.SetBit(&dataFlags, bitPosAbortAddress)
}

// set 'revertMessage' flag if provided
if f.RevertOptions.CallOnRevert {
zetamath.SetBit(&dataFlags, bitPosRevertMessage)
}

return dataFlags
}

// packFieldsV0 packs the memo fields for version 0
func (f *FieldsV0) packFields(codec Codec, dataFlags uint8) ([]byte, error) {
// add 'receiver' argument optionally
if zetamath.IsBitSet(dataFlags, bitPosReceiver) {
codec.AddArguments(ArgReceiver(f.Receiver))
}

// add 'payload' argument optionally
if zetamath.IsBitSet(dataFlags, bitPosPayload) {
codec.AddArguments(ArgPayload(f.Payload))
}

// add 'revertAddress' argument optionally
if zetamath.IsBitSet(dataFlags, bitPosRevertAddress) {
codec.AddArguments(ArgRevertAddress(f.RevertOptions.RevertAddress))
}

// add 'abortAddress' argument optionally
abortAddress := common.HexToAddress(f.RevertOptions.AbortAddress)
if !crypto.IsEmptyAddress(abortAddress) {
zetamath.SetBit(&dataFlags, bitPosAbortAddress)
if zetamath.IsBitSet(dataFlags, bitPosAbortAddress) {
codec.AddArguments(ArgAbortAddress(abortAddress))
}

// add 'revertMessage' argument optionally
if f.RevertOptions.CallOnRevert {
zetamath.SetBit(&dataFlags, bitPosRevertMessage)
codec.AddArguments(ArgRevertMessage(f.RevertOptions.RevertMessage))
}

// pack the codec arguments into data
data, err := codec.PackArguments()
if err != nil { // never happens
return 0, nil, errors.Wrap(err, "failed to pack arguments")
return nil, errors.Wrap(err, "failed to pack arguments")

Check warning on line 161 in pkg/memo/fields_v0.go

View check run for this annotation

Codecov / codecov/patch

pkg/memo/fields_v0.go#L161

Added line #L161 was not covered by tests
}

return dataFlags, data, nil
return data, nil
}

// unpackFields unpacks the memo fields for version 0
func (f *FieldsV0) unpackFields(codec Codec, dataFlags byte, data []byte) error {
// add 'receiver' as the first argument
codec.AddArguments(ArgReceiver(&f.Receiver))
// add 'receiver' argument optionally
if zetamath.IsBitSet(dataFlags, bitPosReceiver) {
codec.AddArguments(ArgReceiver(&f.Receiver))
}

// add 'payload' argument optionally
if zetamath.IsBitSet(dataFlags, bitPosPayload) {
Expand Down
Loading

0 comments on commit dd80da8

Please sign in to comment.