Skip to content

Backend bridge service for Arbitrum: builds unsigned transaction payloads for ETH/ERC‑20 deposits & withdrawals, checks allowances/balances, and provides status APIs to monitor message confirmation and execution across chains.

Notifications You must be signed in to change notification settings

achal-singh/Arbitrum-Bridge-Service

Repository files navigation

Bridge Service

Bridge Service is a backend API server built on Express framework that allows a user to request unsigned deposit and withdraw transaction payloads for bridging ETH and ERC20 tokens between Ethereum Sepolia (L1) and Arbitrum Sepolia (L2). The API validates payloads, checks balances/allowance, and returns unsigned transaction payloads to initiate deposit and withdrawals to and from Arbitrum Sepolia. The service also offers status endpoints: /v1/status/deposit and /v1/status/withdraw to track the status of published transactions on the Child (Arbitrum Sepolia) and Parent Chain (Ethereum Sepolia) respectively.

Requirements

  • Node.js 18+ (for global fetch)
  • A funded test wallet on Ethereum Sepolia for live calls
  • RPC URLs (Infura or equivalent)

Setup

  1. Install dependencies

    yarn install
  2. Create .env (copy .env.example) and set values:

  • Set the ERC_20_DEPLOYED_TOKEN_ADDRESS to a sample ERC-20 token contract on Ethereum Sepolia that you have sufficient funds of, this ERC-20 token will be used to deposit and withdraw to and from Arbitrum Sepolia chain.

  • In case you have no such ERC-20 Token contract on Ethereum Sepola Network, set TOKEN_DEPLOYER_PRIVATE_KEY to the private key of the account through which you can deploy one on Ethereum Sepolia. To deploy run npm run deploy:erc20, it will deploy the Fake Token Contract.

  • The PARENT_CHAIN_WALLET_KEY should be set to a wallet with sufficient Sepolia ETH, as it is used in End-to-End Testing Script to sign and publish the deposit and withdrawal transactions.

  • Set the L1_RPC_URL and L2_RPC_URL to any RPC provider URL of your choice.

  • The INFURA_L1_RPC_URL and INFURA_L2_RPC_URL variables should only hold Infura RPC URLs, these are used to make /v1/status/withdraw calls to query Outgoing message status for ETH and ERC-20 withdrawals, since these are eth_getLogs heavy calls, that's why Infura is used.

  1. Run the server

    npm run dev

API

Base URL: http://localhost:3000

Health

GET /health

Response:

{ "status": "ok" }

Deposit Payload

POST /v1/payloads/deposit

Body:

{
  "assetType": "ETH" | "ERC20",
  "amount": "0.1",
  "chainId": 11155111,
  "from": "0x...",
  "tokenAddress": "0x..." // required if assetType = "ERC20"
}

✅ Success (ETH or ERC20 with sufficient allowance):

// ETH Deposit
// txRequest in the response below is the ETH deposit payload
{
  "kind": "deposit",
  "txRequest": {
    "to": "0xaAe29B0366299461418F5324a79Afc425BE5ae21",
    "value": {
      "type": "BigNumber",
      "hex": "0x........."
    },
    "data": "0x...",
    "from": "0x..."
  }
}

// ERC-20 Deposit
// txRequest in the response below is the ERC-20 token deposit payload
{
	"kind": "deposit",
	"txRequest": {
		"to": "0x...",
		"data": "0x...",
		"value": {
			"type": "BigNumber",
			"hex": "0x08a742799900"
		},
		"from": "0x..."
	}
}

✅ Success (ERC20 approve required):

// txRequest in the response below is the approve transaction payload
{
  "kind": "approve",
  "message": "Approve the gateway to spend your token before depositing.",
  "txRequest": {
    "to": "0x...",
    "data": "0x...",
    "value": "0x0"
  }
}

❌ Errors:

// For ETH
{
  "error": "RequestError",
  "message": "Insufficient ETH balance (0.5).",
  "details": null
}
// For ERC-20
{
  "error": "RequestError",
  "message": "Insufficient Token balance (51.5).",
  "details": null
}
// OR
// Unknown Error
{
	"error": "RequestError",
	"message": "Something Went Wrong."
}

Withdraw Payload

POST /v1/payloads/withdraw

Body:

{
  "assetType": "ETH" | "ERC20",
  "amount": "0.1",
  "chainId": 421614,
  "from": "0x...",
  "destinationAddress": "0x...",
  "tokenAddress": "0x..." // required if assetType = "ERC20"
}

✅ Success:

// For both ETH & ERC-20
// txRequest in the response below is the withdraw transaction payload
{
  "txRequest": {
    "data": "0x...",
    "to": "0x...",
    "value": {
      "type": "BigNumber",
      "hex": "0x00"
    },
    "from": "0x..."
  }
}

❌ Errors:

// For ETH
{
  "error": "RequestError",
  "message": "Insufficient ETH balance (0.5).",
  "details": null
}
// For ERC-20
{
  "error": "RequestError",
  "message": "Insufficient Token balance (11.5).",
  "details": null
}
// OR
// Unknown Error
{
	"error": "RequestError",
	"message": "Something Went Wrong."
}

Deposit Status

GET /v1/status/deposit/:parentTxHash

Response:

// ETH Deposit Status
{
  "status": "PENDING" | "DEPOSITED",
  "message": "ETH-Deposit yet to be confirmed on Child Chain...⌛️" | "ETH-Deposit Confirmed on Child Chain ✅"
}

// ERC-20 Deposit Status
{
  "status": "NOT_YET_CREATED" | "CREATION_FAILED" | "FUNDS_DEPOSITED_ON_CHILD" | "REDEEMED" | "EXPIRED",
  "message": "The message has not been created yet." | "Deposit Transaction was not created or creation failed ❌" | "Deposit Transaction has been created on Child Chain, but not redeemed yet." | "Transaction has been redeemed on the Child chain ✅" | "Transaction has Expired on the Child chain ❌"
}

Withdraw Status

GET /v1/status/withdraw/:childTxHash

Response:

{
  "status": "UNCONFIRMED" | "CONFIRMED" | "EXECUTED",
  "message": "Outgoing Message yet to be Confirmed on Parent chain... ⌛️" | "Outgoing Message Confirmed ✅, yet to be Executed." | "Message already executed on Parent chain 👍🏻"
}

Common Error Responses for all routes

// If request body is more than 1Kb.
{
  "error": "Internal Server Error",
  "message": "request entity too large"
}

// If v1/payloads/* routes take more than 20s to return
// If v1/status/* routes take more than 45s to return
{
	"message": "Request timed out"
}

Scripts

  • npm run dev: start server with hot reload
  • npm run build: compile TypeScript
  • npm run start: run built server
  • npm run lint: lint code
  • npm run deploy:erc20: deploy test ERC20 on parent chain
  • npm run call:deposit -- --assetType <ETH|ERC20> --amount 0.1 --from 0x...
  • npm run call:withdraw -- --assetType <ETH|ERC20> --amount 0.1 --from 0x... --to 0x...

Tests

  • npm run test:integration: local HTTP tests (no RPC usage)
  • npm run test:e2e: real network tests (requires RUN_E2E=1 and RPC keys)

Example E2E:

RUN_E2E=1 npm run test:e2e

About

Backend bridge service for Arbitrum: builds unsigned transaction payloads for ETH/ERC‑20 deposits & withdrawals, checks allowances/balances, and provides status APIs to monitor message confirmation and execution across chains.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published