Skip to content

Commit

Permalink
Merge pull request #18 from zenrocklabs/hal
Browse files Browse the repository at this point in the history
Hal
  • Loading branch information
VenimirPetkov authored May 2, 2024
2 parents b079aa4 + 635d93b commit 4492c49
Show file tree
Hide file tree
Showing 38 changed files with 411 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity 0.8.20;
pragma solidity 0.8.19;

import { IAccessControl } from "../interfaces/IAccessControl.sol";
import { Context } from "./Context.sol";
import { ContextUpgradeable } from "./ContextUpgradeable.sol";
import { ERC165 } from "./ERC165.sol";

/**
Expand Down Expand Up @@ -45,7 +45,7 @@ import { ERC165 } from "./ERC165.sol";
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
abstract contract AccessControlUpgradeable is ContextUpgradeable, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
Expand Down
4 changes: 2 additions & 2 deletions contracts/Context.sol → contracts/ContextUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity 0.8.20;
pragma solidity 0.8.19;
import { Initializable } from "./Initializable.sol";

/**
Expand All @@ -14,7 +14,7 @@ import { Initializable } from "./Initializable.sol";
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context is Initializable {
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {}

function __Context_init_unchained() internal onlyInitializing {}
Expand Down
2 changes: 1 addition & 1 deletion contracts/ERC165.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity 0.8.20;
pragma solidity 0.8.19;

import { IERC165 } from "../interfaces/IERC165.sol";
import { Initializable } from "./Initializable.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/Initializable.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity 0.8.20;
pragma solidity 0.8.19;

/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
Expand Down
2 changes: 1 addition & 1 deletion contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity 0.8.19;

contract Migrations {
address public owner = msg.sender;
Expand Down
6 changes: 3 additions & 3 deletions contracts/Pausable.sol → contracts/PausableUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;
pragma solidity 0.8.19;

import { Context } from "./Context.sol";
import { ContextUpgradeable } from "./ContextUpgradeable.sol";

/**
* @dev Contract module which allows children to implement an emergency stop
Expand All @@ -14,7 +14,7 @@ import { Context } from "./Context.sol";
* 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.
*/
abstract contract Pausable is Context {
abstract contract PausableUpgradeable is ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
Expand Down
113 changes: 113 additions & 0 deletions contracts/ReentrancyGuardUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity 0.8.19;
import { Initializable } from "./Initializable.sol";

/**
* @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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* 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].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// 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.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;

/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}

// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

function _getReentrancyGuardStorage()
private
pure
returns (ReentrancyGuardStorage storage $)
{
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}

/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();

function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}

function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._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.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}

function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}

// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}

function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// 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() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}
2 changes: 1 addition & 1 deletion contracts/proxy/ERC1967Proxy.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity 0.8.19;

import { Proxy } from "./Proxy.sol";
import { ERC1967Upgrade } from "./ERC1967Upgrade.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/proxy/ERC1967Upgrade.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity 0.8.20;
pragma solidity 0.8.19;

import { IBeacon } from "../../interfaces/IBeacon.sol";
import { Address } from "../../libraries/Address.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/proxy/Proxy.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)

pragma solidity 0.8.20;
pragma solidity 0.8.19;

/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
Expand Down
2 changes: 1 addition & 1 deletion contracts/proxy/ZrProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// This file is a modification of OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol), released under the MIT license

pragma solidity 0.8.20;
pragma solidity 0.8.19;

import { ERC1967Proxy } from "./ERC1967Proxy.sol";

Expand Down
45 changes: 36 additions & 9 deletions contracts/zr/Sign.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: BUSL
// SPDX-FileCopyrightText: 2024 Zenrock labs Ltd.

pragma solidity 0.8.20;
pragma solidity 0.8.19;

// Importing necessary modules from local and external sources
import { AccessControl } from "../AccessControl.sol"; // Access control functionalities for role management
import { Pausable } from "../Pausable.sol"; // Pausable control functionalities
import { AccessControlUpgradeable } from "../AccessControlUpgradeable.sol"; // Access control functionalities for role management
import { PausableUpgradeable } from "../PausableUpgradeable.sol"; // Pausable control functionalities
import { ECDSA } from "../../libraries/ECDSA.sol"; // Library for Elliptic Curve Digital Signature Algorithm operations
import { MessageHashUtils } from "../../libraries/MessageHashUtils.sol"; // Utility functions for message hashing

Expand All @@ -14,7 +14,7 @@ import { SignTypes } from "../../libraries/zr/SignTypes.sol"; // Definitions of
import { ZrSignTypes } from "../../libraries/zr/ZrSignTypes.sol"; // Definitions of types specific to Zenrock implementations

// Abstract contract for signing functionalities, inheriting from AccessControl for role management
abstract contract Sign is AccessControl, Pausable, ISign {
abstract contract Sign is AccessControlUpgradeable, PausableUpgradeable, ISign {
using ZrSignTypes for ZrSignTypes.ChainInfo; // Attach methods from ZrSignTypes to ChainInfo type
using MessageHashUtils for bytes32; // Attach message hashing utilities to bytes32 type
using ECDSA for bytes32; // Attach ECDSA functions to bytes32 type
Expand All @@ -32,6 +32,9 @@ abstract contract Sign is AccessControl, Pausable, ISign {
uint8 public constant IS_DATA_MASK = 1 << 1; // 0b0010
uint8 public constant IS_TX_MASK = 1 << 2; // 0b0100;

uint8 private constant PUBLIC_KEY_NOT_REGISTERED = 0;
uint8 private constant PUBLIC_KEY_REGISTERED = 1;

// Error declaration
error InsufficientFee(uint256 requiredFee, uint256 providedFee);

Expand All @@ -40,22 +43,27 @@ abstract contract Sign is AccessControl, Pausable, ISign {

error ChainIdNotSupported(bytes32 walletTypeId, bytes32 chainId);
error ChainIdAlreadySupported(bytes32 walletTypeId, bytes32 chainId);

error AlreadyProcessed(uint256 traceId);

error OwnableInvalidOwner(address owner);
error IncorrectWalletIndex(uint256 expectedIndex, uint256 providedIndex);
error PublicKeyAlreadyRegistered(string publicKey);
error InvalidPayloadLength(uint256 expectedLength, uint256 actualLength);
error BroadcastNotAllowed();
error InvalidSignature(ECDSA.RecoverError error);
error UnauthorizedCaller(address caller);
error InvalidPublicKeyLength(uint256 minLength, uint256 actualLength);

/// @custom:storage-location erc7201:zrsign.storage.Sign
struct SignStorage {
uint256 _baseFee;
uint256 _networkFee;
uint256 _traceId;
mapping(bytes32 => ZrSignTypes.ChainInfo) supportedWalletTypes; //keccak256(abi.encode(ChainInfo)) => ChainInfo
mapping(bytes32 => mapping(bytes32 => bool)) supportedChainIds;
mapping(bytes32 => string[]) wallets;
mapping(string => uint8) indexByWallet;
mapping(bytes32 => uint256) processed;
}

// keccak256(abi.encode(uint256(keccak256("zrsign.storage.sign")) - 1)) & ~bytes32(uint256(0xff));
Expand Down Expand Up @@ -118,6 +126,7 @@ abstract contract Sign is AccessControl, Pausable, ISign {
//****************************************************************** INIT FUNCTIONS ******************************************************************/

function __Sign_init() internal onlyInitializing {
__AccessControl_init_unchained();
__Pausable_init_unchained();
__Sign_init_unchained();
}
Expand Down Expand Up @@ -434,7 +443,7 @@ abstract contract Sign is AccessControl, Pausable, ISign {
* @notice This function performs crucial validations such as signature authenticity and public key integrity. It ensures
* that the wallet index is correct, preventing unauthorized key updates.
*/
function _zrKeyRes(SignTypes.ZrKeyResParams memory params) internal virtual {
function _zrKeyRes(SignTypes.ZrKeyResParams memory params) internal virtual whenNotPaused {
SignStorage storage $ = _getSignStorage();

bytes memory payload = abi.encode(
Expand All @@ -459,11 +468,18 @@ abstract contract Sign is AccessControl, Pausable, ISign {
});
}

if ($.indexByWallet[params.publicKey] == PUBLIC_KEY_REGISTERED) {
revert PublicKeyAlreadyRegistered({ publicKey: params.publicKey });
}

$.wallets[id].push(params.publicKey);

$.indexByWallet[params.publicKey] = PUBLIC_KEY_REGISTERED;

emit ZrKeyResolve(
params.walletTypeId,
params.owner,
$.wallets[id].length - 1,
params.walletIndex,
params.publicKey
);
}
Expand Down Expand Up @@ -522,17 +538,28 @@ abstract contract Sign is AccessControl, Pausable, ISign {
* @notice This function validates the authorization signature to ensure it matches the expected payload hash.
* The function emits a `ZrSigResolve` event indicating the resolution of a signature request.
*/
function _sigRes(SignTypes.SignResParams memory params) internal virtual {
function _sigRes(SignTypes.SignResParams memory params) internal virtual whenNotPaused {
SignStorage storage $ = _getSignStorage();

bytes memory payload = abi.encode(
SRC_CHAIN_ID,
params.traceId,
params.signature,
params.broadcast
);

bytes32 payloadHash = keccak256(payload).toEthSignedMessageHash();

if ($.processed[payloadHash] != 0) {
revert AlreadyProcessed({
traceId: $.processed[payloadHash]
});
}

_mustValidateAuthSignature(payloadHash, params.authSignature);

$.processed[payloadHash] = params.traceId;

emit ZrSigResolve(params.traceId, params.signature, params.broadcast);
}

Expand Down Expand Up @@ -561,7 +588,7 @@ abstract contract Sign is AccessControl, Pausable, ISign {
}

if (!hasRole(MPC_ROLE, authAddress)) {
revert UnauthorizedCaller(authAddress);
revert AccessControlUnauthorizedAccount(authAddress, MPC_ROLE);
}
}

Expand Down
Loading

0 comments on commit 4492c49

Please sign in to comment.