github.com/status-im/status-go@v1.1.0/services/wallet/router/pathprocessor/processor_stickers_buy.go (about)

     1  package pathprocessor
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  	"strings"
     7  
     8  	"github.com/ethereum/go-ethereum"
     9  	"github.com/ethereum/go-ethereum/accounts/abi"
    10  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    11  	"github.com/ethereum/go-ethereum/common"
    12  	ethTypes "github.com/ethereum/go-ethereum/core/types"
    13  	"github.com/status-im/status-go/account"
    14  	"github.com/status-im/status-go/contracts"
    15  	"github.com/status-im/status-go/contracts/snt"
    16  	stickersContracts "github.com/status-im/status-go/contracts/stickers"
    17  	"github.com/status-im/status-go/eth-node/types"
    18  	"github.com/status-im/status-go/rpc"
    19  	"github.com/status-im/status-go/services/stickers"
    20  	walletCommon "github.com/status-im/status-go/services/wallet/common"
    21  	"github.com/status-im/status-go/transactions"
    22  )
    23  
    24  type StickersBuyProcessor struct {
    25  	contractMaker   *contracts.ContractMaker
    26  	transactor      transactions.TransactorIface
    27  	stickersService *stickers.Service
    28  }
    29  
    30  func NewStickersBuyProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, stickersService *stickers.Service) *StickersBuyProcessor {
    31  	return &StickersBuyProcessor{
    32  		contractMaker: &contracts.ContractMaker{
    33  			RPCClient: rpcClient,
    34  		},
    35  		transactor:      transactor,
    36  		stickersService: stickersService,
    37  	}
    38  }
    39  
    40  func createStickersBuyErrorResponse(err error) error {
    41  	return createErrorResponse(ProcessorStickersBuyName, err)
    42  }
    43  
    44  func (s *StickersBuyProcessor) Name() string {
    45  	return ProcessorStickersBuyName
    46  }
    47  
    48  func (s *StickersBuyProcessor) AvailableFor(params ProcessorInputParams) (bool, error) {
    49  	return params.FromChain.ChainID == walletCommon.EthereumMainnet || params.FromChain.ChainID == walletCommon.EthereumSepolia, nil
    50  }
    51  
    52  func (s *StickersBuyProcessor) CalculateFees(params ProcessorInputParams) (*big.Int, *big.Int, error) {
    53  	return ZeroBigIntValue, ZeroBigIntValue, nil
    54  }
    55  
    56  func (s *StickersBuyProcessor) PackTxInputData(params ProcessorInputParams) ([]byte, error) {
    57  	stickerType, err := s.contractMaker.NewStickerType(params.FromChain.ChainID)
    58  	if err != nil {
    59  		return []byte{}, createStickersBuyErrorResponse(err)
    60  	}
    61  
    62  	callOpts := &bind.CallOpts{Context: context.Background(), Pending: false}
    63  
    64  	packInfo, err := stickerType.GetPackData(callOpts, params.PackID)
    65  	if err != nil {
    66  		return []byte{}, createStickersBuyErrorResponse(err)
    67  	}
    68  
    69  	stickerMarketABI, err := abi.JSON(strings.NewReader(stickersContracts.StickerMarketABI))
    70  	if err != nil {
    71  		return []byte{}, createStickersBuyErrorResponse(err)
    72  	}
    73  
    74  	extraData, err := stickerMarketABI.Pack("buyToken", params.PackID, params.FromAddr, packInfo.Price)
    75  	if err != nil {
    76  		return []byte{}, createStickersBuyErrorResponse(err)
    77  	}
    78  
    79  	sntABI, err := abi.JSON(strings.NewReader(snt.SNTABI))
    80  	if err != nil {
    81  		return []byte{}, createStickersBuyErrorResponse(err)
    82  	}
    83  
    84  	stickerMarketAddress, err := stickersContracts.StickerMarketContractAddress(params.FromChain.ChainID)
    85  	if err != nil {
    86  		return []byte{}, createStickersBuyErrorResponse(err)
    87  	}
    88  
    89  	return sntABI.Pack("approveAndCall", stickerMarketAddress, packInfo.Price, extraData)
    90  }
    91  
    92  func (s *StickersBuyProcessor) EstimateGas(params ProcessorInputParams) (uint64, error) {
    93  	if params.TestsMode {
    94  		if params.TestEstimationMap != nil {
    95  			if val, ok := params.TestEstimationMap[s.Name()]; ok {
    96  				return val.Value, val.Err
    97  			}
    98  		}
    99  		return 0, ErrNoEstimationFound
   100  	}
   101  
   102  	contractAddress, err := s.GetContractAddress(params)
   103  	if err != nil {
   104  		return 0, createStickersBuyErrorResponse(err)
   105  	}
   106  
   107  	input, err := s.PackTxInputData(params)
   108  	if err != nil {
   109  		return 0, createStickersBuyErrorResponse(err)
   110  	}
   111  
   112  	ethClient, err := s.contractMaker.RPCClient.EthClient(params.FromChain.ChainID)
   113  	if err != nil {
   114  		return 0, createStickersBuyErrorResponse(err)
   115  	}
   116  
   117  	msg := ethereum.CallMsg{
   118  		From:  params.FromAddr,
   119  		To:    &contractAddress,
   120  		Value: ZeroBigIntValue,
   121  		Data:  input,
   122  	}
   123  
   124  	estimation, err := ethClient.EstimateGas(context.Background(), msg)
   125  	if err != nil {
   126  		return 0, createStickersBuyErrorResponse(err)
   127  	}
   128  
   129  	increasedEstimation := float64(estimation) * IncreaseEstimatedGasFactor
   130  
   131  	return uint64(increasedEstimation), nil
   132  }
   133  
   134  func (s *StickersBuyProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) {
   135  	return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce, verifiedAccount)
   136  }
   137  
   138  func (s *StickersBuyProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) {
   139  	return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx, lastUsedNonce)
   140  }
   141  
   142  func (s *StickersBuyProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) {
   143  	return params.AmountIn, nil
   144  }
   145  
   146  func (s *StickersBuyProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) {
   147  	return snt.ContractAddress(params.FromChain.ChainID)
   148  }