-
Notifications
You must be signed in to change notification settings - Fork 71
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
feat: network contracts #382
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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,59 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.25; | ||
|
||
import {NetworkStorage} from "./NetworkStorage.sol"; | ||
import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; | ||
import {OwnableUpgradeable} from "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol"; | ||
|
||
interface INetworkAdminEvents { | ||
event FeeVaultSet(address oldFeeVault, address newFeeVault); | ||
event DefaultProverUpdated(address indexed prover, bool added); | ||
} | ||
|
||
interface INetworkAdminErrors { | ||
error RecoverFailed(); | ||
} | ||
|
||
interface INetworkAdmin is INetworkAdminEvents, INetworkAdminErrors { | ||
function addDefaultProver(address prover) external; | ||
function removeDefaultProver(address prover) external; | ||
function setFeeVault(address feeVault) external; | ||
function recover(address to, uint256 amount) external; | ||
} | ||
|
||
abstract contract NetworkAdmin is | ||
INetworkAdmin, | ||
NetworkStorage, | ||
Initializable, | ||
OwnableUpgradeable | ||
{ | ||
function __NetworkAdmin_init(address _owner, address _feeVault, address _defaultProver) | ||
internal | ||
{ | ||
_transferOwnership(_owner); | ||
feeVault = _feeVault; | ||
allowedProvers[address(0)][_defaultProver] = true; | ||
} | ||
|
||
function addDefaultProver(address _prover) external onlyOwner { | ||
allowedProvers[address(0)][_prover] = true; | ||
emit DefaultProverUpdated(_prover, true); | ||
} | ||
|
||
function removeDefaultProver(address _prover) external onlyOwner { | ||
delete allowedProvers[address(0)][_prover]; | ||
emit DefaultProverUpdated(_prover, false); | ||
} | ||
|
||
function setFeeVault(address _feeVault) external onlyOwner { | ||
emit FeeVaultSet(feeVault, _feeVault); | ||
feeVault = _feeVault; | ||
} | ||
|
||
function recover(address _to, uint256 _amount) external onlyOwner { | ||
(bool success,) = _to.call{value: _amount}(""); | ||
if (!success) { | ||
revert RecoverFailed(); | ||
} | ||
} | ||
} |
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,326 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.25; | ||
|
||
import {IFeeVault} from "./payments/interfaces/IFeeVault.sol"; | ||
import {INetworkVerifier} from "./interfaces/INetworkVerifier.sol"; | ||
import {NetworkStorage} from "./NetworkStorage.sol"; | ||
import {NetworkAdmin} from "./NetworkAdmin.sol"; | ||
import {NetworkRegistry} from "./NetworkRegistry.sol"; | ||
|
||
interface INetworkGatewayEvents { | ||
event RequestCallback( | ||
uint32 indexed nonce, | ||
address indexed verifier, | ||
bytes32 programHash, | ||
bytes input, | ||
bytes context, | ||
address callback, | ||
bytes4 callbackSelector, | ||
uint32 callbackGasLimit, | ||
uint256 value | ||
); | ||
event RequestCall( | ||
address indexed verifier, | ||
bytes32 programHash, | ||
bytes input, | ||
address callback, | ||
bytes callbackCalldata, | ||
uint32 callbackGasLimit, | ||
address caller, | ||
uint256 value | ||
); | ||
event FulfilledCallback( | ||
uint32 indexed nonce, | ||
address indexed verifier, | ||
bytes32 programHash, | ||
address callback, | ||
address prover, | ||
bytes32 inputHash, | ||
bytes32 outputHash | ||
); | ||
event FullfilledCall( | ||
address indexed verifier, | ||
bytes32 programHash, | ||
address callback, | ||
address prover, | ||
bytes32 inputHash, | ||
bytes32 outputHash | ||
); | ||
} | ||
|
||
interface INetworkGatewayErrors { | ||
error ReentrantFulfill(); | ||
error InvalidRequest(uint32 nonce, bytes32 expected, bytes32 actual); | ||
error InvalidProof(); | ||
error CallbackFailed(bytes4 callbackSelector, bytes output, bytes context); | ||
error CallFailed(address callback, bytes callbackData); | ||
error InvalidCall(address verifier, bytes input); | ||
} | ||
|
||
interface INetworkGateway is INetworkGatewayEvents, INetworkGatewayErrors { | ||
function requestCallback( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: these interfaces wont be backwards compatible with olds ones since verifer/programHash is used instead of functionID |
||
address verifier, | ||
bytes32 programHash, | ||
bytes calldata input, | ||
bytes calldata context, | ||
bytes4 callbackSelector, | ||
uint32 callbackGasLimit | ||
) external payable returns (bytes32); | ||
|
||
function requestCall( | ||
address verifier, | ||
bytes32 programHash, | ||
bytes calldata input, | ||
address callback, | ||
bytes calldata callbackCalldata, | ||
uint32 callbackGasLimit | ||
) external payable; | ||
|
||
function isCallback() external view returns (bool); | ||
|
||
function verifiedCall(address verifier, bytes calldata input) | ||
external | ||
view | ||
returns (bytes memory); | ||
|
||
function fulfillCallback( | ||
uint32 nonce, | ||
address verifier, | ||
bytes32 programHash, | ||
bytes32 inputHash, | ||
address callback, | ||
bytes4 callbackSelector, | ||
uint32 callbackGasLimit, | ||
bytes calldata context, | ||
bytes calldata output, | ||
bytes calldata proof | ||
) external; | ||
|
||
function fulfillCall( | ||
address verifier, | ||
bytes calldata input, | ||
bytes calldata output, | ||
bytes calldata proof, | ||
address callback, | ||
bytes calldata callbackData | ||
) external; | ||
} | ||
|
||
contract NetworkGateway is INetworkGateway, NetworkStorage, NetworkAdmin, NetworkRegistry { | ||
modifier nonReentrant() { | ||
if ( | ||
executingCallback || verifiedVerifier != address(0) || verifiedInputHash != bytes32(0) | ||
|| verifiedOutput.length != 0 | ||
) { | ||
revert ReentrantFulfill(); | ||
} | ||
_; | ||
} | ||
|
||
function initialize(address _owner, address _feeVault, address _defaultProver) | ||
external | ||
initializer | ||
{ | ||
_transferOwnership(_owner); | ||
feeVault = _feeVault; | ||
allowedProvers[address(0)][_defaultProver] = true; | ||
} | ||
|
||
function requestCallback( | ||
address _verifier, | ||
bytes32 _programHash, | ||
bytes calldata _input, | ||
bytes calldata _context, | ||
bytes4 _callbackSelector, | ||
uint32 _callbackGasLimit | ||
) external payable override returns (bytes32) { | ||
bytes32 inputHash = sha256(_input); | ||
bytes32 contextHash = keccak256(_context); | ||
address callback = msg.sender; | ||
bytes32 requestHash = _requestHash( | ||
nonce, | ||
_verifier, | ||
_programHash, | ||
inputHash, | ||
contextHash, | ||
callback, | ||
_callbackSelector, | ||
_callbackGasLimit | ||
); | ||
|
||
requests[nonce] = requestHash; | ||
emit RequestCallback( | ||
nonce, | ||
_verifier, | ||
_programHash, | ||
_input, | ||
_context, | ||
callback, | ||
_callbackSelector, | ||
_callbackGasLimit, | ||
msg.value | ||
); | ||
|
||
nonce++; | ||
|
||
if (msg.value > 0 && feeVault != address(0)) { | ||
IFeeVault(feeVault).depositNative{value: msg.value}(callback); | ||
} | ||
|
||
return requestHash; | ||
} | ||
|
||
function requestCall( | ||
address _verifier, | ||
bytes32 _programHash, | ||
bytes calldata _input, | ||
address _callback, | ||
bytes calldata _callbackCalldata, | ||
uint32 _callbackGasLimit | ||
) external payable override { | ||
emit RequestCall( | ||
_verifier, | ||
_programHash, | ||
_input, | ||
_callback, | ||
_callbackCalldata, | ||
_callbackGasLimit, | ||
msg.sender, | ||
msg.value | ||
); | ||
|
||
if (msg.value > 0 && feeVault != address(0)) { | ||
IFeeVault(feeVault).depositNative{value: msg.value}(msg.sender); | ||
} | ||
} | ||
|
||
function isCallback() external view override returns (bool) { | ||
return executingCallback; | ||
} | ||
|
||
function verifiedCall(address _verifier, bytes calldata _input) | ||
external | ||
view | ||
override | ||
returns (bytes memory) | ||
{ | ||
bytes32 inputHash = sha256(_input); | ||
if (verifiedVerifier == _verifier && verifiedInputHash == inputHash) { | ||
return verifiedOutput; | ||
} else { | ||
revert InvalidCall(_verifier, _input); | ||
} | ||
} | ||
|
||
function fulfillCallback( | ||
uint32 _nonce, | ||
address _verifier, | ||
bytes32 _programHash, | ||
bytes32 _inputHash, | ||
address _callback, | ||
bytes4 _callbackSelector, | ||
uint32 _callbackGasLimit, | ||
bytes calldata _context, | ||
bytes calldata _output, | ||
bytes calldata _proof | ||
) external nonReentrant onlyProver(_verifier) { | ||
bytes32 contextHash = keccak256(_context); | ||
bytes32 requestHash = _requestHash( | ||
_nonce, | ||
_verifier, | ||
_programHash, | ||
_inputHash, | ||
contextHash, | ||
_callback, | ||
_callbackSelector, | ||
_callbackGasLimit | ||
); | ||
|
||
if (requests[_nonce] != requestHash) { | ||
revert InvalidRequest(_nonce, requests[_nonce], requestHash); | ||
} | ||
delete requests[_nonce]; | ||
|
||
bytes32 outputHash = sha256(_output); | ||
|
||
_verify(_verifier, _programHash, _inputHash, outputHash, _proof); | ||
|
||
executingCallback = true; | ||
(bool status,) = _callback.call{gas: _callbackGasLimit}( | ||
abi.encodeWithSelector(_callbackSelector, _output, _context) | ||
); | ||
delete executingCallback; | ||
|
||
if (!status) { | ||
revert CallbackFailed(_callbackSelector, _output, _context); | ||
} | ||
|
||
emit FulfilledCallback( | ||
_nonce, _verifier, _programHash, _callback, msg.sender, _inputHash, outputHash | ||
); | ||
} | ||
|
||
function fulfillCall( | ||
address _verifier, | ||
bytes32 _programHash, | ||
bytes calldata _input, | ||
bytes calldata _output, | ||
bytes calldata _proof, | ||
address _callback, | ||
bytes calldata _callbackData | ||
) external nonReentrant onlyProver(_verifier) { | ||
bytes32 inputHash = sha256(_input); | ||
bytes32 outputHash = sha256(_output); | ||
|
||
_verify(_verifier, _programHash, inputHash, outputHash, _proof); | ||
|
||
verifiedVerifier = _verifier; | ||
verifiedInputHash = inputHash; | ||
verifiedOutput = _output; | ||
(bool status,) = _callback.call(_callbackData); | ||
if (!status) { | ||
revert CallFailed(_callback, _callbackData); | ||
} | ||
delete verifiedVerifier; | ||
delete verifiedInputHash; | ||
delete verifiedOutput; | ||
|
||
emit FullfilledCall(_verifier, _programHash, _callback, msg.sender, inputHash, outputHash); | ||
} | ||
|
||
function _requestHash( | ||
uint32 _nonce, | ||
address _verifier, | ||
bytes32 _programHash, | ||
bytes32 _inputHash, | ||
bytes32 _contextHash, | ||
address _callback, | ||
bytes4 _callbackSelector, | ||
uint32 _callbackGasLimit | ||
) internal pure returns (bytes32) { | ||
return keccak256( | ||
abi.encodePacked( | ||
_nonce, | ||
_verifier, | ||
_programHash, | ||
_inputHash, | ||
_contextHash, | ||
_callback, | ||
_callbackSelector, | ||
_callbackGasLimit | ||
) | ||
); | ||
} | ||
|
||
function _verify( | ||
address _verifier, | ||
bytes32 _programHash, | ||
bytes32 _inputHash, | ||
bytes32 _outputHash, | ||
bytes calldata _proof | ||
) internal { | ||
if (!INetworkVerifier(_verifier).verify(_programHash, _inputHash, _outputHash, _proof)) { | ||
revert InvalidProof(); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cancun is live on all the chains we deploy on except scroll, and they have an ETA of early April