From 0eac326d1844066fecdb82dbc448ac40a35efd05 Mon Sep 17 00:00:00 2001
From: sunbreak1211 <sunbreak1211@proton.me>
Date: Mon, 16 Sep 2024 23:35:31 -0300
Subject: [PATCH] Implement fileable escrow

---
 deploy/TokenBridgeDeploy.sol |  2 +-
 deploy/TokenBridgeInit.sol   |  6 ++++--
 src/L1TokenBridge.sol        | 12 +++++++++---
 test/L1TokenBridge.t.sol     | 12 ++++++++----
 4 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/deploy/TokenBridgeDeploy.sol b/deploy/TokenBridgeDeploy.sol
index ee3b6a1..034584c 100644
--- a/deploy/TokenBridgeDeploy.sol
+++ b/deploy/TokenBridgeDeploy.sol
@@ -37,7 +37,7 @@ library TokenBridgeDeploy {
     ) internal returns (L1TokenBridgeInstance memory l1BridgeInstance) {
         l1BridgeInstance.govRelay = address(new L1GovernanceRelay(l2GovRelay, l1Messenger));
         l1BridgeInstance.escrow = address(new Escrow());
-        l1BridgeInstance.bridge = address(new L1TokenBridge(l2Bridge, l1BridgeInstance.escrow, l1Messenger));
+        l1BridgeInstance.bridge = address(new L1TokenBridge(l2Bridge, l1Messenger));
         ScriptTools.switchOwner(l1BridgeInstance.govRelay, deployer, owner);
         ScriptTools.switchOwner(l1BridgeInstance.escrow, deployer, owner);
         ScriptTools.switchOwner(l1BridgeInstance.bridge, deployer, owner);
diff --git a/deploy/TokenBridgeInit.sol b/deploy/TokenBridgeInit.sol
index 73e9911..9914211 100644
--- a/deploy/TokenBridgeInit.sol
+++ b/deploy/TokenBridgeInit.sol
@@ -27,7 +27,8 @@ interface L1TokenBridgeLike {
     function otherBridge() external view returns (address);
     function escrow() external view returns (address);
     function messenger() external view returns (address);
-    function registerToken(address l1Token, address l2Token) external;
+    function file(bytes32, address) external;
+    function registerToken(address, address) external;
 }
 
 interface L1RelayLike {
@@ -69,13 +70,14 @@ library TokenBridgeInit {
         // sanity checks
         require(l1Bridge.isOpen() == 1, "TokenBridgeInit/not-open");
         require(l1Bridge.otherBridge() == l2BridgeInstance.bridge, "TokenBridgeInit/other-bridge-mismatch");
-        require(l1Bridge.escrow() == address(escrow), "TokenBridgeInit/escrow-mismatch");
         require(l1Bridge.messenger() == cfg.l1Messenger, "TokenBridgeInit/l1-bridge-messenger-mismatch");
         require(l1GovRelay.l2GovernanceRelay() == l2BridgeInstance.govRelay, "TokenBridgeInit/l2-gov-relay-mismatch");
         require(l1GovRelay.messenger() == cfg.l1Messenger, "TokenBridgeInit/l1-gov-relay-messenger-mismatch");
         require(cfg.l1Tokens.length == cfg.l2Tokens.length, "TokenBridgeInit/token-arrays-mismatch");
         require(cfg.minGasLimit <= 1_000_000_000, "TokenBridgeInit/min-gas-limit-out-of-bounds");
 
+        l1Bridge.file("escrow", address(escrow));
+
         for (uint256 i; i < cfg.l1Tokens.length; ++i) {
             (address l1Token, address l2Token) = (cfg.l1Tokens[i], cfg.l2Tokens[i]);
             require(l1Token != address(0), "TokenBridgeInit/invalid-l1-token");
diff --git a/src/L1TokenBridge.sol b/src/L1TokenBridge.sol
index 4debc8c..43a55c8 100644
--- a/src/L1TokenBridge.sol
+++ b/src/L1TokenBridge.sol
@@ -32,17 +32,18 @@ contract L1TokenBridge {
     mapping(address => uint256) public wards;
     mapping(address => address) public l1ToL2Token;
     uint256 public isOpen = 1;
+    address public escrow;
 
     // --- immutables ---
 
     address public immutable otherBridge;
-    address public immutable escrow;
     CrossDomainMessengerLike public immutable messenger;
 
     // --- events ---
 
     event Rely(address indexed usr);
     event Deny(address indexed usr);
+    event File(bytes32 indexed what, address data);
     event Closed();
     event TokenSet(address indexed l1Token, address indexed l2Token);
     event ERC20BridgeInitiated(
@@ -81,11 +82,9 @@ contract L1TokenBridge {
 
     constructor(
         address _otherBridge,
-        address _escrow,
         address _messenger
     ) {
         otherBridge = _otherBridge;
-        escrow = _escrow;
         messenger = CrossDomainMessengerLike(_messenger);
 
         wards[msg.sender] = 1;
@@ -104,6 +103,13 @@ contract L1TokenBridge {
         emit Deny(usr);
     }
 
+    function file(bytes32 what, address data) external auth {
+        if (what == "escrow") {
+            escrow = data;
+        } else revert("L1TokenBridge/file-unrecognized-param");
+        emit File(what, data);
+    }
+
     function close() external auth {
         isOpen = 0;
         emit Closed();
diff --git a/test/L1TokenBridge.t.sol b/test/L1TokenBridge.t.sol
index 9ebf688..6100867 100644
--- a/test/L1TokenBridge.t.sol
+++ b/test/L1TokenBridge.t.sol
@@ -61,7 +61,8 @@ contract L1TokenBridgeTest is DssTest {
     function setUp() public {
         messenger = new MessengerMock();
         messenger.setXDomainMessageSender(otherBridge);
-        bridge = new L1TokenBridge(otherBridge, escrow, address(messenger));
+        bridge = new L1TokenBridge(otherBridge, address(messenger));
+        bridge.file("escrow", escrow);
         l1Token = new GemMock(1_000_000 ether);
         l1Token.transfer(address(0xe0a), 500_000 ether);
         vm.prank(escrow); l1Token.approve(address(bridge), type(uint256).max);
@@ -71,12 +72,11 @@ contract L1TokenBridgeTest is DssTest {
     function testConstructor() public {
         vm.expectEmit(true, true, true, true);
         emit Rely(address(this));
-        L1TokenBridge b = new L1TokenBridge(address(111), address(222), address(333));
+        L1TokenBridge b = new L1TokenBridge(address(111), address(222));
 
         assertEq(b.isOpen(), 1);
         assertEq(b.otherBridge(), address(111));
-        assertEq(b.escrow(), address(222));
-        assertEq(address(b.messenger()), address(333));
+        assertEq(address(b.messenger()), address(222));
         assertEq(b.wards(address(this)), 1);
     }
 
@@ -93,6 +93,10 @@ contract L1TokenBridgeTest is DssTest {
         ]);
     }
 
+    function testFileAddress() public {
+        checkFileAddress(address(bridge), "L1TokenBridge", ["escrow"]);
+    }
+
     function testTokenRegistration() public {
         assertEq(bridge.l1ToL2Token(address(11)), address(0));