forked from ensdomains/evmgateway
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from unruggable-labs/trusted-clones
Redesign TrustedVerifier using Clones
- Loading branch information
Showing
13 changed files
with
379 additions
and
170 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
// works like OpenZeppelin Ownable except | ||
// it uses initialize() instead of constructor() | ||
|
||
import {Ownable, Context} from '@openzeppelin/contracts/access/Ownable.sol'; | ||
|
||
error LazyOwnableAlreadyInitialized(); | ||
|
||
abstract contract LazyOwnable is Context { | ||
address private _owner; | ||
bool private _disowned; | ||
|
||
// constructor() { | ||
// _disowned = true; | ||
// } | ||
|
||
function initialized() public view returns (bool) { | ||
return _disowned || _owner != address(0); | ||
} | ||
|
||
function initialize(address initialOwner) internal virtual { | ||
if (initialized()) { | ||
revert LazyOwnableAlreadyInitialized(); | ||
} | ||
if (initialOwner == address(0)) { | ||
//revert Ownable.OwnableInvalidOwner(address(0)); | ||
// the standard behavior is stupid | ||
// NOTE: this does not emit OwnershipTransferred() | ||
_disowned = true; | ||
} else { | ||
_transferOwnership(initialOwner); | ||
} | ||
} | ||
|
||
/** | ||
* @dev Throws if called by any account other than the owner. | ||
*/ | ||
modifier onlyOwner() { | ||
_checkOwner(); | ||
_; | ||
} | ||
|
||
/** | ||
* @dev Returns the address of the current owner. | ||
*/ | ||
function owner() public view virtual returns (address) { | ||
return _owner; | ||
} | ||
|
||
/** | ||
* @dev Throws if the sender is not the owner. | ||
*/ | ||
function _checkOwner() internal view virtual { | ||
if (_disowned || owner() != _msgSender()) { | ||
revert Ownable.OwnableUnauthorizedAccount(_msgSender()); | ||
} | ||
} | ||
|
||
/** | ||
* @dev Leaves the contract without owner. It will not be possible to call | ||
* `onlyOwner` functions. Can only be called by the current owner. | ||
* | ||
* NOTE: Renouncing ownership will leave the contract without an owner, | ||
* thereby disabling any functionality that is only available to the owner. | ||
*/ | ||
function renounceOwnership() public virtual onlyOwner { | ||
_disowned = true; | ||
_transferOwnership(address(0)); | ||
} | ||
|
||
/** | ||
* @dev Transfers ownership of the contract to a new account (`newOwner`). | ||
* Can only be called by the current owner. | ||
*/ | ||
function transferOwnership(address newOwner) public virtual onlyOwner { | ||
if (newOwner == address(0)) { | ||
revert Ownable.OwnableInvalidOwner(address(0)); | ||
} | ||
_transferOwnership(newOwner); | ||
} | ||
|
||
/** | ||
* @dev Transfers ownership of the contract to a new account (`newOwner`). | ||
* Internal function without access restriction. | ||
*/ | ||
function _transferOwnership(address newOwner) internal virtual { | ||
address oldOwner = _owner; | ||
_owner = newOwner; | ||
emit Ownable.OwnershipTransferred(oldOwner, newOwner); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {IGatewayVerifier} from '../IGatewayVerifier.sol'; | ||
import {IVerifierHooks} from '../IVerifierHooks.sol'; | ||
import {GatewayRequest, GatewayVM, ProofSequence} from '../GatewayVM.sol'; | ||
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; | ||
import {LazyOwnable} from './LazyOwnable.sol'; | ||
|
||
event TrustedVerifierChanged(); | ||
|
||
contract LazyTrustedVerifier is LazyOwnable, IGatewayVerifier { | ||
|
||
IVerifierHooks _hooks; | ||
mapping(address => bool) _signers; | ||
uint256 _expSec; | ||
string[] _urls; | ||
|
||
function init( | ||
address _owner, | ||
IVerifierHooks hooks, | ||
string[] memory urls, | ||
address[] memory signers, | ||
uint256 expSec | ||
) external { | ||
initialize(_owner, hooks, urls, signers, expSec); | ||
} | ||
|
||
function initialize( | ||
address _owner, | ||
IVerifierHooks hooks, | ||
string[] memory urls, | ||
address[] memory signers, | ||
uint256 expSec | ||
) internal { | ||
super.initialize(_owner); | ||
_hooks = hooks; | ||
_urls = urls; | ||
for (uint256 i; i < signers.length; i++) { | ||
_signers[signers[i]] = true; | ||
} | ||
_expSec = expSec; | ||
} | ||
|
||
function getExpSec() external view returns (uint256) { | ||
return _expSec; | ||
} | ||
|
||
function getHooks() external view returns (IVerifierHooks) { | ||
return _hooks; | ||
} | ||
|
||
function isSigner(address signer) external view returns (bool) { | ||
return _signers[signer]; | ||
} | ||
|
||
function setGatewayURLs(string[] memory urls) external onlyOwner { | ||
_urls = urls; | ||
emit TrustedVerifierChanged(); | ||
} | ||
|
||
function setHooks(IVerifierHooks hooks) external onlyOwner { | ||
_hooks = hooks; | ||
emit TrustedVerifierChanged(); | ||
} | ||
|
||
function setExpSec(uint256 expSec) external onlyOwner { | ||
_expSec = expSec; | ||
emit TrustedVerifierChanged(); | ||
} | ||
|
||
function setSigner(address signer, bool allow) external onlyOwner { | ||
_signers[signer] = allow; | ||
emit TrustedVerifierChanged(); | ||
} | ||
|
||
function gatewayURLs() external view returns (string[] memory) { | ||
return _urls; | ||
} | ||
|
||
function getLatestContext() external view returns (bytes memory) { | ||
return abi.encode(block.timestamp); | ||
} | ||
|
||
struct GatewayProof { | ||
bytes signature; | ||
uint64 signedAt; | ||
bytes32 stateRoot; | ||
bytes[] proofs; | ||
bytes order; | ||
} | ||
|
||
function getStorageValues( | ||
bytes memory context, | ||
GatewayRequest memory req, | ||
bytes memory proof | ||
) external view returns (bytes[] memory, uint8 exitCode) { | ||
uint256 t = abi.decode(context, (uint256)); | ||
GatewayProof memory p = abi.decode(proof, (GatewayProof)); | ||
bytes32 hash = keccak256( | ||
// https://github.com/ethereum/eips/issues/191 | ||
abi.encodePacked( | ||
hex'1900', // magic + version(0) | ||
address(0), // unbound | ||
p.signedAt, | ||
p.stateRoot | ||
) | ||
); | ||
address signer = ECDSA.recover(hash, p.signature); | ||
require(_signers[signer], 'Trusted: signer'); | ||
uint256 dt = p.signedAt > t ? p.signedAt - t : t - p.signedAt; | ||
require(dt <= _expSec, 'Trusted: expired'); | ||
return | ||
GatewayVM.evalRequest( | ||
req, | ||
ProofSequence(0, p.stateRoot, p.proofs, p.order, _hooks) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import {LazyTrustedVerifier, IVerifierHooks} from './LazyTrustedVerifier.sol'; | ||
|
||
contract TrustedVerifier is LazyTrustedVerifier { | ||
constructor( | ||
IVerifierHooks hooks, | ||
string[] memory urls, | ||
address[] memory signers, | ||
uint256 expSec | ||
) { | ||
initialize(msg.sender, hooks, urls, signers, expSec); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.23; | ||
|
||
import {LazyTrustedVerifier, IVerifierHooks} from './LazyTrustedVerifier.sol'; | ||
import {Clones} from '@openzeppelin/contracts/proxy/Clones.sol'; | ||
|
||
event NewTrustedVerifier(address verifier); | ||
|
||
contract TrustedVerifierFactory { | ||
LazyTrustedVerifier public immutable impl; | ||
|
||
constructor() { | ||
impl = new LazyTrustedVerifier(); | ||
} | ||
|
||
function create( | ||
address owner, | ||
IVerifierHooks hooks, | ||
string[] calldata urls, | ||
address[] calldata signers, | ||
uint256 expSec | ||
) external returns (LazyTrustedVerifier verifier) { | ||
verifier = impl.initialized() ? LazyTrustedVerifier(Clones.clone(address(impl))) : impl; | ||
verifier.init(owner, hooks, urls, signers, expSec); | ||
emit NewTrustedVerifier(address(verifier)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.