diff --git a/periphery/bytes.go b/periphery/bytes.go new file mode 100644 index 0000000..c990775 --- /dev/null +++ b/periphery/bytes.go @@ -0,0 +1,76 @@ +package periphery + +import ( + "errors" + "github.com/ethereum/go-ethereum/common" + "math/big" +) + +const ( + AddressSize = 20 + FeeSize = 3 + NextOffset = AddressSize + FeeSize + PopOffset = NextOffset + AddressSize + MultiplePoolsLength = PopOffset + NextOffset +) + +func GetFirstPool(path []byte) []byte { + if len(path) == 0 || len(path) < PopOffset { + return nil + } + return path[0:PopOffset] +} + +func HasMultiplePools(path []byte) bool { + return len(path) >= MultiplePoolsLength +} + +func SkipToken(path []byte) []byte { + if len(path) < NextOffset { + return nil + } + + return path[NextOffset : len(path)-NextOffset] +} + +func ToAddress(bytes []byte, start *big.Int) (common.Address, error) { + offset := start.Int64() + + if len(bytes) < int(offset)+20 { + return common.Address{}, errors.New("toAddress outOfBounds") + } + + tempBigInt := new(big.Int).SetBytes(bytes[offset : offset+20]) + tempAddress := common.BigToAddress(tempBigInt) + + return tempAddress, nil +} + +func ToFee(bytes []byte, offset int) (*big.Int, error) { + if len(bytes) < offset+3 { + return nil, errors.New("toAddress outOfBounds") + } + var tempUint int64 + + tempUint = int64(bytes[offset]) << 16 + tempUint |= int64(bytes[offset+1]) << 8 + tempUint |= int64(bytes[offset+2]) + + return new(big.Int).SetInt64(tempUint), nil +} + +func DecodeFirstPool(path []byte) (common.Address, common.Address, *big.Int, error) { + token0, err := ToAddress(path, new(big.Int).SetInt64(0)) + if err != nil { + return common.Address{}, common.Address{}, nil, err + } + fee, err := ToFee(path, AddressSize) + if err != nil { + return common.Address{}, common.Address{}, nil, err + } + token1, err := ToAddress(path, new(big.Int).SetInt64(NextOffset)) + if err != nil { + return common.Address{}, common.Address{}, nil, err + } + return token0, token1, fee, nil +} diff --git a/periphery/bytes_test.go b/periphery/bytes_test.go new file mode 100644 index 0000000..08008e1 --- /dev/null +++ b/periphery/bytes_test.go @@ -0,0 +1,39 @@ +package periphery + +import ( + "encoding/hex" + "github.com/stretchr/testify/assert" + "strings" + "testing" +) + +func TestDecodeFirstPool(t *testing.T) { + input := "0x9e32b13ce7f2e80a01932b42553652e053d6ed8e000bb8c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + input = strings.TrimPrefix(input, "0x") + + // Convert the binary data to bytes + pathBytes, err := hex.DecodeString(input) + if err != nil { + t.Fatal(err) + } + + token0, token1, fee, err := DecodeFirstPool(pathBytes) + if err != nil { + t.Fatal(err) + } + + expected := struct { + Token0 string + Token1 string + Fee string + }{ + Token0: strings.ToLower("0x9E32b13ce7f2E80A01932B42553652E053D6ed8e"), + Token1: strings.ToLower("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + Fee: "3000", + } + + assert.Equal(t, false, HasMultiplePools(pathBytes)) + assert.Equal(t, expected.Token0, strings.ToLower(token0.String())) + assert.Equal(t, expected.Token1, strings.ToLower(token1.String())) + assert.Equal(t, expected.Fee, fee.String()) +}