Skip to content

Commit

Permalink
fix: symbiotic contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
drewstone committed Oct 29, 2024
1 parent 2d21f6e commit bb7e5b5
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -259,31 +259,4 @@ contract IncredibleSquaringTaskManager is
function getTaskResponseWindowBlock() external view returns (uint32) {
return TASK_RESPONSE_WINDOW_BLOCK;
}

/**
* trySignatureAndApkVerification verifies a BLS aggregate signature and the veracity of a calculated G1 Public key
* @param msgHash is the hash being signed
* @param apk is the claimed G1 public key
* @param apkG2 is provided G2 public key
* @param sigma is the G1 point signature
* @return pairingSuccessful is true if the pairing precompile call was successful
* @return siganatureIsValid is true if the signature is valid
*/
function trySignatureAndApkVerification2(
bytes32 msgHash,
BN254.G1Point memory apk,
BN254.G2Point memory apkG2,
BN254.G1Point memory sigma
) public view returns(bool pairingSuccessful, bool siganatureIsValid) {
// gamma = keccak256(abi.encodePacked(msgHash, apk, apkG2, sigma))
uint256 gamma = uint256(keccak256(abi.encodePacked(msgHash, apk.X, apk.Y, apkG2.X[0], apkG2.X[1], apkG2.Y[0], apkG2.Y[1], sigma.X, sigma.Y))) % BN254.FR_MODULUS;
// verify the signature
(pairingSuccessful, siganatureIsValid) = BN254.safePairing(
sigma.plus(apk.scalar_mul(gamma)),
BN254.negGeneratorG2(),
BN254.hashToG1(msgHash).plus(BN254.generatorG1().scalar_mul(gamma)),
apkG2,
PAIRING_EQUALITY_CHECK_GAS
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13;

interface IIncredibleSquaringTaskManager {
// EVENTS
event NewTaskCreated(uint32 indexed taskIndex, Task task);

event TaskResponded(TaskResponse taskResponse, uint32 indexed taskIndex);

event TaskCompleted(uint32 indexed taskIndex);

// STRUCTS
struct Task {
uint256 numberToBeSquared;
uint32 taskCreatedBlock;
}

// Task response is hashed and signed by operators.
// these signatures are aggregated and sent to the contract as response.
struct TaskResponse {
// Can be obtained by the operator from the event NewTaskCreated.
uint32 referenceTaskIndex;
// This is just the response that the operator has to compute by itself.
uint256 numberSquared;
}

// FUNCTIONS
// NOTE: this function creates new task.
function createNewTask(
uint256 numberToBeSquared
) external;

/// @notice Returns the current 'taskNumber' for the middleware
function taskNumber() external view returns (uint32);

/// @notice Returns the TASK_RESPONSE_WINDOW_BLOCK
function getTaskResponseWindowBlock() external view returns (uint32);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13;

import "incredible-squaring/SimpleMiddleware.sol";
import "incredible-squaring/IIncredibleSquaringTaskManager.sol";

contract IncredibleSquaringTaskManager is
SimpleMiddleware,
IIncredibleSquaringTaskManager
{

/* CONSTANT */
// The number of blocks from the task initialization within which the aggregator has to respond to
uint32 public immutable TASK_RESPONSE_WINDOW_BLOCK;
uint32 public constant TASK_CHALLENGE_WINDOW_BLOCK = 100;
uint256 internal constant _THRESHOLD_DENOMINATOR = 100;

/* STORAGE */
// The latest task index
uint32 public latestTaskNum;

// mapping of task indices to all tasks hashes
// when a task is created, task hash is stored here,
// and responses need to pass the actual task,
// which is hashed onchain and checked against this mapping
mapping(uint32 => bytes32) public allTaskHashes;

// mapping of task indices to hash of abi.encode(taskResponse, taskResponseMetadata)
mapping(uint32 => bytes32) public allTaskResponses;

mapping(uint32 => bool) public taskSuccesfullyChallenged;

address public aggregator;
address public generator;

/* MODIFIERS */

// onlyTaskGenerator is used to restrict createNewTask from only being called by a permissioned entity
// in a real world scenario, this would be removed by instead making createNewTask a payable function
modifier onlyTaskGenerator() {
require(msg.sender == generator, "Task generator must be the caller");
_;
}

constructor(
address _network,
address _operatorRegistry,
address _vaultRegistry,
address _operatorNetOptin,
uint48 _epochDuration,
uint48 _slashingWindow,
uint32 _taskResponseWindowBlock
) SimpleMiddleware(_network, _operatorRegistry, _vaultRegistry, _operatorNetOptin, _epochDuration, _slashingWindow) {
TASK_RESPONSE_WINDOW_BLOCK = _taskResponseWindowBlock;
}

function initialize(
address initialOwner,
address _generator
) public initializer {
_transferOwnership(initialOwner);
generator = _generator;
}

/* FUNCTIONS */
// NOTE: this function creates new task, assigns it a taskId
function createNewTask(
uint256 numberToBeSquared
) external onlyTaskGenerator {
// create a new task struct
Task memory newTask;
newTask.numberToBeSquared = numberToBeSquared;
newTask.taskCreatedBlock = uint32(block.number);

// store hash of task onchain, emit event, and increase taskNum
allTaskHashes[latestTaskNum] = keccak256(abi.encode(newTask));
emit NewTaskCreated(latestTaskNum, newTask);
latestTaskNum = latestTaskNum + 1;
}

// NOTE: this function responds to existing tasks.
function respondToTask(
Task calldata task,
TaskResponse calldata taskResponse
) external onlyOperator {
uint32 taskCreatedBlock = task.taskCreatedBlock;

// check that the task is valid, hasn't been responsed yet, and is being responsed in time
require(
keccak256(abi.encode(task)) ==
allTaskHashes[taskResponse.referenceTaskIndex],
"Task hash does not match"
);
require(
allTaskResponses[taskResponse.referenceTaskIndex] == bytes32(0),
"Task already responded to"
);
require(
uint32(block.number) <=
taskCreatedBlock + TASK_RESPONSE_WINDOW_BLOCK,
"Task responded to too late"
);
require(
taskResponse.numberSquared == task.numberToBeSquared * task.numberToBeSquared,
"Task response invalid, numberSquared is not the square of numberToBeSquared"
);

// updating the storage with task response hash
allTaskResponses[taskResponse.referenceTaskIndex] = keccak256(
abi.encode(taskResponse)
);

// emitting event
emit TaskResponded(taskResponse, taskResponse.referenceTaskIndex);
}

function taskNumber() external view returns (uint32) {
return latestTaskNum;
}

function getTaskResponseWindowBlock() external view returns (uint32) {
return TASK_RESPONSE_WINDOW_BLOCK;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
pragma solidity 0.8.20;

import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";

import {IRegistry} from "@symbiotic/interfaces/common/IRegistry.sol";
Expand All @@ -19,7 +20,7 @@ import {Subnetwork} from "@symbiotic/contracts/libraries/Subnetwork.sol";
import {SimpleKeyRegistry32} from "./SimpleKeyRegistry32.sol";
import {MapWithTimeData} from "./libraries/MapWithTimeData.sol";

contract SimpleMiddleware is SimpleKeyRegistry32, Ownable {
contract SimpleMiddleware is SimpleKeyRegistry32, Initializable, OwnableUpgradeable {
using EnumerableMap for EnumerableMap.AddressToUintMap;
using MapWithTimeData for EnumerableMap.AddressToUintMap;
using Subnetwork for address;
Expand Down Expand Up @@ -54,7 +55,6 @@ contract SimpleMiddleware is SimpleKeyRegistry32, Ownable {
address public immutable OPERATOR_REGISTRY;
address public immutable VAULT_REGISTRY;
address public immutable OPERATOR_NET_OPTIN;
address public immutable OWNER;
uint48 public immutable EPOCH_DURATION;
uint48 public immutable SLASHING_WINDOW;
uint48 public immutable START_TIME;
Expand All @@ -76,28 +76,36 @@ contract SimpleMiddleware is SimpleKeyRegistry32, Ownable {
_;
}

modifier onlyOperator() {
if (!operators.contains(msg.sender)) {
revert NotOperator();
}
_;
}

constructor(
address _network,
address _operatorRegistry,
address _vaultRegistry,
address _operatorNetOptin,
address _owner,
uint48 _epochDuration,
uint48 _slashingWindow
) SimpleKeyRegistry32() Ownable(_owner) {
) SimpleKeyRegistry32() {
if (_slashingWindow < _epochDuration) {
revert SlashingWindowTooShort();
}

START_TIME = Time.timestamp();
EPOCH_DURATION = _epochDuration;
NETWORK = _network;
OWNER = _owner;
OPERATOR_REGISTRY = _operatorRegistry;
VAULT_REGISTRY = _vaultRegistry;
OPERATOR_NET_OPTIN = _operatorNetOptin;
SLASHING_WINDOW = _slashingWindow;
}

function initialize(address initialOwner) public initializer {
_transferOwnership(initialOwner);
subnetworksCnt = 1;
}

Expand Down

0 comments on commit bb7e5b5

Please sign in to comment.