编译器
0.8.27+commit.40a35a09
文件 1 的 22:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 22:Address.sol
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
library Address {
error AddressEmptyCode(address target);
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
文件 3 的 22:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
文件 4 的 22:BridgeMiddleware.sol
pragma solidity 0.8.27;
import "../vendors/zksync/bridgehub/IBridgehub.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {ILiquidityManager} from "../interfaces/ILiquidityManager.sol";
import {IUSDVault} from "../interfaces/IUSDVault.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
import {Swap} from "../core/Swap.sol";
contract BridgeMiddleware is AccessControl, ReentrancyGuard {
using SafeERC20 for IERC20;
event ShareMinted(address indexed sender, uint256 amount, uint256 shares);
event CanonicalTxHash(bytes32 indexed canonicalTxHash);
event Swept(address indexed token, address indexed to);
event StakeAndBridge(address token, uint256 amount, uint256 ozUSDMinted, uint256 l2GasLimit, uint256 l2GasPerPubdataByteLimit, uint256 gasMinted);
event TokenAllowed(address indexed token, bool allowed);
bytes32 public constant WITHDRAW_ROLE = keccak256("WITHDRAW_ROLE");
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
address public immutable native;
uint256 public immutable chainId;
IBridgehub public immutable bridgeHub;
ILiquidityManager public immutable liquidityManager;
IUSDVault public immutable ozUSDVault;
address public immutable univ3router;
mapping (address => bool) public isAllowedToken;
modifier onlyAllowedToken(address token) {
require(isAllowedToken[token], "onlyAllowedToken: token not allowed");
_;
}
constructor (
address _nativeCoin,
uint256 _chainId,
address _bridgeHub,
address _admin,
address _withdrawer,
address _liquidityManager,
address _ozUSDVault,
address _univ3router
) {
require(_nativeCoin != address(0), "BridgeWrap: native coin address is zero");
require(_bridgeHub != address(0), "BridgeWrap: bridgeHub address is zero");
require(_admin != address(0), "BridgeWrap: admin address is zero");
require(_withdrawer != address(0), "BridgeWrap: withdrawer address is zero");
require(_liquidityManager != address(0), "BridgeWrap: liquidity manager address is zero");
require(_ozUSDVault != address(0), "BridgeWrap: ozUSD vault address is zero");
require(_univ3router != address(0), "BridgeWrap: univ3 router address is zero");
native = _nativeCoin;
chainId = _chainId;
bridgeHub = IBridgehub(_bridgeHub);
liquidityManager = ILiquidityManager(_liquidityManager);
ozUSDVault = IUSDVault(_ozUSDVault);
isAllowedToken[ozUSDVault.asset()] = true;
univ3router = _univ3router;
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(WITHDRAW_ROLE, _withdrawer);
_grantRole(WITHDRAW_ROLE, _admin);
_grantRole(OPERATOR_ROLE, _admin);
}
function stakeAndBridge(uint256 _l2GasLimit) external payable nonReentrant {
uint256 sharesMinted = _stakeNative(msg.value);
_bridgeNative(msg.sender, sharesMinted, _l2GasLimit, 800);
emit StakeAndBridge(address(0), msg.value, 0, _l2GasLimit, 800, msg.value);
}
function stakeAndBridgeStable(address token, uint256 amount, uint256 _l2GasLimit) external payable nonReentrant {
require(isAllowedToken[token], "BridgeWrap: token not allowed");
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
uint256 gasCost = l2TransactionBaseCost(tx.gasprice, _l2GasLimit, 800);
uint256 neededEth = _convertToEthAmount(gasCost);
require (msg.value >= neededEth, "BridgeWrap: not enough ETH to cover the gas cost");
uint256 gasMinted = _stakeNative(neededEth);
if (token != ozUSDVault.asset()) {
amount = _performSwap(token, amount);
}
uint256 ozUSDMinted = _stakeDai(amount);
require(ozUSDMinted > 0, "BridgeWrap: ozUSD minted is zero");
_bridgeErc20(msg.sender, address(ozUSDVault), ozUSDMinted, _l2GasLimit, 800, gasMinted);
emit StakeAndBridge(token, amount, ozUSDMinted, _l2GasLimit, 800, gasMinted);
(bool success, ) = payable(msg.sender).call{value: msg.value - neededEth}("");
require(success, "BridgeWrap: refund failed");
}
function allowToken(address token, bool allow) external onlyRole(OPERATOR_ROLE) {
require(token != address(0), "allowToken: token cannot be zero address");
isAllowedToken[token] = allow;
emit TokenAllowed(token, allow);
}
function sweepTokens(address token, address to) external onlyRole(WITHDRAW_ROLE) {
IERC20(token).safeTransfer(to, IERC20(token).balanceOf(address(this)));
emit Swept(token, to);
}
function recoverEth() external onlyRole(WITHDRAW_ROLE) {
payable(msg.sender).transfer(address(this).balance);
emit Swept(address(0), msg.sender);
}
function l2TransactionBaseCost(uint256 _l1GasPrice, uint256 _l2GasLimit, uint256 _l2GasPerPubdataByteLimit)
public
view
returns (uint256)
{
return bridgeHub.l2TransactionBaseCost(chainId, _l1GasPrice, _l2GasLimit, _l2GasPerPubdataByteLimit);
}
function l2TransactionEthCost(uint256 _l1GasPrice, uint256 _l2GasLimit, uint256 _l2GasPerPubdataByteLimit)
external
returns (uint256)
{
uint256 baseCost = l2TransactionBaseCost(_l1GasPrice, _l2GasLimit, _l2GasPerPubdataByteLimit);
return _convertToEthAmount(baseCost);
}
function _convertToEthAmount(uint256 _baseTokenAmount) internal returns (uint256) {
uint256 nativeCoinAmount = IERC20(native).totalSupply();
uint256 lmValue = liquidityManager.virtualBalance();
if (lmValue == 0) {
return _baseTokenAmount;
}
return _baseTokenAmount * lmValue * 1_000_000 / (nativeCoinAmount * 950_000);
}
function _bridgeNative (
address _l2Receiver,
uint256 _amount,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) internal returns (bytes32 canonicalTxHash) {
uint256 txCost = l2TransactionBaseCost(tx.gasprice, _l2GasLimit, _l2GasPerPubdataByteLimit);
require(_amount > txCost, "BridgeWrap: not enough to cover the tx cost");
bytes memory empty;
IERC20(native).safeIncreaseAllowance(address(bridgeHub.sharedBridge()), _amount);
canonicalTxHash = bridgeHub.requestL2TransactionDirect(
L2TransactionRequestDirect({
chainId: chainId,
mintValue: _amount,
l2Contract: _l2Receiver,
l2Value: _amount - txCost,
l2Calldata: empty,
l2GasLimit: _l2GasLimit,
l2GasPerPubdataByteLimit: _l2GasPerPubdataByteLimit,
factoryDeps: new bytes[](0),
refundRecipient: _l2Receiver
})
);
emit CanonicalTxHash(canonicalTxHash);
}
function _bridgeErc20(
address _l2Receiver,
address _token,
uint256 _amount,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit,
uint256 _l2GasMinted
) internal returns (bytes32 canonicalTxHash) {
address sharedBridge = address(bridgeHub.sharedBridge());
IERC20(_token).approve(sharedBridge, _amount);
IERC20(native).safeIncreaseAllowance(sharedBridge, _l2GasMinted);
bytes memory callData = _getDepositL2Calldata(_l2Receiver, _token, _amount);
canonicalTxHash = bridgeHub.requestL2TransactionTwoBridges(
L2TransactionRequestTwoBridgesOuter({
chainId: chainId,
mintValue: _l2GasMinted,
l2Value: 0,
l2GasLimit: _l2GasLimit,
l2GasPerPubdataByteLimit: _l2GasPerPubdataByteLimit,
refundRecipient: _l2Receiver,
secondBridgeAddress: sharedBridge,
secondBridgeValue: 0,
secondBridgeCalldata: callData
})
);
emit CanonicalTxHash(canonicalTxHash);
}
function _getDepositL2Calldata(address _l2Receiver, address _l1Token, uint256 _amount)
internal
pure
returns (bytes memory)
{
return abi.encode(_l1Token, _amount, _l2Receiver);
}
function _stakeNative (uint256 amount) internal returns (uint256 sharesMinted){
sharesMinted = IERC20(native).balanceOf(address(this));
liquidityManager.stake{value: amount}();
sharesMinted = IERC20(native).balanceOf(address(this)) - sharesMinted;
emit ShareMinted(msg.sender, amount, sharesMinted);
}
function _stakeDai (uint256 amount) internal returns (uint256) {
IERC20(ozUSDVault.asset()).safeIncreaseAllowance(address(ozUSDVault), amount);
return ozUSDVault.deposit(amount, address(this));
}
function _getAmountOutMin (uint256 amountIn, address tokenIn, address tokenOut) internal view returns (uint256) {
uint decimalsIn = IERC20Metadata(tokenIn).decimals();
uint decimalsOut = IERC20Metadata(tokenOut).decimals();
return (amountIn * (10 ** decimalsOut) * 995) / (1000 * (10 ** decimalsIn));
}
function _performSwap (address token, uint256 amount) internal returns (uint256) {
IERC20(token).safeIncreaseAllowance(univ3router, amount);
return Swap.swap(
univ3router,
100,
token,
ozUSDVault.asset(),
address(this),
amount,
_getAmountOutMin(amount, token, ozUSDVault.asset())
);
}
}
文件 5 的 22:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 6 的 22:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 7 的 22:Errors.sol
pragma solidity ^0.8.20;
library Errors {
error InsufficientBalance(uint256 balance, uint256 needed);
error FailedCall();
error FailedDeployment();
error MissingPrecompile(address);
}
文件 8 的 22:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 9 的 22:IBridgehub.sol
pragma solidity ^0.8.21;
import {IL1SharedBridge} from "../bridge/interfaces/IL1SharedBridge.sol";
import {L2Message, L2Log, TxStatus} from "../common/Messaging.sol";
struct L2TransactionRequestDirect {
uint256 chainId;
uint256 mintValue;
address l2Contract;
uint256 l2Value;
bytes l2Calldata;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
bytes[] factoryDeps;
address refundRecipient;
}
struct L2TransactionRequestTwoBridgesOuter {
uint256 chainId;
uint256 mintValue;
uint256 l2Value;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
address refundRecipient;
address secondBridgeAddress;
uint256 secondBridgeValue;
bytes secondBridgeCalldata;
}
struct L2TransactionRequestTwoBridgesInner {
bytes32 magicValue;
address l2Contract;
bytes l2Calldata;
bytes[] factoryDeps;
bytes32 txDataHash;
}
interface IBridgehub {
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
function setPendingAdmin(address _newPendingAdmin) external;
function acceptAdmin() external;
function stateTransitionManagerIsRegistered(address _stateTransitionManager) external view returns (bool);
function stateTransitionManager(uint256 _chainId) external view returns (address);
function tokenIsRegistered(address _baseToken) external view returns (bool);
function baseToken(uint256 _chainId) external view returns (address);
function sharedBridge() external view returns (IL1SharedBridge);
function getHyperchain(uint256 _chainId) external view returns (address);
function proveL2MessageInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
function proveL2LogInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Log memory _log,
bytes32[] calldata _proof
) external view returns (bool);
function proveL1ToL2TransactionStatus(
uint256 _chainId,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof,
TxStatus _status
) external view returns (bool);
function requestL2TransactionDirect(
L2TransactionRequestDirect calldata _request
) external payable returns (bytes32 canonicalTxHash);
function requestL2TransactionTwoBridges(
L2TransactionRequestTwoBridgesOuter calldata _request
) external payable returns (bytes32 canonicalTxHash);
function l2TransactionBaseCost(
uint256 _chainId,
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256);
function createNewChain(
uint256 _chainId,
address _stateTransitionManager,
address _baseToken,
uint256 _salt,
address _admin,
bytes calldata _initData
) external returns (uint256 chainId);
function addStateTransitionManager(address _stateTransitionManager) external;
function removeStateTransitionManager(address _stateTransitionManager) external;
function addToken(address _token) external;
function setSharedBridge(address _sharedBridge) external;
event NewChain(uint256 indexed chainId, address stateTransitionManager, address indexed chainGovernance);
}
文件 10 的 22:IERC1363.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
interface IERC1363 is IERC20, IERC165 {
function transferAndCall(address to, uint256 value) external returns (bool);
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
function approveAndCall(address spender, uint256 value) external returns (bool);
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
文件 11 的 22:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 12 的 22:IERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
文件 13 的 22:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 14 的 22:IL1ERC20Bridge.sol
pragma solidity ^0.8.21;
import {IL1SharedBridge} from "./IL1SharedBridge.sol";
interface IL1ERC20Bridge {
event DepositInitiated(
bytes32 indexed l2DepositTxHash,
address indexed from,
address indexed to,
address l1Token,
uint256 amount
);
event WithdrawalFinalized(address indexed to, address indexed l1Token, uint256 amount);
event ClaimedFailedDeposit(address indexed to, address indexed l1Token, uint256 amount);
function isWithdrawalFinalized(uint256 _l2BatchNumber, uint256 _l2MessageIndex) external view returns (bool);
function deposit(
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte,
address _refundRecipient
) external payable returns (bytes32 txHash);
function deposit(
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte
) external payable returns (bytes32 txHash);
function claimFailedDeposit(
address _depositSender,
address _l1Token,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
function finalizeWithdrawal(
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
function l2TokenAddress(address _l1Token) external view returns (address);
function SHARED_BRIDGE() external view returns (IL1SharedBridge);
function l2TokenBeacon() external view returns (address);
function l2Bridge() external view returns (address);
function depositAmount(
address _account,
address _l1Token,
bytes32 _depositL2TxHash
) external returns (uint256 amount);
function transferTokenToSharedBridge(address _token) external;
}
文件 15 的 22:IL1SharedBridge.sol
pragma solidity ^0.8.21;
import {L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehub.sol";
import {IBridgehub} from "../../bridgehub/IBridgehub.sol";
import {IL1ERC20Bridge} from "./IL1ERC20Bridge.sol";
interface IL1SharedBridge {
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
event LegacyDepositInitiated(
uint256 indexed chainId,
bytes32 indexed l2DepositTxHash,
address indexed from,
address to,
address l1Token,
uint256 amount
);
event BridgehubDepositInitiated(
uint256 indexed chainId,
bytes32 indexed txDataHash,
address indexed from,
address to,
address l1Token,
uint256 amount
);
event BridgehubDepositBaseTokenInitiated(
uint256 indexed chainId,
address indexed from,
address l1Token,
uint256 amount
);
event BridgehubDepositFinalized(
uint256 indexed chainId,
bytes32 indexed txDataHash,
bytes32 indexed l2DepositTxHash
);
event WithdrawalFinalizedSharedBridge(
uint256 indexed chainId,
address indexed to,
address indexed l1Token,
uint256 amount
);
event ClaimedFailedDepositSharedBridge(
uint256 indexed chainId,
address indexed to,
address indexed l1Token,
uint256 amount
);
function isWithdrawalFinalized(
uint256 _chainId,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex
) external view returns (bool);
function depositLegacyErc20Bridge(
address _msgSender,
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte,
address _refundRecipient
) external payable returns (bytes32 txHash);
function claimFailedDepositLegacyErc20Bridge(
address _depositSender,
address _l1Token,
uint256 _amount,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
function claimFailedDeposit(
uint256 _chainId,
address _depositSender,
address _l1Token,
uint256 _amount,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
function finalizeWithdrawalLegacyErc20Bridge(
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external returns (address l1Receiver, address l1Token, uint256 amount);
function finalizeWithdrawal(
uint256 _chainId,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
function setEraPostDiamondUpgradeFirstBatch(uint256 _eraPostDiamondUpgradeFirstBatch) external;
function setEraPostLegacyBridgeUpgradeFirstBatch(uint256 _eraPostLegacyBridgeUpgradeFirstBatch) external;
function setEraLegacyBridgeLastDepositTime(
uint256 _eraLegacyBridgeLastDepositBatch,
uint256 _eraLegacyBridgeLastDepositTxNumber
) external;
function L1_WETH_TOKEN() external view returns (address);
function BRIDGE_HUB() external view returns (IBridgehub);
function legacyBridge() external view returns (IL1ERC20Bridge);
function l2BridgeAddress(uint256 _chainId) external view returns (address);
function depositHappened(uint256 _chainId, bytes32 _l2TxHash) external view returns (bytes32);
function bridgehubDeposit(
uint256 _chainId,
address _prevMsgSender,
uint256 _l2Value,
bytes calldata _data
) external payable returns (L2TransactionRequestTwoBridgesInner memory request);
function bridgehubDepositBaseToken(
uint256 _chainId,
address _prevMsgSender,
address _l1Token,
uint256 _amount
) external payable;
function bridgehubConfirmL2Transaction(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external;
function receiveEth(uint256 _chainId) external payable;
function setPendingAdmin(address _newPendingAdmin) external;
function acceptAdmin() external;
}
文件 16 的 22:ILiquidityManager.sol
pragma solidity 0.8.27;
interface ILiquidityManager {
function stake() payable external;
function virtualBalance() external returns (uint256);
}
文件 17 的 22:ISwapRouter.sol
pragma solidity 0.8.27;
interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
struct ExactInputParams {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInputSingle(
ExactInputSingleParams calldata params
) external returns (uint256 amountOut);
function exactInput(
ExactInputParams calldata params
) external payable returns (uint256 amountOut);
}
文件 18 的 22:IUSDVault.sol
pragma solidity ^0.8.27;
interface IUSDVault {
function asset() external view returns (address);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function depositToken(address token, uint256 assets, address receiver) external returns (uint256 shares);
function queueWithdraw(uint256 shares) external returns (uint256 index, uint256 cliff);
function queueWithdrawToken(uint256 shares, address token) external returns (uint256 index, uint256 cliff);
function withdraw(uint256 index) external returns (uint256 amount);
function setNewCliff (uint256 cliff) external;
function canWithdraw(uint256 index) external view returns (bool);
}
文件 19 的 22:Messaging.sol
pragma solidity ^0.8.21;
enum TxStatus {
Failure,
Success
}
struct L2Log {
uint8 l2ShardId;
bool isService;
uint16 txNumberInBatch;
address sender;
bytes32 key;
bytes32 value;
}
struct L2Message {
uint16 txNumberInBatch;
address sender;
bytes data;
}
struct WritePriorityOpParams {
uint256 txId;
uint256 l2GasPrice;
uint64 expirationTimestamp;
BridgehubL2TransactionRequest request;
}
struct L2CanonicalTransaction {
uint256 txType;
uint256 from;
uint256 to;
uint256 gasLimit;
uint256 gasPerPubdataByteLimit;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
uint256 paymaster;
uint256 nonce;
uint256 value;
uint256[4] reserved;
bytes data;
bytes signature;
uint256[] factoryDeps;
bytes paymasterInput;
bytes reservedDynamic;
}
struct BridgehubL2TransactionRequest {
address sender;
address contractL2;
uint256 mintValue;
uint256 l2Value;
bytes l2Calldata;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
bytes[] factoryDeps;
address refundRecipient;
}
文件 20 的 22:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 21 的 22:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
文件 22 的 22:Swap.sol
pragma solidity 0.8.27;
import {ISwapRouter} from "../vendors/Uniswap/ISwapRouter.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
library Swap {
uint256 constant SLIPPAGE_TOLERANCE = 997_000;
uint256 constant SCALE = 1_000_000;
function approveAndSwap(
address router,
uint24 fee,
address tokenIn,
address tokenOut,
address recipient,
uint256 amountIn
) internal returns (uint256 amountOut) {
IERC20(tokenIn).approve(router, amountIn);
amountOut = swapWithMaximumSlippage(
router,
fee,
tokenIn,
tokenOut,
recipient,
amountIn
);
}
function swap(
address router,
uint24 fee,
address tokenIn,
address tokenOut,
address recipient,
uint256 amountIn,
uint256 amountOutMinimum
) internal returns (uint256 amountOut) {
ISwapRouter swapRouter = ISwapRouter(router);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: tokenIn,
tokenOut: tokenOut,
fee: fee,
recipient: recipient,
amountIn: amountIn,
amountOutMinimum: amountOutMinimum,
sqrtPriceLimitX96: 0
});
amountOut = swapRouter.exactInputSingle(params);
}
function swapWithMaximumSlippage(
address router,
uint24 fee,
address tokenIn,
address tokenOut,
address recipient,
uint256 amountIn
) internal returns (uint256 amountOut) {
uint256 tokenInDecimals = IERC20Metadata(tokenIn).decimals();
uint256 tokenOutDecimals = IERC20Metadata(tokenOut).decimals();
uint256 normalizedAmountIn = amountIn;
if (tokenOutDecimals > tokenInDecimals) {
normalizedAmountIn = amountIn * (10 ** (tokenOutDecimals - tokenInDecimals));
}
uint256 amountOutMinimum = normalizedAmountIn * SLIPPAGE_TOLERANCE / SCALE;
if (tokenInDecimals > tokenOutDecimals) {
amountOutMinimum = amountOutMinimum / (10 ** (tokenInDecimals - tokenOutDecimals));
}
amountOut = swap(
router,
fee,
tokenIn,
tokenOut,
recipient,
amountIn,
amountOutMinimum
);
}
function swapWithMaximumSlippageRETH(
address router,
uint24 fee,
address tokenIn,
address tokenOut,
address recipient,
uint256 amountIn,
uint256 amountOutMinimum
) internal returns (uint256 amountOut) {
amountOut = swap(
router,
fee,
tokenIn,
tokenOut,
recipient,
amountIn,
amountOutMinimum
);
}
function _swapWithMultipleHops(
ISwapRouter swapRouter,
bytes calldata _path,
address _recipient,
uint256 _amountIn,
uint256 _amountOutMinimum
) internal returns (uint256 amountOut){
ISwapRouter.ExactInputParams memory params =
ISwapRouter.ExactInputParams({
path: _path,
recipient: _recipient,
amountIn: _amountIn,
amountOutMinimum: _amountOutMinimum
});
amountOut = swapRouter.exactInput(params);
}
}
{
"compilationTarget": {
"contracts/bridge/BridgeMiddleware.sol": "BridgeMiddleware"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 100
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_nativeCoin","type":"address"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_bridgeHub","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_withdrawer","type":"address"},{"internalType":"address","name":"_liquidityManager","type":"address"},{"internalType":"address","name":"_ozUSDVault","type":"address"},{"internalType":"address","name":"_univ3router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"canonicalTxHash","type":"bytes32"}],"name":"CanonicalTxHash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"ShareMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ozUSDMinted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"l2GasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"l2GasPerPubdataByteLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasMinted","type":"uint256"}],"name":"StakeAndBridge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"TokenAllowed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITHDRAW_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"allow","type":"bool"}],"name":"allowToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeHub","outputs":[{"internalType":"contract IBridgehub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAllowedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l1GasPrice","type":"uint256"},{"internalType":"uint256","name":"_l2GasLimit","type":"uint256"},{"internalType":"uint256","name":"_l2GasPerPubdataByteLimit","type":"uint256"}],"name":"l2TransactionBaseCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l1GasPrice","type":"uint256"},{"internalType":"uint256","name":"_l2GasLimit","type":"uint256"},{"internalType":"uint256","name":"_l2GasPerPubdataByteLimit","type":"uint256"}],"name":"l2TransactionEthCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidityManager","outputs":[{"internalType":"contract ILiquidityManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"native","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ozUSDVault","outputs":[{"internalType":"contract IUSDVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recoverEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2GasLimit","type":"uint256"}],"name":"stakeAndBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"_l2GasLimit","type":"uint256"}],"name":"stakeAndBridgeStable","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"sweepTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"univ3router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]