Skip to content

Commit 385c13c

Browse files
committed
writes
1 parent 6bcc901 commit 385c13c

File tree

7 files changed

+233
-1
lines changed

7 files changed

+233
-1
lines changed

pkg/flags/flags.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,20 @@ var (
6666
Required: true,
6767
Aliases: []string{"s"},
6868
}
69+
70+
ShowMagnitudesFlag = cli.StringFlag{
71+
Name: "show-magnitudes",
72+
Usage: "Show magnitudes of stake share",
73+
Required: true,
74+
Aliases: []string{"m"},
75+
}
76+
77+
RebalanceFilePathFlag = cli.PathFlag{
78+
Name: "rebalance-file-path",
79+
Usage: `Path to the CSV file.
80+
The CSV file should have the following columns: operator set,allocation percentage.
81+
This file must have all the operator sets and their allocation percentages for a strategy.`,
82+
Required: true,
83+
Aliases: []string{"r"},
84+
}
6985
)

pkg/operator/stakeallocation.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func StakeAllocationCmd(p utils.Prompter) *cli.Command {
1515
Subcommands: []*cli.Command{
1616
stakeallocation.ShowCmd(p),
1717
stakeallocation.UpdateCmd(p),
18+
stakeallocation.RebalanceCmd(p),
1819
},
1920
}
2021
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package stakeallocation
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/Layr-Labs/eigenlayer-cli/pkg/flags"
7+
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry"
8+
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils"
9+
"github.com/urfave/cli/v2"
10+
)
11+
12+
func RebalanceCmd(p utils.Prompter) *cli.Command {
13+
return &cli.Command{
14+
Name: "rebalance",
15+
Aliases: []string{"r"},
16+
Usage: "Rebalance stake allocation",
17+
Description: `
18+
Rebalance the stake allocation for the operator for a particular strategy.
19+
This CSV file requires the following columns for only one stragegy:
20+
operator_set,allocation percentage
21+
Example
22+
1,10
23+
2,15
24+
`,
25+
Action: rebalanceStakeAllocation,
26+
After: telemetry.AfterRunAction(),
27+
Flags: []cli.Flag{
28+
&flags.ConfigurationFileFlag,
29+
&flags.DryRunFlag,
30+
&flags.BroadcastFlag,
31+
&flags.ShowMagnitudesFlag,
32+
&flags.RebalanceFilePathFlag,
33+
},
34+
}
35+
}
36+
37+
func rebalanceStakeAllocation(ctx *cli.Context) error {
38+
fmt.Println("unimplemented")
39+
return nil
40+
}

pkg/operator/stakeallocation/show.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"github.com/Layr-Labs/eigenlayer-cli/pkg/flags"
77
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry"
88
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils"
9-
9+
1010
"github.com/urfave/cli/v2"
1111
)
1212

pkg/operator/stakeallocation/update.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func UpdateCmd(p utils.Prompter) *cli.Command {
2828
&flags.BroadcastFlag,
2929
&flags.AllocationPercentageFlag,
3030
&flags.StakeSourceFlag,
31+
&flags.ShowMagnitudesFlag,
3132
},
3233
}
3334
}

