// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)pragmasolidity ^0.8.20;import {IAccessControl} from"./IAccessControl.sol";
import {Context} from"../utils/Context.sol";
import {ERC165} from"../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/abstractcontractAccessControlisContext, IAccessControl, ERC165{
structRoleData {
mapping(address account =>bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32publicconstant DEFAULT_ADMIN_ROLE =0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/modifieronlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IAccessControl).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) publicviewvirtualreturns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/function_checkRole(bytes32 role) internalviewvirtual{
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/function_checkRole(bytes32 role, address account) internalviewvirtual{
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) publicviewvirtualreturns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/functiongrantRole(bytes32 role, address account) publicvirtualonlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/functionrevokeRole(bytes32 role, address account) publicvirtualonlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/functionrenounceRole(bytes32 role, address callerConfirmation) publicvirtual{
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/function_setRoleAdmin(bytes32 role, bytes32 adminRole) internalvirtual{
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/function_grantRole(bytes32 role, address account) internalvirtualreturns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] =true;
emit RoleGranted(role, account, _msgSender());
returntrue;
} else {
returnfalse;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/function_revokeRole(bytes32 role, address account) internalvirtualreturns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] =false;
emit RoleRevoked(role, account, _msgSender());
returntrue;
} else {
returnfalse;
}
}
}
Contract Source Code
File 2 of 11: CanonicalBridge.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity 0.8.21;import { AccessControl, IAccessControl } from"openzeppelin-contracts/contracts/access/AccessControl.sol";
import { ReentrancyGuard } from"openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import { Pausable } from"openzeppelin-contracts/contracts/utils/Pausable.sol";
import { ICanonicalBridge } from"./interfaces/ICanonicalBridge.sol";
import { ITreasury } from"./interfaces/ITreasury.sol";
import { ISemVer } from"./interfaces/ISemVer.sol";
/// @title CanonicalBridge/// @dev A bridge contract for depositing and withdrawing ether to and from the Eclipse rollup.contractCanonicalBridgeisICanonicalBridge,
ISemVer,
AccessControl,
Pausable,
ReentrancyGuard{
addressprivateconstant NULL_ADDRESS =address(0);
bytes32privateconstant NULL_BYTES32 =bytes32(0);
bytesprivateconstant NULL_BYTES ="";
uint256privateconstant NEVER =type(uint256).max;
uint256privateconstant MIN_DEPOSIT_LAMPORTS =2_000_000;
uint256privateconstant WEI_PER_LAMPORT =1_000_000_000;
uint256privateconstant DEFAULT_FRAUD_WINDOW_DURATION =7days;
uint256privateconstant MIN_FRAUD_WINDOW_DURATION =1days;
uint256privateconstant PRECISION =1e18;
uint8privateconstant MAJOR_VERSION =2;
uint8privateconstant MINOR_VERSION =0;
uint8privateconstant PATCH_VERSION =0;
bytes32publicconstantoverride PAUSER_ROLE =keccak256("Pauser");
bytes32publicconstantoverride STARTER_ROLE =keccak256("Starter");
bytes32publicconstantoverride WITHDRAW_AUTHORITY_ROLE =keccak256("WithdrawAuthority");
bytes32publicconstantoverride CLAIM_AUTHORITY_ROLE =keccak256("ClaimAuthority");
bytes32publicconstantoverride WITHDRAW_CANCELLER_ROLE =keccak256("WithdrawCanceller");
bytes32publicconstantoverride FRAUD_WINDOW_SETTER_ROLE =keccak256("FraudWindowSetter");
uint256publicconstantoverride MIN_DEPOSIT = MIN_DEPOSIT_LAMPORTS * WEI_PER_LAMPORT;
addresspublicimmutableoverride TREASURY;
uint256publicoverride fraudWindowDuration =7days;
mapping (bytes32 withdrawMessageHash =>uint256 startTime) publicoverride startTime;
mapping (uint64 withdrawMessageId =>uint256 blockNumber) publicoverride withdrawMsgIdProcessed;
/// @notice Explain to an end user what this does/// @dev Explain to a developer any extra details/// @dev Ensures that bytes32 data is initialized with data.modifierbytes32Initialized(bytes32 _data) {
if(_data == NULL_BYTES32) revert EmptyBytes32();
_;
}
/// @dev Ensures the deposit amount and msg.value are valid, equal and they are >= to the min deposit amount./// @param amountWei The amount to be deposited.modifiervalidDepositAmount(uint256 amountWei) {
if (msg.value!= amountWei) revert CanonicalBridgeTransactionRejected(0, "Deposit amount mismatch");
if (msg.value% WEI_PER_LAMPORT !=0) revert CanonicalBridgeTransactionRejected(0, "Fractional value not allowed");
if (msg.value< MIN_DEPOSIT) revert CanonicalBridgeTransactionRejected(0, "Deposit less than minimum");
_;
}
/// @dev Ensure that withdraw messages are complete.modifiervalidWithdrawMessage(WithdrawMessage memory message) {
if (message.from == NULL_BYTES32) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "Null message.from");
}
if (message.destination == NULL_ADDRESS) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "Null message.destination");
}
if (message.amountWei ==0) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "message.amountWei is 0");
}
if (message.withdrawId ==0) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "message.withdrawId is 0");
}
if (message.feeWei > message.amountWei) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "message.fee exceeds message.amount");
}
if (message.feeReceiver == NULL_ADDRESS) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "Null fee receiver");
}
_;
}
/// @dev Constructor that initializes the contract.constructor(address owner, address treasuryAddress) {
/// @dev The owner receives default ACL-admin role that controls access to the/// operational roles that follow.
_grantRole(DEFAULT_ADMIN_ROLE, owner);
/// @dev These assignments are conveniences, since the owner now has user admin authority.
_grantRole(PAUSER_ROLE, owner);
_grantRole(STARTER_ROLE, owner);
_grantRole(WITHDRAW_AUTHORITY_ROLE, owner);
_grantRole(CLAIM_AUTHORITY_ROLE, owner);
_grantRole(WITHDRAW_CANCELLER_ROLE, owner);
_grantRole(FRAUD_WINDOW_SETTER_ROLE, owner);
TREASURY = treasuryAddress;
emit Deployed(msg.sender, owner, treasuryAddress);
_setFraudWindowDuration(DEFAULT_FRAUD_WINDOW_DURATION);
}
/// @inheritdoc ICanonicalBridgefunctionwithdrawMessageStatus(
WithdrawMessage calldata message
)
externalviewoverridevalidWithdrawMessage(message)
returns (WithdrawStatus)
{
return withdrawMessageStatus(withdrawMessageHash(message));
}
/// @inheritdoc ICanonicalBridgefunctionwithdrawMessageStatus(bytes32 messageHash) publicviewoverridereturns (WithdrawStatus) {
uint256 startTime_ = startTime[messageHash];
if (startTime_ ==0) return WithdrawStatus.UNKNOWN;
if (startTime_ == NEVER) return WithdrawStatus.CLOSED;
if (startTime_ >block.timestamp) return WithdrawStatus.PROCESSING;
return WithdrawStatus.PENDING;
}
/// @inheritdoc ICanonicalBridgefunctionwithdrawMessageHash(WithdrawMessage memory message) publicpureoverridereturns (bytes32) {
returnkeccak256(abi.encode(message));
}
/// @inheritdoc ISemVer/// @dev Retrieves the constant version details of the smart contract.functiongetVersionComponents() publicpureoverridereturns (Version memory) {
return Version(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION);
}
// Operations/// @inheritdoc ICanonicalBridge/// @dev Access controlled, pausiblefunctiondeposit(bytes32 recipient, uint256 amountWei)
externalpayablevirtualoverridewhenNotPausedbytes32Initialized(recipient)
validDepositAmount(amountWei)
nonReentrant{
bool success;
(success,) =payable(address(TREASURY)).call{value: amountWei}(abi.encodeWithSignature("depositEth()"));
if (!success) revert CanonicalBridgeTransactionRejected(0, "failed to transfer funds to the treasury");
// Emit deposit messageuint256 amountGwei = amountWei / WEI_PER_LAMPORT;
emit Deposited(msg.sender, recipient, amountWei, amountGwei);
}
/// @inheritdoc ICanonicalBridge/// @dev Access controlled, pausablefunctionauthorizeWithdraws(
WithdrawMessage[] calldata messages
)
externaloverridewhenNotPausedonlyRole(WITHDRAW_AUTHORITY_ROLE)
{
for (uint256 i =0; i < messages.length; i++) {
_authorizeWithdraw(messages[i]);
}
}
/// @inheritdoc ICanonicalBridge/// @dev Access controlled, pausablefunctionauthorizeWithdraw(
WithdrawMessage calldata message
)
externaloverridewhenNotPausedonlyRole(WITHDRAW_AUTHORITY_ROLE)
{
_authorizeWithdraw(message);
}
/// @notice Inserts a withdraw authorization with a start time after the fraud window./// @param message The message to record./// @dev Message must pass validation rules.function_authorizeWithdraw(
WithdrawMessage memory message
)
privatevalidWithdrawMessage(message)
{
bytes32 messageHash = withdrawMessageHash(message);
uint256 messageStartTime =block.timestamp+ fraudWindowDuration;
/// @dev This would occur if the relayer passed the same message twice.if (withdrawMessageStatus(messageHash) != WithdrawStatus.UNKNOWN) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "Message already exists");
}
/// @dev This would only occur if the same message Id was used for two different messages.if (withdrawMsgIdProcessed[message.withdrawId] !=0) {
revert CanonicalBridgeTransactionRejected(message.withdrawId, "Message Id already exists");
}
startTime[messageHash] = messageStartTime;
withdrawMsgIdProcessed[message.withdrawId] =block.number;
/// @dev Transfer fee to feeReceiver.bool success = ITreasury(TREASURY).withdrawEth(
message.feeReceiver,
message.feeWei
);
/// @dev The following condition should never occur and the error should be unreachable code.if (!success) revert WithdrawFailed();
emit WithdrawAuthorized(
msg.sender,
message,
messageHash,
messageStartTime
);
}
/// @inheritdoc ICanonicalBridge/// @dev PausablefunctionclaimWithdraw(
WithdrawMessage calldata message
)
externaloverridewhenNotPausednonReentrantvalidWithdrawMessage(message)
{
bool authorizedWithdrawer = (msg.sender== message.destination || hasRole(CLAIM_AUTHORITY_ROLE, msg.sender));
if (!authorizedWithdrawer) {
revert IAccessControl.AccessControlUnauthorizedAccount(msg.sender, CLAIM_AUTHORITY_ROLE);
}
bytes32 messageHash = withdrawMessageHash(message);
if (withdrawMessageStatus(messageHash) != WithdrawStatus.PENDING) revert WithdrawUnauthorized();
startTime[messageHash] = NEVER;
emit WithdrawClaimed(message.destination, message.from, messageHash, message);
/// @dev Transfer amountWei - feeWei to recipient.bool success = ITreasury(TREASURY).withdrawEth(
message.destination,
message.amountWei - message.feeWei
);
/// @dev The following condition should never occur and the error should be unreachable code.if (!success) revert WithdrawFailed();
}
// Admin/// @inheritdoc ICanonicalBridge/// @dev Access controlledfunctiondeleteWithdrawMessage(
WithdrawMessage calldata message
)
externaloverridevalidWithdrawMessage(message)
onlyRole(WITHDRAW_CANCELLER_ROLE)
{
bytes32 messageHash = withdrawMessageHash(message);
WithdrawStatus status = withdrawMessageStatus(messageHash);
if (status != WithdrawStatus.PENDING && status != WithdrawStatus.PROCESSING) {
revert CannotCancel();
}
startTime[messageHash] =0;
withdrawMsgIdProcessed[message.withdrawId] =0;
emit WithdrawMessageDeleted(msg.sender, message);
}
/// @inheritdoc ICanonicalBridge/// @dev Access controlledfunctionsetFraudWindowDuration(uint256 durationSeconds) publiconlyRole(FRAUD_WINDOW_SETTER_ROLE) {
if (durationSeconds < MIN_FRAUD_WINDOW_DURATION) revert DurationTooShort();
_setFraudWindowDuration(durationSeconds);
}
function_setFraudWindowDuration(uint256 durationSeconds) internal{
fraudWindowDuration = durationSeconds;
emit FraudWindowSet(msg.sender, durationSeconds);
}
/// @dev Pause deposits/// @dev Access controlledfunctionpause() externalvirtualonlyRole(PAUSER_ROLE) {
_pause();
}
/// @dev Unpause deposits/// @dev Access controlledfunctionunpause() externalvirtualonlyRole(STARTER_ROLE) {
_unpause();
}
}
Contract Source Code
File 3 of 11: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)pragmasolidity ^0.8.20;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
function_contextSuffixLength() internalviewvirtualreturns (uint256) {
return0;
}
}
Contract Source Code
File 4 of 11: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)pragmasolidity ^0.8.20;import {IERC165} from"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualreturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 5 of 11: IAccessControl.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)pragmasolidity ^0.8.20;/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/interfaceIAccessControl{
/**
* @dev The `account` is missing a role.
*/errorAccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/errorAccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/eventRoleAdminChanged(bytes32indexed role, bytes32indexed previousAdminRole, bytes32indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/eventRoleGranted(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/eventRoleRevoked(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) externalviewreturns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) externalviewreturns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functiongrantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functionrevokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/functionrenounceRole(bytes32 role, address callerConfirmation) external;
}
Contract Source Code
File 6 of 11: ICanonicalBridge.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity 0.8.21;/// @title IEtherBridge/// @notice Interface for a bridge contract that handles deposits of ether.interfaceICanonicalBridge{
/// @notice Contains deposit details sent to the target rollup chain./// @param sender The address which provided the ether to deposit./// @param recipient Abi packed bytes32 of a base58-encoded Solana address on the target chain./// @param amountGwei The amount deposited in Gwei.structDepositMessage {
address sender;
bytes32 recipient;
uint256 amountGwei;
}
/// @notice Contains withdraw details sent by an authoritative state updater./// @param pubKey Public key of the primary txn signer./// @param destination Receiver who can claim the withdraw./// @param amountWei Amount of wei that can be withdrawn./// @param withdrawId Unique identifier can be used once./// @param feeReceiver The address that will receive the transaction fee./// @param feeWei The amount of fee to deduct from the amountWei.structWithdrawMessage {
bytes32from;
address destination;
uint256 amountWei;
uint64 withdrawId;
address feeReceiver;
uint256 feeWei;
}
enumWithdrawStatus { UNKNOWN, PROCESSING, PENDING, CLOSED }
/// @notice Emitted from the contract constructor./// @param deployer The deployer address./// @param owner The address that received the default permissions./// @param treasuryAddress The address that will hold received funds.eventDeployed(addressindexed deployer, address owner, address treasuryAddress);
/// @notice Emitted when the fraud window is set./// @param sender The authority that updated the fraud window./// @param durationSeconds The new fraud window.eventFraudWindowSet(addressindexed sender, uint256 durationSeconds);
/// @notice Emitted on a successful deposit./// @param sender The address of the user who made the deposit./// @param recipient The recipient account on the target chain./// @param amountWei The amount in wei deposited.eventDeposited(addressindexed sender,
bytes32indexed recipient,
uint256 amountWei,
uint256 amountLamports
);
/// @notice Emitted when a withdraw message is accepted./// @param sender The address of the withdraw authority that forwarded the message./// @param message The withdraw message accepted./// @param messageHash The hash of the withdrawMessage./// @param startTime The earliest timestamp when the withdraw can be executed.eventWithdrawAuthorized(addressindexed sender,
WithdrawMessage message,
bytes32indexed messageHash,
uint256 startTime);
/// @notice Emitted when a withdraw is claimed and executed./// @param receiver The recipient of the funds who is also the requester./// @param message The withdraw message includes details such as origin and amount./// @param messageHash The hash of the withdrawMessage.eventWithdrawClaimed(addressindexed receiver,
bytes32indexed remoteSender,
bytes32indexed messageHash,
WithdrawMessage message
);
/// @notice Emitted when an authorized withdraw is cancelled, by pre-image./// @param authority The sender to authorized the cancellation./// @param message The withdraw message that was cancelled.eventWithdrawMessageDeleted(address authority, WithdrawMessage message);
/// @notice Emitted when an authorized withdraw is cancelled, by hash./// @param authority The sender to authorized the cancellation./// @param messageHash The withdraw message hash that was cancelled.eventWithdrawMessageHashDeleted(addressindexed authority, bytes32indexed messageHash);
/// @notice Emitted when a withdraw authorization is cancelled./// @param sender The authority that cancelled with the withdraw./// @param messageHash The hash of the withdraw message that was cancelled.eventWithdrawCancelled(addressindexed sender, bytes32indexed messageHash);
/// @notice Emitted when the withdraw authorization is rejected./// @param withdrawId The transactionId that was rejected./// @dev withdrawId is 0 if deposit transaction. It is meaningful if a withdraw transaction or batch.errorCanonicalBridgeTransactionRejected(uint64 withdrawId, string reason);
/// @notice Emitted when the requested fraud window is less than the hard-code minimum.errorDurationTooShort();
/// @notice Emitted when the Treasury fails to withdraw funds as instructed.errorWithdrawFailed();
/// @notice Emitted when an attempted withdraw is unauthorized.errorWithdrawUnauthorized();
/// @notice Emitted when an unable to cancel an authorized withdraw./// @dev The authorized withdraw must be in the PENDING state or it cannot be cancelled.errorCannotCancel();
/// @notice Emitted when a bytes32 input is empty.errorEmptyBytes32();
/// @notice Returns the pauser role id.functionPAUSER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the starter role id.functionSTARTER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the withdraw authority role id.functionWITHDRAW_AUTHORITY_ROLE() externalviewreturns (bytes32);
/// @notice Returns the claim authority role id.functionCLAIM_AUTHORITY_ROLE() externalviewreturns (bytes32);
/// @notice Returns the withdraw canceller role id.functionWITHDRAW_CANCELLER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the fraud window duration setter role id.functionFRAUD_WINDOW_SETTER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the minimum wei required to acquire a single lamport.functionMIN_DEPOSIT() externalviewreturns (uint256);
/// @notice Returns the address of the treasury that will receive locked funds.functionTREASURY() externalviewreturns (address);
/// @notice Returns the fraud window duration that governs withdraw eligibility.functionfraudWindowDuration() externalviewreturns (uint256);
/// @notice Returns the startTime of withdraw eligibility for a withdraw message hash./// @param withdrawMessageHash A hash of a withdraw message./// @dev Eth timestamp format is in seconds. zero is not possible for a withdraw message/// with a non-zero amount. 2^^256 means the withdraw has been claimed and can never/// be executed again.functionstartTime(bytes32 withdrawMessageHash) externalviewreturns (uint256);
/// @notice Returns the status of the withdraw message./// @param message The message to check.functionwithdrawMessageStatus(WithdrawMessage calldata message) externalviewreturns (WithdrawStatus);
/// @notice Returns the status of the withdraw message./// @param messageHash The message to check.functionwithdrawMessageStatus(bytes32 messageHash) externalviewreturns (WithdrawStatus);
/// @notice Set the duration to delay withdraw eligibility./// @param durationSeconds The delay duration when withdraw messages are accepted.functionsetFraudWindowDuration(uint256 durationSeconds) external;
/// @notice Allows users to deposit ether to the target chain./// @dev Accepts Ether along with the deposit message. Emits the `Deposited` event upon success./// @param recipient The recipient account on target chain./// @param amountWei The amount in wei to deposit.functiondeposit(bytes32 recipient, uint256 amountWei) externalpayable;
/// @notice Establishes permission to withdraw funds after the fraud window passes./// @param messages abi.encoded array of Withdraw messages to authorize.functionauthorizeWithdraws(WithdrawMessage[] calldata messages) external;
/// @notice Establishes permission to withdraw funds after the fraud window passes./// @param message abi.encoded Withdraw message to authorize.functionauthorizeWithdraw(WithdrawMessage calldata message) external;
/// @notice Allows the receiver to claim an authorized withdraw./// @param message The message to execute.functionclaimWithdraw(WithdrawMessage calldata message) external;
/// @notice Allows the fraud authority to cancel a pending withdraw./// @param message The authorized withdraw message to cancel.functiondeleteWithdrawMessage(WithdrawMessage calldata message) external;
/// @notice Returns the hash of a withdraw message./// @param message The message to hashfunctionwithdrawMessageHash(WithdrawMessage calldata message) externalpurereturns (bytes32);
/// @notice Returns the block number if the withdraw message id has been observed and recorded./// @param withdrawMsgId The message id to inspect.functionwithdrawMsgIdProcessed(uint64 withdrawMsgId) externalviewreturns (uint256);
}
Contract Source Code
File 7 of 11: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)pragmasolidity ^0.8.20;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 8 of 11: ISemVer.sol
// SPDX-License-Identifier: UNLICENSED pragmasolidity 0.8.21;/**
* @title ISemVer
* @dev Interface for SemVer versioning within smart contracts.
*/interfaceISemVer{
/// @dev Struct to hold the version components./// @param major The major version component, incremented for incompatible API changes./// @param minor The minor version component, incremented for added functionality in a backwards-compatible manner./// @param patch The patch version component, incremented for backwards-compatible bug fixes.structVersion {
uint8 major;
uint8 minor;
uint8 patch;
}
/// @dev Returns the major, minor, and patch components of the version as a struct./// @return Version memory Returns the version details encapsulated in a Version struct.functiongetVersionComponents() externalpurereturns (Version memory);
}
Contract Source Code
File 9 of 11: ITreasury.sol
// SPDX-License-Identifier: UNLICENSED pragmasolidity 0.8.21;/// @title ITreasury/// @notice Interface for a treasury contract stores ether./// @dev This interface assumes the implementation will provide a fallback function to receive ether.interfaceITreasury{
/// @notice Emitted when the treasury is re-initialized. /// @param admin Address that initiated the re-initialization. /// @param oldOwner Address that was granted various permissions. eventTreasuryReinitialized(address admin, address oldOwner);
/// @notice Emitted when ether is deposited into the treasury./// @param from The address of the sender who deposited ether./// @param amountWei The amount of ether deposited.eventTreasuryDeposit(addressindexedfrom, uint256 amountWei);
/// @notice Emitted when ether is withdrawn from the treasury./// @param authority The sender of the withdraw instruction./// @param to The address of the sender who received ether./// @param amountWei The amount of ether withdrawn.eventTreasuryWithdraw(address authority,
addressindexed to,
uint256 amountWei
);
/// @notice Emitted when ether is withdrawn from the treasury during an emergency withdraw./// @param to The address to which ether was sent./// @param amountWei The amount of ether withdrawn.eventEmergencyTreasuryWithdraw(addressindexed to, uint256 amountWei);
/// @notice Emitted when withdraws couldn't be sent to the receiver.errorTreasuryTransferFailed();
/// @notice Emitted when withdraw amount exceeds funds on hand.errorInsufficientFunds();
/// @notice Emitted when an input address is a prohibited address(0).errorZeroAddress();
/// @notice Returns the depositor role id.functionDEPOSITOR_ROLE() externalviewreturns (bytes32);
/// @notice Returns the withdraw authority role id.functionWITHDRAW_AUTHORITY_ROLE() externalviewreturns (bytes32);
/// @notice Returns the pauser role id.functionPAUSER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the starter role id.functionSTARTER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the upgrader role id.functionUPGRADER_ROLE() externalviewreturns (bytes32);
/// @notice Returns the emergency authority role id. functionEMERGENCY_ROLE() externalviewreturns (bytes32);
/// @notice Reinitializes the Treasury. Grants roles to the owner.functionreinitialize() external;
/// @notice Accepts eth deposits. functiondepositEth() externalpayable;
/// @notice Withdraws Eth from the Treasury./// @param to The receiver of the withdrawn Eth./// @param amountWei The gross amount of Eth to withdraw./// @return success True if the withdraw was succesful.functionwithdrawEth(address to,
uint256 amountWei
) externalreturns (bool success);
/// @notice Stops deposits. Requires the PAUSER_ROLE.functionpause() external;
/// @notice Starts deposits. Requires the STARTER_ROLE.functionunpause() external;
/// @notice Withdraws an 'amount' of ether during emergencies./// @param amountWei The amount of ether to be sent.functionemergencyWithdraw(uint256 amountWei) external;
}
Contract Source Code
File 10 of 11: Pausable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)pragmasolidity ^0.8.20;import {Context} from"../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/abstractcontractPausableisContext{
boolprivate _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/eventPaused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/eventUnpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/errorEnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/errorExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/constructor() {
_paused =false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/modifierwhenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/modifierwhenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/functionpaused() publicviewvirtualreturns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/function_requireNotPaused() internalviewvirtual{
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/function_requirePaused() internalviewvirtual{
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/function_pause() internalvirtualwhenNotPaused{
_paused =true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/function_unpause() internalvirtualwhenPaused{
_paused =false;
emit Unpaused(_msgSender());
}
}
Contract Source Code
File 11 of 11: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)pragmasolidity ^0.8.20;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant NOT_ENTERED =1;
uint256privateconstant ENTERED =2;
uint256private _status;
/**
* @dev Unauthorized reentrant call.
*/errorReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be NOT_ENTEREDif (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/function_reentrancyGuardEntered() internalviewreturns (bool) {
return _status == ENTERED;
}
}