Skip to content

Commit

Permalink
Merge pull request #152 from CirclesUBI/20240509-operators
Browse files Browse the repository at this point in the history
20240509 operators
  • Loading branch information
jaensen authored May 15, 2024
2 parents 6819670 + 0d5ee61 commit 10cb6b1
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 55 deletions.
28 changes: 2 additions & 26 deletions src/hub/Hub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "../lift/IERC20Lift.sol";
import "../migration/IHub.sol";
import "../migration/IToken.sol";
import "../names/INameRegistry.sol";
import "./MetadataDefinitions.sol";
import "./TypeDefinitions.sol";

/**
* @title Hub v2 contract for Circles
Expand All @@ -21,31 +21,7 @@ import "./MetadataDefinitions.sol";
* It further allows to wrap any token into an inflationary or demurraged
* ERC20 Circles contract.
*/
contract Hub is Circles, MetadataDefinitions, IHubErrors {
// Type declarations

/**
* @notice TrustMarker stores the expiry of a trust relation as uint96,
* and is iterable as a linked list of trust markers.
* @dev This is used to store the directional trust relation between two avatars,
* and the expiry of the trust relation as uint96 in unix time.
*/
struct TrustMarker {
address previous;
uint96 expiry;
}

struct FlowEdge {
uint16 streamSinkId;
uint240 amount; // todo: set this to uint192 (align with demurrage), and leave it to compiler to pad
}

struct Stream {
uint16 sourceCoordinate;
uint16[] flowEdgeIds; // todo: this can possible be packed more compactly manually, evaluate
bytes data;
}

contract Hub is Circles, TypeDefinitions, IHubErrors {
// Constants

/**
Expand Down
8 changes: 8 additions & 0 deletions src/hub/IHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity >=0.8.24;

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "../circles/ICircles.sol";
import "./TypeDefinitions.sol";

interface IHubV2 is IERC1155, ICircles {
function avatars(address avatar) external view returns (address);
Expand All @@ -13,4 +14,11 @@ interface IHubV2 is IERC1155, ICircles {
function migrate(address owner, address[] calldata avatars, uint256[] calldata amounts) external;
function mintPolicies(address avatar) external view returns (address);
function burn(uint256 id, uint256 amount, bytes calldata data) external;

function operateFlowMatrix(
address[] calldata _flowVertices,
TypeDefinitions.FlowEdge[] calldata _flow,
TypeDefinitions.Stream[] calldata _streams,
bytes calldata _packedCoordinates
) external;
}
23 changes: 0 additions & 23 deletions src/hub/MetadataDefinitions.sol

This file was deleted.

45 changes: 45 additions & 0 deletions src/hub/TypeDefinitions.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.24;

contract TypeDefinitions {
// Type declarations

/**
* @notice TrustMarker stores the expiry of a trust relation as uint96,
* and is iterable as a linked list of trust markers.
* @dev This is used to store the directional trust relation between two avatars,
* and the expiry of the trust relation as uint96 in unix time.
*/
struct TrustMarker {
address previous;
uint96 expiry;
}

struct FlowEdge {
uint16 streamSinkId;
uint240 amount; // todo: set this to uint192 (align with demurrage), and leave it to compiler to pad
}

struct Stream {
uint16 sourceCoordinate;
uint16[] flowEdgeIds; // todo: this can possible be packed more compactly manually, evaluate
bytes data;
}

struct Metadata {
bytes32 metadataType;
bytes metadata;
bytes erc1155UserData;
}

struct GroupMintMetadata {
address group;
}

// note: Redemption does not require Metadata

// Constants

bytes32 internal constant METADATATYPE_GROUPMINT = keccak256("CIRCLESv2:RESERVED_DATA:CirclesGroupMint");
bytes32 internal constant METADATATYPE_GROUPREDEEM = keccak256("CIRCLESv2:RESERVED_DATA:CirclesGroupRedeem");
}
22 changes: 22 additions & 0 deletions src/operators/BaseOperator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.24;

import "../errors/Errors.sol";
import "../hub/IHub.sol";

contract BaseOperator is ICirclesErrors {
// State variables

IHubV2 public hub;

// Constructor

constructor(IHubV2 _hub) {
if (address(_hub) == address(0)) {
// Must not be the zero address.
revert CirclesAddressCannotBeZero(0);
}

hub = _hub;
}
}
53 changes: 53 additions & 0 deletions src/operators/SignedPathOperator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.24;

import "../hub/IHub.sol";
import "../hub/TypeDefinitions.sol";
import "./BaseOperator.sol";

contract SignedPathOperator is BaseOperator, TypeDefinitions {
// Errors

error CirclesOperatorInvalidStreamSource(
uint256 streamIndex, uint256 singleSourceCoordinate, uint256 streamSourceCoordinate
);

// Constructor

constructor(IHubV2 _hub) BaseOperator(_hub) {}

// External functions

function operateSignedFlowMatrix(
address[] calldata _flowVertices,
FlowEdge[] calldata _flow,
Stream[] calldata _streams,
bytes calldata _packedCoordinates,
uint256 _sourceIndex
) external {
// Extract the alleged source vertex from the flow vertices
uint16 sourceCoordinate = _extractSource(_packedCoordinates, _sourceIndex);
address source = _flowVertices[sourceCoordinate];
// Ensure the source is the caller
if (msg.sender != source) {
revert CirclesInvalidFunctionCaller(msg.sender, source, 0);
}

// check that for every stream the source of the stream matches the alleged single source
for (uint256 i = 0; i < _streams.length; i++) {
if (_streams[i].sourceCoordinate != sourceCoordinate) {
revert CirclesOperatorInvalidStreamSource(i, sourceCoordinate, _streams[i].sourceCoordinate);
}
}

// Call the hub to operate the flow matrix
hub.operateFlowMatrix(_flowVertices, _flow, _streams, _packedCoordinates);
}

// Internal functions

function _extractSource(bytes calldata _packedCoordinates, uint256 _sourceIndex) internal pure returns (uint16) {
return
uint16(uint8(_packedCoordinates[_sourceIndex])) << 8 | uint16(uint8(_packedCoordinates[_sourceIndex + 1]));
}
}
4 changes: 2 additions & 2 deletions src/treasury/StandardTreasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "../errors/Errors.sol";
import "../hub/MetadataDefinitions.sol";
import "../hub/TypeDefinitions.sol";
import "../hub/IHub.sol";
import "../groups/IMintPolicy.sol";
import "../proxy/ProxyFactory.sol";
Expand All @@ -14,7 +14,7 @@ import "./IStandardVault.sol";
contract StandardTreasury is
ERC165,
ProxyFactory,
MetadataDefinitions,
TypeDefinitions,
IERC1155Receiver,
ICirclesErrors,
IStandardTreasuryErrors
Expand Down
2 changes: 1 addition & 1 deletion test/hub/MockHub.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.13;
pragma solidity >=0.8.24;

import "../../src/hub/Hub.sol";

Expand Down
9 changes: 6 additions & 3 deletions test/hub/PathTransferHub.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {Test} from "forge-std/Test.sol";
import {StdCheats} from "forge-std/StdCheats.sol";
import "forge-std/console.sol";
import "../../src/hub/Hub.sol";
import "../../src/hub/TypeDefinitions.sol";
import "../setup/TimeCirclesSetup.sol";
import "../setup/HumanRegistration.sol";
import "../utils/Approximation.sol";
Expand All @@ -15,6 +16,8 @@ contract HubPathTransferTest is Test, TimeCirclesSetup, HumanRegistration, Appro

MockPathTransferHub public mockHub;

// Constructor

constructor() HumanRegistration(4) {}

// Setup
Expand Down Expand Up @@ -82,12 +85,12 @@ contract HubPathTransferTest is Test, TimeCirclesSetup, HumanRegistration, Appro
// C-D . . -5C 5C

address[] memory flowVertices = new address[](M);
Hub.FlowEdge[] memory flow = new Hub.FlowEdge[](M - 1);
TypeDefinitions.FlowEdge[] memory flow = new Hub.FlowEdge[](M - 1);

// allocate three coordinates per flow edge
uint16[] memory coordinates = new uint16[]((M - 1) * 3);

// the flow vertices need to be provided in ascending order\
// the flow vertices need to be provided in ascending order
for (uint256 i = 0; i < M; i++) {
flowVertices[i] = sortedAddresses[i];
}
Expand Down Expand Up @@ -119,7 +122,7 @@ contract HubPathTransferTest is Test, TimeCirclesSetup, HumanRegistration, Appro
bytes memory packedCoordinates = packCoordinates(coordinates);

// Lastly we need to define the streams (only one from Alice to David)
Hub.Stream[] memory streams = new Hub.Stream[](1);
TypeDefinitions.Stream[] memory streams = new Hub.Stream[](1);
// the source coordinate for Alice
streams[0].sourceCoordinate = lookupMap[0];
// the flow edges that constitute the termination of this stream
Expand Down
Loading

0 comments on commit 10cb6b1

Please sign in to comment.