github.com/ethersphere/bee/v2@v2.2.0/pkg/api/staking.go (about)

     1  // Copyright 2022 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package api
     6  
     7  import (
     8  	"errors"
     9  	"math/big"
    10  	"net/http"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/bigint"
    13  
    14  	"github.com/ethersphere/bee/v2/pkg/jsonhttp"
    15  	"github.com/ethersphere/bee/v2/pkg/storageincentives/staking"
    16  	"github.com/gorilla/mux"
    17  )
    18  
    19  func (s *Service) stakingAccessHandler(h http.Handler) http.Handler {
    20  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    21  		if !s.stakingSem.TryAcquire(1) {
    22  			s.logger.Debug("staking access: simultaneous on-chain operations not supported")
    23  			s.logger.Error(nil, "staking access: simultaneous on-chain operations not supported")
    24  			jsonhttp.TooManyRequests(w, "simultaneous on-chain operations not supported")
    25  			return
    26  		}
    27  		defer s.stakingSem.Release(1)
    28  
    29  		h.ServeHTTP(w, r)
    30  	})
    31  }
    32  
    33  type getStakeResponse struct {
    34  	StakedAmount *bigint.BigInt `json:"stakedAmount"`
    35  }
    36  
    37  type getWithdrawableResponse struct {
    38  	WithdrawableAmount *bigint.BigInt `json:"withdrawableAmount"`
    39  }
    40  type stakeTransactionReponse struct {
    41  	TxHash string `json:"txHash"`
    42  }
    43  
    44  func (s *Service) stakingDepositHandler(w http.ResponseWriter, r *http.Request) {
    45  	logger := s.logger.WithName("post_stake_deposit").Build()
    46  
    47  	paths := struct {
    48  		Amount *big.Int `map:"amount" validate:"required"`
    49  	}{}
    50  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
    51  		response("invalid path params", logger, w)
    52  		return
    53  	}
    54  
    55  	txHash, err := s.stakingContract.DepositStake(r.Context(), paths.Amount)
    56  	if err != nil {
    57  		if errors.Is(err, staking.ErrInsufficientStakeAmount) {
    58  			logger.Debug("insufficient stake amount", "minimum_stake", staking.MinimumStakeAmount, "error", err)
    59  			logger.Error(nil, "insufficient stake amount")
    60  			jsonhttp.BadRequest(w, "insufficient stake amount")
    61  			return
    62  		}
    63  		if errors.Is(err, staking.ErrNotImplemented) {
    64  			logger.Debug("not implemented", "error", err)
    65  			logger.Error(nil, "not implemented")
    66  			jsonhttp.NotImplemented(w, "not implemented")
    67  			return
    68  		}
    69  		if errors.Is(err, staking.ErrInsufficientFunds) {
    70  			logger.Debug("out of funds", "error", err)
    71  			logger.Error(nil, "out of funds")
    72  			jsonhttp.BadRequest(w, "out of funds")
    73  			return
    74  		}
    75  		logger.Debug("deposit failed", "error", err)
    76  		logger.Error(nil, "deposit failed")
    77  		jsonhttp.InternalServerError(w, "cannot stake")
    78  		return
    79  	}
    80  	jsonhttp.OK(w, stakeTransactionReponse{
    81  		TxHash: txHash.String(),
    82  	})
    83  }
    84  
    85  func (s *Service) getPotentialStake(w http.ResponseWriter, r *http.Request) {
    86  	logger := s.logger.WithName("get_stake").Build()
    87  
    88  	stakedAmount, err := s.stakingContract.GetPotentialStake(r.Context())
    89  	if err != nil {
    90  		logger.Debug("get staked amount failed", "overlayAddr", s.overlay, "error", err)
    91  		logger.Error(nil, "get staked amount failed")
    92  		jsonhttp.InternalServerError(w, "get staked amount failed")
    93  		return
    94  	}
    95  
    96  	jsonhttp.OK(w, getStakeResponse{StakedAmount: bigint.Wrap(stakedAmount)})
    97  }
    98  
    99  func (s *Service) getWithdrawableStakeHandler(w http.ResponseWriter, r *http.Request) {
   100  	logger := s.logger.WithName("get_stake").Build()
   101  
   102  	withdrawableAmount, err := s.stakingContract.GetWithdrawableStake(r.Context())
   103  	if err != nil {
   104  		logger.Debug("get staked amount failed", "overlayAddr", s.overlay, "error", err)
   105  		logger.Error(nil, "get staked amount failed")
   106  		jsonhttp.InternalServerError(w, "get staked amount failed")
   107  		return
   108  	}
   109  
   110  	jsonhttp.OK(w, getWithdrawableResponse{WithdrawableAmount: bigint.Wrap(withdrawableAmount)})
   111  }
   112  
   113  func (s *Service) withdrawStakeHandler(w http.ResponseWriter, r *http.Request) {
   114  	logger := s.logger.WithName("withdraw_stake").Build()
   115  
   116  	txHash, err := s.stakingContract.WithdrawStake(r.Context())
   117  	if err != nil {
   118  		if errors.Is(err, staking.ErrInsufficientStake) {
   119  			logger.Debug("insufficient stake", "overlayAddr", s.overlay, "error", err)
   120  			logger.Error(nil, "insufficient stake")
   121  			jsonhttp.BadRequest(w, "insufficient stake to withdraw")
   122  			return
   123  		}
   124  		logger.Debug("withdraw stake failed", "error", err)
   125  		logger.Error(nil, "withdraw stake failed")
   126  		jsonhttp.InternalServerError(w, "cannot withdraw stake")
   127  		return
   128  	}
   129  
   130  	jsonhttp.OK(w, stakeTransactionReponse{TxHash: txHash.String()})
   131  }
   132  
   133  func (s *Service) migrateStakeHandler(w http.ResponseWriter, r *http.Request) {
   134  	logger := s.logger.WithName("migrate_stake").Build()
   135  
   136  	txHash, err := s.stakingContract.MigrateStake(r.Context())
   137  	if err != nil {
   138  		if errors.Is(err, staking.ErrInsufficientStake) {
   139  			logger.Debug("insufficient stake", "overlayAddr", s.overlay, "error", err)
   140  			logger.Error(nil, "insufficient stake")
   141  			jsonhttp.BadRequest(w, "insufficient stake to migrate")
   142  			return
   143  		}
   144  		if errors.Is(err, staking.ErrNotPaused) {
   145  			logger.Debug("contract is not paused", "error", err)
   146  			logger.Error(nil, "contract is not paused")
   147  			jsonhttp.BadRequest(w, "contract is not paused")
   148  			return
   149  		}
   150  		logger.Debug("migrate stake failed", "error", err)
   151  		logger.Error(nil, "migrate stake failed")
   152  		jsonhttp.InternalServerError(w, "cannot migrate stake")
   153  		return
   154  	}
   155  
   156  	jsonhttp.OK(w, stakeTransactionReponse{TxHash: txHash.String()})
   157  }