Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add NatSpec Documentation to Ethereum Contracts #3489

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions ethereum/contracts/Getters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,71 @@ pragma solidity ^0.8.0;

import "./State.sol";

/// @title Getters for Wormhole State
/// @notice Provides read-only access to the state variables of Wormhole stored in the State contract.
contract Getters is State {
/// @notice Fetches the guardian set for the given index
/// @param index The index for the guardian set
/// @return guardianSet Returns a guardian set
function getGuardianSet(uint32 index) public view returns (Structs.GuardianSet memory) {
return _state.guardianSets[index];
}

/// @notice Retrieves the index of the current guardian set
/// @return index Returns the guardian set's index
function getCurrentGuardianSetIndex() public view returns (uint32) {
return _state.guardianSetIndex;
}

/// @notice Returns the expiration time for the current guardian set
function getGuardianSetExpiry() public view returns (uint32) {
return _state.guardianSetExpiry;
}

/// @notice Checks whether a governance action has already been consumed
/// @return consumed Returns true if consumed
function governanceActionIsConsumed(bytes32 hash) public view returns (bool) {
return _state.consumedGovernanceActions[hash];
}

/// @notice Determines if the given contract implementation has been initialized
/// @param impl The address of the contract implementation
/// @return initialized Returns true if initialized
function isInitialized(address impl) public view returns (bool) {
return _state.initializedImplementations[impl];
}

/// @notice Returns the chain ID
function chainId() public view returns (uint16) {
return _state.provider.chainId;
}

/// @notice Returns the EVM chain ID
function evmChainId() public view returns (uint256) {
return _state.evmChainId;
}

/// @notice Checks if the current chain is a fork
function isFork() public view returns (bool) {
return evmChainId() != block.chainid;
}

/// @notice Returns the governance chain ID
function governanceChainId() public view returns (uint16){
return _state.provider.governanceChainId;
}

/// @notice Returns the address of the governance contract in bytes32
function governanceContract() public view returns (bytes32){
return _state.provider.governanceContract;
}

/// @notice Gets the current message fee
function messageFee() public view returns (uint256) {
return _state.messageFee;
}

/// @notice Fetches the next sequence number for a given emitter address
function nextSequence(address emitter) public view returns (uint64) {
return _state.sequences[emitter];
}
Expand Down
14 changes: 12 additions & 2 deletions ethereum/contracts/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import "./Setters.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";

/**
* @dev `Governance` defines a means to enacting changes to the core bridge contract,
* guardianSets, message fees, and transfer fees
* @title Wormhole Governance Abstract Contract
* @notice Provides functionality for governance actions such as contract upgrades, fee setting, and guardian set updates to the core bridge contract.
* @dev This abstract contract inherits from GovernanceStructs, Messages, Setters, and the standard ERC1967Upgrade.
*/
abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upgrade {
event ContractUpgraded(address indexed oldContract, address indexed newContract);
Expand All @@ -23,6 +24,7 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Upgrades a contract via Governance VAA/VM
* @param _vm The encoded VAA/VM data
*/
function submitContractUpgrade(bytes memory _vm) public {
require(!isFork(), "invalid fork");
Expand Down Expand Up @@ -50,6 +52,7 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Sets a `messageFee` via Governance VAA/VM
* @param _vm The encoded VAA/VM data
*/
function submitSetMessageFee(bytes memory _vm) public {
Structs.VM memory vm = parseVM(_vm);
Expand All @@ -75,6 +78,7 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Deploys a new `guardianSet` via Governance VAA/VM
* @param _vm The encoded VAA/VM data
*/
function submitNewGuardianSet(bytes memory _vm) public {
Structs.VM memory vm = parseVM(_vm);
Expand Down Expand Up @@ -113,6 +117,7 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Submits transfer fees to the recipient via Governance VAA/VM
* @param _vm The encoded VAA/VM data
*/
function submitTransferFees(bytes memory _vm) public {
Structs.VM memory vm = parseVM(_vm);
Expand Down Expand Up @@ -142,6 +147,7 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Updates the `chainId` and `evmChainId` on a forked chain via Governance VAA/VM
* @param _vm The encoded VAA/VM data
*/
function submitRecoverChainId(bytes memory _vm) public {
require(isFork(), "not a fork");
Expand Down Expand Up @@ -170,6 +176,7 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Upgrades the `currentImplementation` with a `newImplementation`
* @param newImplementation The address of the new contract implementation
*/
function upgradeImplementation(address newImplementation) internal {
address currentImplementation = _getImplementation();
Expand All @@ -186,6 +193,9 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg

/**
* @dev Verifies a Governance VAA/VM is valid
* @param vm The governance VAA/VM to verify
* @return isValid True if the VAA/VM is valid
* @return reason The reason string if the VAA/VM is not valid
*/
function verifyGovernanceVM(Structs.VM memory vm) internal view returns (bool, string memory){
// Verify the VAA is valid
Expand Down
38 changes: 29 additions & 9 deletions ethereum/contracts/GovernanceStructs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ pragma solidity ^0.8.0;
import "./libraries/external/BytesLib.sol";
import "./Structs.sol";

/**
* @dev `GovernanceStructs` defines a set of structs and parsing functions
* for minimal struct validation
*/

/// @title Governance Structures for Wormhole
/// @notice Defines governance structs and parsing functions for minimal struct validation.
contract GovernanceStructs {
using BytesLib for bytes;

/// @dev Enum representing different types of governance actions.
enum GovernanceAction {
UpgradeContract,
UpgradeGuardianset
}

/// @dev Represents a contract upgrade action.
struct ContractUpgrade {
bytes32 module;
uint8 action;
Expand All @@ -26,6 +27,7 @@ contract GovernanceStructs {
address newContract;
}

/// @dev Represents a guardian set upgrade action.
struct GuardianSetUpgrade {
bytes32 module;
uint8 action;
Expand All @@ -35,6 +37,7 @@ contract GovernanceStructs {
uint32 newGuardianSetIndex;
}

/// @dev Represents an action to set a new message fee.
struct SetMessageFee {
bytes32 module;
uint8 action;
Expand All @@ -43,6 +46,7 @@ contract GovernanceStructs {
uint256 messageFee;
}

/// @dev Represents an action to transfer fees to a recipient.
struct TransferFees {
bytes32 module;
uint8 action;
Expand All @@ -52,6 +56,7 @@ contract GovernanceStructs {
bytes32 recipient;
}

/// @dev Represents an action to recover the chain ID.
struct RecoverChainId {
bytes32 module;
uint8 action;
Expand All @@ -60,7 +65,10 @@ contract GovernanceStructs {
uint16 newChainId;
}

/// @dev Parse a contract upgrade (action 1) with minimal validation
/// @notice Parse a ContractUpgrade (action 1) from bytes.
/// @dev Performs minimal validation.
/// @param encodedUpgrade The bytes containing the encoded ContractUpgrade.
/// @return cu The parsed ContractUpgrade struct.
function parseContractUpgrade(bytes memory encodedUpgrade) public pure returns (ContractUpgrade memory cu) {
uint index = 0;

Expand All @@ -81,7 +89,10 @@ contract GovernanceStructs {
require(encodedUpgrade.length == index, "invalid ContractUpgrade");
}

/// @dev Parse a guardianSet upgrade (action 2) with minimal validation
/// @notice Parses a GuardianSetUpgrade (action 2) from bytes.
/// @dev Performs minimal validation.
/// @param encodedUpgrade The bytes containing the encoded GuardianSetUpgrade.
/// @return gsu The parsed GuardianSetUpgrade struct.
function parseGuardianSetUpgrade(bytes memory encodedUpgrade) public pure returns (GuardianSetUpgrade memory gsu) {
uint index = 0;

Expand Down Expand Up @@ -115,7 +126,10 @@ contract GovernanceStructs {
require(encodedUpgrade.length == index, "invalid GuardianSetUpgrade");
}

/// @dev Parse a setMessageFee (action 3) with minimal validation
/// @notice Parses a setMessageFee (action 3) from bytes.
/// @dev Performs minimal validation.
/// @param encodedSetMessageFee The bytes containing the encoded SetMessageFee.
/// @return smf The parsed SetMessageFee struct.
function parseSetMessageFee(bytes memory encodedSetMessageFee) public pure returns (SetMessageFee memory smf) {
uint index = 0;

Expand All @@ -136,7 +150,10 @@ contract GovernanceStructs {
require(encodedSetMessageFee.length == index, "invalid SetMessageFee");
}

/// @dev Parse a transferFees (action 4) with minimal validation
/// @notice Parses a transferFees (action 4) from bytes.
/// @dev Performs minimal validation.
/// @param encodedTransferFees The bytes containing the encoded encodedTransferFees.
/// @return tf The parsed TransferFees struct.
function parseTransferFees(bytes memory encodedTransferFees) public pure returns (TransferFees memory tf) {
uint index = 0;

Expand All @@ -160,7 +177,10 @@ contract GovernanceStructs {
require(encodedTransferFees.length == index, "invalid TransferFees");
}

/// @dev Parse a recoverChainId (action 5) with minimal validation
/// @notice Parses a recoverChainId (action 5) from bytes.
/// @dev Performs minimal validation.
/// @param encodedRecoverChainId The bytes containing the encoded RecoverChainId.
/// @return rci The parsed RecoverChainId struct.
function parseRecoverChainId(bytes memory encodedRecoverChainId) public pure returns (RecoverChainId memory rci) {
uint index = 0;

Expand Down
17 changes: 16 additions & 1 deletion ethereum/contracts/Implementation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ import "./Governance.sol";

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";

/// @title Wormhole Governance Implementation Contract upgrades
/// @notice This contract is an implementation of Wormhole's Governance contract.
contract Implementation is Governance {

/// @notice Emitted when a message is published to the Wormhole network
event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel);

// Publish a message to be attested by the Wormhole network
/// @notice Publish a message to be attested by the Wormhole network
/// @param nonce The nonce to ensure message uniqueness
/// @param payload The content of the emitted message to be published, an arbitrary byte array
/// @param consistencyLevel The level of finality to reach before the guardians will observe and attest the emitted event
/// @return sequence A number that is unique and increments for every message for a given emitter (and implicitly chain)
function publishMessage(
uint32 nonce,
bytes memory payload,
Expand All @@ -25,11 +33,15 @@ contract Implementation is Governance {
emit LogMessagePublished(msg.sender, sequence, nonce, payload, consistencyLevel);
}

/// @dev Update and fetch the current sequence for a given emitter
/// @param emitter The address that emits a message
/// @return sequence The next sequence for a given emitter
function useSequence(address emitter) internal returns (uint64 sequence) {
sequence = nextSequence(emitter);
setNextSequence(emitter, sequence + 1);
}

/// @notice Initializes the contract with the EVM chain ID mapping upon deployment or upgrade
function initialize() initializer public virtual {
// this function needs to be exposed for an upgrade to pass
if (evmChainId() == 0) {
Expand Down Expand Up @@ -61,6 +73,7 @@ contract Implementation is Governance {
}
}

/// @dev Modifier to ensure the contract is only initialized once
modifier initializer() {
address implementation = ERC1967Upgrade._getImplementation();

Expand All @@ -74,7 +87,9 @@ contract Implementation is Governance {
_;
}

/// @dev Fallback function that reverts all calls
fallback() external payable {revert("unsupported");}

/// @dev Receive function that reverts all transactions with assets
receive() external payable {revert("the Wormhole contract does not accept assets");}
}
19 changes: 15 additions & 4 deletions ethereum/contracts/Messages.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,27 @@ import "./libraries/external/BytesLib.sol";
contract Messages is Getters {
using BytesLib for bytes;

/// @dev parseAndVerifyVM serves to parse an encodedVM and wholy validate it for consumption
/// @notice parseAndVerifyVM serves to parse an encodedVM and wholy validate it for consumption
/// @return vm a decoded VM struct
/// @return valid if the VM is valid or not
/// @return reason if the VM is not valid, the reason is contained in this string
function parseAndVerifyVM(bytes calldata encodedVM) public view returns (Structs.VM memory vm, bool valid, string memory reason) {
vm = parseVM(encodedVM);
/// setting checkHash to false as we can trust the hash field in this case given that parseVM computes and then sets the hash field above
(valid, reason) = verifyVMInternal(vm, false);
}

/**
* @dev `verifyVM` serves to validate an arbitrary vm against a valid Guardian set
* @notice `verifyVM` serves to validate an arbitrary vm against a valid Guardian set
* - it aims to make sure the VM is for a known guardianSet
* - it aims to ensure the guardianSet is not expired
* - it aims to ensure the VM has reached quorum
* - it aims to verify the signatures provided against the guardianSet
* - it aims to verify the hash field provided against the contents of the vm
* @return valid if the VM is valid or not
* @return reason if the VM is not valid, the reason is contained in this string
*/

function verifyVM(Structs.VM memory vm) public view returns (bool valid, string memory reason) {
(valid, reason) = verifyVMInternal(vm, true);
}
Expand Down Expand Up @@ -105,9 +111,12 @@ contract Messages is Getters {
/**
* @dev verifySignatures serves to validate arbitrary sigatures against an arbitrary guardianSet
* - it intentionally does not solve for expectations within guardianSet (you should use verifyVM if you need these protections)
* - it intentioanlly does not solve for quorum (you should use verifyVM if you need these protections)
* - it intentionally does not solve for quorum (you should use verifyVM if you need these protections)
* - it intentionally returns true when signatures is an empty set (you should use verifyVM if you need these protections)
* @return valid if the signatures are valid or not
* @return reason if the signatures are not valid, the reason is contained in this string
*/
///
function verifySignatures(bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet) public pure returns (bool valid, string memory reason) {
uint8 lastIndex = 0;
uint256 guardianCount = guardianSet.keys.length;
Expand Down Expand Up @@ -143,6 +152,7 @@ contract Messages is Getters {
/**
* @dev parseVM serves to parse an encodedVM into a vm struct
* - it intentionally performs no validation functions, it simply parses raw into a struct
* @return vm a decoded VM struct
*/
function parseVM(bytes memory encodedVM) public pure virtual returns (Structs.VM memory vm) {
uint index = 0;
Expand Down Expand Up @@ -208,7 +218,8 @@ contract Messages is Getters {
}

/**
* @dev quorum serves solely to determine the number of signatures required to acheive quorum
* @dev quorum serves solely to determine the number of signatures required to achieve quorum
* @return numSignaturesRequiredForQuorum The number of signatures required to achieve quorum
*/
function quorum(uint numGuardians) public pure virtual returns (uint numSignaturesRequiredForQuorum) {
// The max number of guardians is 255
Expand Down
7 changes: 7 additions & 0 deletions ethereum/contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

/// @title Migrations Contract
/// @notice This contract is designed to facilitate and record migrations of contract states during upgrades.
contract Migrations {
/// @notice The owner of the contract, set upon deployment to the address deploying the contract.
address public owner = msg.sender;
uint public last_completed_migration;

/// @dev Restricts function calls to only the owner of the contract.
modifier restricted() {
require(
msg.sender == owner,
Expand All @@ -13,6 +17,9 @@ contract Migrations {
_;
}

/// @notice Sets a given migration as complete.
/// @dev Callable only by the current owner due to the `restricted` modifier.
/// @param completed The identifier of the migration that has been completed.
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
Expand Down
Loading
Loading