github.com/status-im/status-go@v1.1.0/services/wallet/router/pathprocessor/processor_bridge_hop.go (about) 1 package pathprocessor 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "math/big" 8 netUrl "net/url" 9 "strings" 10 "sync" 11 "time" 12 13 "github.com/ethereum/go-ethereum" 14 "github.com/ethereum/go-ethereum/accounts/abi" 15 "github.com/ethereum/go-ethereum/accounts/abi/bind" 16 "github.com/ethereum/go-ethereum/common" 17 "github.com/ethereum/go-ethereum/common/hexutil" 18 ethTypes "github.com/ethereum/go-ethereum/core/types" 19 "github.com/status-im/status-go/account" 20 "github.com/status-im/status-go/contracts" 21 "github.com/status-im/status-go/contracts/hop" 22 hopL1CctpImplementation "github.com/status-im/status-go/contracts/hop/l1Contracts/l1CctpImplementation" 23 hopL1Erc20Bridge "github.com/status-im/status-go/contracts/hop/l1Contracts/l1Erc20Bridge" 24 hopL1EthBridge "github.com/status-im/status-go/contracts/hop/l1Contracts/l1EthBridge" 25 hopL1HopBridge "github.com/status-im/status-go/contracts/hop/l1Contracts/l1HopBridge" 26 hopL2AmmWrapper "github.com/status-im/status-go/contracts/hop/l2Contracts/l2AmmWrapper" 27 hopL2ArbitrumBridge "github.com/status-im/status-go/contracts/hop/l2Contracts/l2ArbitrumBridge" 28 hopL2CctpImplementation "github.com/status-im/status-go/contracts/hop/l2Contracts/l2CctpImplementation" 29 hopL2OptimismBridge "github.com/status-im/status-go/contracts/hop/l2Contracts/l2OptimismBridge" 30 "github.com/status-im/status-go/eth-node/types" 31 "github.com/status-im/status-go/rpc" 32 "github.com/status-im/status-go/rpc/chain" 33 "github.com/status-im/status-go/rpc/network" 34 "github.com/status-im/status-go/services/wallet/bigint" 35 walletCommon "github.com/status-im/status-go/services/wallet/common" 36 "github.com/status-im/status-go/services/wallet/thirdparty" 37 "github.com/status-im/status-go/services/wallet/token" 38 "github.com/status-im/status-go/transactions" 39 ) 40 41 type HopBridgeTxArgs struct { 42 transactions.SendTxArgs 43 ChainID uint64 `json:"chainId"` 44 ChainIDTo uint64 `json:"chainIdTo"` 45 Symbol string `json:"symbol"` 46 Recipient common.Address `json:"recipient"` 47 Amount *hexutil.Big `json:"amount"` 48 BonderFee *hexutil.Big `json:"bonderFee"` 49 } 50 51 type BonderFee struct { 52 AmountIn *bigint.BigInt `json:"amountIn"` 53 Slippage float32 `json:"slippage"` 54 AmountOutMin *bigint.BigInt `json:"amountOutMin"` 55 DestinationAmountOutMin *bigint.BigInt `json:"destinationAmountOutMin"` 56 BonderFee *bigint.BigInt `json:"bonderFee"` 57 EstimatedRecieved *bigint.BigInt `json:"estimatedRecieved"` 58 Deadline int64 `json:"deadline"` 59 DestinationDeadline int64 `json:"destinationDeadline"` 60 } 61 62 func (bf *BonderFee) UnmarshalJSON(data []byte) error { 63 type Alias BonderFee 64 aux := &struct { 65 AmountIn string `json:"amountIn"` 66 Slippage float32 `json:"slippage"` 67 AmountOutMin string `json:"amountOutMin"` 68 DestinationAmountOutMin string `json:"destinationAmountOutMin"` 69 BonderFee string `json:"bonderFee"` 70 EstimatedRecieved string `json:"estimatedRecieved"` 71 Deadline int64 `json:"deadline"` 72 DestinationDeadline *int64 `json:"destinationDeadline"` 73 *Alias 74 }{ 75 Alias: (*Alias)(bf), 76 } 77 78 if err := json.Unmarshal(data, aux); err != nil { 79 return createBridgeHopErrorResponse(err) 80 } 81 82 bf.AmountIn = &bigint.BigInt{Int: new(big.Int)} 83 bf.AmountIn.SetString(aux.AmountIn, 10) 84 85 bf.Slippage = aux.Slippage 86 87 bf.AmountOutMin = &bigint.BigInt{Int: new(big.Int)} 88 bf.AmountOutMin.SetString(aux.AmountOutMin, 10) 89 90 bf.DestinationAmountOutMin = &bigint.BigInt{Int: new(big.Int)} 91 bf.DestinationAmountOutMin.SetString(aux.DestinationAmountOutMin, 10) 92 93 bf.BonderFee = &bigint.BigInt{Int: new(big.Int)} 94 bf.BonderFee.SetString(aux.BonderFee, 10) 95 96 bf.EstimatedRecieved = &bigint.BigInt{Int: new(big.Int)} 97 bf.EstimatedRecieved.SetString(aux.EstimatedRecieved, 10) 98 99 bf.Deadline = aux.Deadline 100 101 if aux.DestinationDeadline != nil { 102 bf.DestinationDeadline = *aux.DestinationDeadline 103 } 104 105 return nil 106 } 107 108 type HopBridgeProcessor struct { 109 transactor transactions.TransactorIface 110 httpClient *thirdparty.HTTPClient 111 tokenManager *token.Manager 112 contractMaker *contracts.ContractMaker 113 networkManager network.ManagerInterface 114 bonderFee *sync.Map // [fromChainName-toChainName]BonderFee 115 } 116 117 func NewHopBridgeProcessor(rpcClient rpc.ClientInterface, transactor transactions.TransactorIface, tokenManager *token.Manager, networkManager network.ManagerInterface) *HopBridgeProcessor { 118 return &HopBridgeProcessor{ 119 contractMaker: &contracts.ContractMaker{RPCClient: rpcClient}, 120 httpClient: thirdparty.NewHTTPClient(), 121 transactor: transactor, 122 tokenManager: tokenManager, 123 networkManager: networkManager, 124 bonderFee: &sync.Map{}, 125 } 126 } 127 128 func createBridgeHopErrorResponse(err error) error { 129 return createErrorResponse(ProcessorBridgeHopName, err) 130 } 131 132 func (h *HopBridgeProcessor) Name() string { 133 return ProcessorBridgeHopName 134 } 135 136 func (h *HopBridgeProcessor) Clear() { 137 h.bonderFee = &sync.Map{} 138 } 139 140 func (h *HopBridgeProcessor) AvailableFor(params ProcessorInputParams) (bool, error) { 141 if params.FromChain == nil || params.ToChain == nil { 142 return false, ErrNoChainSet 143 } 144 if params.FromToken == nil { 145 return false, ErrNoTokenSet 146 } 147 if params.ToToken != nil { 148 return false, ErrToTokenShouldNotBeSet 149 } 150 if params.FromChain.ChainID == params.ToChain.ChainID { 151 return false, ErrFromAndToChainsMustBeDifferent 152 } 153 // We chcek if the contract is available on the network for the token 154 _, err := h.GetContractAddress(params) 155 // toToken is not nil only if the send type is Swap 156 return err == nil, err 157 } 158 159 func (c *HopBridgeProcessor) getAppropriateABI(contractType string, chainID uint64, token *token.Token) (abi.ABI, error) { 160 switch contractType { 161 case hop.CctpL1Bridge: 162 return abi.JSON(strings.NewReader(hopL1CctpImplementation.HopL1CctpImplementationABI)) 163 case hop.L1Bridge: 164 if token.IsNative() { 165 return abi.JSON(strings.NewReader(hopL1EthBridge.HopL1EthBridgeABI)) 166 } 167 if token.Symbol == HopSymbol { 168 return abi.JSON(strings.NewReader(hopL1HopBridge.HopL1HopBridgeABI)) 169 } 170 return abi.JSON(strings.NewReader(hopL1Erc20Bridge.HopL1Erc20BridgeABI)) 171 case hop.L2AmmWrapper: 172 return abi.JSON(strings.NewReader(hopL2AmmWrapper.HopL2AmmWrapperABI)) 173 case hop.CctpL2Bridge: 174 return abi.JSON(strings.NewReader(hopL2CctpImplementation.HopL2CctpImplementationABI)) 175 case hop.L2Bridge: 176 if chainID == walletCommon.OptimismMainnet || 177 chainID == walletCommon.OptimismSepolia { 178 return abi.JSON(strings.NewReader(hopL2OptimismBridge.HopL2OptimismBridgeABI)) 179 } 180 if chainID == walletCommon.ArbitrumMainnet || 181 chainID == walletCommon.ArbitrumSepolia { 182 return abi.JSON(strings.NewReader(hopL2ArbitrumBridge.HopL2ArbitrumBridgeABI)) 183 } 184 } 185 186 return abi.ABI{}, ErrNotAvailableForContractType 187 } 188 189 func (h *HopBridgeProcessor) PackTxInputData(params ProcessorInputParams) ([]byte, error) { 190 _, contractType, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol) 191 if err != nil { 192 return []byte{}, createBridgeHopErrorResponse(err) 193 } 194 195 return h.packTxInputDataInternally(params, contractType) 196 } 197 198 func (h *HopBridgeProcessor) packTxInputDataInternally(params ProcessorInputParams, contractType string) ([]byte, error) { 199 abi, err := h.getAppropriateABI(contractType, params.FromChain.ChainID, params.FromToken) 200 if err != nil { 201 return []byte{}, createBridgeHopErrorResponse(err) 202 } 203 204 bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "") 205 bonderFeeIns, ok := h.bonderFee.Load(bonderKey) 206 if !ok { 207 return nil, ErrNoBonderFeeFound 208 } 209 bonderFee := bonderFeeIns.(*BonderFee) 210 211 switch contractType { 212 case hop.CctpL1Bridge: 213 return h.packCctpL1BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee) 214 case hop.L1Bridge: 215 return h.packL1BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee) 216 case hop.L2AmmWrapper: 217 return h.packL2AmmWrapperTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee) 218 case hop.CctpL2Bridge: 219 return h.packCctpL2BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee) 220 case hop.L2Bridge: 221 return h.packL2BridgeTx(abi, params.ToChain.ChainID, params.ToAddr, bonderFee) 222 } 223 224 return []byte{}, ErrContractTypeNotSupported 225 } 226 227 func (h *HopBridgeProcessor) EstimateGas(params ProcessorInputParams) (uint64, error) { 228 if params.TestsMode { 229 if params.TestEstimationMap != nil { 230 if val, ok := params.TestEstimationMap[h.Name()]; ok { 231 return val.Value, val.Err 232 } 233 } 234 return 0, ErrNoEstimationFound 235 } 236 237 value := big.NewInt(0) 238 if params.FromToken.IsNative() { 239 value = params.AmountIn 240 } 241 242 contractAddress, contractType, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol) 243 if err != nil { 244 return 0, createBridgeHopErrorResponse(err) 245 } 246 247 input, err := h.packTxInputDataInternally(params, contractType) 248 if err != nil { 249 return 0, createBridgeHopErrorResponse(err) 250 } 251 252 ethClient, err := h.contractMaker.RPCClient.EthClient(params.FromChain.ChainID) 253 if err != nil { 254 return 0, createBridgeHopErrorResponse(err) 255 } 256 257 msg := ethereum.CallMsg{ 258 From: params.FromAddr, 259 To: &contractAddress, 260 Value: value, 261 Data: input, 262 } 263 264 estimation, err := ethClient.EstimateGas(context.Background(), msg) 265 if err != nil { 266 if !params.FromToken.IsNative() { 267 // TODO: this is a temporary solution until we find a better way to estimate the gas 268 // hardcoding the estimation for other than ETH, cause we cannot get a proper estimation without having an approval placed first 269 // this is an error we're facing otherwise: `execution reverted: ERC20: transfer amount exceeds allowance` 270 estimation = 350000 271 } else { 272 return 0, createBridgeHopErrorResponse(err) 273 } 274 } 275 276 increasedEstimation := float64(estimation) * IncreaseEstimatedGasFactor 277 return uint64(increasedEstimation), nil 278 } 279 280 func (h *HopBridgeProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) { 281 address, _, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol) 282 return address, createBridgeHopErrorResponse(err) 283 } 284 285 func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) { 286 fromChain := h.networkManager.Find(sendArgs.HopTx.ChainID) 287 if fromChain == nil { 288 return tx, fmt.Errorf("ChainID not supported %d", sendArgs.HopTx.ChainID) 289 } 290 291 token := h.tokenManager.FindToken(fromChain, sendArgs.HopTx.Symbol) 292 293 var nonce uint64 294 if lastUsedNonce < 0 { 295 nonce, err = h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From) 296 if err != nil { 297 return tx, createBridgeHopErrorResponse(err) 298 } 299 } else { 300 nonce = uint64(lastUsedNonce) + 1 301 } 302 303 argNonce := hexutil.Uint64(nonce) 304 sendArgs.HopTx.Nonce = &argNonce 305 306 txOpts := sendArgs.HopTx.ToTransactOpts(signerFn) 307 if token.IsNative() { 308 txOpts.Value = (*big.Int)(sendArgs.HopTx.Amount) 309 } 310 311 ethClient, err := h.contractMaker.RPCClient.EthClient(fromChain.ChainID) 312 if err != nil { 313 return tx, createBridgeHopErrorResponse(err) 314 } 315 316 contractAddress, contractType, err := hop.GetContractAddress(fromChain.ChainID, sendArgs.HopTx.Symbol) 317 if err != nil { 318 return tx, createBridgeHopErrorResponse(err) 319 } 320 321 bonderKey := makeKey(sendArgs.HopTx.ChainID, sendArgs.HopTx.ChainIDTo, "", "") 322 bonderFeeIns, ok := h.bonderFee.Load(bonderKey) 323 if !ok { 324 return nil, ErrNoBonderFeeFound 325 } 326 bonderFee := bonderFeeIns.(*BonderFee) 327 328 switch contractType { 329 case hop.CctpL1Bridge: 330 tx, err = h.sendCctpL1BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee) 331 case hop.L1Bridge: 332 tx, err = h.sendL1BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, token, bonderFee) 333 case hop.L2AmmWrapper: 334 tx, err = h.sendL2AmmWrapperTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee) 335 case hop.CctpL2Bridge: 336 tx, err = h.sendCctpL2BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee) 337 case hop.L2Bridge: 338 tx, err = h.sendL2BridgeTx(contractAddress, ethClient, sendArgs.HopTx.ChainIDTo, sendArgs.HopTx.Recipient, txOpts, bonderFee) 339 default: 340 return tx, ErrContractTypeNotSupported 341 } 342 if err != nil { 343 return tx, createBridgeHopErrorResponse(err) 344 } 345 err = h.transactor.StoreAndTrackPendingTx(txOpts.From, sendArgs.HopTx.Symbol, sendArgs.HopTx.ChainID, sendArgs.HopTx.MultiTransactionID, tx) 346 if err != nil { 347 return tx, createBridgeHopErrorResponse(err) 348 } 349 return tx, nil 350 } 351 352 func (h *HopBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) { 353 tx, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.HopTx.ChainID, sendArgs.HopTx.From, verifiedAccount), lastUsedNonce) 354 if err != nil { 355 return types.Hash{}, 0, createBridgeHopErrorResponse(err) 356 } 357 return types.Hash(tx.Hash()), tx.Nonce(), nil 358 } 359 360 func (h *HopBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) { 361 tx, err := h.sendOrBuild(sendArgs, nil, lastUsedNonce) 362 return tx, tx.Nonce(), createBridgeHopErrorResponse(err) 363 } 364 365 func (h *HopBridgeProcessor) CalculateFees(params ProcessorInputParams) (*big.Int, *big.Int, error) { 366 bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "") 367 if params.TestsMode { 368 if val, ok := params.TestBonderFeeMap[params.FromToken.Symbol]; ok { 369 res := new(big.Int).Sub(params.AmountIn, val) 370 bonderFee := &BonderFee{ 371 AmountIn: &bigint.BigInt{Int: params.AmountIn}, 372 Slippage: 5, 373 AmountOutMin: &bigint.BigInt{Int: res}, 374 DestinationAmountOutMin: &bigint.BigInt{Int: res}, 375 BonderFee: &bigint.BigInt{Int: val}, 376 EstimatedRecieved: &bigint.BigInt{Int: res}, 377 Deadline: time.Now().Add(SevenDaysInSeconds).Unix(), 378 } 379 h.bonderFee.Store(bonderKey, bonderFee) 380 return val, ZeroBigIntValue, nil 381 } 382 return nil, nil, ErrNoBonderFeeFound 383 } 384 385 hopChainsMap := map[uint64]string{ 386 walletCommon.EthereumMainnet: "ethereum", 387 walletCommon.OptimismMainnet: "optimism", 388 walletCommon.ArbitrumMainnet: "arbitrum", 389 } 390 391 fromChainName, ok := hopChainsMap[params.FromChain.ChainID] 392 if !ok { 393 return nil, nil, ErrFromChainNotSupported 394 } 395 396 toChainName, ok := hopChainsMap[params.ToChain.ChainID] 397 if !ok { 398 return nil, nil, ErrToChainNotSupported 399 } 400 401 reqParams := netUrl.Values{} 402 reqParams.Add("amount", params.AmountIn.String()) 403 reqParams.Add("token", params.FromToken.Symbol) 404 reqParams.Add("fromChain", fromChainName) 405 reqParams.Add("toChain", toChainName) 406 reqParams.Add("slippage", "0.5") // menas 0.5% 407 408 url := "https://api.hop.exchange/v1/quote" 409 response, err := h.httpClient.DoGetRequest(context.Background(), url, reqParams, nil) 410 if err != nil { 411 return nil, nil, err 412 } 413 414 bonderFee := &BonderFee{} 415 err = json.Unmarshal(response, bonderFee) 416 if err != nil { 417 return nil, nil, createBridgeHopErrorResponse(err) 418 } 419 420 h.bonderFee.Store(bonderKey, bonderFee) 421 422 // Remove token fee from bonder fee as said here: 423 // https://docs.hop.exchange/v/developer-docs/api/api#get-v1-quote 424 // `bonderFee` - The suggested bonder fee for the amount in. The bonder fee also includes the cost of the destination transaction fee. 425 tokenFee := new(big.Int).Sub(bonderFee.AmountIn.Int, bonderFee.EstimatedRecieved.Int) 426 427 return bonderFee.BonderFee.Int, tokenFee, nil 428 } 429 430 func (h *HopBridgeProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) { 431 bonderKey := makeKey(params.FromChain.ChainID, params.ToChain.ChainID, "", "") 432 bonderFeeIns, ok := h.bonderFee.Load(bonderKey) 433 if !ok { 434 return nil, ErrNoBonderFeeFound 435 } 436 bonderFee := bonderFeeIns.(*BonderFee) 437 return bonderFee.AmountOutMin.Int, nil 438 } 439 440 func (h *HopBridgeProcessor) packCctpL1BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) { 441 return abi.Pack("send", 442 big.NewInt(int64(toChainID)), 443 to, 444 bonderFee.AmountIn.Int, 445 bonderFee.BonderFee.Int) 446 } 447 448 func (h *HopBridgeProcessor) sendCctpL1BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64, 449 to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) { 450 contractInstance, err := hopL1CctpImplementation.NewHopL1CctpImplementation( 451 contractAddress, 452 ethClient, 453 ) 454 if err != nil { 455 return tx, createBridgeHopErrorResponse(err) 456 } 457 458 return contractInstance.Send( 459 txOpts, 460 big.NewInt(int64(toChainID)), 461 to, 462 bonderFee.AmountIn.Int, 463 bonderFee.BonderFee.Int) 464 } 465 466 func (h *HopBridgeProcessor) packL1BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) { 467 return abi.Pack("sendToL2", 468 big.NewInt(int64(toChainID)), 469 to, 470 bonderFee.AmountIn.Int, 471 bonderFee.AmountOutMin.Int, 472 big.NewInt(bonderFee.Deadline), 473 common.Address{}, 474 ZeroBigIntValue) 475 } 476 477 func (h *HopBridgeProcessor) sendL1BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64, 478 to common.Address, txOpts *bind.TransactOpts, token *token.Token, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) { 479 if token.IsNative() { 480 contractInstance, err := hopL1EthBridge.NewHopL1EthBridge( 481 contractAddress, 482 ethClient, 483 ) 484 if err != nil { 485 return tx, createBridgeHopErrorResponse(err) 486 } 487 488 return contractInstance.SendToL2( 489 txOpts, 490 big.NewInt(int64(toChainID)), 491 to, 492 bonderFee.AmountIn.Int, 493 bonderFee.AmountOutMin.Int, 494 big.NewInt(bonderFee.Deadline), 495 common.Address{}, 496 ZeroBigIntValue) 497 } 498 499 if token.Symbol == HopSymbol { 500 contractInstance, err := hopL1HopBridge.NewHopL1HopBridge( 501 contractAddress, 502 ethClient, 503 ) 504 if err != nil { 505 return tx, createBridgeHopErrorResponse(err) 506 } 507 508 return contractInstance.SendToL2( 509 txOpts, 510 big.NewInt(int64(toChainID)), 511 to, 512 bonderFee.AmountIn.Int, 513 bonderFee.AmountOutMin.Int, 514 big.NewInt(bonderFee.Deadline), 515 common.Address{}, 516 ZeroBigIntValue) 517 } 518 519 contractInstance, err := hopL1Erc20Bridge.NewHopL1Erc20Bridge( 520 contractAddress, 521 ethClient, 522 ) 523 if err != nil { 524 return tx, createBridgeHopErrorResponse(err) 525 } 526 527 return contractInstance.SendToL2( 528 txOpts, 529 big.NewInt(int64(toChainID)), 530 to, 531 bonderFee.AmountIn.Int, 532 bonderFee.AmountOutMin.Int, 533 big.NewInt(bonderFee.Deadline), 534 common.Address{}, 535 ZeroBigIntValue) 536 537 } 538 539 func (h *HopBridgeProcessor) packCctpL2BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) { 540 return abi.Pack("send", 541 big.NewInt(int64(toChainID)), 542 to, 543 bonderFee.AmountIn.Int, 544 bonderFee.BonderFee.Int) 545 } 546 547 func (h *HopBridgeProcessor) sendCctpL2BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64, 548 to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) { 549 contractInstance, err := hopL2CctpImplementation.NewHopL2CctpImplementation( 550 contractAddress, 551 ethClient, 552 ) 553 if err != nil { 554 return tx, createBridgeHopErrorResponse(err) 555 } 556 557 return contractInstance.Send( 558 txOpts, 559 big.NewInt(int64(toChainID)), 560 to, 561 bonderFee.AmountIn.Int, 562 bonderFee.BonderFee.Int, 563 ) 564 } 565 566 func (h *HopBridgeProcessor) packL2AmmWrapperTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) { 567 return abi.Pack("swapAndSend", 568 big.NewInt(int64(toChainID)), 569 to, 570 bonderFee.AmountIn.Int, 571 bonderFee.BonderFee.Int, 572 bonderFee.AmountOutMin.Int, 573 big.NewInt(bonderFee.Deadline), 574 bonderFee.DestinationAmountOutMin.Int, 575 big.NewInt(bonderFee.DestinationDeadline)) 576 } 577 578 func (h *HopBridgeProcessor) sendL2AmmWrapperTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64, 579 to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) { 580 contractInstance, err := hopL2AmmWrapper.NewHopL2AmmWrapper( 581 contractAddress, 582 ethClient, 583 ) 584 if err != nil { 585 return tx, createBridgeHopErrorResponse(err) 586 } 587 588 return contractInstance.SwapAndSend( 589 txOpts, 590 big.NewInt(int64(toChainID)), 591 to, 592 bonderFee.AmountIn.Int, 593 bonderFee.BonderFee.Int, 594 bonderFee.AmountOutMin.Int, 595 big.NewInt(bonderFee.Deadline), 596 bonderFee.DestinationAmountOutMin.Int, 597 big.NewInt(bonderFee.DestinationDeadline)) 598 } 599 600 func (h *HopBridgeProcessor) packL2BridgeTx(abi abi.ABI, toChainID uint64, to common.Address, bonderFee *BonderFee) ([]byte, error) { 601 return abi.Pack("send", 602 big.NewInt(int64(toChainID)), 603 to, 604 bonderFee.AmountIn.Int, 605 bonderFee.BonderFee.Int, 606 bonderFee.AmountOutMin.Int, 607 big.NewInt(bonderFee.Deadline)) 608 } 609 610 func (h *HopBridgeProcessor) sendL2BridgeTx(contractAddress common.Address, ethClient chain.ClientInterface, toChainID uint64, 611 to common.Address, txOpts *bind.TransactOpts, bonderFee *BonderFee) (tx *ethTypes.Transaction, err error) { 612 fromChainID := ethClient.NetworkID() 613 if fromChainID == walletCommon.OptimismMainnet || 614 fromChainID == walletCommon.OptimismSepolia { 615 contractInstance, err := hopL2OptimismBridge.NewHopL2OptimismBridge( 616 contractAddress, 617 ethClient, 618 ) 619 if err != nil { 620 return tx, createBridgeHopErrorResponse(err) 621 } 622 623 return contractInstance.Send( 624 txOpts, 625 big.NewInt(int64(toChainID)), 626 to, 627 bonderFee.AmountIn.Int, 628 bonderFee.BonderFee.Int, 629 bonderFee.AmountOutMin.Int, 630 big.NewInt(bonderFee.Deadline)) 631 } 632 if fromChainID == walletCommon.ArbitrumMainnet || 633 fromChainID == walletCommon.ArbitrumSepolia { 634 contractInstance, err := hopL2ArbitrumBridge.NewHopL2ArbitrumBridge( 635 contractAddress, 636 ethClient, 637 ) 638 if err != nil { 639 return tx, createBridgeHopErrorResponse(err) 640 } 641 642 return contractInstance.Send( 643 txOpts, 644 big.NewInt(int64(toChainID)), 645 to, 646 bonderFee.AmountIn.Int, 647 bonderFee.BonderFee.Int, 648 bonderFee.AmountOutMin.Int, 649 big.NewInt(bonderFee.Deadline)) 650 } 651 652 return tx, ErrTxForChainNotSupported 653 }