Skip to content

Instantly share code, notes, and snippets.

@csknk
Created July 17, 2025 14:40
Show Gist options
  • Save csknk/d494abc86194ec6d17000aff80fead42 to your computer and use it in GitHub Desktop.
Save csknk/d494abc86194ec6d17000aff80fead42 to your computer and use it in GitHub Desktop.
Go Challenge Solana Encoding
package main
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"fmt"
"strings"
)
var (
discriminator = MustUnhex("e445a52e51cb9a1d")
eventDiscriminator = getEventDiscriminator("PacketSentEvent") // 005ca7c98b2eab52
)
func getEventDiscriminator(evtName string) []byte {
payload := fmt.Appendf(nil, "event:%s", evtName)
return sha256hash(payload)[0:8]
}
func MustUnhex(hexString string) []byte {
// More concise, improves readability without changing behaviour
hexString = strings.TrimPrefix(hexString, "0x")
h, err := hex.DecodeString(hexString)
if err != nil {
panic(err)
}
return h
}
func sha256hash(data ...[]byte) []byte {
h := sha256.New()
for _, d := range data {
h.Write(d)
}
return h.Sum(nil)
}
type PacketSentEvent struct {
EncodedPayload []byte
Options []byte
SendLibrary []byte
}
type InstructionData []byte
func (data InstructionData) IsPacketSentEvent() bool {
// should probalby include some guards here: check data is not nil, and has the sufficient length...
if bytes.Equal(data[:8], discriminator) && bytes.Equal(data[8:16], eventDiscriminator) {
return true
}
return false
}
// ExtractPacketSentEvent --
// After some experimentation it appears that the data we are trying to unpack is structured
// like this: [u32 length][EncodedPayload][u32 length][Options][SendLibrary - fixed length, 32 bytes]
func (data InstructionData) ExtractPacketSentEvent() (PacketSentEvent, error) {
buf := bytes.NewReader(data[16:])
readBytes := func() ([]byte, error) {
var length uint32
// read the length variable which denotes the size of the following field
if err := binary.Read(buf, binary.LittleEndian, &length); err != nil {
return nil, err
}
bytes := make([]byte, length)
// read the required n bytes from the buffer
if _, err := buf.Read(bytes); err != nil {
return nil, err
}
return bytes, nil
}
encodedPayload, err := readBytes()
if err != nil {
return PacketSentEvent{}, fmt.Errorf("reading EncodedPayload: %w", err)
}
options, err := readBytes()
if err != nil {
return PacketSentEvent{}, fmt.Errorf("reading Options: %w", err)
}
// Looks like the SendLibrary field has fixed-size: 32 bytes
// cursor is at the correct offset, so just read the bytes
sendLibrary := make([]byte, 32)
if _, err := buf.Read(sendLibrary); err != nil {
return PacketSentEvent{}, fmt.Errorf("reading SendLibrary: %w", err)
}
return PacketSentEvent{
EncodedPayload: encodedPayload,
Options: options,
SendLibrary: sendLibrary,
}, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment