Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts-upgradeable5/access/AccessControlUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
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) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
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}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
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.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(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.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(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.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
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) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
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) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @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) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
"
},
"@openzeppelin/contracts-upgradeable5/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
"
},
"@openzeppelin/contracts-upgradeable5/utils/ContextUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
"
},
"@openzeppelin/contracts-upgradeable5/utils/introspection/ERC165Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.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);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
"
},
"@openzeppelin/contracts/access/IAccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed 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}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed 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`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (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.
*/
function grantRole(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.
*/
function revokeRole(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`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^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}.
*/
interface IERC165 {
/**
* @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.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
},
"contracts/AgglayerGateway.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {ISP1Verifier} from "./interfaces/ISP1Verifier.sol";
import {IAgglayerGateway} from "./interfaces/IAgglayerGateway.sol";
import {IVersion} from "./interfaces/IVersion.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable5/proxy/utils/Initializable.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable5/access/AccessControlUpgradeable.sol";
// Based on https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/SP1VerifierGateway.sol
/**
* @title AgglayerGateway
* @notice Contract to handle the verification keys for the pessimistic proof.
* It supports adding and freezing PP verification keys and verifying the PP.
* Also maintains the default verification keys of aggchains
*/
contract AgglayerGateway is
Initializable,
AccessControlUpgradeable,
IAgglayerGateway,
IVersion
{
////////////////////////////////////////////////////////////
// Constants & Immutables //
////////////////////////////////////////////////////////////
// Roles
// Default admin role, can grant roles to addresses
// @dev value: 0x131410eab1236cee2db19035b0e825c94e5ab705dffe23321dd53856da531617
bytes32 internal constant AGGCHAIN_DEFAULT_VKEY_ROLE =
keccak256("AGGCHAIN_DEFAULT_VKEY_ROLE");
// Can add a route to a pessimistic verification key.
// @dev value 0x0fdc2a718b96bc741c7544001e3dd7c26730802c54781668fa78a120e622629b
bytes32 internal constant AL_ADD_PP_ROUTE_ROLE =
keccak256("AL_ADD_PP_ROUTE_ROLE");
// Can freeze a route to a pessimistic verification key.
// @dev value 0xca75ae4228cde6195f9fa3dbde8dc352fb30aa63780717a378ccfc50274355dd
bytes32 internal constant AL_FREEZE_PP_ROUTE_ROLE =
keccak256("AL_FREEZE_PP_ROUTE_ROLE");
// Can manage multisig signers and threshold
// @dev value 0x0c3038a1ecdf82843b70709289ff1703351ad391e3e27df7f6fa7d913601e15e
bytes32 internal constant AL_MULTISIG_ROLE = keccak256("AL_MULTISIG_ROLE");
// Current AgglayerGateway version
string public constant AGGLAYER_GATEWAY_VERSION = "v1.1.0";
// Maximum number of aggchain signers supported
uint256 public constant MAX_AGGCHAIN_SIGNERS = 255;
////////////////////////////////////////////////////////////
// Transient Storage //
////////////////////////////////////////////////////////////
/// @notice Value to detect if the contract has been initialized previously.
uint64 private transient _initializerVersion;
////////////////////////////////////////////////////////////
// Mappings //
////////////////////////////////////////////////////////////
// Mapping with the default aggchain verification keys
mapping(bytes4 defaultAggchainSelector => bytes32 defaultAggchainVKey)
public defaultAggchainVKeys;
// Mapping with the pessimistic verification key routes
mapping(bytes4 pessimisticVKeySelector => AggLayerVerifierRoute)
public pessimisticVKeyRoutes;
////////////////////////////////////////////////////////////
// Multisig //
////////////////////////////////////////////////////////////
/// @notice Array of multisig aggchainSigners
address[] public aggchainSigners;
/// @notice Mapping that stores the URL of each signer
/// It's used as well to check if an address is a signer
mapping(address => string) public signerToURLs;
/// @notice Threshold required for multisig operations
uint256 internal threshold;
/// @notice Hash of the current aggchainSigners array
bytes32 public aggchainMultisigHash;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* Updated to account for new multisig storage variables (4 slots used)
*/
uint256[46] private __gap;
////////////////////////////////////////////////////////////
// Constructor //
////////////////////////////////////////////////////////////
/**
* @dev Disable initializers on the implementation following the best practices.
*/
constructor() {
// disable initializers for implementation contract
_disableInitializers();
}
////////////////////////////////////////////////////////////
// Modifiers //
////////////////////////////////////////////////////////////
/// @dev Modifier to retrieve initializer version value previous on using the reinitializer modifier, its used in the initialize function.
modifier getInitializedVersion() {
_initializerVersion = _getInitializedVersion();
_;
}
////////////////////////////////////////////////////////////
// Initialization //
////////////////////////////////////////////////////////////
/**
* @notice Initializer function to set up the AgglayerGateway contract.
* @param defaultAdmin The address of the default admin. Can grant role to addresses.
* @dev This address is the highest privileged address so it's recommended to use a timelock
* @param aggchainDefaultVKeyRole The address that can manage the aggchain verification keys.
* @param addRouteRole The address that can add a route to a pessimistic verification key.
* @param freezeRouteRole The address that can freeze a route to a pessimistic verification key.
* @param pessimisticVKeySelector The 4 bytes selector to add to the pessimistic verification keys.
* @param verifier The address of the verifier contract.
* @param pessimisticVKey New pessimistic program verification key.
* @param multisigRole The address that can manage multisig signers and threshold.
* @param signersToAdd Array of signers to add with their URLs
* @param newThreshold New threshold value
*/
function initialize(
address defaultAdmin,
address aggchainDefaultVKeyRole,
address addRouteRole,
address freezeRouteRole,
bytes4 pessimisticVKeySelector,
address verifier,
bytes32 pessimisticVKey,
address multisigRole,
SignerInfo[] memory signersToAdd,
uint256 newThreshold
) external getInitializedVersion reinitializer(2) {
if (_initializerVersion != 0) {
revert InvalidInitializer();
}
if (
multisigRole == address(0) ||
defaultAdmin == address(0) ||
aggchainDefaultVKeyRole == address(0) ||
addRouteRole == address(0) ||
freezeRouteRole == address(0)
) {
revert InvalidZeroAddress();
}
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
_grantRole(AGGCHAIN_DEFAULT_VKEY_ROLE, aggchainDefaultVKeyRole);
_grantRole(AL_ADD_PP_ROUTE_ROLE, addRouteRole);
_grantRole(AL_FREEZE_PP_ROUTE_ROLE, freezeRouteRole);
_grantRole(AL_MULTISIG_ROLE, multisigRole);
_addPessimisticVKeyRoute(
pessimisticVKeySelector,
verifier,
pessimisticVKey
);
// Add the signers to the contract
_updateSignersAndThreshold(
new RemoveSignerInfo[](0), // No signers to remove
signersToAdd,
newThreshold
);
}
/**
* @notice Upgrade initializer to add multisig functionality to existing deployment.
* @param multisigRole The address of the multisig role. Can manage multisig signers and threshold.
* @param signersToAdd Array of signers to add with their URLs
* @param newThreshold New threshold value
*/
function initialize(
address multisigRole,
SignerInfo[] memory signersToAdd,
uint256 newThreshold
) external getInitializedVersion reinitializer(2) {
if (_initializerVersion != 1) {
revert InvalidInitializer();
}
if (multisigRole == address(0)) {
revert InvalidZeroAddress();
}
_grantRole(AL_MULTISIG_ROLE, multisigRole);
// Add the signers to the contract
_updateSignersAndThreshold(
new RemoveSignerInfo[](0), // No signers to remove
signersToAdd,
newThreshold
);
}
////////////////////////////////////////////////////////////
// Functions: AgglayerGateway (pessimistic) //
////////////////////////////////////////////////////////////
/**
* @notice Function to verify the pessimistic proof.
* @param publicValues Public values of the proof.
* @param proofBytes Proof for the pessimistic verification.
* @dev First 4 bytes of the pessimistic proof are the pp selector.
* proof[0:4]: 4 bytes selector pp
* proof[4:8]: 4 bytes selector SP1 verifier
* proof[8:]: proof
*/
function verifyPessimisticProof(
bytes calldata publicValues,
bytes calldata proofBytes
) external view {
/// @dev By protocol the proof should at least have the 4 bytes selector, the other bytes are not part of our protocol
if (proofBytes.length < 4) {
revert InvalidProofBytesLength();
}
bytes4 ppSelector = bytes4(proofBytes[:4]);
AggLayerVerifierRoute memory route = pessimisticVKeyRoutes[ppSelector];
if (route.verifier == address(0)) {
revert RouteNotFound(ppSelector);
} else if (route.frozen) {
revert RouteIsFrozen(ppSelector);
}
ISP1Verifier(route.verifier).verifyProof(
route.pessimisticVKey,
publicValues,
proofBytes[4:]
);
}
/**
* @notice Internal function to add a pessimistic verification key route
* @param pessimisticVKeySelector The 4 bytes selector to add to the pessimistic verification keys.
* @param verifier The address of the verifier contract.
* @param pessimisticVKey New pessimistic program verification key
*/
function _addPessimisticVKeyRoute(
bytes4 pessimisticVKeySelector,
address verifier,
bytes32 pessimisticVKey
) internal {
if (verifier == address(0)) {
revert InvalidZeroAddress();
}
if (pessimisticVKeySelector == bytes4(0)) {
revert PPSelectorCannotBeZero();
}
if (pessimisticVKey == bytes32(0)) {
revert VKeyCannotBeZero();
}
AggLayerVerifierRoute storage route = pessimisticVKeyRoutes[
pessimisticVKeySelector
];
if (route.verifier != address(0)) {
revert RouteAlreadyExists(pessimisticVKeySelector, route.verifier);
}
route.verifier = verifier;
route.pessimisticVKey = pessimisticVKey;
emit RouteAdded(pessimisticVKeySelector, verifier, pessimisticVKey);
}
/**
* @notice Function to add a pessimistic verification key route
* @param pessimisticVKeySelector The 4 bytes selector to add to the pessimistic verification keys.
* @param verifier The address of the verifier contract.
* @param pessimisticVKey New pessimistic program verification key
*/
function addPessimisticVKeyRoute(
bytes4 pessimisticVKeySelector,
address verifier,
bytes32 pessimisticVKey
) external onlyRole(AL_ADD_PP_ROUTE_ROLE) {
_addPessimisticVKeyRoute(
pessimisticVKeySelector,
verifier,
pessimisticVKey
);
}
/**
* @notice Function to freeze a pessimistic verification key route
* @param pessimisticVKeySelector The 4 bytes selector to freeze the pessimistic verification key route.
*/
function freezePessimisticVKeyRoute(
bytes4 pessimisticVKeySelector
) external onlyRole(AL_FREEZE_PP_ROUTE_ROLE) {
AggLayerVerifierRoute storage route = pessimisticVKeyRoutes[
pessimisticVKeySelector
];
if (route.verifier == address(0)) {
revert RouteNotFound(pessimisticVKeySelector);
}
if (route.frozen) {
revert RouteIsAlreadyFrozen(pessimisticVKeySelector);
}
route.frozen = true;
emit RouteFrozen(
pessimisticVKeySelector,
route.verifier,
route.pessimisticVKey
);
}
////////////////////////////////////////////////////////////
// Functions: defaultAggchainVkey //
////////////////////////////////////////////////////////////
/**
* @notice Function to add an aggchain verification key
* @param defaultAggchainSelector The 4 bytes selector to add to the default aggchain verification keys.
* @dev First 2 bytes of the selector are the 'verification key identifier', the last 2 bytes are the aggchain type (ex: FEP, ECDSA)
* @param newAggchainVKey New default aggchain verification key to be added
*/
function addDefaultAggchainVKey(
bytes4 defaultAggchainSelector,
bytes32 newAggchainVKey
) external onlyRole(AGGCHAIN_DEFAULT_VKEY_ROLE) {
// Check already exists
if (defaultAggchainVKeys[defaultAggchainSelector] != bytes32(0)) {
revert AggchainVKeyAlreadyExists();
}
// Check new key is non-zero
if (newAggchainVKey == bytes32(0)) {
revert VKeyCannotBeZero();
}
// Add the new VKey to the mapping
defaultAggchainVKeys[defaultAggchainSelector] = newAggchainVKey;
emit AddDefaultAggchainVKey(defaultAggchainSelector, newAggchainVKey);
}
/**
* @notice Function to update a default aggchain verification key from the mapping
* @param defaultAggchainSelector The 4 bytes selector to update the default aggchain verification keys.
* @param newDefaultAggchainVKey Updated default aggchain verification key value
*/
function updateDefaultAggchainVKey(
bytes4 defaultAggchainSelector,
bytes32 newDefaultAggchainVKey
) external onlyRole(AGGCHAIN_DEFAULT_VKEY_ROLE) {
// Check if the key exists
if (defaultAggchainVKeys[defaultAggchainSelector] == bytes32(0)) {
revert AggchainVKeyNotFound();
}
// Check new key is non-zero
if (newDefaultAggchainVKey == bytes32(0)) {
revert VKeyCannotBeZero();
}
// Update the VKey
bytes32 previousVKey = defaultAggchainVKeys[defaultAggchainSelector];
defaultAggchainVKeys[defaultAggchainSelector] = newDefaultAggchainVKey;
emit UpdateDefaultAggchainVKey(
defaultAggchainSelector,
previousVKey,
newDefaultAggchainVKey
);
}
/**
* @notice Function to unset a default aggchain verification key from the mapping
* @param defaultAggchainSelector The 4 bytes selector to update the default aggchain verification keys.
*/
function unsetDefaultAggchainVKey(
bytes4 defaultAggchainSelector
) external onlyRole(AGGCHAIN_DEFAULT_VKEY_ROLE) {
// Check if the key exists
if (defaultAggchainVKeys[defaultAggchainSelector] == bytes32(0)) {
revert AggchainVKeyNotFound();
}
// Set key to zero
defaultAggchainVKeys[defaultAggchainSelector] = bytes32(0);
emit UnsetDefaultAggchainVKey(defaultAggchainSelector);
}
/**
* @notice function to retrieve the default aggchain verification key.
* @param defaultAggchainSelector The default aggchain selector for the verification key.
* @dev First 2 bytes of the selector are the 'verification key identifier', the last 2 bytes are the aggchain type (ex: FEP, ECDSA)
*/
function getDefaultAggchainVKey(
bytes4 defaultAggchainSelector
) external view returns (bytes32) {
if (defaultAggchainVKeys[defaultAggchainSelector] == bytes32(0)) {
revert AggchainVKeyNotFound();
}
return defaultAggchainVKeys[defaultAggchainSelector];
}
/**
* @notice Function to retrieve the current version of the contract.
* @return version of the contract.
*/
function version() external pure returns (string memory) {
return AGGLAYER_GATEWAY_VERSION;
}
////////////////////////////////////////////////////////////
// Multisig Functions //
////////////////////////////////////////////////////////////
/**
* @notice Updates signers and threshold for multisig operations
* @dev Removes signers first (in descending index order), then adds new signers, then updates threshold
* @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
* @param _signersToAdd Array of new signers to add with their URLs
* @param _newThreshold New threshold value
*/
function updateSignersAndThreshold(
RemoveSignerInfo[] memory _signersToRemove,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) external onlyRole(AL_MULTISIG_ROLE) {
_updateSignersAndThreshold(
_signersToRemove,
_signersToAdd,
_newThreshold
);
}
/**
* @notice Batch update signers and threshold in a single transaction
* @dev Internal function that handles the actual logic
* @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
* @param _signersToAdd Array of new signers to add with their URLs
* @param _newThreshold New threshold value
*/
function _updateSignersAndThreshold(
RemoveSignerInfo[] memory _signersToRemove,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) internal {
// Validate descending order of indices for removal to avoid index shifting issues
// When removing multiple signers, we must process them from highest index to lowest
if (_signersToRemove.length > 1) {
for (uint256 i = 0; i < _signersToRemove.length - 1; i++) {
if (
_signersToRemove[i].index <= _signersToRemove[i + 1].index
) {
revert IndicesNotInDescendingOrder();
}
}
}
// Remove signers (in descending index order to avoid index shifting issues)
for (uint256 i = 0; i < _signersToRemove.length; i++) {
_removeSignerInternal(
_signersToRemove[i].addr,
_signersToRemove[i].index
);
}
// Add new signers
for (uint256 i = 0; i < _signersToAdd.length; i++) {
_addSignerInternal(_signersToAdd[i].addr, _signersToAdd[i].url);
}
if (aggchainSigners.length > MAX_AGGCHAIN_SIGNERS) {
revert AggchainSignersTooHigh();
}
if (
_newThreshold > aggchainSigners.length ||
(aggchainSigners.length != 0 && _newThreshold == 0)
) {
revert InvalidThreshold();
}
threshold = _newThreshold;
// Update the signers hash once after all operations
_updateAggchainMultisigHash();
}
/**
* @notice Internal function to add a signer with validation
* @param _signer Address of the signer to add
* @param url URL associated with the signer
*/
function _addSignerInternal(address _signer, string memory url) internal {
if (_signer == address(0)) {
revert SignerCannotBeZero();
}
if (bytes(url).length == 0) {
revert SignerURLCannotBeEmpty();
}
if (isSigner(_signer)) {
revert SignerAlreadyExists();
}
aggchainSigners.push(_signer);
signerToURLs[_signer] = url;
}
/**
* @notice Internal function to remove a signer with validation
* @param _signer Address of the signer to remove
* @param _signerIndex Index of the signer in the aggchainSigners array
*/
function _removeSignerInternal(
address _signer,
uint256 _signerIndex
) internal {
// Cache array length
uint256 signersLength = aggchainSigners.length;
// Validate input parameters
if (_signerIndex >= signersLength) {
revert SignerDoesNotExist();
}
if (aggchainSigners[_signerIndex] != _signer) {
revert SignerDoesNotExist();
}
// Remove from mapping
delete signerToURLs[_signer];
// Move the last element to the deleted spot and remove the last element
aggchainSigners[_signerIndex] = aggchainSigners[signersLength - 1];
aggchainSigners.pop();
}
/**
* @notice Update the hash of the aggchainSigners array
* @dev Combines threshold and signers array into a single hash for efficient verification
*/
function _updateAggchainMultisigHash() internal {
aggchainMultisigHash = keccak256(
abi.encodePacked(threshold, aggchainSigners)
);
emit SignersAndThresholdUpdated(
aggchainSigners,
threshold,
aggchainMultisigHash
);
}
/**
* @notice Get the threshold for the multisig
* @return threshold for the multisig
*/
function getThreshold() external view returns (uint256) {
return threshold;
}
/**
* @notice Check if an address is a signer
* @param _signer Address to check
* @return True if the address is a signer
*/
function isSigner(address _signer) public view returns (bool) {
return bytes(signerToURLs[_signer]).length > 0;
}
/**
* @notice Get the number of aggchainSigners
* @return Number of aggchainSigners in the multisig
*/
function getAggchainSignersCount() external view returns (uint256) {
return aggchainSigners.length;
}
/**
* @notice Get all aggchainSigners
* @return Array of signer addresses
*/
function getAggchainSigners() external view returns (address[] memory) {
return aggchainSigners;
}
/**
* @notice Returns the aggchain signers hash for verification
* @dev Used by aggchain contracts to include in their hash computation
* @return The current aggchainMultisigHash
*/
function getAggchainMultisigHash() external view returns (bytes32) {
// Sanity check to realize earlier that the aggchainMultisigHash has not been set given
// that the proof cannot be computed since there is no hash reconstruction to be 0
if (aggchainMultisigHash == bytes32(0)) {
revert AggchainSignersHashNotInitialized();
}
return aggchainMultisigHash;
}
/**
* @notice Get all aggchainSigners with their URLs
* @return Array of SignerInfo structs containing signer addresses and URLs
*/
function getAggchainSignerInfos()
external
view
returns (SignerInfo[] memory)
{
SignerInfo[] memory signerInfos = new SignerInfo[](
aggchainSigners.length
);
for (uint256 i = 0; i < aggchainSigners.length; i++) {
signerInfos[i] = SignerInfo({
addr: aggchainSigners[i],
url: signerToURLs[aggchainSigners[i]]
});
}
return signerInfos;
}
}
"
},
"contracts/interfaces/IAggchainSigners.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;
/**
* @title IAggchainSigners
* @notice Interface for multisig signer management functionality
* @dev This interface is implemented by both AggchainBase contracts and AgglayerGateway,
* providing a unified way to manage signers for consensus verification.
* Implementations may use local storage or delegate to a gateway contract.
*/
interface IAggchainSigners {
////////////////////////////////////////////////////////////
// Structs //
////////////////////////////////////////////////////////////
/**
* @notice Struct to hold signer information
* @param addr The address of the signer
* @param url The URL associated with the signer
*/
struct SignerInfo {
address addr;
string url;
}
/**
* @notice Struct to hold information for removing a signer
* @param addr The address of the signer to remove
* @param index The index of the signer in the aggchainSigners array
*/
struct RemoveSignerInfo {
address addr;
uint256 index;
}
/**
* @notice Emitted when signers and threshold are updated in a batch operation.
* @param aggchainSigners The updated array of signer addresses.
* @param newThreshold The new threshold value.
* @param newAggchainMultisigHash The new hash of the aggchainMultisig configuration.
*/
event SignersAndThresholdUpdated(
address[] aggchainSigners,
uint256 newThreshold,
bytes32 newAggchainMultisigHash
);
////////////////////////////////////////////////////////////
// View Functions //
////////////////////////////////////////////////////////////
/**
* @notice Check if an address is a signer
* @param _signer Address to check
* @return True if the address is a signer
*/
function isSigner(address _signer) external view returns (bool);
/**
* @notice Get the minimum number of signatures required for consensus
* @dev Returns the threshold value for multisig validation
* @return threshold Minimum number of signatures required
*/
function getThreshold() external view returns (uint256);
/**
* @notice Get the total number of registered signers
* @dev Returns the count of active signers in the multisig
* @return count Total number of aggchainSigners currently registered
*/
function getAggchainSignersCount() external view returns (uint256);
/**
* @notice Get all registered signer addresses
* @dev Returns the complete list of active signers
* @return signers Array containing all signer addresses
*/
function getAggchainSigners() external view returns (address[] memory);
/**
* @notice Returns the hash of current multisig configuration
* @dev Computed as keccak256(abi.encodePacked(threshold, aggchainSigners)).
* Used by aggchain contracts for efficient consensus verification.
* @return multisigHash The current aggchainMultisigHash for validation
*/
function getAggchainMultisigHash() external view returns (bytes32);
/**
* @notice Get detailed information for all registered signers
* @dev Returns both addresses and associated URLs/endpoints for each signer
* @return signerInfos Array of SignerInfo structs containing complete signer details
*/
function getAggchainSignerInfos()
external
view
returns (SignerInfo[] memory);
}
"
},
"contracts/interfaces/IAgglayerGateway.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import "./IAggchainSigners.sol";
// based on: https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGatewayEvents {
/// @notice Emitted when a verifier route is added.
/// @param selector The verifier selector that was added.
/// @param verifier The address of the verifier contract.
/// @param pessimisticVKey The verification key
event RouteAdded(
bytes4 selector,
address verifier,
bytes32 pessimisticVKey
);
/// @notice Emitted when a verifier route is frozen.
/// @param selector The verifier selector that was frozen.
/// @param verifier The address of the verifier contract.
event RouteFrozen(
bytes4 selector,
address verifier,
bytes32 pessimisticVKey
);
/**
* Emitted when a new default aggchain verification key is added
* @param selector The 4 bytes selector of the added default aggchain verification key.
* @param newVKey New aggchain verification key to be added
*/
event AddDefaultAggchainVKey(bytes4 selector, bytes32 newVKey);
/**
* Emitted when a default aggchain verification key is update
* @param selector The 4 bytes selector of the updated default aggchain verification key.
* @param previousVKey Aggchain verification key previous value
* @param newVKey Aggchain verification key updated value
*/
event UpdateDefaultAggchainVKey(
bytes4 selector,
bytes32 previousVKey,
bytes32 newVKey
);
/**
* Emitted when a default aggchain verification key is set to zero
* @param selector The 4 bytes selector of the updated default aggchain verification key.
*/
event UnsetDefaultAggchainVKey(bytes4 selector);
}
/// @dev Extended error events from https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGatewayErrors {
/// @notice Thrown when the verifier route is not found.
/// @param selector The verifier selector that was specified.
error RouteNotFound(bytes4 selector);
/// @notice Thrown when the verifier route is found, but is frozen.
/// @param selector The verifier selector that was specified.
error RouteIsFrozen(bytes4 selector);
/// @notice Thrown when trying to freeze a route that is already frozen.
/// @param selector The pessimistic verification key selector that was specified.
error RouteIsAlreadyFrozen(bytes4 selector);
/// @notice Thrown when adding a verifier route and the selector already contains a route.
/// @param selector The pessimistic verification key selector that was specified.
/// @param verifier The address of the verifier contract in the existing route.
error RouteAlreadyExists(bytes4 selector, address verifier);
/// @notice Thrown when adding a verifier route and the selector returned by the verifier is
/// zero.
error PPSelectorCannotBeZero();
/// @notice Thrown when adding a verifier key with value zero
error VKeyCannotBeZero();
/// @notice Thrown when the caller is not the AggLayerAdmin
error OnlyAggLayerAdmin();
//// @notice Thrown when the caller is not the pending AggLayerAdmin
error OnlyPendingAggLayerAdmin();
/// @notice Thrown when trying to add an aggchain verification key that already exists
error AggchainVKeyAlreadyExists();
/// @notice Thrown when trying to retrieve an aggchain verification key from the mapping that doesn't exists
error AggchainVKeyNotFound();
/// @notice Thrown when trying to call a function with an input zero address
error InvalidZeroAddress();
/// @notice Thrown when trying to call a function with an invalid initializer version
error InvalidInitializer();
/// @notice Thrown when the input proof bytes are invalid.
error InvalidProofBytesLength();
/// @notice Thrown when the aggchain signers hash has not been initialized
error AggchainSignersHashNotInitialized();
/// @notice Thrown when indices for signer removal are not in descending order
error IndicesNotInDescendingOrder();
/// @notice Thrown when trying to set more than 255 signers
error AggchainSignersTooHigh();
/// @notice Thrown when the threshold exceeds the number of signers
error InvalidThreshold();
/// @notice Thrown when trying to add a zero address as signer
error SignerCannotBeZero();
/// @notice Thrown when trying to add a signer with empty URL
error SignerURLCannotBeEmpty();
/// @notice Thrown when trying to add a signer that already exists
error SignerAlreadyExists();
/// @notice Thrown when trying to remove a signer that doesn't exist
error SignerDoesNotExist();
}
/// @title IAgglayerGateway
/// @notice This contract is the interface for the AgglayerGateway.
/// @notice Based on https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGateway is
IAgglayerGatewayEvents,
IAgglayerGatewayErrors,
IAggchainSigners
{
/**
* Struct that defines a verifier route
* @param verifier The address of the verifier contract.
* @param pessimisticVKey The verification key to be used for verifying pessimistic proofs.
* @param frozen Whether the route is frozen.
*/
struct AggLayerVerifierRoute {
address verifier; // SP1 Verifier. It contains sanity check SP1 version with the 4 first bytes of the proof. proof[4:]
bytes32 pessimisticVKey;
bool frozen;
}
/**
* @notice returns the current aggchain verification key, used to verify chain's FEP.
* @dev This function is necessary to query the map from an external function. In solidity maps are not
* directly accessible from external functions like other state variables.
*/
function getDefaultAggchainVKey(
bytes4 defaultAggchainSelector
) external view returns (bytes32);
/// @notice Verifies a pessimistic proof with given public values and proof.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyPessimisticProof(
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
/// @notice Adds a verifier route. This enable proofs to be routed to this verifier.
/// @dev Only callable by the owner. The owner is responsible for ensuring that the specified
/// verifier is correct with a valid VERIFIER_HASH. Once a route to a verifier is added, it
/// cannot be removed.
/// @param pessimisticVKeySelector The verifier selector to add.
/// @param verifier The address of the verifier contract. This verifier MUST implement the
/// ISP1VerifierWithHash interface.
/// @param pessimisticVKey The verification key to be used for verifying pessimistic proofs.
function addPessimisticVKeyRoute(
bytes4 pessimisticVKeySelector,
address verifier,
bytes32 pessimisticVKey
) external;
/// @notice Freezes a verifier route. This prevents proofs from being routed to this verifier.
/// @dev Only callable by the owner. Once a route to a verifier is frozen, it cannot be
/// unfrozen.
/// @param pessimisticVKeySelector The verifier selector to freeze.
function freezePessimisticVKeyRoute(
bytes4 pessimisticVKeySelector
) external;
////////////////////////////////////////////////////////////
// Multisig Functions //
////////////////////////////////////////////////////////////
/**
* @notice Updates signers and threshold for multisig operations
* @dev Removes signers first (in descending index order), then adds new signers, then updates threshold
* @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
* @param _signersToAdd Array of new signers to add with their URLs
* @param _newThreshold New threshold value
*/
function updateSignersAndThreshold(
RemoveSignerInfo[] memory _signersToRemove,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) external;
}
"
},
"contracts/interfaces/ISP1Verifier.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// imported from: https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1Verifier.sol
/// @title SP1 Verifier Interface
/// @author Succinct Labs
/// @notice This contract is the interface for the SP1 Verifier.
interface ISP1Verifier {
/// @notice Verifies a proof with given public values and vkey.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
}
interface ISP1VerifierWithHash is ISP1Verifier {
/// @notice Returns the hash of the verifier.
function VERIFIER_HASH() external pure returns (bytes32);
}
"
},
"contracts/interfaces/IVersion.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface IVersion {
function version() external pure returns (string memory);
}
"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 999999
},
"evmVersion": "cancun",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-10-03 17:52:53
Comments
Log in to comment.
No comments yet.