Skip to content

Commit

Permalink
feat: add rewards-v2 support to staker-operator table generation (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmcgary committed Dec 20, 2024
2 parents 7de44a2 + e56eea4 commit 6a198ce
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 16 deletions.
2 changes: 1 addition & 1 deletion internal/multicall/multicall_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/stretchr/testify/assert"
)

const ethNodeURL = "https://eth.drpc.org"
const ethNodeURL = "https://eth.llamarpc.com/"

func setupClient(t *testing.T) *ethclient.Client {
client, err := ethclient.Dial(ethNodeURL)
Expand Down
2 changes: 1 addition & 1 deletion pkg/rewards/11_goldStaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (rc *RewardsCalculator) ListGoldStagingRowsForSnapshot(snapshotDate string)
rc.logger.Sugar().Errorw("Failed to render query template", "error", err)
return nil, err
}
res := rc.grm.Debug().Raw(query,
res := rc.grm.Raw(query,
sql.Named("cutoffDate", snapshotDate),
).Scan(&results)
if res.Error != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/rewards/rewards.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ func (rc *RewardsCalculator) fetchRewardsForSnapshot(snapshotDate string) ([]*Re
if err != nil {
return nil, err
}
res := rc.grm.Debug().Raw(query).Scan(&goldRows)
res := rc.grm.Raw(query).Scan(&goldRows)
if res.Error != nil {
return nil, res.Error
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/rewards/rewardsV2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ func Test_RewardsV2(t *testing.T) {
// t.Logf("%d: %s %s %s %s %s", i, row.Earner, row.Snapshot.String(), row.RewardHash, row.Token, row.Amount)
}

t.Logf("Generating staker operators table")
err = rc.sog.GenerateStakerOperatorsTable(snapshotDate)
assert.Nil(t, err)

fmt.Printf("Total duration for rewards compute %s: %v\n", snapshotDate, time.Since(snapshotStartTime))
testStart = time.Now()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ type StakerOperator struct {
Snapshot time.Time
}

func (sog *StakerOperatorsGenerator) GenerateAndInsert7StakerOperator(cutoffDate string) error {
func (sog *StakerOperatorsGenerator) GenerateAndInsert10StakerOperator(cutoffDate string) error {
sog.logger.Sugar().Infow("Generating and inserting 7_stakerOperator",
zap.String("cutoffDate", cutoffDate),
)
allTableNames := rewardsUtils.GetGoldTableNames(cutoffDate)
destTableName := rewardsUtils.Sot_7_StakerOperatorTable
destTableName := rewardsUtils.Sot_10_StakerOperatorTable

sog.logger.Sugar().Infow("Generating 7_stakerOperator",
zap.String("destTableName", destTableName),
Expand All @@ -64,7 +64,7 @@ func (sog *StakerOperatorsGenerator) GenerateAndInsert7StakerOperator(cutoffDate

query, err := rewardsUtils.RenderQueryTemplate(_7_stakerOperator, map[string]interface{}{
"destTableName": destTableName,
"stakerOperatorStaging": allTableNames[rewardsUtils.Sot_6_StakerOperatorStaging],
"stakerOperatorStaging": allTableNames[rewardsUtils.Sot_9_StakerOperatorStaging],
})
if err != nil {
sog.logger.Sugar().Errorw("Failed to render 7_stakerOperator query", "error", err)
Expand Down
66 changes: 66 additions & 0 deletions pkg/rewards/stakerOperators/6_operatorODStrategyPayouts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package stakerOperators

import (
"github.com/Layr-Labs/sidecar/pkg/rewardsUtils"
"time"
)

// _6_operatorODStrategyPayoutQuery is the query that generates the operator OD strategy payouts.
//
// In OperatorDirectedRewards (OD), the operator is paid a reward set by the AVS irrespective of the strategies
// that are delegated to the operator. Because we cant break out by strategy, we can only take the amount that
// the operator is paid of ALL strategies for the given snapshot since it doesnt matter if there are 1 or N strategies
// delegated to the operator; the amount remains the same.
const _6_operatorODStrategyPayoutQuery = `
create table {{.destTableName}} as
select
od.operator,
od.reward_hash,
od.snapshot,
od.token,
od.avs,
od.strategy,
od.multiplier,
od.reward_submission_date,
od.split_pct,
od.operator_tokens
from {{.operatorODRewardAmountsTable}} as od
`

type OperatorODStrategyPayout struct {
RewardHash string
Snapshot time.Time
Token string
Avs string
Strategy string
Multiplier string
RewardSubmissionDate time.Time
SplitPct string
OperatorTokens string
}

func (sog *StakerOperatorsGenerator) GenerateAndInsert6OperatorODStrategyPayouts(cutoffDate string) error {
allTableNames := rewardsUtils.GetGoldTableNames(cutoffDate)
destTableName := allTableNames[rewardsUtils.Sot_6_OperatorODStrategyPayouts]

sog.logger.Sugar().Infow("Generating and inserting 6_operatorODStrategyPayouts",
"cutoffDate", cutoffDate,
)

query, err := rewardsUtils.RenderQueryTemplate(_6_operatorODStrategyPayoutQuery, map[string]interface{}{
"destTableName": destTableName,
"operatorODRewardAmountsTable": allTableNames[rewardsUtils.Table_8_OperatorODRewardAmounts],
})
if err != nil {
sog.logger.Sugar().Errorw("Failed to render 6_operatorODStrategyPayouts query", "error", err)
return err
}

res := sog.db.Exec(query)

if res.Error != nil {
sog.logger.Sugar().Errorw("Failed to generate 6_operatorODStrategyPayouts", "error", res.Error)
return err
}
return nil
}
66 changes: 66 additions & 0 deletions pkg/rewards/stakerOperators/7_stakerODStrategyPayouts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package stakerOperators

import (
"github.com/Layr-Labs/sidecar/pkg/rewardsUtils"
"time"
)

// _7_stakerODStrategyPayoutQuery is a constant value that represents a query.
//
// Unlike rewards v1 where all staker amounts are pre-summed across operator/strategies,
// in rewards v2 they are already represented at the staker/operator/strategy/reward_hash level
// so adding them to the staker-operator table is a simple select from what we have already.
const _7_stakerODStrategyPayoutQuery = `
create table {{.destTableName}} as
select
staker,
operator,
avs,
token,
strategy,
multiplier,
shares,
staker_tokens,
reward_hash,
snapshot
from {{.stakerODRewardAmountsTable}}
`

type StakerODStrategyPayout struct {
Staker string
Operator string
Avs string
Token string
Strategy string
Multiplier string
Shares string
StakerTokens string
RewardHash string
Snapshot time.Time
}

func (sog *StakerOperatorsGenerator) GenerateAndInsert7StakerODStrategyPayouts(cutoffDate string) error {
allTableNames := rewardsUtils.GetGoldTableNames(cutoffDate)
destTableName := allTableNames[rewardsUtils.Sot_7_StakerODStrategyPayouts]

sog.logger.Sugar().Infow("Generating and inserting 7_stakerODStrategyPayouts",
"cutoffDate", cutoffDate,
)

query, err := rewardsUtils.RenderQueryTemplate(_7_stakerODStrategyPayoutQuery, map[string]interface{}{
"destTableName": destTableName,
"stakerODRewardAmountsTable": allTableNames[rewardsUtils.Table_9_StakerODRewardAmounts],
})
if err != nil {
sog.logger.Sugar().Errorw("Failed to render 7_stakerODStrategyPayouts query", "error", err)
return err
}

res := sog.db.Exec(query)

if res.Error != nil {
sog.logger.Sugar().Errorw("Failed to generate 7_stakerODStrategyPayouts", "error", res.Error)
return err
}
return nil
}
59 changes: 59 additions & 0 deletions pkg/rewards/stakerOperators/8_avsODStrategyPayouts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package stakerOperators

import (
"github.com/Layr-Labs/sidecar/pkg/rewardsUtils"
)

// _8_avsODStrategyPayoutQuery is the query that generates the 8_avsODStrategyPayouts table
//
// AVS operator directed rewards are not actually rewards, but refunds for the case when the operator
// defined in the rewards-v2 submission wasnt delegated at the time of the snapshot. Since operator rewards
// in rewards-v2 are not based on strategy and are a lump sum between the AVS and operator, the refund
// is also the same; a lump sum BACK to the AVS that was originally intended for the operator. As such,
// there is no strategy, shares or multiplier fields to represent.
const _8_avsODStrategyPayoutQuery = `
create table {{.destTableName}} as
select
reward_hash,
snapshot,
token,
avs,
operator,
avs_tokens
from {{.avsODRewardAmountsTable}}
`

type AvsODStrategyPayout struct {
RewardHash string
Snapshot string
Token string
Avs string
Operator string
AvsTokens string
}

func (sog *StakerOperatorsGenerator) GenerateAndInsert8AvsODStrategyPayouts(cutoffDate string) error {
allTableNames := rewardsUtils.GetGoldTableNames(cutoffDate)
destTableName := allTableNames[rewardsUtils.Sot_8_AvsODStrategyPayouts]

sog.logger.Sugar().Infow("Generating and inserting 8_avsODStrategyPayouts",
"cutoffDate", cutoffDate,
)

query, err := rewardsUtils.RenderQueryTemplate(_8_avsODStrategyPayoutQuery, map[string]interface{}{
"destTableName": destTableName,
"avsODRewardAmountsTable": allTableNames[rewardsUtils.Table_10_AvsODRewardAmounts],
})
if err != nil {
sog.logger.Sugar().Errorw("Failed to render 8_avsODStrategyPayouts query", "error", err)
return err
}

res := sog.db.Exec(query)

if res.Error != nil {
sog.logger.Sugar().Errorw("Failed to generate 8_avsODStrategyPayouts", "error", res.Error)
return err
}
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,54 @@ SELECT
reward_hash,
snapshot
FROM {{.sot5RfaeOperatorStrategyPayout}}
UNION ALL
SELECT
operator as earner,
operator as operator,
'operator_od_reward' as reward_type,
avs,
token,
'0x0000000000000000000000000000000000000000' as strategy,
'0' as multiplier,
'0' as shares,
operator_tokens as amount,
reward_hash,
snapshot
from {{.sot6OperatorODStrategyPayouts}}
UNION ALL
SELECT
staker as earner,
operator,
'staker_od_reward' as reward_type,
avs,
token,
strategy,
multiplier,
shares,
staker_tokens as amount,
reward_hash,
snapshot
from {{.sot7StakerODStrategyPayouts}}
UNION ALL
SELECT
avs as earner,
operator,
'avs_od_reward' as reward_type,
avs,
token,
'0x0000000000000000000000000000000000000000' as strategy,
'0' as multiplier,
'0' as shares,
avs_tokens as amount,
reward_hash,
snapshot
from {{.sot8AvsODStrategyPayouts}}
`

type StakerOperatorStaging struct {
Expand All @@ -101,11 +149,11 @@ type StakerOperatorStaging struct {
Snapshot time.Time
}

func (sog *StakerOperatorsGenerator) GenerateAndInsert6StakerOperatorStaging(cutoffDate string) error {
func (sog *StakerOperatorsGenerator) GenerateAndInsert9StakerOperatorStaging(cutoffDate string) error {
allTableNames := rewardsUtils.GetGoldTableNames(cutoffDate)
destTableName := allTableNames[rewardsUtils.Sot_6_StakerOperatorStaging]
destTableName := allTableNames[rewardsUtils.Sot_9_StakerOperatorStaging]

sog.logger.Sugar().Infow("Generating and inserting 6_stakerOperatorsStaging",
sog.logger.Sugar().Infow("Generating and inserting 9_stakerOperatorsStaging",
zap.String("cutoffDate", cutoffDate),
)

Expand All @@ -114,7 +162,7 @@ func (sog *StakerOperatorsGenerator) GenerateAndInsert6StakerOperatorStaging(cut
return err
}

sog.logger.Sugar().Infow("Generating 6_stakerOperatorsStaging",
sog.logger.Sugar().Infow("Generating 9_stakerOperatorsStaging",
zap.String("destTableName", destTableName),
zap.String("cutoffDate", cutoffDate),
)
Expand All @@ -126,9 +174,12 @@ func (sog *StakerOperatorsGenerator) GenerateAndInsert6StakerOperatorStaging(cut
"sot3RewardsForAllStrategyPayouts": allTableNames[rewardsUtils.Sot_3_RewardsForAllStrategyPayout],
"sot4RfaeStakerStrategyPayout": allTableNames[rewardsUtils.Sot_4_RfaeStakers],
"sot5RfaeOperatorStrategyPayout": allTableNames[rewardsUtils.Sot_5_RfaeOperators],
"sot6OperatorODStrategyPayouts": allTableNames[rewardsUtils.Sot_6_OperatorODStrategyPayouts],
"sot7StakerODStrategyPayouts": allTableNames[rewardsUtils.Sot_7_StakerODStrategyPayouts],
"sot8AvsODStrategyPayouts": allTableNames[rewardsUtils.Sot_8_AvsODStrategyPayouts],
})
if err != nil {
sog.logger.Sugar().Errorw("Failed to render 6_stakerOperatorsStaging query", "error", err)
sog.logger.Sugar().Errorw("Failed to render 9_stakerOperatorsStaging query", "error", err)
return err
}

Expand Down
28 changes: 26 additions & 2 deletions pkg/rewards/stakerOperators/stakerOperator.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,39 @@ func (sog *StakerOperatorsGenerator) GenerateStakerOperatorsTable(cutoffDate str
return err
}

if err := sog.GenerateAndInsert6StakerOperatorStaging(cutoffDate); err != nil {
if err := sog.GenerateAndInsert6OperatorODStrategyPayouts(cutoffDate); err != nil {
sog.logger.Sugar().Errorw("Failed to generate and insert 6 staker strategy rewards",
zap.String("cutoffDate", cutoffDate),
zap.Error(err),
)
return err
}

if err := sog.GenerateAndInsert7StakerOperator(cutoffDate); err != nil {
if err := sog.GenerateAndInsert7StakerODStrategyPayouts(cutoffDate); err != nil {
sog.logger.Sugar().Errorw("Failed to generate and insert 7 staker strategy rewards",
zap.String("cutoffDate", cutoffDate),
zap.Error(err),
)
return err
}

if err := sog.GenerateAndInsert8AvsODStrategyPayouts(cutoffDate); err != nil {
sog.logger.Sugar().Errorw("Failed to generate and insert 8 staker strategy rewards",
zap.String("cutoffDate", cutoffDate),
zap.Error(err),
)
return err
}

if err := sog.GenerateAndInsert9StakerOperatorStaging(cutoffDate); err != nil {
sog.logger.Sugar().Errorw("Failed to generate and insert 6 staker strategy rewards",
zap.String("cutoffDate", cutoffDate),
zap.Error(err),
)
return err
}

if err := sog.GenerateAndInsert10StakerOperator(cutoffDate); err != nil {
sog.logger.Sugar().Errorw("Failed to generate and insert 7 staker strategy rewards",
zap.String("cutoffDate", cutoffDate),
zap.Error(err),
Expand Down
Loading

0 comments on commit 6a198ce

Please sign in to comment.