Skip to content

Commit

Permalink
feat: add sqllite db connection and userop data type
Browse files Browse the repository at this point in the history
  • Loading branch information
V00D00-child committed Jul 8, 2024
1 parent caa1e86 commit 6a77b0e
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 1 deletion.
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ require (
github.com/tyler-smith/go-bip32 v1.0.0
github.com/tyler-smith/go-bip39 v1.1.0
github.com/urfave/cli/v2 v2.27.2
gorm.io/driver/sqlite v1.5.6
gorm.io/gorm v1.25.10
)

require (
Expand Down Expand Up @@ -49,11 +51,14 @@ require (
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand All @@ -149,6 +151,10 @@ github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
Expand Down Expand Up @@ -177,6 +183,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
Expand Down Expand Up @@ -355,6 +363,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
Expand Down
25 changes: 25 additions & 0 deletions internal/data/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package data

import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)

func OpenConnection(isInMemory bool) (*gorm.DB, error) {
var db *gorm.DB
var err error

if isInMemory {
db, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
} else {
db, err = gorm.Open(sqlite.Open("betsy.db"), &gorm.Config{})
}

if err != nil {
return nil, err
}

db.AutoMigrate(&UserOpV7Hexify{})

return db, nil
}
279 changes: 279 additions & 0 deletions internal/data/userop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
package data

import (
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/transeptorlabs/betsy/contracts/entrypoint"
"github.com/transeptorlabs/betsy/internal/utils"
"gorm.io/gorm"
)

// UserOpV7Hexify is a struct used to store user operations in a database. Contains all EIP-4337 with all hex fields.
type UserOpV7Hexify struct {
gorm.Model // Embedding gorm.Model adds fields ID(primaryKey), CreatedAt, UpdatedAt, DeletedAt
UserOpHash string `gorm:"index;unique;not null"`
Sender string `json:"sender" mapstructure:"sender" validate:"required" gorm:"not null"`
Nonce string `json:"nonce" mapstructure:"nonce" validate:"required" gorm:"not null"`

// (optional)
Factory string `json:"factory" mapstructure:"factory" validate:"required"`
FactoryData string `json:"factoryData" mapstructure:"factoryData"`

CallData string `json:"callData" mapstructure:"callData" validate:"required" gorm:"not null"`
CallGasLimit string `json:"callGasLimit" mapstructure:"callGasLimit" validate:"required" gorm:"not null"`
VerificationGasLimit string `json:"verificationGasLimit" mapstructure:"verificationGasLimit" validate:"required" gorm:"not null"`
PreVerificationGas string `json:"preVerificationGas" mapstructure:"preVerificationGas" validate:"required" gorm:"not null" `
MaxFeePerGas string `json:"maxFeePerGas" mapstructure:"maxFeePerGas" validate:"required" gorm:"not null"`
MaxPriorityFeePerGas string `json:"maxPriorityFeePerGas" mapstructure:"maxPriorityFeePerGas" validate:"required" gorm:"not null"`

// (optional)
Paymaster string `json:"paymaster" mapstructure:"paymaster" validate:"required"`
PaymasterVerificationGasLimit string `json:"paymasterVerificationGasLimit" mapstructure:"paymasterVerificationGasLimit"`
PaymasterPostOpGasLimit string `json:"paymasterPostOpGasLimit" mapstructure:"paymasterPostOpGasLimit"`
PaymasterData string `json:"paymasterAndData" mapstructure:"paymasterAndData"`

Signature string `gorm:"not null" json:"signature" mapstructure:"signature"`
}

func (op *UserOpV7Hexify) BeforeCreate(tx *gorm.DB) (err error) {
ok, invalidAddress := op.IsValidAddresses()
if !ok {
return errors.New("can't save invalid eth address:" + invalidAddress)
}

err = op.SetUserOpHash()
if err != nil {
return err
}

return nil
}

func (op *UserOpV7Hexify) IsValidAddresses() (bool, string) {
isSenderAddress := common.IsHexAddress(op.Sender)
if !isSenderAddress {
return isSenderAddress, op.Sender
}

return true, ""
}

func (op *UserOpV7Hexify) SetUserOpHash() error {
op.UserOpHash = ""
return nil
}

func (op *UserOpV7Hexify) GetInitCode() ([]byte, error) {
if op.Factory == "0x" {
return []byte{}, nil
}

if op.FactoryData == "0x" {
return nil, errors.New("Got Factory but missing FactoryData")
}

factoryDecoded, err := hexutil.Decode(op.Factory)
if err != nil {
return nil, errors.New("factory (bytes) conversion failed")
}

factoryDataDecoded, err := hexutil.Decode(op.FactoryData)
if err != nil {
return nil, errors.New("factoryData (bytes) conversion failed")
}

concatenatedBytes := append(factoryDecoded, factoryDataDecoded...)

return concatenatedBytes, nil
}

func (op *UserOpV7Hexify) GetAccountGasLimits() ([32]byte, error) {
verificationGasLimitDecoded, err := hexutil.Decode(op.VerificationGasLimit)
if err != nil {
return [32]byte{}, errors.New("verificationGasLimit (bytes) conversion failed")
}

callGasLimitDecoded, err := hexutil.Decode(op.CallGasLimit)
if err != nil {
return [32]byte{}, errors.New("callGasLimit (bytes) conversion failed")
}

// Truncate if longer than 16 bytes or Pad with leading zeros if shorter than 16 bytes
verificationGasLimitDecodedPadded, err := utils.PadToBytes16(verificationGasLimitDecoded)
if err != nil {
return [32]byte{}, err
}

callGasLimitDecodedPadded, err := utils.PadToBytes16(callGasLimitDecoded)
if err != nil {
return [32]byte{}, err
}

// Concatenate the byte slices
concatenatedBytes := append(verificationGasLimitDecodedPadded, callGasLimitDecodedPadded...)

if len(concatenatedBytes) != 32 {
return [32]byte{}, errors.New("concatenatedBytes(verificationGasLimitDecodedPadded, callGasLimitDecodedPadded) is not equal to 32 bytes")
}

// Convert concatenatedBytes to [32]byte
var result [32]byte
copy(result[:], concatenatedBytes)

return result, nil
}

func (op *UserOpV7Hexify) GasFees() ([32]byte, error) {
maxPriorityFeePerGasDecoded, err := hexutil.Decode(op.MaxPriorityFeePerGas)
if err != nil {
return [32]byte{}, errors.New("maxPriorityFeePerGas (bytes) conversion failed")
}

maxFeePerGasDecoded, err := hexutil.Decode(op.MaxFeePerGas)
if err != nil {
return [32]byte{}, errors.New("maxFeePerGas (bytes) conversion failed")
}

// Truncate if longer than 16 bytes or Pad with leading zeros if shorter than 16 bytes
maxPriorityFeePerGasDecodedPadded, err := utils.PadToBytes16(maxPriorityFeePerGasDecoded)
if err != nil {
return [32]byte{}, err
}

maxFeePerGasDecodedPadded, err := utils.PadToBytes16(maxFeePerGasDecoded)
if err != nil {
return [32]byte{}, err
}

// Concatenate the byte slices
concatenatedBytes := append(maxPriorityFeePerGasDecodedPadded, maxFeePerGasDecodedPadded...)

if len(concatenatedBytes) != 32 {
return [32]byte{}, errors.New("concatenatedBytes(maxPriorityFeePerGasDecodedPadded, maxFeePerGasDecodedPadded) is not equal to 32 bytes")
}

// Convert concatenatedBytes to [32]byte
var result [32]byte
copy(result[:], concatenatedBytes)

return result, nil
}

func (op *UserOpV7Hexify) GetPaymasterAndData() ([]byte, error) {
if op.Paymaster == "0x" {
return []byte{}, nil
}

if op.PreVerificationGas == "0x" {
return nil, errors.New("Got Paymaster but missing PreVerificationGas")
}

if op.PaymasterPostOpGasLimit == "0x" {
return nil, errors.New("Got Paymaster but missing PaymasterPostOpGasLimit")
}

// Decode all paymaster values
paymasterDecoded, err := hexutil.Decode(op.Paymaster)
if err != nil {
return nil, errors.New("paymasterDecoded (bytes) conversion failed")
}

preVerificationGasDecoded, err := hexutil.Decode(op.PreVerificationGas)
if err != nil {
return []byte{}, errors.New("preVerificationGas (bytes) conversion failed")
}

paymasterPostOpGasLimitDecoded, err := hexutil.Decode(op.PaymasterPostOpGasLimit)
if err != nil {
return []byte{}, errors.New("paymasterPostOpGasLimit (bytes) conversion failed")
}

// Truncate if longer than 16 bytes or Pad with leading zeros if shorter than 16 bytes
preVerificationGasDecodedPadded, err := utils.PadToBytes16(preVerificationGasDecoded)
if err != nil {
return []byte{}, err
}

paymasterPostOpGasLimitDecodedPadded, err := utils.PadToBytes16(paymasterPostOpGasLimitDecoded)
if err != nil {
return []byte{}, err
}
concatenatedGasBytes := append(preVerificationGasDecodedPadded, paymasterPostOpGasLimitDecodedPadded...)

// Concatenate the byte slices
concatenatedPaymasterBytes := append(
paymasterDecoded,
concatenatedGasBytes...,
)

var paymasterDataDecoded []byte
if op.PaymasterData == "0x" {
paymasterDataDecoded = []byte{}
} else {
paymasterDataDecoded, err = hexutil.Decode(op.PaymasterData)
if err != nil {
return nil, errors.New("paymasterData (bytes) conversion failed")
}
}

return append(
concatenatedPaymasterBytes,
paymasterDataDecoded...,
), nil
}

func (op *UserOpV7Hexify) PackUserOp() (*entrypoint.PackedUserOperation, error) {
nonceDecoded, err := hexutil.DecodeBig(op.Nonce)
if err != nil {
return nil, errors.New("nonce (bigInt) conversion failed")
}

initCodeDecoded, err := op.GetInitCode()
if err != nil {
return nil, errors.New("nonce (bigInt) conversion failed")
}

callDataDecoded, err := hexutil.Decode(op.CallData)
if err != nil {
return nil, errors.New("calldata (bytes) conversion failed")
}

preVerificationGaseDecoded, err := hexutil.DecodeBig(op.PreVerificationGas)
if err != nil {
return nil, errors.New("preVerificationGas (bigInt) conversion failed")
}

accountGasLimitsDecoded, err := op.GetAccountGasLimits()
if err != nil {
return nil, errors.New("accountGasLimit (bytes 32) conversion failed")
}

gasFeesDecoded, err := op.GasFees()
if err != nil {
return nil, errors.New("gasFees (bytes 32) conversion failed")
}

paymasterAndDataDecoded, err := op.GetPaymasterAndData()
if err != nil {
return nil, errors.New("paymasterAndData (bytes) conversion failed")
}

signatureDecoded, err := hexutil.Decode(op.Signature)
if err != nil {
return nil, errors.New("signature (bytes) conversion failed")
}

return &entrypoint.PackedUserOperation{
Sender: common.HexToAddress(op.Sender),
Nonce: nonceDecoded,
InitCode: initCodeDecoded,
CallData: callDataDecoded,
AccountGasLimits: accountGasLimitsDecoded,
PreVerificationGas: preVerificationGaseDecoded,
GasFees: gasFeesDecoded,
PaymasterAndData: paymasterAndDataDecoded,
Signature: signatureDecoded,
}, nil
}
1 change: 1 addition & 0 deletions internal/mempool/mempool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package mempool
Loading

0 comments on commit 6a77b0e

Please sign in to comment.