Skip to content

Commit

Permalink
Add arbitrum bridging and teleport
Browse files Browse the repository at this point in the history
  • Loading branch information
karacurt committed Dec 13, 2024
1 parent fd9f27a commit 5821519
Show file tree
Hide file tree
Showing 8 changed files with 6,115 additions and 16 deletions.
3,714 changes: 3,714 additions & 0 deletions bindings/L1Teleporter/L1Teleporter.go

Large diffs are not rendered by default.

1,546 changes: 1,546 additions & 0 deletions bindings/L2ForwarderFactory/L2ForwarderFactory.go

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions cmd/arbitrum/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"os"
"strings"

"github.com/G7DAO/bifrost/bindings/ArbitrumL1OrbitCustomGateway"
"github.com/G7DAO/bifrost/bindings/ERC20Inbox"
"github.com/G7DAO/bifrost/bindings/L1GatewayRouter"
"github.com/G7DAO/bifrost/bindings/NodeInterface"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -121,3 +123,164 @@ func NativeTokenBridgePropose(inboxAddress common.Address, keyFile string, passw

return CreateSafeProposal(l1Client, key, safeAddress, inboxAddress, createRetryableTicketData, big.NewInt(0), safeApi, OperationType(safeOperation), safeNonce)
}

func GetERC20BridgeCalldataAndValue(routerAddress common.Address, key *keystore.Key, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int) ([]byte, *big.Int, error) {
l1Client, l1ClientErr := ethclient.DialContext(context.Background(), l1Rpc)
if l1ClientErr != nil {
fmt.Fprintln(os.Stderr, "l1ClientErr", l1ClientErr.Error())
return nil, nil, l1ClientErr
}

l2Client, l2ClientErr := ethclient.DialContext(context.Background(), l2Rpc)
if l2ClientErr != nil {
fmt.Fprintln(os.Stderr, "l2ClientErr", l2ClientErr.Error())
return nil, nil, l2ClientErr
}

gasPriceBid, gasPriceBidErr := l1Client.SuggestGasPrice(context.Background())
if gasPriceBidErr != nil {
fmt.Fprintln(os.Stderr, "gasPriceBidErr", gasPriceBidErr.Error())
return nil, nil, gasPriceBidErr
}

router, routerErr := L1GatewayRouter.NewL1GatewayRouter(routerAddress, l1Client)
if routerErr != nil {
fmt.Fprintln(os.Stderr, "routerErr", routerErr.Error())
return nil, nil, routerErr
}

outboundCalldata, outboundCalldataErr := router.GetOutboundCalldata(nil, tokenAddress, key.Address, to, amount, []byte{})
if outboundCalldataErr != nil {
fmt.Fprintln(os.Stderr, "outboundCalldataErr", outboundCalldataErr.Error())
return nil, nil, outboundCalldataErr
}

gatewayAddress, gatewayAddressErr := router.GetGateway(nil, tokenAddress)
if gatewayAddressErr != nil {
return nil, nil, gatewayAddressErr
}

gateway, gatewayErr := ArbitrumL1OrbitCustomGateway.NewL1OrbitCustomGateway(gatewayAddress, l1Client)
if gatewayErr != nil {
return nil, nil, gatewayErr
}

// Source: https://github.com/OffchainLabs/arbitrum-sdk/blob/0da65020438fc3e46728ea182f1b4dcf04e3cb7f/src/lib/message/L1ToL2MessageGasEstimator.ts#L154
senderDeposit := big.NewInt(0).Add(big.NewInt(0), ONE_ETHER)
counterpartGatewayAddress, counterpartGatewayAddressErr := gateway.CounterpartGateway(nil)
if counterpartGatewayAddressErr != nil {
return nil, nil, counterpartGatewayAddressErr
}

gasLimit, gasLimitErr := CalculateRetryableGasLimit(l2Client, gatewayAddress, senderDeposit, counterpartGatewayAddress, big.NewInt(0), to, RemapL1Address(key.Address), outboundCalldata)
if gasLimitErr != nil {
fmt.Fprintln(os.Stderr, "gasLimitErr", gasLimitErr.Error())
return nil, nil, gasLimitErr
}
maxGas := big.NewInt(0).SetUint64(gasLimit)

maxSubmissionCost, maxSubmissionCostErr := CalculateRetryableSubmissionFee(outboundCalldata, gasPriceBid)
if maxSubmissionCostErr != nil {
fmt.Fprintln(os.Stderr, "maxSubmissionCostErr", maxSubmissionCostErr.Error())
return nil, nil, maxSubmissionCostErr
}

executionCost := big.NewInt(0).Mul(maxGas, gasPriceBid)
tokenTotalFeeAmount := big.NewInt(0).Add(maxSubmissionCost, executionCost)
tokenTotalFeeAmount.Add(tokenTotalFeeAmount, big.NewInt(0))

// Encode (uint256 maxSubmissionCost, bytes callHookData, uint256 tokenTotalFeeAmount)
arguments := abi.Arguments{
{Type: abi.Type{T: abi.UintTy, Size: 256}},
{Type: abi.Type{T: abi.BytesTy}},
{Type: abi.Type{T: abi.UintTy, Size: 256}},
}
data, dataErr := arguments.Pack(maxSubmissionCost, []byte{}, tokenTotalFeeAmount)
if dataErr != nil {
fmt.Fprintln(os.Stderr, "dataErr", dataErr.Error())
return nil, nil, dataErr
}

routerAbi, routerAbiErr := abi.JSON(strings.NewReader(L1GatewayRouter.L1GatewayRouterABI))
if routerAbiErr != nil {
fmt.Fprintln(os.Stderr, "routerAbiErr", routerAbiErr.Error())
return nil, nil, routerAbiErr
}

callData, callDataErr := routerAbi.Pack("outboundTransfer", tokenAddress, to, amount, maxGas, gasPriceBid, data)
if callDataErr != nil {
fmt.Fprintln(os.Stderr, "callDataErr", callDataErr.Error())
return nil, nil, callDataErr
}

return callData, tokenTotalFeeAmount, nil
}

