mirror of
https://github.com/status-im/status-go.git
synced 2025-01-12 23:55:03 +00:00
79b1c547d1
* chore_: unused `BuildTx` function removed from the processor interface and types that are implement it Since the `BuildTx` function is not used anywhere, it's removed from the code. * fix_: resolving nonce improvements When the app sends more than a single tx from the same account on the same chain, some chains do not return appropriate nonce (they do not consider pending txs), because of that we place more tx with the same nonce, where all but the first one fail. Changes in this PR keep track of nonces being used in the same sending/bridging flow, which means for the first tx from the multi txs the app asks the chain for the nonce, and every next nonce is resolved by incrementing the last used nonce by 1.
654 lines
22 KiB
Go
654 lines
22 KiB
Go
package pathprocessor
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
netUrl "net/url"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum"
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/status-im/status-go/account"
|
|
"github.com/status-im/status-go/contracts"
|
|
"github.com/status-im/status-go/contracts/hop"
|
|
hopL1CctpImplementation "github.com/status-im/status-go/contracts/hop/l1Contracts/l1CctpImplementation"
|
|
hopL1Erc20Bridge "github.com/status-im/status-go/contracts/hop/l1Contracts/l1Erc20Bridge"
|
|
hopL1EthBridge "github.com/status-im/status-go/contracts/hop/l1Contracts/l1EthBridge"
|
|
hopL1HopBridge "github.com/status-im/status-go/contracts/hop/l1Contracts/l1HopBridge"
|
|
hopL2AmmWrapper "github.com/status-im/status-go/contracts/hop/l2Contracts/l2AmmWrapper"
|
|
hopL2ArbitrumBridge "github.com/status-im/status-go/contracts/hop/l2Contracts/l2ArbitrumBridge"
|
|
hopL2CctpImplementation "github.com/status-im/status-go/contracts/hop/l2Contracts/l2CctpImplementation"
|
|
hopL2OptimismBridge "github.com/status-im/status-go/contracts/hop/l2Contracts/l2OptimismBridge"
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/status-im/status-go/rpc"
|
|
"github.com/status-im/status-go/rpc/chain"
|
|
"github.com/status-im/status-go/rpc/network"
|
|
"github.com/status-im/status-go/services/wallet/bigint"
|
|
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
|
"github.com/status-im/status-go/services/wallet/token"
|
|
"github.com/status-im/status-go/transactions"
|
|
)
|
|
|
|
type HopBridgeTxArgs struct {
|
|
transactions.SendTxArgs
|
|
ChainID uint64 `json:"chainId"`
|
|
ChainIDTo uint64 `json:"chainIdTo"`
|
|
Symbol string `json:"symbol"`
|
|
Recipient common.Address `json:"recipient"`
|
|
Amount *hexutil.Big `json:"amount"`
|
|
BonderFee *hexutil.Big `json:"bonderFee"`
|
|
}
|
|
|
|
type BonderFee struct {
|
|
AmountIn *bigint.BigInt `json:"amountIn"`
|
|
Slippage float32 `json:"slippage"`
|
|
AmountOutMin *bigint.BigInt `json:"amountOutMin"`
|
|
DestinationAmountOutMin *bigint.BigInt `json:"destinationAmountOutMin"`
|
|
BonderFee *bigint.BigInt `json:"bonderFee"`
|
|
EstimatedRecieved *bigint.BigInt `json:"estimatedRecieved"`
|
|
Deadline int64 `json:"deadline"`
|
|
DestinationDeadline int64 `json:"destinationDeadline"`
|
|
}
|
|
|
|
func (bf *BonderFee) UnmarshalJSON(data []byte) error {
|
|
type Alias BonderFee
|
|
aux := &struct {
|
|
AmountIn string `json:"amountIn"`
|
|
Slippage float32 `json:"slippage"`
|
|
AmountOutMin string `json:"amountOutMin"`
|
|
DestinationAmountOutMin string `json:"destinationAmountOutMin"`
|
|
BonderFee string `json:"bonderFee"`
|
|
EstimatedRecieved string `json:"estimatedRecieved"`
|
|
Deadline int64 `json:"deadline"`
|
|
DestinationDeadline *int64 `json:"destinationDeadline"`
|
|
*Alias
|
|
}{
|
|
Alias: (*Alias)(bf),
|
|
}
|
|
|
|
if err := json.Unmarshal(data, aux); err != nil {
|
|
return createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
bf.AmountIn = &bigint.BigInt{Int: new(big.Int)}
|
|
bf.AmountIn.SetString(aux.AmountIn, 10)
|
|
|
|
bf.Slippage = aux.Slippage
|
|
|
|
bf.AmountOutMin = &bigint.BigInt{Int: new(big.Int)}
|
|
bf.AmountOutMin.SetString(aux.AmountOutMin, 10)
|
|
|
|
bf.DestinationAmountOutMin = &bigint.BigInt{Int: new(big.Int)}
|
|
bf.DestinationAmountOutMin.SetString(aux.DestinationAmountOutMin, 10)
|
|
|
|
bf.BonderFee = &bigint.BigInt{Int: new(big.Int)}
|
|
bf.BonderFee.SetString(aux.BonderFee, 10)
|
|
|
|
bf.EstimatedRecieved = &bigint.BigInt{Int: new(big.Int)}
|
|
bf.EstimatedRecieved.SetString(aux.EstimatedRecieved, 10)
|
|
|
|
bf.Deadline = aux.Deadline
|
|
|
|
if aux.DestinationDeadline != nil {
|
|
bf.DestinationDeadline = *aux.DestinationDeadline
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type HopBridgeProcessor struct {
|
|
transactor transactions.TransactorIface
|
|
httpClient *thirdparty.HTTPClient
|
|
tokenManager *token.Manager
|
|
contractMaker *contracts.ContractMaker
|
|
networkManager network.ManagerInterface
|
|
bonderFee *sync.Map // [fromChainName-toChainName]BonderFee
|
|
}
|
|
|
|
func NewHopBridgeProcessor(rpcClient rpc.ClientInterface, transactor transactions.TransactorIface, tokenManager *token.Manager, networkManager network.ManagerInterface) *HopBridgeProcessor {
|
|
return &HopBridgeProcessor{
|
|
contractMaker: &contracts.ContractMaker{RPCClient: rpcClient},
|
|
httpClient: thirdparty.NewHTTPClient(),
|
|
transactor: transactor,
|
|
tokenManager: tokenManager,
|
|
networkManager: networkManager,
|
|
bonderFee: &sync.Map{},
|
|
}
|
|
}
|
|
|
|
func createBridgeHopErrorResponse(err error) error {
|
|
return createErrorResponse(ProcessorBridgeHopName, err)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) Name() string {
|
|
return ProcessorBridgeHopName
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) Clear() {
|
|
h.bonderFee = &sync.Map{}
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) AvailableFor(params ProcessorInputParams) (bool, error) {
|
|
if params.FromChain == nil || params.ToChain == nil {
|
|
return false, ErrNoChainSet
|
|
}
|
|
if params.FromToken == nil {
|
|
return false, ErrNoTokenSet
|
|
}
|
|
if params.ToToken != nil {
|
|
return false, ErrToTokenShouldNotBeSet
|
|
}
|
|
if params.FromChain.ChainID == params.ToChain.ChainID {
|
|
return false, ErrFromAndToChainsMustBeDifferent
|
|
}
|
|
// We chcek if the contract is available on the network for the token
|
|
_, err := h.GetContractAddress(params)
|
|
// toToken is not nil only if the send type is Swap
|
|
return err == nil, err
|
|
}
|
|
|
|
func (c *HopBridgeProcessor) getAppropriateABI(contractType string, chainID uint64, token *token.Token) (abi.ABI, error) {
|
|
switch contractType {
|
|
case hop.CctpL1Bridge:
|
|
return abi.JSON(strings.NewReader(hopL1CctpImplementation.HopL1CctpImplementationABI))
|
|
case hop.L1Bridge:
|
|
if token.IsNative() {
|
|
return abi.JSON(strings.NewReader(hopL1EthBridge.HopL1EthBridgeABI))
|
|
}
|
|
if token.Symbol == HopSymbol {
|
|
return abi.JSON(strings.NewReader(hopL1HopBridge.HopL1HopBridgeABI))
|
|
}
|
|
return abi.JSON(strings.NewReader(hopL1Erc20Bridge.HopL1Erc20BridgeABI))
|
|
case hop.L2AmmWrapper:
|
|
return abi.JSON(strings.NewReader(hopL2AmmWrapper.HopL2AmmWrapperABI))
|
|
case hop.CctpL2Bridge:
|
|
return abi.JSON(strings.NewReader(hopL2CctpImplementation.HopL2CctpImplementationABI))
|
|
case hop.L2Bridge:
|
|
if chainID == walletCommon.OptimismMainnet ||
|
|
chainID == walletCommon.OptimismSepolia {
|
|
return abi.JSON(strings.NewReader(hopL2OptimismBridge.HopL2OptimismBridgeABI))
|
|
}
|
|
if chainID == walletCommon.ArbitrumMainnet ||
|
|
chainID == walletCommon.ArbitrumSepolia {
|
|
return abi.JSON(strings.NewReader(hopL2ArbitrumBridge.HopL2ArbitrumBridgeABI))
|
|
}
|
|
}
|
|
|
|
return abi.ABI{}, ErrNotAvailableForContractType
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) PackTxInputData(params ProcessorInputParams) ([]byte, error) {
|
|
_, contractType, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol)
|
|
if err != nil {
|
|
return []byte{}, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return h.packTxInputDataInternally(params, contractType)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) packTxInputDataInternally(params ProcessorInputParams, contractType string) ([]byte, error) {
|
|
abi, err := h.getAppropriateABI(contractType, params.FromChain.ChainID, params.FromToken)
|
|
if err != nil {
|
|
return []byte{}, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "")
|
|
bonderFeeIns, ok := h.bonderFee.Load(bonderKey)
|
|
if !ok {
|
|
return nil, ErrNoBonderFeeFound
|
|
}
|
|
bonderFee := bonderFeeIns.(*BonderFee)
|
|
|
|
switch contractType {
|
|
case hop.CctpL1Bridge:
|
|
return h.packCctpL1BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee)
|
|
case hop.L1Bridge:
|
|
return h.packL1BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee)
|
|
case hop.L2AmmWrapper:
|
|
return h.packL2AmmWrapperTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee)
|
|
case hop.CctpL2Bridge:
|
|
return h.packCctpL2BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee)
|
|
case hop.L2Bridge:
|
|
return h.packL2BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee)
|
|
}
|
|
|
|
return []byte{}, ErrContractTypeNotSupported
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) EstimateGas(params ProcessorInputParams) (uint64, error) {
|
|
if params.TestsMode {
|
|
if params.TestEstimationMap != nil {
|
|
if val, ok := params.TestEstimationMap[h.Name()]; ok {
|
|
return val, nil
|
|
}
|
|
}
|
|
return 0, ErrNoEstimationFound
|
|
}
|
|
|
|
value := big.NewInt(0)
|
|
if params.FromToken.IsNative() {
|
|
value = params.AmountIn
|
|
}
|
|
|
|
contractAddress, contractType, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol)
|
|
if err != nil {
|
|
return 0, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
input, err := h.packTxInputDataInternally(params, contractType)
|
|
if err != nil {
|
|
return 0, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
ethClient, err := h.contractMaker.RPCClient.EthClient(params.FromChain.ChainID)
|
|
if err != nil {
|
|
return 0, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
msg := ethereum.CallMsg{
|
|
From: params.FromAddr,
|
|
To: &contractAddress,
|
|
Value: value,
|
|
Data: input,
|
|
}
|
|
|
|
estimation, err := ethClient.EstimateGas(context.Background(), msg)
|
|
if err != nil {
|
|
if !params.FromToken.IsNative() {
|
|
// TODO: this is a temporary solution until we find a better way to estimate the gas
|
|
// hardcoding the estimation for other than ETH, cause we cannot get a proper estimation without having an approval placed first
|
|
// this is an error we're facing otherwise: `execution reverted: ERC20: transfer amount exceeds allowance`
|
|
estimation = 350000
|
|
} else {
|
|
return 0, createBridgeHopErrorResponse(err)
|
|
}
|
|
}
|
|
|
|
increasedEstimation := float64(estimation) * IncreaseEstimatedGasFactor
|
|
return uint64(increasedEstimation), nil
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) {
|
|
address, _, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol)
|
|
return address, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) {
|
|
fromChain := h.networkManager.Find(sendArgs.HopTx.ChainID)
|
|
if fromChain == nil {
|
|
return tx, fmt.Errorf("ChainID not supported %d", sendArgs.HopTx.ChainID)
|
|
}
|
|
|
|
token := h.tokenManager.FindToken(fromChain, sendArgs.HopTx.Symbol)
|
|
|
|
var nonce uint64
|
|
if lastUsedNonce < 0 {
|
|
nonce, err = h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
} else {
|
|
nonce = uint64(lastUsedNonce) + 1
|
|
}
|
|
|
|
argNonce := hexutil.Uint64(nonce)
|
|
sendArgs.HopTx.Nonce = &argNonce
|
|
|
|
txOpts := sendArgs.HopTx.ToTransactOpts(signerFn)
|
|
if token.IsNative() {
|
|
txOpts.Value = (*big.Int)(sendArgs.HopTx.Amount)
|
|
}
|
|
|
|
ethClient, err := h.contractMaker.RPCClient.EthClient(fromChain.ChainID)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
contractAddress, contractType, err := hop.GetContractAddress(fromChain.ChainID, sendArgs.HopTx.Symbol)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
bonderKey := makeKey(sendArgs.HopTx.ChainID, sendArgs.HopTx.ChainIDTo, "", "")
|
|
bonderFeeIns, ok := h.bonderFee.Load(bonderKey)
|
|
if !ok {
|
|
return nil, ErrNoBonderFeeFound
|
|
}
|
|
bonderFee := bonderFeeIns.(*BonderFee)
|
|
|
|
switch contractType {
|
|
case hop.CctpL1Bridge:
|
|
tx, err = h.sendCctpL1BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee)
|
|
case hop.L1Bridge:
|
|
tx, err = h.sendL1BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, token, bonderFee)
|
|
case hop.L2AmmWrapper:
|
|
tx, err = h.sendL2AmmWrapperTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee)
|
|
case hop.CctpL2Bridge:
|
|
tx, err = h.sendCctpL2BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee)
|
|
case hop.L2Bridge:
|
|
tx, err = h.sendL2BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee)
|
|
default:
|
|
return tx, ErrContractTypeNotSupported
|
|
}
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
err = h.transactor.StoreAndTrackPendingTx(txOpts.From, sendArgs.HopTx.Symbol, sendArgs.HopTx.ChainID, sendArgs.HopTx.MultiTransactionID, tx)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
return tx, nil
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) {
|
|
tx, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.HopTx.ChainID, sendArgs.HopTx.From, verifiedAccount), lastUsedNonce)
|
|
if err != nil {
|
|
return types.Hash{}, 0, createBridgeHopErrorResponse(err)
|
|
}
|
|
return types.Hash(tx.Hash()), tx.Nonce(), nil
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) {
|
|
tx, err := h.sendOrBuild(sendArgs, nil, lastUsedNonce)
|
|
return tx, tx.Nonce(), createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) CalculateFees(params ProcessorInputParams) (*big.Int, *big.Int, error) {
|
|
bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "")
|
|
if params.TestsMode {
|
|
if val, ok := params.TestBonderFeeMap[params.FromToken.Symbol]; ok {
|
|
res := new(big.Int).Sub(params.AmountIn, val)
|
|
bonderFee := &BonderFee{
|
|
AmountIn: &bigint.BigInt{Int: params.AmountIn},
|
|
Slippage: 5,
|
|
AmountOutMin: &bigint.BigInt{Int: res},
|
|
DestinationAmountOutMin: &bigint.BigInt{Int: res},
|
|
BonderFee: &bigint.BigInt{Int: val},
|
|
EstimatedRecieved: &bigint.BigInt{Int: res},
|
|
Deadline: time.Now().Add(SevenDaysInSeconds).Unix(),
|
|
}
|
|
h.bonderFee.Store(bonderKey, bonderFee)
|
|
return val, ZeroBigIntValue, nil
|
|
}
|
|
return nil, nil, ErrNoBonderFeeFound
|
|
}
|
|
|
|
hopChainsMap := map[uint64]string{
|
|
walletCommon.EthereumMainnet: "ethereum",
|
|
walletCommon.OptimismMainnet: "optimism",
|
|
walletCommon.ArbitrumMainnet: "arbitrum",
|
|
}
|
|
|
|
fromChainName, ok := hopChainsMap[params.FromChain.ChainID]
|
|
if !ok {
|
|
return nil, nil, ErrFromChainNotSupported
|
|
}
|
|
|
|
toChainName, ok := hopChainsMap[params.ToChain.ChainID]
|
|
if !ok {
|
|
return nil, nil, ErrToChainNotSupported
|
|
}
|
|
|
|
reqParams := netUrl.Values{}
|
|
reqParams.Add("amount", params.AmountIn.String())
|
|
reqParams.Add("token", params.FromToken.Symbol)
|
|
reqParams.Add("fromChain", fromChainName)
|
|
reqParams.Add("toChain", toChainName)
|
|
reqParams.Add("slippage", "0.5") // menas 0.5%
|
|
|
|
url := "https://api.hop.exchange/v1/quote"
|
|
response, err := h.httpClient.DoGetRequest(context.Background(), url, reqParams, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
bonderFee := &BonderFee{}
|
|
err = json.Unmarshal(response, bonderFee)
|
|
if err != nil {
|
|
return nil, nil, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
h.bonderFee.Store(bonderKey, bonderFee)
|
|
|
|
// Remove token fee from bonder fee as said here:
|
|
// https://docs.hop.exchange/v/developer-docs/api/api#get-v1-quote
|
|
// `bonderFee` - The suggested bonder fee for the amount in. The bonder fee also includes the cost of the destination transaction fee.
|
|
tokenFee := new(big.Int).Sub(bonderFee.AmountIn.Int, bonderFee.EstimatedRecieved.Int)
|
|
|
|
return bonderFee.BonderFee.Int, tokenFee, nil
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) {
|
|
bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "")
|
|
bonderFeeIns, ok := h.bonderFee.Load(bonderKey)
|
|
if !ok {
|
|
return nil, ErrNoBonderFeeFound
|
|
}
|
|
bonderFee := bonderFeeIns.(*BonderFee)
|
|
return bonderFee.AmountOutMin.Int, nil
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) packCctpL1BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) {
|
|
return abi.Pack("send",
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) sendCctpL1BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64,
|
|
to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) {
|
|
contractInstance, err := hopL1CctpImplementation.NewHopL1CctpImplementation(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.Send(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) packL1BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) {
|
|
return abi.Pack("sendToL2",
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline),
|
|
common.Address{},
|
|
ZeroBigIntValue)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) sendL1BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64,
|
|
to common.Address, txOpts *bind.TransactOpts, token *token.Token, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) {
|
|
if token.IsNative() {
|
|
contractInstance, err := hopL1EthBridge.NewHopL1EthBridge(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.SendToL2(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline),
|
|
common.Address{},
|
|
ZeroBigIntValue)
|
|
}
|
|
|
|
if token.Symbol == HopSymbol {
|
|
contractInstance, err := hopL1HopBridge.NewHopL1HopBridge(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.SendToL2(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline),
|
|
common.Address{},
|
|
ZeroBigIntValue)
|
|
}
|
|
|
|
contractInstance, err := hopL1Erc20Bridge.NewHopL1Erc20Bridge(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.SendToL2(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline),
|
|
common.Address{},
|
|
ZeroBigIntValue)
|
|
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) packCctpL2BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) {
|
|
return abi.Pack("send",
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) sendCctpL2BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64,
|
|
to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) {
|
|
contractInstance, err := hopL2CctpImplementation.NewHopL2CctpImplementation(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.Send(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int,
|
|
)
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) packL2AmmWrapperTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) {
|
|
return abi.Pack("swapAndSend",
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline),
|
|
bonderFee.DestinationAmountOutMin.Int,
|
|
big.NewInt(bonderFee.DestinationDeadline))
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) sendL2AmmWrapperTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64,
|
|
to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) {
|
|
contractInstance, err := hopL2AmmWrapper.NewHopL2AmmWrapper(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.SwapAndSend(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline),
|
|
bonderFee.DestinationAmountOutMin.Int,
|
|
big.NewInt(bonderFee.DestinationDeadline))
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) packL2BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) {
|
|
return abi.Pack("send",
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline))
|
|
}
|
|
|
|
func (h *HopBridgeProcessor) sendL2BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64,
|
|
to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) {
|
|
fromChainID := ethClient.NetworkID()
|
|
if fromChainID == walletCommon.OptimismMainnet ||
|
|
fromChainID == walletCommon.OptimismSepolia {
|
|
contractInstance, err := hopL2OptimismBridge.NewHopL2OptimismBridge(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.Send(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline))
|
|
}
|
|
if fromChainID == walletCommon.ArbitrumMainnet ||
|
|
fromChainID == walletCommon.ArbitrumSepolia {
|
|
contractInstance, err := hopL2ArbitrumBridge.NewHopL2ArbitrumBridge(
|
|
contractAddress,
|
|
ethClient,
|
|
)
|
|
if err != nil {
|
|
return tx, createBridgeHopErrorResponse(err)
|
|
}
|
|
|
|
return contractInstance.Send(
|
|
txOpts,
|
|
big.NewInt(int64(toChainID)),
|
|
to,
|
|
bonderFee.AmountIn.Int,
|
|
bonderFee.BonderFee.Int,
|
|
bonderFee.AmountOutMin.Int,
|
|
big.NewInt(bonderFee.Deadline))
|
|
}
|
|
|
|
return tx, ErrTxForChainNotSupported
|
|
}
|