pkg/slashing/slashing.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package slashing
2+
3+
import (
4+
"fmt"
5+
"math"
6+
)
7+
8+
type StakeSource string
9+
10+
const (
11+
StakeSourceSlashable StakeSource = "slashable"
12+
StakeSourceNonSlashable StakeSource = "non-slashable"
13+
StakeSourceBoth StakeSource = "both"
14+
)
15+
16+
type State struct {
17+
totalMagnitude float64
18+
operatorSets []int
19+
slashableMagnitude []float64
20+
}
21+
22+
func CalculateNewState(
23+
oldState State,
24+
stakeSource StakeSource,
25+
operatorSet int,
26+
slashableProportion float64,
27+
) *State {
28+
29+
if stakeSource == StakeSourceSlashable {
30+
// non slashable proportion
31+
nonSlashableProportion := (oldState.totalMagnitude - sumFloatArray(oldState.slashableMagnitude)) / oldState.totalMagnitude
32+
fmt.Println("nonSlashableProportion: ", nonSlashableProportion)
33+
34+
allocatedMagnitude := sumFloatArray(oldState.slashableMagnitude)
35+
fmt.Println("allocatedMagnitude: ", allocatedMagnitude)
36+
37+
totalMagnitudeNew := allocatedMagnitude / (1 - slashableProportion - nonSlashableProportion)
38+
fmt.Println("totalMagnitudeNew: ", totalMagnitudeNew)
39+
40+
slashableMagnitude := slashableProportion * totalMagnitudeNew
41+
fmt.Println("slashableMagnitude: ", slashableMagnitude)
42+
43+
nonSlashableMagnitude := nonSlashableProportion * totalMagnitudeNew
44+
fmt.Println("nonSlashableMagnitude: ", nonSlashableMagnitude)
45+
46+
opSetToUpdate := []int{operatorSet}
47+
slashableMagnitudeSet := []float64{Round(slashableMagnitude, 10)}
48+
49+
return &State{
50+
totalMagnitude: Round(totalMagnitudeNew, 10),
51+
operatorSets: opSetToUpdate,
52+
slashableMagnitude: slashableMagnitudeSet,
53+
}
54+
} else if stakeSource == StakeSourceNonSlashable {
55+
// TODO: need to first verify if the operator set is already in the state
56+
// and also if there is enough non slashable stake to allocate
57+
58+
return &State{
59+
totalMagnitude: oldState.totalMagnitude,
60+
operatorSets: []int{operatorSet},
61+
slashableMagnitude: []float64{Round(oldState.totalMagnitude*slashableProportion, 10)},
62+
}
63+
} else {
64+
// Stake is sourced from both slashable and non-slashable proportionally
65+
}
66+
67+
// non slashable proportion
68+
nonSlashableProportion := (oldState.totalMagnitude - sumFloatArray(oldState.slashableMagnitude)) / oldState.totalMagnitude
69+
fmt.Println("nonSlashableProportion: ", nonSlashableProportion)
70+
71+
allocatedMagnitude := sumFloatArray(oldState.slashableMagnitude)
72+
fmt.Println("allocatedMagnitude: ", allocatedMagnitude)
73+
74+
/*
75+
i = new operator set
76+
slashablePercentage = slashable magnitude (i) / total magnitude new
77+
78+
*/
79+
totalMagnitudeNew := allocatedMagnitude / (1 - slashableProportion - nonSlashableProportion)
80+
fmt.Println("totalMagnitudeNew: ", totalMagnitudeNew)
81+
82+
slashableMagnitude := slashableProportion * totalMagnitudeNew
83+
fmt.Println("slashableMagnitude: ", slashableMagnitude)
84+
85+
nonSlashableMagnitude := nonSlashableProportion * totalMagnitudeNew
86+
fmt.Println("nonSlashableMagnitude: ", nonSlashableMagnitude)
87+
88+
opSetToUpdate := []int{operatorSet}
89+
slashableMagnitudeSet := []float64{Round(slashableMagnitude, 10)}
90+
91+
return &State{
92+
totalMagnitude: Round(totalMagnitudeNew, 10),
93+
operatorSets: opSetToUpdate,
94+
slashableMagnitude: slashableMagnitudeSet,
95+
}
96+
}
97+
98+
func sumFloatArray(arr []float64) float64 {
99+
sum := 0.0
100+
for _, i := range arr {
101+
sum += i
102+
}
103+
return sum
104+
}
105+
106+
// Round rounds the floating point number to the specified number of decimal places.
107+
func Round(val float64, places int) float64 {
108+
if places < 0 {
109+
return val
110+
}
111+
factor := math.Pow(10, float64(places))
112+
return math.Round(val*factor) / factor
113+
}

pkg/slashing/slashing_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package slashing
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestCalculateNewState(t *testing.T) {
10+
11+
var tests = []struct {
12+
name string
13+
oldState State
14+
stakeSource StakeSource
15+
operatorSet int
16+
slashableProportion float64
17+
newState *State
18+
}{
19+
{
20+
name: "Simple case where stake is sourced from slashable stake",
21+
oldState: State{
22+
totalMagnitude: 10,
23+
operatorSets: []int{1, 2},
24+
slashableMagnitude: []float64{1, 1},
25+
},
26+
stakeSource: StakeSourceSlashable,
27+
operatorSet: 4,
28+
slashableProportion: 0.1,
29+
newState: &State{
30+
totalMagnitude: 20.0,
31+
operatorSets: []int{4},
32+
slashableMagnitude: []float64{2.0},
33+
},
34+
},
35+
{
36+
name: "Simple case where stake is sourced from non slashable stake",
37+
oldState: State{
38+
totalMagnitude: 10,
39+
operatorSets: []int{1, 2},
40+
slashableMagnitude: []float64{1, 1},
41+
},
42+
stakeSource: StakeSourceNonSlashable,
43+
operatorSet: 4,
44+
slashableProportion: 0.1,
45+
newState: &State{
46+
totalMagnitude: 10.0,
47+
operatorSets: []int{4},
48+
slashableMagnitude: []float64{1.0},
49+
},
50+
},
51+
}
52+
53+
for _, tt := range tests {
54+
t.Run(tt.name, func(t *testing.T) {
55+
newState := CalculateNewState(tt.oldState, tt.stakeSource, tt.operatorSet, tt.slashableProportion)
56+
assert.Equal(t, tt.newState, newState)
57+
})
58+
59+
}
60+
61+
}

0 commit comments

Comments
 (0)