-
Notifications
You must be signed in to change notification settings - Fork 0
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 #4 from shutter-network/shutter-api
Shutter api
- Loading branch information
Showing
9 changed files
with
886 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ gnoshcontracts/ | |
shopcontracts/ | ||
out/ | ||
.tool-versions | ||
.env |
Large diffs are not rendered by default.
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
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,53 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import "forge-std/Script.sol"; | ||
import "../src/common/KeyBroadcastContract.sol"; | ||
import "../src/common/KeyperSet.sol"; | ||
import "../src/common/KeyperSetManager.sol"; | ||
import "../src/shutter-service/ShutterRegistry.sol"; | ||
|
||
contract Deploy is Script { | ||
function deployKeyperSetManager( | ||
address deployerAddress | ||
) public returns (KeyperSetManager) { | ||
KeyperSetManager ksm = new KeyperSetManager(deployerAddress); | ||
ksm.initialize(deployerAddress, deployerAddress); | ||
console.log("keyper set manager initialised"); | ||
|
||
// add bootstrap keyper set | ||
KeyperSet fakeKeyperset = new KeyperSet(); | ||
fakeKeyperset.setFinalized(); | ||
ksm.addKeyperSet(0, address(fakeKeyperset)); | ||
|
||
console.log("KeyperSetManager:", address(ksm)); | ||
return ksm; | ||
} | ||
|
||
function deployKeyBroadcastContract( | ||
KeyperSetManager ksm | ||
) public returns (KeyBroadcastContract) { | ||
KeyBroadcastContract kbc = new KeyBroadcastContract(address(ksm)); | ||
console.log("KeyBroadcastContract:", address(kbc)); | ||
return kbc; | ||
} | ||
|
||
function deployRegistry() public returns (ShutterRegistry) { | ||
ShutterRegistry s = new ShutterRegistry(); | ||
console.log("Registry:", address(s)); | ||
return s; | ||
} | ||
|
||
function run() external { | ||
uint256 deployKey = vm.envUint("DEPLOY_KEY"); | ||
address deployerAddress = vm.addr(deployKey); | ||
console.log("Deployer:", deployerAddress); | ||
vm.startBroadcast(deployKey); | ||
|
||
KeyperSetManager ksm = deployKeyperSetManager(deployerAddress); | ||
deployKeyBroadcastContract(ksm); | ||
deployRegistry(); | ||
|
||
vm.stopBroadcast(); | ||
} | ||
} |
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,22 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import "forge-std/Script.sol"; | ||
import "../src/shutter-service/ShutterRegistry.sol"; | ||
|
||
contract Deploy is Script { | ||
function run() external { | ||
uint256 deployKey = vm.envUint("DEPLOY_KEY"); | ||
address deployerAddress = vm.addr(deployKey); | ||
console.log("Deployer:", deployerAddress); | ||
vm.startBroadcast(deployKey); | ||
deploySequencer(); | ||
vm.stopBroadcast(); | ||
} | ||
|
||
function deploySequencer() public returns (ShutterRegistry) { | ||
ShutterRegistry s = new ShutterRegistry(); | ||
console.log("ShutterRegistry:", address(s)); | ||
return s; | ||
} | ||
} |
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,21 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import "forge-std/Script.sol"; | ||
import {ShutterRegistry} from "src/shutter-service/ShutterRegistry.sol"; | ||
|
||
contract SubmitTransaction is Script { | ||
function run() external { | ||
uint256 privateKey = vm.envUint("TX_SENDER_KEY"); | ||
ShutterRegistry registry = ShutterRegistry( | ||
vm.envAddress("REGISTRY_ADDRESS") | ||
); | ||
uint64 eon = uint64(vm.envUint("EON")); | ||
bytes32 identityPrefix = vm.envBytes32("IDENTITY_PREFIX"); | ||
uint64 ts = uint64(vm.envUint("TIMESTAMP")); | ||
|
||
vm.startBroadcast(privateKey); | ||
registry.register(eon, identityPrefix, ts); | ||
vm.stopBroadcast(); | ||
} | ||
} |
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,86 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.28; | ||
|
||
import "openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
/** | ||
* @title ShutterRegistry | ||
* @dev A contract for managing the registration of identities with timestamps, ensuring unique and future-dated registrations. | ||
* Inherits from OpenZeppelin's Ownable contract to enable ownership-based access control. | ||
*/ | ||
contract ShutterRegistry is Ownable { | ||
// Custom error for when an identity is already registered. | ||
error AlreadyRegistered(); | ||
|
||
// Custom error for when a provided timestamp is in the past. | ||
error TimestampInThePast(); | ||
|
||
// Custom error for when a identityPrefix provided is empty. | ||
error InvalidIdentityPrefix(); | ||
|
||
struct RegistrationData { | ||
uint64 eon; | ||
uint64 timestamp; | ||
} | ||
/** | ||
* @dev Mapping to store registration data for each identity. | ||
* The identity is represented as a `bytes32` hash and mapped to struct RegistrationData. | ||
*/ | ||
mapping(bytes32 identity => RegistrationData) public registrations; | ||
|
||
/** | ||
* @dev Emitted when a new identity is successfully registered. | ||
* @param eon The eon associated with the identity. | ||
* @param identityPrefix The raw prefix input used to derive the registered identity hash. | ||
* @param sender The address of the account that performed the registration. | ||
* @param timestamp The timestamp associated with the registered identity. | ||
*/ | ||
event IdentityRegistered( | ||
uint64 eon, | ||
bytes32 identityPrefix, | ||
address sender, | ||
uint64 timestamp | ||
); | ||
|
||
/** | ||
* @dev Initializes the contract and assigns ownership to the deployer. | ||
*/ | ||
constructor() Ownable(msg.sender) {} | ||
|
||
/** | ||
* @notice Registers a new identity with a specified timestamp and eon. | ||
* @dev The identity is derived by hashing the provided `identityPrefix` concatenated with the sender's address. | ||
* @param eon The eon associated with the identity. | ||
* @param identityPrefix The input used to derive the identity hash. | ||
* @param timestamp The future timestamp to be associated with the identity. | ||
* @custom:requirements | ||
* - The identity must not already be registered. | ||
* - The provided timestamp must not be in the past. | ||
*/ | ||
function register( | ||
uint64 eon, | ||
bytes32 identityPrefix, | ||
uint64 timestamp | ||
) external { | ||
// Ensure the timestamp is not in the past. | ||
require(timestamp >= block.timestamp, TimestampInThePast()); | ||
|
||
// Ensure identityPrefix passed in correct. | ||
require(identityPrefix != bytes32(0), InvalidIdentityPrefix()); | ||
|
||
// Generate the identity hash from the provided prefix and the sender's address. | ||
bytes32 identity = keccak256( | ||
abi.encodePacked(identityPrefix, msg.sender) | ||
); | ||
RegistrationData storage registrationData = registrations[identity]; | ||
// Ensure the identity is not already registered. | ||
require(registrationData.timestamp == 0, AlreadyRegistered()); | ||
|
||
// Store the registration timestamp. | ||
registrationData.eon = eon; | ||
registrationData.timestamp = timestamp; | ||
|
||
// Emit the IdentityRegistered event. | ||
emit IdentityRegistered(eon, identityPrefix, msg.sender, timestamp); | ||
} | ||
} |
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,92 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import "forge-std/Test.sol"; | ||
import "../src/shutter-service/ShutterRegistry.sol"; | ||
|
||
contract ShutterRegistryTest is Test { | ||
ShutterRegistry public shutterRegistry; | ||
|
||
function setUp() public { | ||
shutterRegistry = new ShutterRegistry(); | ||
} | ||
|
||
function testIdentityRegistration() public { | ||
uint64 eon = 5; | ||
bytes32 identityPrefix = hex"001122"; | ||
uint64 timestamp = uint64(block.timestamp) + 100; | ||
address sender = makeAddr("sender"); | ||
|
||
vm.expectEmit(address(shutterRegistry)); | ||
emit ShutterRegistry.IdentityRegistered( | ||
eon, | ||
identityPrefix, | ||
sender, | ||
timestamp | ||
); | ||
|
||
hoax(sender); | ||
shutterRegistry.register(eon, identityPrefix, timestamp); | ||
|
||
bytes32 identity = keccak256(abi.encodePacked(identityPrefix, sender)); | ||
(uint64 registeredEon, uint64 registeredTimestamp) = shutterRegistry | ||
.registrations(identity); | ||
|
||
//verifying registered timestamp | ||
assertEqUint(registeredEon, eon); | ||
assertEqUint(registeredTimestamp, timestamp); | ||
} | ||
|
||
function testDuplicateRegistration() public { | ||
uint64 eon = 5; | ||
bytes32 identityPrefix = hex"001122"; | ||
uint64 timestamp = uint64(block.timestamp) + 100; | ||
address sender = makeAddr("sender"); | ||
|
||
vm.expectEmit(address(shutterRegistry)); | ||
emit ShutterRegistry.IdentityRegistered( | ||
eon, | ||
identityPrefix, | ||
sender, | ||
timestamp | ||
); | ||
|
||
hoax(sender); | ||
shutterRegistry.register(eon, identityPrefix, timestamp); | ||
|
||
uint64 newTimestamp = uint64(block.timestamp) + 200; | ||
vm.expectRevert(ShutterRegistry.AlreadyRegistered.selector); | ||
hoax(sender); | ||
shutterRegistry.register(eon, identityPrefix, newTimestamp); | ||
|
||
//verifying registered timestamp | ||
bytes32 identity = keccak256(abi.encodePacked(identityPrefix, sender)); | ||
(, uint64 registeredTimestamp) = shutterRegistry.registrations( | ||
identity | ||
); | ||
assertEqUint(registeredTimestamp, timestamp); | ||
} | ||
|
||
function testInvalidTimestamp() public { | ||
uint64 eon = 5; | ||
bytes32 identityPrefix = hex"001122"; | ||
uint64 timestamp = uint64(block.timestamp) - 1; | ||
address sender = makeAddr("sender"); | ||
|
||
vm.expectRevert(ShutterRegistry.TimestampInThePast.selector); | ||
hoax(sender); | ||
shutterRegistry.register(eon, identityPrefix, timestamp); | ||
} | ||
|
||
function testMissingIdentity() public { | ||
uint64 eon = 5; | ||
// zero bytes for identity prefix should fail | ||
bytes32 identityPrefix = hex"00"; | ||
uint64 timestamp = uint64(block.timestamp) + 100; | ||
address sender = makeAddr("sender"); | ||
|
||
vm.expectRevert(ShutterRegistry.InvalidIdentityPrefix.selector); | ||
hoax(sender); | ||
shutterRegistry.register(eon, identityPrefix, timestamp); | ||
} | ||
} |