-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6bcc901
commit 385c13c
Showing
7 changed files
with
233 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package stakeallocation | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/Layr-Labs/eigenlayer-cli/pkg/flags" | ||
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry" | ||
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
func RebalanceCmd(p utils.Prompter) *cli.Command { | ||
return &cli.Command{ | ||
Name: "rebalance", | ||
Aliases: []string{"r"}, | ||
Usage: "Rebalance stake allocation", | ||
Description: ` | ||
Rebalance the stake allocation for the operator for a particular strategy. | ||
This CSV file requires the following columns for only one stragegy: | ||
operator_set,allocation percentage | ||
Example | ||
1,10 | ||
2,15 | ||
`, | ||
Action: rebalanceStakeAllocation, | ||
After: telemetry.AfterRunAction(), | ||
Flags: []cli.Flag{ | ||
&flags.ConfigurationFileFlag, | ||
&flags.DryRunFlag, | ||
&flags.BroadcastFlag, | ||
&flags.ShowMagnitudesFlag, | ||
&flags.RebalanceFilePathFlag, | ||
}, | ||
} | ||
} | ||
|
||
func rebalanceStakeAllocation(ctx *cli.Context) error { | ||
fmt.Println("unimplemented") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package slashing | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
) | ||
|
||
type StakeSource string | ||
|
||
const ( | ||
StakeSourceSlashable StakeSource = "slashable" | ||
StakeSourceNonSlashable StakeSource = "non-slashable" | ||
StakeSourceBoth StakeSource = "both" | ||
) | ||
|
||
type State struct { | ||
totalMagnitude float64 | ||
operatorSets []int | ||
slashableMagnitude []float64 | ||
} | ||
|
||
func CalculateNewState( | ||
oldState State, | ||
stakeSource StakeSource, | ||
operatorSet int, | ||
slashableProportion float64, | ||
) *State { | ||
|
||
if stakeSource == StakeSourceSlashable { | ||
// non slashable proportion | ||
nonSlashableProportion := (oldState.totalMagnitude - sumFloatArray(oldState.slashableMagnitude)) / oldState.totalMagnitude | ||
fmt.Println("nonSlashableProportion: ", nonSlashableProportion) | ||
|
||
allocatedMagnitude := sumFloatArray(oldState.slashableMagnitude) | ||
fmt.Println("allocatedMagnitude: ", allocatedMagnitude) | ||
|
||
totalMagnitudeNew := allocatedMagnitude / (1 - slashableProportion - nonSlashableProportion) | ||
fmt.Println("totalMagnitudeNew: ", totalMagnitudeNew) | ||
|
||
slashableMagnitude := slashableProportion * totalMagnitudeNew | ||
fmt.Println("slashableMagnitude: ", slashableMagnitude) | ||
|
||
nonSlashableMagnitude := nonSlashableProportion * totalMagnitudeNew | ||
fmt.Println("nonSlashableMagnitude: ", nonSlashableMagnitude) | ||
|
||
opSetToUpdate := []int{operatorSet} | ||
slashableMagnitudeSet := []float64{Round(slashableMagnitude, 10)} | ||
|
||
return &State{ | ||
totalMagnitude: Round(totalMagnitudeNew, 10), | ||
operatorSets: opSetToUpdate, | ||
slashableMagnitude: slashableMagnitudeSet, | ||
} | ||
} else if stakeSource == StakeSourceNonSlashable { | ||
// TODO: need to first verify if the operator set is already in the state | ||
// and also if there is enough non slashable stake to allocate | ||
|
||
return &State{ | ||
totalMagnitude: oldState.totalMagnitude, | ||
operatorSets: []int{operatorSet}, | ||
slashableMagnitude: []float64{Round(oldState.totalMagnitude*slashableProportion, 10)}, | ||
} | ||
} else { | ||
// Stake is sourced from both slashable and non-slashable proportionally | ||
} | ||
|
||
// non slashable proportion | ||
nonSlashableProportion := (oldState.totalMagnitude - sumFloatArray(oldState.slashableMagnitude)) / oldState.totalMagnitude | ||
fmt.Println("nonSlashableProportion: ", nonSlashableProportion) | ||
|
||
allocatedMagnitude := sumFloatArray(oldState.slashableMagnitude) | ||
fmt.Println("allocatedMagnitude: ", allocatedMagnitude) | ||
|
||
/* | ||
i = new operator set | ||
slashablePercentage = slashable magnitude (i) / total magnitude new | ||
*/ | ||
totalMagnitudeNew := allocatedMagnitude / (1 - slashableProportion - nonSlashableProportion) | ||
fmt.Println("totalMagnitudeNew: ", totalMagnitudeNew) | ||
|
||
slashableMagnitude := slashableProportion * totalMagnitudeNew | ||
fmt.Println("slashableMagnitude: ", slashableMagnitude) | ||
|
||
nonSlashableMagnitude := nonSlashableProportion * totalMagnitudeNew | ||
fmt.Println("nonSlashableMagnitude: ", nonSlashableMagnitude) | ||
|
||
opSetToUpdate := []int{operatorSet} | ||
slashableMagnitudeSet := []float64{Round(slashableMagnitude, 10)} | ||
|
||
return &State{ | ||
totalMagnitude: Round(totalMagnitudeNew, 10), | ||
operatorSets: opSetToUpdate, | ||
slashableMagnitude: slashableMagnitudeSet, | ||
} | ||
} | ||
|
||
func sumFloatArray(arr []float64) float64 { | ||
sum := 0.0 | ||
for _, i := range arr { | ||
sum += i | ||
} | ||
return sum | ||
} | ||
|
||
// Round rounds the floating point number to the specified number of decimal places. | ||
func Round(val float64, places int) float64 { | ||
if places < 0 { | ||
return val | ||
} | ||
factor := math.Pow(10, float64(places)) | ||
return math.Round(val*factor) / factor | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package slashing | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCalculateNewState(t *testing.T) { | ||
|
||
var tests = []struct { | ||
name string | ||
oldState State | ||
stakeSource StakeSource | ||
operatorSet int | ||
slashableProportion float64 | ||
newState *State | ||
}{ | ||
{ | ||
name: "Simple case where stake is sourced from slashable stake", | ||
oldState: State{ | ||
totalMagnitude: 10, | ||
operatorSets: []int{1, 2}, | ||
slashableMagnitude: []float64{1, 1}, | ||
}, | ||
stakeSource: StakeSourceSlashable, | ||
operatorSet: 4, | ||
slashableProportion: 0.1, | ||
newState: &State{ | ||
totalMagnitude: 20.0, | ||
operatorSets: []int{4}, | ||
slashableMagnitude: []float64{2.0}, | ||
}, | ||
}, | ||
{ | ||
name: "Simple case where stake is sourced from non slashable stake", | ||
oldState: State{ | ||
totalMagnitude: 10, | ||
operatorSets: []int{1, 2}, | ||
slashableMagnitude: []float64{1, 1}, | ||
}, | ||
stakeSource: StakeSourceNonSlashable, | ||
operatorSet: 4, | ||
slashableProportion: 0.1, | ||
newState: &State{ | ||
totalMagnitude: 10.0, | ||
operatorSets: []int{4}, | ||
slashableMagnitude: []float64{1.0}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
newState := CalculateNewState(tt.oldState, tt.stakeSource, tt.operatorSet, tt.slashableProportion) | ||
assert.Equal(t, tt.newState, newState) | ||
}) | ||
|
||
} | ||
|
||
} |