{"id":19096830,"url":"https://github.com/makerdao/arbitrum-dai-bridge","last_synced_at":"2025-04-18T16:31:25.089Z","repository":{"id":43058877,"uuid":"372168368","full_name":"makerdao/arbitrum-dai-bridge","owner":"makerdao","description":null,"archived":true,"fork":false,"pushed_at":"2022-03-21T15:30:03.000Z","size":2983,"stargazers_count":29,"open_issues_count":1,"forks_count":18,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-03-11T19:49:48.007Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/makerdao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-30T09:02:21.000Z","updated_at":"2025-02-12T18:27:12.000Z","dependencies_parsed_at":"2022-09-10T00:21:33.135Z","dependency_job_id":null,"html_url":"https://github.com/makerdao/arbitrum-dai-bridge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Farbitrum-dai-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Farbitrum-dai-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Farbitrum-dai-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Farbitrum-dai-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/makerdao","download_url":"https://codeload.github.com/makerdao/arbitrum-dai-bridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249517937,"owners_count":21284861,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T03:37:57.406Z","updated_at":"2025-04-18T16:31:24.751Z","avatar_url":"https://github.com/makerdao.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Lint](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/lint.yml/badge.svg)](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/lint.yml)\n[![Check](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/slither.yml/badge.svg)](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/slither.yml)\n[![Tests](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/tests.yml/badge.svg)](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/tests.yml)\n[![Fuzz](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/fuzz.yml/badge.svg)](https://github.com/makerdao/arbitrum-dai-bridge/actions/workflows/fuzz.yml)\n\n# Arbitrum Dai Bridge\n\nArbitrum Dai, upgradable token bridge and governance relay\n\n## Contracts\n\n- `dai.sol` - Improved DAI contract.\n- `L1DaiGateway.sol` - L1 side of the bridge. Escrows L1 DAI in `L1Escrow` contract. Unlocks L1 DAI upon withdrawal\n  message from `L2DaiGateway`.\n- `L2DaiGateway.sol` - L2 side of the bridge. Mints new L2 DAI after receiving a message from `L1DaiGateway`. Burns L2\n  DAI tokens when withdrawals happen.\n- `L1Escrow` - Hold funds on L1. Allows having many bridges coexist on L1 and share liquidity.\n- `L1GovernanceRelay` \u0026 `L2GovernanceRelay` - allows to execute a governance spell on L2.\n\n## Diagrams:\n\n![Basic deposit](docs/deposit.png?raw=true 'Basic deposit')\n\n[Full diagram](docs/full.png)\n\n## Upgrade guide\n\n### Deploying new token bridge\n\nThis bridge stores funds in an external escrow account rather than on the bridge address itself. To upgrade, deploy the\nnew bridge independently and connect it to the same escrow. Thanks to this, multiple bridges can operate at the same\ntime (with potentially different interfaces), and no bridge will ever run out of funds.\n\n### Closing bridge\n\nAfter deploying a new bridge, you might consider closing the old one. The procedure is slightly complicated due to async\nmessages (`finalizeInboundTransfer`) that can be in progress.\n\nAn owner calls `L2DaiGateway.close()` and `L1DaiGateway.close()` so no new async messages can be sent to the other part\nof the bridge. After all async messages are done processing (can take up to 1 week), the bridge is effectively closed.\nNow, the owner can consider revoking approval to access funds from escrow on L1 and token minting rights on L2.\n\n## Emergency shutdown\n\nIf ES is triggered, ESM contract can be used to `deny` access from the `PauseProxy` (governance). In such scenario the\nbridge continues to work as usual and it's impossible to close it.\n\n## Known Risks\n\n### Wrong parameters for xchain messages\n\nArbitrum's xchain messages require\n[a couple of arguments](https://developer.offchainlabs.com/docs/l1_l2_messages#parameters). We expose these in our\npublic interfaces so it's up to the users to select appropriate values. Wrong values will cause a need to manually retry\nL1 -\u003e L2 messages or in the worst case can cause a message to be lost. This is especially difficult when interacting\nwith `L1GovernanceRelay` via MakerDAO governance spells with a long delay (2 days).\n\n### Arbitrum bug\n\nIn this section, we describe various risks caused by possible **bugs** in Arbitrum system.\n\n**L1 -\u003e L2 message passing bug**\n\nBug allowing to send arbitrary messages from L1 to L2 ie. This could result in minting of uncollateralized L2 DAI. This\ncan be done via:\n\n- sending `finalizeInboundTransfer` messages directly to `L2DaiGateway`\n- granting minting rights by executing malicious spell with `L2GovernanceRelay`\n\nImmediately withdrawing L2 DAI to L1 DAI is not possible because of the dispute period (1 week). In case of such bug,\ngovernance can disconnect `L1DAITokenBridge` from `L1Escrow`, ensuring that no L1 DAI can be stolen. Even with 2 days\ndelay on governance actions, there should be plenty of time to coordinate action. Later off-chain coordination is\nrequired to send DAI back to rightful owners or redeploy Arbitrum system.\n\n**L2 -\u003e L1 message passing bug**\n\nBug allowing to send arbitrary messages from L2 to L1 is potentially more harmful. This can happen in two ways:\n\n1. Bug in `Outbox` allows sending arbitrary messages on L1 bypassing the dispute period,\n2. The fraud proof system stops working which allows submitting incorrect state root. Such state root can be used to\n   proof an arbitrary message sent from L2 to L1. This will be a subject to a dispute period (1 week).\n\nIf (1) happens, an attacker can immediately drain L1 DAI from `L1Escrow`.\n\nIf (2) happens, governance can disconnect `L1DAITokenBridge` from `L1Escrow` and prevent the theft of L1 DAI.\n\n**Malicious router**\n\n`GatewayRouter` developed by Arbitrum team, is a privileged actor in our system and allows explicitly passing addresses\nthat initiated deposits/withdrawals. It was reviewed by our team but if there is a bug in its implementation it could in\ntheory be used to steal funds from the escrow (burn arbitrary L2 DAI tokens and withdraw them to any address, or steal\nDAI that was already approved on L1). If it's malicious, it could be used to steal funds.\n\n### Arbitrum upgrade\n\nArbitrum contracts ARE upgradable. A malicious upgrade could result in stealing user funds in many ways. Users need to\ntrust Arbitrum admins while using this bridge or while interacting with the Arbitrum network.\n\n### Governance mistake during upgrade\n\nBridge upgrade is not a trivial procedure due to the async messages between L1 and L2. The whole process is described in\n_Upgrade guide_ in this document.\n\nIf a governance spell mistakenly revokes old bridge approval to access escrow funds, async withdrawal messages will\nfail. Fortunately, reverted messages can be retried at a later date (for one week for L1 -\u003e L2 messages), so governance\nhas a chance to fix its mistake and process pending messages again.\n\n## Invariants\n\n### L1 DAI Locked and L2 DAI Minted\n\n```\nL1DAI.balanceOf(escrow) ≥ L2DAI.totalSupply()\n```\n\nAll DAI available on L2 should be locked on L1. This should hold true with more bridges as well.\n\nIt's `\u003e=` because:\n\na) when depositing on L1, locking is instant but minting is an async message\n\nb) when withdrawing from L2, burning is instant but unlocking on L1 is an async message and is subject to a dispute\nperiod (1 week)\n\nc) someone can send L1 DAI directly to the escrow\n\n## Deployments\n\n### Mainnet\n\n```json\n{\n  \"l1DaiGateway\": \"0xD3B5b60020504bc3489D6949d545893982BA3011\",\n  \"l1Escrow\": \"0xA10c7CE4b876998858b1a9E12b10092229539400\",\n  \"l2Dai\": \"0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1\",\n  \"l2DaiGateway\": \"0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65\",\n  \"l1Dai\": \"0x6B175474E89094C44Da98b954EedeAC495271d0F\",\n  \"l1GovRelay\": \"0x9ba25c289e351779E0D481Ba37489317c34A899d\",\n  \"l2GovRelay\": \"0x10E6593CDda8c58a1d0f14C5164B376352a55f2F\"\n}\n```\n\n### Rinkeby\n\n```json\n{\n  \"l1DaiGateway\": \"0x10E6593CDda8c58a1d0f14C5164B376352a55f2F\",\n  \"l1Escrow\": \"0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65\",\n  \"l2Dai\": \"0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1\",\n  \"l2DaiGateway\": \"0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65\",\n  \"l1Dai\": \"0xd9e66A2f546880EA4d800F189d6F12Cc15Bff281\",\n  \"l1GovRelay\": \"0x09B354CDA89203BB7B3131CC728dFa06ab09Ae2F\",\n  \"l2GovRelay\": \"0x10E6593CDda8c58a1d0f14C5164B376352a55f2F\"\n}\n```\n\n## Running\n\n```\nyarn\nyarn build\nyarn test  # runs unit tests\n```\n\n## Running E2E tests\n\nArbitrum doesn't provide local dev environment so E2E tests are executed against the Rinkeby network.\n\n## Development\n\nRun `yarn test:fix` to run linting in fix mode, auto-formatting and unit tests.\n\nRunning `yarn test` makes sure that contracts are compiled. Running `yarn test-e2e` doesn't.\n\n## Fuzzing\n\n### Install Echidna\n\n- Precompiled Binaries (recommended)\n\nBefore starting, make sure Slither is installed:\n\n```\n$ pip3 install slither-analyzer\n```\n\nTo quickly test Echidna in Linux or MacOS: [release page](https://github.com/crytic/echidna/releases)\n\n### Local Dependencies\n\n- Slither:\n  ```\n  $ pip3 install slither-analyzer\n  ```\n- solc-select:\n  ```\n  $ pip3 install solc-select\n  ```\n\n### Run Echidna Tests\n\n- Install solc version:\n  ```\n  $ solc-select install 0.6.11\n  ```\n- Select solc version:\n  ```\n  $ solc-select use 0.6.11\n  ```\n- Run Echidna Tests:\n  ```\n  $ yarn fuzz\n  ```\n\n## Certora\n\n### Install Certora\n\n- Install Java\n  ```\n  sudo apt install openjdk-14-jdk\n  ```\n- Install Certora Prover\n  ```\n  pip3 install certora-cli\n  ```\n- Set Certora Key\n  ```\n  export CERTORAKEY=\u003ckey\u003e\n  ```\n\n### Local Dependencies\n\n- solc-select:\n  ```\n  pip3 install solc-select\n  ```\n\n### Run Certora Specs\n\n- Install solc version:\n  ```\n  solc-select install 0.6.11\n  ```\n- Run Certora Specs:\n  ```\n  yarn certora\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerdao%2Farbitrum-dai-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakerdao%2Farbitrum-dai-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerdao%2Farbitrum-dai-bridge/lists"}