Skip to content

Commit

Permalink
skip autodeposit if staked, use latest data for autodeposit operations
Browse files Browse the repository at this point in the history
  • Loading branch information
rauljordan committed Jan 23, 2025
1 parent 60b5e36 commit e724bf7
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 11 deletions.
2 changes: 1 addition & 1 deletion assertions/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ func (m *Manager) Start(ctx context.Context) {
if err2 != nil {
return false, err2
}
if err2 := m.chain.Deposit(ctx, latestConfirmedInfo.RequiredStake); err2 != nil {
if err2 := m.chain.AutoDepositTokenForStaking(ctx, latestConfirmedInfo.RequiredStake); err2 != nil {
return false, err2
}
return true, nil
Expand Down
2 changes: 1 addition & 1 deletion chain-abstraction/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ type AssertionChain interface {
TopLevelClaimHeights(ctx context.Context, edgeId EdgeId) (OriginHeights, error)

// Mutating methods.
Deposit(
AutoDepositTokenForStaking(
ctx context.Context,
amount *big.Int,
) error
Expand Down
24 changes: 17 additions & 7 deletions chain-abstraction/sol-implementation/assertion_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ func (a *AssertionChain) LatestConfirmed(ctx context.Context, opts *bind.CallOpt

// Returns true if the staker's address is currently staked in the assertion chain.
func (a *AssertionChain) IsStaked(ctx context.Context) (bool, error) {
return a.rollup.IsStaked(a.GetCallOptsWithDesiredRpcHeadBlockNumber(&bind.CallOpts{Context: ctx}), a.StakerAddress())
return a.rollup.IsStaked(&bind.CallOpts{Context: ctx}, a.StakerAddress())
}

// RollupAddress for the assertion chain.
Expand Down Expand Up @@ -397,25 +397,36 @@ func (a *AssertionChain) IsChallengeComplete(
return challengeConfirmed, nil
}

func (a *AssertionChain) Deposit(
// AutoDepositTokenForStaking ensures that the validator has enough funds to stake
// on assertions if not already staked, and then deposits the difference required to participate.
func (a *AssertionChain) AutoDepositTokenForStaking(
ctx context.Context,
amount *big.Int,
) error {
staked, err := a.IsStaked(ctx)
if err != nil {
return err
}
if staked {
return nil
}
return a.autoDepositFunds(ctx, amount)
}

// Attempts to auto-wrap ETH to WETH with the required amount that is specified to the function.
// This function uses `latest` onchain data to determine the current balance of the staker
// and deposits the difference between the required amount and the current balance.
func (a *AssertionChain) autoDepositFunds(ctx context.Context, amount *big.Int) error {
if !a.autoDeposit {
return nil
}
callOpts := a.GetCallOptsWithDesiredRpcHeadBlockNumber(&bind.CallOpts{Context: ctx})
// The validity of the stake token address containing code is checked in the constructor
// of the assertion chain.
erc20, err := testgen.NewERC20Token(a.stakeTokenAddr, a.backend)
if err != nil {
return err
}
balance, err := erc20.BalanceOf(callOpts, a.txOpts.From)
balance, err := erc20.BalanceOf(&bind.CallOpts{Context: ctx}, a.txOpts.From)
if err != nil {
return err
}
Expand Down Expand Up @@ -444,18 +455,17 @@ func (a *AssertionChain) autoDepositFunds(ctx context.Context, amount *big.Int)
func (a *AssertionChain) ApproveAllowances(
ctx context.Context,
) error {
opts := a.GetCallOptsWithDesiredRpcHeadBlockNumber(&bind.CallOpts{Context: ctx})
// The validity of the stake token address containing code is checked in the constructor
// of the assertion chain.
erc20, err := testgen.NewERC20Token(a.stakeTokenAddr, a.backend)
if err != nil {
return err
}
rollupAllowance, err := erc20.Allowance(opts, a.txOpts.From, a.rollupAddr)
rollupAllowance, err := erc20.Allowance(&bind.CallOpts{Context: ctx}, a.txOpts.From, a.rollupAddr)
if err != nil {
return err
}
chalManagerAllowance, err := erc20.Allowance(opts, a.txOpts.From, a.chalManagerAddr)
chalManagerAllowance, err := erc20.Allowance(&bind.CallOpts{Context: ctx}, a.txOpts.From, a.chalManagerAddr)
if err != nil {
return err
}
Expand Down
60 changes: 59 additions & 1 deletion chain-abstraction/sol-implementation/assertion_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,9 +525,67 @@ func Test_autoDepositFunds(t *testing.T) {

expectedNewBalance := new(big.Int).Add(balance, big.NewInt(20))
ctx := context.Background()
require.NoError(t, setupCfg.Chains[0].Deposit(ctx, expectedNewBalance))
require.NoError(t, setupCfg.Chains[0].AutoDepositTokenForStaking(ctx, expectedNewBalance))

newBalance, err := erc20.BalanceOf(&bind.CallOpts{}, account.AccountAddr)
require.NoError(t, err)
require.Equal(t, expectedNewBalance, newBalance)
}

func Test_autoDepositFunds_SkipsIfAlreadyStaked(t *testing.T) {
setupCfg, err := setup.ChainsWithEdgeChallengeManager(setup.WithMockOneStepProver())
require.NoError(t, err)
rollupAddr := setupCfg.Addrs.Rollup
rollup, err := rollupgen.NewRollupUserLogic(rollupAddr, setupCfg.Backend)
require.NoError(t, err)
stakeTokenAddr, err := rollup.StakeToken(&bind.CallOpts{})
require.NoError(t, err)
erc20, err := mocksgen.NewTestWETH9(stakeTokenAddr, setupCfg.Backend)
require.NoError(t, err)
account := setupCfg.Accounts[1]
assertionChain := setupCfg.Chains[0]

balance, err := erc20.BalanceOf(&bind.CallOpts{}, account.AccountAddr)
require.NoError(t, err)

expectedNewBalance := new(big.Int).Add(balance, big.NewInt(20))
ctx := context.Background()
require.NoError(t, assertionChain.AutoDepositTokenForStaking(ctx, expectedNewBalance))

newBalance, err := erc20.BalanceOf(&bind.CallOpts{}, account.AccountAddr)
require.NoError(t, err)
require.Equal(t, expectedNewBalance, newBalance)

// Tries to stake on an assertion.
genesisHash, err := assertionChain.GenesisAssertionHash(ctx)
require.NoError(t, err)
genesisInfo, err := assertionChain.ReadAssertionCreationInfo(ctx, protocol.AssertionHash{Hash: genesisHash})
require.NoError(t, err)
postState := &protocol.ExecutionState{
GlobalState: protocol.GoGlobalState{
BlockHash: common.BytesToHash([]byte("foo")),
SendRoot: common.Hash{},
Batch: 1,
PosInBatch: 0,
},
MachineStatus: protocol.MachineStatusFinished,
}
_, err = assertionChain.NewStakeOnNewAssertion(ctx, genesisInfo, postState)
require.NoError(t, err)

// Check we are staked.
staked, err := assertionChain.IsStaked(ctx)
require.NoError(t, err)
require.True(t, staked)

// Attempt to auto-deposit again.
oldBalance := newBalance
evenBiggerBalance := new(big.Int).Add(oldBalance, big.NewInt(100))
require.NoError(t, setupCfg.Chains[0].AutoDepositTokenForStaking(ctx, evenBiggerBalance))

// Check that we our balance does not increase if we try to auto-deposit again given we are
// already staked as a validator. In fact, expect it decreased.
newBalance, err = erc20.BalanceOf(&bind.CallOpts{}, account.AccountAddr)
require.NoError(t, err)
require.True(t, oldBalance.Cmp(newBalance) > 0)
}
2 changes: 1 addition & 1 deletion testing/mocks/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ func (m *MockProtocol) IsStaked(ctx context.Context) (bool, error) {
return args.Get(0).(bool), args.Error(1)
}

func (m *MockProtocol) Deposit(
func (m *MockProtocol) AutoDepositTokenForStaking(
ctx context.Context,
amount *big.Int,
) error {
Expand Down

0 comments on commit e724bf7

Please sign in to comment.