Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/GovernanceAdmin.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
pragma solidity ^0.8.30;
import {GovernanceConstants, IGovernance} from "./interfaces/IGovernance.sol";
import {IMessageHandler} from "./interfaces/IMessageHandler.sol";
import {IPausable} from "./interfaces/IPausable.sol";
import {IUUPSUpgradeable} from "./interfaces/IUUPSUpgradeable.sol";
/**
* @dev GovernanceAdmin smart contract is responsible for processing messages
* originated from Vara Network. It is used to change governance address,
* upgrade proxies and pause/unpause them.
*/
contract GovernanceAdmin is IMessageHandler, IGovernance {
/**
* @dev `uint8 discriminant` bit shift.
*/
uint256 internal constant DISCRIMINANT_BIT_SHIFT = 248;
/**
* @dev `address proxy` bit shift.
*/
uint256 internal constant PROXY_ADDRESS_BIT_SHIFT = 96;
/**
* @dev `address newImplementation` bit shift.
*/
uint256 internal constant NEW_IMPLEMENTATION_BIT_SHIFT = 96;
/**
* @dev `DISCRIMINANT_SIZE` offset.
*/
uint256 internal constant OFFSET1 = 1;
/**
* @dev `DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE` offset.
*/
uint256 internal constant OFFSET2 = 21;
bytes32 public governance;
address public wrappedVara;
address public messageQueue;
address public erc20Manager;
/**
* @dev Initializes the GovernanceAdmin contract.
* @param _governance The governance address (Vara Network address).
* @param _messageQueue The message queue address.
* @param _erc20Manager The ERC20Manager address.
*/
constructor(bytes32 _governance, address _wrappedVara, address _messageQueue, address _erc20Manager) {
governance = _governance;
wrappedVara = _wrappedVara;
messageQueue = _messageQueue;
erc20Manager = _erc20Manager;
}
/**
* @dev Handles message originated from Vara Network.
* @param source Source of the message (`ActorId` from Vara Network).
* @param payload Payload of the message (message from Vara Network).
*/
function handleMessage(bytes32 source, bytes calldata payload) external {
if (msg.sender != messageQueue) {
revert InvalidSender();
}
if (source != governance) {
revert InvalidSource();
}
if (!_tryParseAndApplyMessage(payload)) {
revert InvalidPayload();
}
}
/**
* @dev Tries to parse and apply message originated from Vara Network.
*
* Payload format:
* ```solidity
* uint8 discriminant;
* ```
*
* `discriminant` can be:
* - `GovernanceConstants.CHANGE_GOVERNANCE = 0x00` - change governance address to `newGovernance`
* ```solidity
* bytes32 newGovernance;
* ```
*
* - `GovernanceConstants.PAUSE_PROXY = 0x01` - pause `proxy`
* ```solidity
* address proxy;
* ```
*
* - `GovernanceConstants.UNPAUSE_PROXY = 0x02` - unpause `proxy`
* ```solidity
* address proxy;
* ```
*
* - `GovernanceConstants.UPGRADE_PROXY = 0x03` - upgrade `proxy` to `newImplementation` and call `data` on it
* ```solidity
* address proxy;
* address newImplementation;
* bytes data;
* ```
*
* @param payload Payload of the message (message from Vara Network).
* @return success `true` if the message is parsed and applied, `false` otherwise.
*/
function _tryParseAndApplyMessage(bytes calldata payload) private returns (bool) {
if (!(payload.length > 0)) {
return false;
}
uint256 discriminant;
assembly ("memory-safe") {
// `DISCRIMINANT_BIT_SHIFT` right bit shift is required to remove extra bits since `calldataload` returns `uint256`
discriminant := shr(DISCRIMINANT_BIT_SHIFT, calldataload(payload.offset))
}
if (!(discriminant >= GovernanceConstants.CHANGE_GOVERNANCE
&& discriminant <= GovernanceConstants.UPGRADE_PROXY)) {
return false;
}
if (discriminant == GovernanceConstants.CHANGE_GOVERNANCE) {
if (!(payload.length == GovernanceConstants.CHANGE_GOVERNANCE_SIZE)) {
return false;
}
// we use offset `OFFSET1 = DISCRIMINANT_SIZE` to skip `uint8 discriminant`
bytes32 newGovernance;
assembly ("memory-safe") {
newGovernance := calldataload(add(payload.offset, OFFSET1))
}
bytes32 previousGovernance = governance;
governance = newGovernance;
emit GovernanceChanged(previousGovernance, newGovernance);
return true;
}
if (!(payload.length > GovernanceConstants.PROXY_ADDRESS_SIZE)) {
return false;
}
// we use offset `OFFSET1 = DISCRIMINANT_SIZE` to skip `uint8 discriminant`
address proxy;
assembly ("memory-safe") {
// `PROXY_ADDRESS_BIT_SHIFT` right bit shift is required to remove extra bits since `calldataload` returns `uint256`
proxy := shr(PROXY_ADDRESS_BIT_SHIFT, calldataload(add(payload.offset, OFFSET1)))
}
if (!(proxy == wrappedVara || proxy == messageQueue || proxy == erc20Manager)) {
return false;
}
if (discriminant >= GovernanceConstants.PAUSE_PROXY && discriminant <= GovernanceConstants.UNPAUSE_PROXY) {
if (!(payload.length == GovernanceConstants.PAUSE_UNPAUSE_PROXY_SIZE)) {
return false;
}
if (discriminant == GovernanceConstants.PAUSE_PROXY) {
IPausable(proxy).pause();
} else if (discriminant == GovernanceConstants.UNPAUSE_PROXY) {
IPausable(proxy).unpause();
}
return true;
}
// `discriminant == GovernanceConstants.UPGRADE_PROXY` is guaranteed by previous checks
if (!(payload.length >= GovernanceConstants.UPGRADE_PROXY_SIZE)) {
return false;
}
// we use offset `OFFSET2 = DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE` to skip `uint8 discriminant` and `address proxy`
address newImplementation;
assembly ("memory-safe") {
// `NEW_IMPLEMENTATION_BIT_SHIFT` right bit shift is required to remove extra bits since `calldataload` returns `uint256`
newImplementation := shr(NEW_IMPLEMENTATION_BIT_SHIFT, calldataload(add(payload.offset, OFFSET2)))
}
// we use offset `OFFSET3 = DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE + NEW_IMPLEMENTATION_SIZE`
// to skip `uint8 discriminant`, `address proxy` and `address newImplementation`
// and get `bytes data`
bytes calldata data = payload[GovernanceConstants.OFFSET3:];
IUUPSUpgradeable(proxy).upgradeToAndCall(newImplementation, data);
return true;
}
}
"
},
"src/interfaces/IGovernance.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
pragma solidity ^0.8.30;
import {IMessageHandler} from "./IMessageHandler.sol";
/**
* @dev Governance constants.
*/
library GovernanceConstants {
/**
* @dev Change governance message discriminant.
*/
uint256 internal constant CHANGE_GOVERNANCE = 0x00;
/**
* @dev Pause proxy message discriminant.
*/
uint256 internal constant PAUSE_PROXY = 0x01;
/**
* @dev Unpause proxy message discriminant.
*/
uint256 internal constant UNPAUSE_PROXY = 0x02;
/**
* @dev Upgrade proxy message discriminant.
*/
uint256 internal constant UPGRADE_PROXY = 0x03;
/**
* @dev `uint8 discriminant` size.
*/
uint256 internal constant DISCRIMINANT_SIZE = 1;
/**
* @dev `bytes32 newGovernance` size.
*/
uint256 internal constant NEW_GOVERNANCE_SIZE = 32;
/**
* @dev `address proxy` size.
*/
uint256 internal constant PROXY_ADDRESS_SIZE = 20;
/**
* @dev `address newImplementation` size.
*/
uint256 internal constant NEW_IMPLEMENTATION_SIZE = 20;
/**
* @dev `DISCRIMINANT_SIZE` offset.
*/
uint256 internal constant OFFSET1 = 1;
/**
* @dev `DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE` offset.
*/
uint256 internal constant OFFSET2 = 21;
/**
* @dev `DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE + NEW_IMPLEMENTATION_SIZE` offset.
*/
uint256 internal constant OFFSET3 = 41;
/**
* @dev `DISCRIMINANT_SIZE + NEW_GOVERNANCE_SIZE` size.
*/
uint256 internal constant CHANGE_GOVERNANCE_SIZE = 33;
/**
* @dev `DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE` size.
*/
uint256 internal constant PAUSE_UNPAUSE_PROXY_SIZE = 21;
/**
* @dev `DISCRIMINANT_SIZE + PROXY_ADDRESS_SIZE + NEW_IMPLEMENTATION_SIZE` size.
*/
uint256 internal constant UPGRADE_PROXY_SIZE = 41;
}
/**
* @dev Interface for the Governance contract.
*/
interface IGovernance is IMessageHandler {
/**
* @dev Error thrown when the sender is not the message queue.
*/
error InvalidSender();
/**
* @dev Error thrown when the source is not the governance.
*/
error InvalidSource();
/**
* @dev Error thrown when the payload is invalid.
*/
error InvalidPayload();
/**
* @dev Emitted when the governance address is changed.
* @param previousGovernance The previous governance address.
* @param newGovernance The new governance address.
*/
event GovernanceChanged(bytes32 indexed previousGovernance, bytes32 indexed newGovernance);
/**
* @dev Returns the governance address.
* @return governance The governance address.
*/
function governance() external view returns (bytes32);
/**
* @dev Returns the WrappedVara address.
* @return wrappedVara The WrappedVara address.
*/
function wrappedVara() external view returns (address);
/**
* @dev Returns the MessageQueue address.
* @return messageQueue The MessageQueue address.
*/
function messageQueue() external view returns (address);
/**
* @dev Returns the ERC20Manager address.
* @return erc20Manager The ERC20Manager address.
*/
function erc20Manager() external view returns (address);
}
/**
* @dev Type representing payload of the message that changes governance address.
*/
struct ChangeGovernanceMessage {
bytes32 newGovernance;
}
/**
* @dev Type representing payload of the message that pauses proxy.
*/
struct PauseProxyMessage {
address proxy;
}
/**
* @dev Type representing payload of the message that unpauses proxy.
*/
struct UnpauseProxyMessage {
address proxy;
}
/**
* @dev Type representing payload of the message that upgrades proxy.
*/
struct UpgradeProxyMessage {
address proxy;
address newImplementation;
bytes data;
}
/**
* @dev Library for packing `Governance` messages into a binary format.
*/
library GovernancePacker {
/**
* @dev Packs `ChangeGovernanceMessage` into a binary format.
* @param message Message to pack.
* @return packed Packed message.
*/
function pack(ChangeGovernanceMessage memory message) internal pure returns (bytes memory) {
return abi.encodePacked(uint8(GovernanceConstants.CHANGE_GOVERNANCE), message.newGovernance);
}
/**
* @dev Packs `PauseProxyMessage` into a binary format.
* @param message Message to pack.
* @return packed Packed message.
*/
function pack(PauseProxyMessage memory message) internal pure returns (bytes memory) {
return abi.encodePacked(uint8(GovernanceConstants.PAUSE_PROXY), message.proxy);
}
/**
* @dev Packs `UnpauseProxyMessage` into a binary format.
* @param message Message to pack.
* @return packed Packed message.
*/
function pack(UnpauseProxyMessage memory message) internal pure returns (bytes memory) {
return abi.encodePacked(uint8(GovernanceConstants.UNPAUSE_PROXY), message.proxy);
}
/**
* @dev Packs `UpgradeProxyMessage` into a binary format.
* @param message Message to pack.
* @return packed Packed message.
*/
function pack(UpgradeProxyMessage memory message) internal pure returns (bytes memory) {
return abi.encodePacked(
uint8(GovernanceConstants.UPGRADE_PROXY), message.proxy, message.newImplementation, message.data
);
}
}
"
},
"src/interfaces/IMessageHandler.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
pragma solidity ^0.8.30;
/**
* @dev Interface for the message handler (messages from MessageQueue).
*/
interface IMessageHandler {
/**
* @dev Handles message originated from Vara Network.
* @param source Source of the message (`ActorId` from Vara Network).
* @param payload Payload of the message (message from Vara Network).
*/
function handleMessage(bytes32 source, bytes calldata payload) external;
}
"
},
"src/interfaces/IPausable.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
pragma solidity ^0.8.30;
/**
* @dev Interface for the pausable contracts.
*/
interface IPausable {
/**
* @dev Pauses the contract.
*/
function pause() external;
/**
* @dev Unpauses the contract.
*/
function unpause() external;
}
"
},
"src/interfaces/IUUPSUpgradeable.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
pragma solidity ^0.8.30;
/**
* @dev Interface for the UUPSUpgradeable contract.
*/
interface IUUPSUpgradeable {
/**
* @dev Upgrades the implementation of the contract.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable;
}
"
}
},
"settings": {
"remappings": [
"src/=src/",
"test/=test/",
"script/=script/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true,
"debug": {
"revertStrings": "strip"
}
}
}}
Submitted on: 2025-10-23 20:40:38
Comments
Log in to comment.
No comments yet.