func ERC20BridgeCall(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int, customNativeToken bool) (*types.Transaction, error) {
key, keyErr := NodeInterface.KeyFromFile(keyFile, password)
if keyErr != nil {
fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error())
return nil, keyErr
}

callData, tokenTotalFeeAmount, callDataErr := GetERC20BridgeCalldataAndValue(routerAddress, key, l1Rpc, l2Rpc, tokenAddress, to, amount)
if callDataErr != nil {
fmt.Fprintln(os.Stderr, "callDataErr", callDataErr.Error())
return nil, callDataErr
}

l1Client, l1ClientErr := ethclient.DialContext(context.Background(), l1Rpc)
if l1ClientErr != nil {
fmt.Fprintln(os.Stderr, "l1ClientErr", l1ClientErr.Error())
return nil, l1ClientErr
}

fmt.Println(key.Address.Hex())

fmt.Println("Sending transaction...")
if customNativeToken {
tokenTotalFeeAmount = big.NewInt(0)
}
transaction, transactionErr := SendTransaction(l1Client, key, password, callData, routerAddress.Hex(), tokenTotalFeeAmount)
if transactionErr != nil {
fmt.Fprintln(os.Stderr, "transactionErr", transactionErr.Error())
return nil, transactionErr
}
fmt.Println("Transaction sent! Transaction hash:", transaction.Hash().Hex())

fmt.Println("Waiting for transaction to be mined...")
_, receiptErr := bind.WaitMined(context.Background(), l1Client, transaction)
if receiptErr != nil {
fmt.Fprintln(os.Stderr, "receiptErr", receiptErr.Error())
return nil, receiptErr
}
fmt.Println("Transaction mined!")

return transaction, nil
}

func ERC20BridgePropose(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int, safeAddress common.Address, safeApi string, safeOperation uint8, safeNonce *big.Int, customNativeToken bool) error {
key, keyErr := NodeInterface.KeyFromFile(keyFile, password)
if keyErr != nil {
fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error())
return keyErr
}

callData, tokenTotalFeeAmount, callDataErr := GetERC20BridgeCalldataAndValue(routerAddress, key, l1Rpc, l2Rpc, tokenAddress, to, amount)
if callDataErr != nil {
fmt.Fprintln(os.Stderr, "callDataErr", callDataErr.Error())
return callDataErr
}

l1Client, l1ClientErr := ethclient.DialContext(context.Background(), l1Rpc)
if l1ClientErr != nil {
fmt.Fprintln(os.Stderr, "l1ClientErr", l1ClientErr.Error())
return l1ClientErr
}

if customNativeToken {
tokenTotalFeeAmount = big.NewInt(0)
}

return CreateSafeProposal(l1Client, key, safeAddress, routerAddress, callData, tokenTotalFeeAmount, safeApi, OperationType(safeOperation), safeNonce)
}
Loading

0 comments on commit 5821519

Please sign in to comment.