Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Updates to work with spark [WIP] #436

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
554 changes: 208 additions & 346 deletions src/DssSpell.sol

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/DssSpell.t.base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2341,7 +2341,7 @@ contract DssSpellTestBase is Config, DssTest {
if (ward > 0) {
emit log_named_address(" Deployer Address", deployer);
emit log_named_string(" Affected Contract", contractName);
fail("Error: Bad Auth");
revert("Error: Bad Auth");
}
}
}
Expand Down
368 changes: 326 additions & 42 deletions src/DssSpell.t.sol

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions src/dependencies/base-token-bridge/L1TokenBridgeInstance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: © 2024 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

struct L1TokenBridgeInstance {
address govRelay;
address escrow;
address bridge;
address bridgeImp;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: © 2023 Dai Foundation <www.daifoundation.org>
// SPDX-FileCopyrightText: © 2024 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
Expand All @@ -16,9 +16,9 @@

pragma solidity >=0.8.0;

struct LockstakeInstance {
address lsmkr;
address engine;
address clipper;
address clipperCalc;
}
struct L2TokenBridgeInstance {
address govRelay;
address bridge;
address bridgeImp;
address spell;
}
96 changes: 96 additions & 0 deletions src/dependencies/base-token-bridge/L2TokenBridgeSpell.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-FileCopyrightText: © 2024 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

interface L2GovRelayLike {
function l1GovernanceRelay() external view returns (address);
function messenger() external view returns (address);
}

interface L2TokenBridgeLike {
function isOpen() external view returns (uint256);
function otherBridge() external view returns (address);
function messenger() external view returns (address);
function version() external view returns (string memory);
function getImplementation() external view returns (address);
function upgradeToAndCall(address, bytes memory) external;
function rely(address) external;
function deny(address) external;
function close() external;
function registerToken(address, address) external;
function setMaxWithdraw(address, uint256) external;
}

interface AuthLike {
function rely(address usr) external;
}

// A reusable L2 spell to be used by the L2GovernanceRelay to exert admin control over L2TokenBridge
contract L2TokenBridgeSpell {
L2TokenBridgeLike public immutable l2Bridge;

constructor(address l2Bridge_) {
l2Bridge = L2TokenBridgeLike(l2Bridge_);
}

function upgradeToAndCall(address newImp, bytes memory data) external { l2Bridge.upgradeToAndCall(newImp, data); }
function rely(address usr) external { l2Bridge.rely(usr); }
function deny(address usr) external { l2Bridge.deny(usr); }
function close() external { l2Bridge.close(); }

function registerTokens(address[] memory l1Tokens, address[] memory l2Tokens) public {
for (uint256 i; i < l2Tokens.length;) {
l2Bridge.registerToken(l1Tokens[i], l2Tokens[i]);
AuthLike(l2Tokens[i]).rely(address(l2Bridge));
unchecked { ++i; }
}
}

function setMaxWithdraws(address[] memory l2Tokens, uint256[] memory maxWithdraws) public {
for (uint256 i; i < l2Tokens.length;) {
l2Bridge.setMaxWithdraw(l2Tokens[i], maxWithdraws[i]);
unchecked { ++i; }
}
}

function init(
address l2GovRelay_,
address l2Bridge_,
address l2BridgeImp,
address l1GovRelay,
address l1Bridge,
address l2Messenger,
address[] calldata l1Tokens,
address[] calldata l2Tokens,
uint256[] calldata maxWithdraws
) external {
L2GovRelayLike l2GovRelay = L2GovRelayLike(l2GovRelay_);

// sanity checks
require(address(l2Bridge) == l2Bridge_, "L2TokenBridgeSpell/l2-bridge-mismatch");
require(keccak256(bytes(l2Bridge.version())) == keccak256("1"), "L2TokenBridgeSpell/version-does-not-match");
require(l2Bridge.getImplementation() == l2BridgeImp, "L2TokenBridgeSpell/imp-does-not-match");
require(l2Bridge.isOpen() == 1, "L2TokenBridgeSpell/not-open");
require(l2Bridge.otherBridge() == l1Bridge, "L2TokenBridgeSpell/other-bridge-mismatch");
require(l2Bridge.messenger() == l2Messenger, "L2TokenBridgeSpell/l2-bridge-messenger-mismatch");
require(l2GovRelay.l1GovernanceRelay() == l1GovRelay, "L2TokenBridgeSpell/l1-gov-relay-mismatch");
require(l2GovRelay.messenger() == l2Messenger, "L2TokenBridgeSpell/l2-gov-relay-messenger-mismatch");

registerTokens(l1Tokens, l2Tokens);
setMaxWithdraws(l2Tokens, maxWithdraws);
}
}
119 changes: 119 additions & 0 deletions src/dependencies/base-token-bridge/TokenBridgeInit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-FileCopyrightText: © 2024 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

import { DssInstance } from "dss-test/MCD.sol";
import { L1TokenBridgeInstance } from "./L1TokenBridgeInstance.sol";
import { L2TokenBridgeInstance } from "./L2TokenBridgeInstance.sol";
import { L2TokenBridgeSpell } from "./L2TokenBridgeSpell.sol";

interface L1TokenBridgeLike {
function l1ToL2Token(address) external view returns (address);
function isOpen() external view returns (uint256);
function otherBridge() external view returns (address);
function messenger() external view returns (address);
function version() external view returns (string memory);
function getImplementation() external view returns (address);
function file(bytes32, address) external;
function registerToken(address, address) external;
}

interface L1RelayLike {
function l2GovernanceRelay() external view returns (address);
function messenger() external view returns (address);
function relay(
address target,
bytes calldata targetData,
uint32 minGasLimit
) external;
}

interface EscrowLike {
function approve(address, address, uint256) external;
}

struct BridgesConfig {
address l1Messenger;
address l2Messenger;
address[] l1Tokens;
address[] l2Tokens;
uint256[] maxWithdraws;
uint32 minGasLimit;
bytes32 govRelayCLKey;
bytes32 escrowCLKey;
bytes32 l1BridgeCLKey;
bytes32 l1BridgeImpCLKey;
}

library TokenBridgeInit {
function initBridges(
DssInstance memory dss,
L1TokenBridgeInstance memory l1BridgeInstance,
L2TokenBridgeInstance memory l2BridgeInstance,
BridgesConfig memory cfg
) internal {
L1RelayLike l1GovRelay = L1RelayLike(l1BridgeInstance.govRelay);
EscrowLike escrow = EscrowLike(l1BridgeInstance.escrow);
L1TokenBridgeLike l1Bridge = L1TokenBridgeLike(l1BridgeInstance.bridge);

// sanity checks
require(keccak256(bytes(l1Bridge.version())) == keccak256("1"), "TokenBridgeInit/version-does-not-match");
require(l1Bridge.getImplementation() == l1BridgeInstance.bridgeImp, "TokenBridgeInit/imp-does-not-match");
require(l1Bridge.isOpen() == 1, "TokenBridgeInit/not-open");
require(l1Bridge.otherBridge() == l2BridgeInstance.bridge, "TokenBridgeInit/other-bridge-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.maxWithdraws.length == cfg.l2Tokens.length, "TokenBridgeInit/max-withdraws-length-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");
require(l2Token != address(0), "TokenBridgeInit/invalid-l2-token");
require(cfg.maxWithdraws[i] > 0, "TokenBridgeInit/max-withdraw-not-set");
require(l1Bridge.l1ToL2Token(l1Token) == address(0), "TokenBridgeInit/existing-l1-token");

l1Bridge.registerToken(l1Token, l2Token);
escrow.approve(l1Token, address(l1Bridge), type(uint256).max);
}

l1GovRelay.relay({
target: l2BridgeInstance.spell,
targetData: abi.encodeCall(L2TokenBridgeSpell.init, (
l2BridgeInstance.govRelay,
l2BridgeInstance.bridge,
l2BridgeInstance.bridgeImp,
address(l1GovRelay),
address(l1Bridge),
cfg.l2Messenger,
cfg.l1Tokens,
cfg.l2Tokens,
cfg.maxWithdraws
)),
minGasLimit: cfg.minGasLimit
});

dss.chainlog.setAddress(cfg.govRelayCLKey, address(l1GovRelay));
dss.chainlog.setAddress(cfg.escrowCLKey, address(escrow));
dss.chainlog.setAddress(cfg.l1BridgeCLKey, address(l1Bridge));
dss.chainlog.setAddress(cfg.l1BridgeImpCLKey, l1BridgeInstance.bridgeImp);
}
}
Loading
Loading