From 817befb99a1cd30b6b487a82dff5251a4ceb2508 Mon Sep 17 00:00:00 2001 From: Sean McGary Date: Mon, 9 Sep 2024 11:53:57 -0500 Subject: [PATCH] Better numeric parsing --- .../eigenState/stakerShares/stakerShares.go | 42 ++++++++--- .../stakerShares/stakerShares_test.go | 70 +++++++++++++++++++ 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/internal/eigenState/stakerShares/stakerShares.go b/internal/eigenState/stakerShares/stakerShares.go index f347de73..7c10d2d9 100644 --- a/internal/eigenState/stakerShares/stakerShares.go +++ b/internal/eigenState/stakerShares/stakerShares.go @@ -37,6 +37,7 @@ type AccumulatedStateChange struct { Strategy string Shares *uint256.Int BlockNumber uint64 + IsNegative bool } type StakerSharesDiff struct { @@ -109,6 +110,11 @@ func parseLogOutputForDepositEvent(outputDataStr string) (*depositOutputData, er decoder.UseNumber() err := decoder.Decode(&outputData) + if err != nil { + return nil, err + } + outputData.Staker = strings.ToLower(outputData.Staker) + outputData.Strategy = strings.ToLower(outputData.Strategy) return outputData, err } @@ -143,22 +149,35 @@ func (ss *StakerSharesModel) handleStakerDepositEvent(log *storage.TransactionLo }, nil } +type podSharesUpdatedOutputData struct { + SharesDelta json.Number `json:"sharesDelta"` +} + +func parseLogOutputForPodSharesUpdatedEvent(outputDataStr string) (*podSharesUpdatedOutputData, error) { + outputData := &podSharesUpdatedOutputData{} + decoder := json.NewDecoder(strings.NewReader(outputDataStr)) + decoder.UseNumber() + + err := decoder.Decode(&outputData) + if err != nil { + return nil, err + } + return outputData, err +} + func (ss *StakerSharesModel) handlePodSharesUpdatedEvent(log *storage.TransactionLog) (*AccumulatedStateChange, error) { arguments, err := ss.ParseLogArguments(log) if err != nil { return nil, err } - outputData, err := ss.ParseLogOutput(log) + outputData, err := parseLogOutputForPodSharesUpdatedEvent(log.OutputData) if err != nil { return nil, err } - staker := arguments[0].Value.(string) + staker := strings.ToLower(arguments[0].Value.(string)) - sharesDeltaStr, ok := outputData["sharesDelta"].(string) - if !ok { - return nil, xerrors.Errorf("sharesDelta not found in event") - } + sharesDeltaStr := outputData.SharesDelta.String() sharesDelta, err := uint256.FromDecimal(sharesDeltaStr) if err != nil { @@ -199,12 +218,14 @@ func (ss *StakerSharesModel) handleM1StakerWithdrawals(log *storage.TransactionL return &AccumulatedStateChange{ Staker: stakerAddress, Strategy: outputData.Strategy, - Shares: shares.Neg(shares), + Shares: shares, BlockNumber: log.BlockNumber, + IsNegative: true, }, nil } func (ss *StakerSharesModel) handleM2StakerWithdrawals(log *storage.TransactionLog) (*AccumulatedStateChange, error) { + // TODO(seanmcgary): come back to this... return nil, nil } @@ -251,7 +272,12 @@ func (ss *StakerSharesModel) GetStateTransitions() (types.StateTransitions[Accum record = parsedRecord ss.stateAccumulator[log.BlockNumber][slotId] = record } else { - record.Shares = record.Shares.Add(record.Shares, parsedRecord.Shares) + if record.IsNegative { + record.Shares = record.Shares.Sub(record.Shares, parsedRecord.Shares) + } else { + record.Shares = record.Shares.Add(record.Shares, parsedRecord.Shares) + } + } return record, nil diff --git a/internal/eigenState/stakerShares/stakerShares_test.go b/internal/eigenState/stakerShares/stakerShares_test.go index 790ea901..12bcf716 100644 --- a/internal/eigenState/stakerShares/stakerShares_test.go +++ b/internal/eigenState/stakerShares/stakerShares_test.go @@ -12,6 +12,7 @@ import ( "go.uber.org/zap" "gorm.io/gorm" "math/big" + "strings" "testing" "time" ) @@ -84,13 +85,82 @@ func Test_StakerSharesState(t *testing.T) { expectedShares, _ := uint256.FromDecimal("159925690037480381") assert.Equal(t, expectedShares, typedChange.Shares) + assert.Equal(t, "0xaf6fb48ac4a60c61a64124ce9dc28f508dc8de8d", typedChange.Staker) + assert.Equal(t, "0x7d704507b76571a51d9cae8addabbfd0ba0e63d3", typedChange.Strategy) teardown(model) }) t.Run("Should capture a staker share M1 Withdrawal", func(t *testing.T) { + esm := stateManager.NewEigenStateManager(l, grm) + blockNumber := uint64(200) + log := storage.TransactionLog{ + TransactionHash: "some hash", + TransactionIndex: big.NewInt(200).Uint64(), + BlockNumber: blockNumber, + Address: cfg.GetContractsMapForEnvAndNetwork().StrategyManager, + Arguments: `[{"Name": "depositor", "Type": "address", "Value": null, "Indexed": false}, {"Name": "nonce", "Type": "uint96", "Value": null, "Indexed": false}, {"Name": "strategy", "Type": "address", "Value": null, "Indexed": false}, {"Name": "shares", "Type": "uint256", "Value": null, "Indexed": false}]`, + EventName: "ShareWithdrawalQueued", + LogIndex: big.NewInt(500).Uint64(), + OutputData: `{"nonce": 0, "shares": 246393621132195985, "strategy": "0x298afb19a105d59e74658c4c334ff360bade6dd2", "depositor": "0x9c01148c464cf06d135ad35d3d633ab4b46b9b78"}`, + CreatedAt: time.Time{}, + UpdatedAt: time.Time{}, + DeletedAt: time.Time{}, + } + + model, err := NewStakerSharesModel(esm, grm, cfg.Network, cfg.Environment, l, cfg) + err = model.InitBlockProcessing(blockNumber) + assert.Nil(t, err) + + change, err := model.HandleStateChange(&log) + assert.Nil(t, err) + assert.NotNil(t, change) + + typedChange := change.(*AccumulatedStateChange) + + expectedShares, _ := uint256.FromDecimal("246393621132195985") + assert.Equal(t, expectedShares, typedChange.Shares) + assert.Equal(t, "0x9c01148c464cf06d135ad35d3d633ab4b46b9b78", typedChange.Staker) + assert.Equal(t, "0x298afb19a105d59e74658c4c334ff360bade6dd2", typedChange.Strategy) + + teardown(model) }) t.Run("Should capture staker EigenPod shares", func(t *testing.T) { + esm := stateManager.NewEigenStateManager(l, grm) + blockNumber := uint64(200) + log := storage.TransactionLog{ + TransactionHash: "some hash", + TransactionIndex: big.NewInt(300).Uint64(), + BlockNumber: blockNumber, + Address: cfg.GetContractsMapForEnvAndNetwork().EigenpodManager, + Arguments: `[{"Name": "podOwner", "Type": "address", "Value": "0x0808D4689B347D499a96f139A5fC5B5101258406"}, {"Name": "sharesDelta", "Type": "int256", "Value": ""}]`, + EventName: "PodSharesUpdated", + LogIndex: big.NewInt(600).Uint64(), + OutputData: `{"sharesDelta": 32000000000000000000}`, + CreatedAt: time.Time{}, + UpdatedAt: time.Time{}, + DeletedAt: time.Time{}, + } + + model, err := NewStakerSharesModel(esm, grm, cfg.Network, cfg.Environment, l, cfg) + + err = model.InitBlockProcessing(blockNumber) + assert.Nil(t, err) + + change, err := model.HandleStateChange(&log) + assert.Nil(t, err) + assert.NotNil(t, change) + typedChange := change.(*AccumulatedStateChange) + + expectedShares, _ := uint256.FromDecimal("32000000000000000000") + assert.Equal(t, expectedShares, typedChange.Shares) + assert.Equal(t, strings.ToLower("0x0808D4689B347D499a96f139A5fC5B5101258406"), typedChange.Staker) + assert.Equal(t, "0xbeac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0", typedChange.Strategy) + + teardown(model) + }) + t.Run("Should capture M2 migrated withdrawals", func(t *testing.T) { + t.Skip("M2 migration is not yet implemented") }) }