-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
559 additions
and
22 deletions.
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,32 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.18; | ||
|
||
interface IRegistries { | ||
struct Registry { | ||
// Percentage of a tickets value that will be rewarded to | ||
// delegated stakers expressed as a fraction of 100000. | ||
// This value is currently locked to the default payout percentage | ||
// until epochs are implemented. | ||
uint32 payoutPercentage; | ||
// Public http/s endpoint to retrieve additional metadata | ||
// about the node. | ||
// The current metadata schema is as follows: | ||
// { name: string, multiaddrs: string[] } | ||
string publicEndpoint; | ||
} | ||
|
||
function register(string calldata publicEndpoint) external; | ||
|
||
function setDefaultPayoutPercentage(uint32 _defaultPayoutPercentage) external; | ||
|
||
function getRegistry(address account) external view returns (Registry memory); | ||
|
||
function getNodes() external view returns (address[] memory); | ||
|
||
function getRegistries( | ||
uint256 start, | ||
uint256 end | ||
) external view returns (address[] memory, Registry[] memory); | ||
|
||
function getTotalNodes() external view returns (uint256); | ||
} |
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,177 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.18; | ||
|
||
import "@openzeppelin/contracts/utils/Strings.sol"; | ||
import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | ||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; | ||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; | ||
|
||
import "./IRegistries.sol"; | ||
|
||
/** | ||
* @notice This contract manages Registries for Nodes. A Registry is a | ||
* set of parameters configured by the Node itself. A Node is required | ||
* to have a valid Registry to be able to participate in the network. | ||
*/ | ||
contract Registries is IRegistries, Initializable, Ownable2StepUpgradeable, ERC165 { | ||
using ECDSA for bytes32; | ||
|
||
/** | ||
* @notice Tracks each Node's registry. | ||
*/ | ||
mapping(address => IRegistries.Registry) public registries; | ||
|
||
/** | ||
* @notice Tracks the address of every registered node. | ||
*/ | ||
address[] public nodes; | ||
|
||
/** | ||
* @notice Payout percentage refers to the portion of a tickets reward | ||
* that will be allocated to the Node's stakers. This is global, and is | ||
* currently set for all Nodes. | ||
*/ | ||
uint32 public defaultPayoutPercentage; | ||
|
||
event DefaultPayoutPercentageUpdated(uint32 defaultPayoutPercentage); | ||
|
||
error EndMustBeGreaterThanStart(); | ||
error PercentageCannotExceed100000(); | ||
error PublicEndpointCannotBeEmpty(); | ||
error EndCannotExceedNumberOfNodes(uint256 nodeLength); | ||
|
||
function initialize(uint32 _defaultPayoutPercentage) external initializer { | ||
if (_defaultPayoutPercentage > 100000) { | ||
revert PercentageCannotExceed100000(); | ||
} | ||
|
||
Ownable2StepUpgradeable.__Ownable2Step_init(); | ||
|
||
defaultPayoutPercentage = _defaultPayoutPercentage; | ||
} | ||
|
||
/** | ||
* @notice Returns true if the contract implements the interface defined by | ||
* `interfaceId` from ERC165. | ||
*/ | ||
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { | ||
return | ||
interfaceId == type(IRegistries).interfaceId || super.supportsInterface(interfaceId); | ||
} | ||
|
||
/** | ||
* @notice Set the global default payout percentage value. Only callable | ||
* by the owner. | ||
* @param _defaultPayoutPercentage The payout percentage as a value where the | ||
* denominator is 100000. | ||
*/ | ||
function setDefaultPayoutPercentage(uint32 _defaultPayoutPercentage) external onlyOwner { | ||
if (_defaultPayoutPercentage > 100000) { | ||
revert PercentageCannotExceed100000(); | ||
} | ||
|
||
defaultPayoutPercentage = _defaultPayoutPercentage; | ||
emit DefaultPayoutPercentageUpdated(_defaultPayoutPercentage); | ||
} | ||
|
||
/** | ||
* @notice Call this as a Node to set or update your Registry entry. | ||
* @param publicEndpoint The public endpoint of your Node. Essential for | ||
* clients to be able to retrieve additional information, such as | ||
* an address to establish a p2p connection. | ||
*/ | ||
function register(string calldata publicEndpoint) external { | ||
if (bytes(publicEndpoint).length == 0) { | ||
revert PublicEndpointCannotBeEmpty(); | ||
} | ||
|
||
// This is the nodes first registration | ||
if (bytes(registries[msg.sender].publicEndpoint).length == 0) { | ||
nodes.push(msg.sender); | ||
} | ||
|
||
registries[msg.sender].publicEndpoint = publicEndpoint; | ||
} | ||
|
||
/** | ||
* @notice Retrieve the registry associated with a Node. | ||
* @param account The address of the Node. | ||
* @return The Node's Registry. | ||
*/ | ||
function getRegistry(address account) external view returns (Registry memory) { | ||
return registries[account]; | ||
} | ||
|
||
/** | ||
* @notice Retrieve all registered nodes. | ||
* @return An array of node addresses. | ||
*/ | ||
function getNodes() external view returns (address[] memory) { | ||
return nodes; | ||
} | ||
|
||
/** | ||
* @notice Retrieves a list of registries. Takes in a | ||
* a start and end indices to allow pagination. | ||
* @param start The start index which is inclusive. | ||
* @param end The end index which is exclusive. | ||
* @return An array of Registries. | ||
*/ | ||
function getRegistries( | ||
uint256 start, | ||
uint256 end | ||
) external view returns (address[] memory, Registry[] memory) { | ||
uint256 nodesLength = nodes.length; | ||
|
||
if (end <= start) { | ||
revert EndMustBeGreaterThanStart(); | ||
} | ||
if (end > nodesLength) { | ||
revert EndCannotExceedNumberOfNodes(nodesLength); | ||
} | ||
|
||
address[] memory _nodes = new address[](end - start); | ||
Registry[] memory _registries = new Registry[](_nodes.length); | ||
|
||
for (uint256 i = start; i < end; ++i) { | ||
_nodes[i - start] = nodes[i]; | ||
_registries[i - start] = registries[nodes[i]]; | ||
} | ||
|
||
return (_nodes, _registries); | ||
} | ||
|
||
/** | ||
* @notice Returns the total number of registered nodes. | ||
* @return The number of registered nodes. | ||
*/ | ||
function getTotalNodes() external view returns (uint256) { | ||
return nodes.length; | ||
} | ||
|
||
/** | ||
* @notice Helper function for deriving the proof message used to | ||
* validate seeker ownership. | ||
* @param seekerId The tokenId of the seeker used for operation. | ||
* @param node The address of the node which that will be operated | ||
* by the specified seeker. | ||
* @param nonce The nonce used for this message. | ||
*/ | ||
function getProofMessage( | ||
uint256 seekerId, | ||
address node, | ||
bytes32 nonce | ||
) public pure returns (bytes memory) { | ||
return | ||
abi.encodePacked( | ||
unicode"🤖 Hi frend! 🤖\n\n📜 Signing this message proves that you're the owner of this Seeker NFT and allows your Seeker to be used to operate your Seeker's Node. It's a simple but important step to ensure smooth operation.\n\nThis request will not trigger a blockchain transaction or cost any gas fees.\n\n🔥 Your node's address: ", | ||
Strings.toHexString(uint256(uint160(node)), 20), | ||
unicode"\n\n🆔 Your seeker id: ", | ||
Strings.toString(seekerId), | ||
unicode"\n\n📦 A unique random value which secures this message: ", | ||
Strings.toHexString(uint256(nonce), 32) | ||
); | ||
} | ||
} |
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
Oops, something went wrong.