diff --git a/contracts/script/Deploy.s.sol b/contracts/script/Deploy.s.sol index 68f0689..8d6b318 100644 --- a/contracts/script/Deploy.s.sol +++ b/contracts/script/Deploy.s.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.19 <=0.9.0; -import { Foo } from "../src/Foo.sol"; +import { ScKeystore } from "../src/ScKeystore.sol"; import { BaseScript } from "./Base.s.sol"; import { DeploymentConfig } from "./DeploymentConfig.s.sol"; contract Deploy is BaseScript { - function run() public returns (Foo foo, DeploymentConfig deploymentConfig) { + function run() public returns (ScKeystore scKeystore, DeploymentConfig deploymentConfig) { deploymentConfig = new DeploymentConfig(broadcaster); - foo = new Foo(); + scKeystore = new ScKeystore(); } } diff --git a/contracts/src/Foo.sol b/contracts/src/Foo.sol deleted file mode 100644 index d69be05..0000000 --- a/contracts/src/Foo.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; - -contract Foo { - function id(uint256 value) external pure returns (uint256) { - return value; - } -} diff --git a/contracts/src/ScKeystore.sol b/contracts/src/ScKeystore.sol new file mode 100644 index 0000000..89266ca --- /dev/null +++ b/contracts/src/ScKeystore.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.24; + +import {IScKeystore, UserInfo, KeyPackage} from "./IScKeystore.sol"; + +error UserAlreadyExists(); +error MalformedKeyPackage(); +error MalformedUserInfo(); +error UserDoesNotExist(); + +contract ScKeystore is IScKeystore { + mapping(address user => UserInfo userInfo) private users; + + function userExists(address user) public view returns (bool) { + return users[user].signaturePubKey.length > 0; + } + + function addUser(UserInfo calldata userInfo) external { + if(userInfo.signaturePubKey.length == 0) revert MalformedUserInfo(); + if(userInfo.keyPackages.length != 1) revert MalformedUserInfo(); + if(userExists(msg.sender)) revert UserAlreadyExists(); + + users[msg.sender] = userInfo; + } + + function getUser(address user) external view returns (UserInfo memory) { + return users[user]; + } + + function addKeyPackage(KeyPackage calldata keyPackage) external { + if(keyPackage.data.length == 0) revert MalformedKeyPackage(); + if(!userExists(msg.sender)) revert UserDoesNotExist(); + + users[msg.sender].keyPackages.push(keyPackage); + } + + function getAvailableKeyPackage(address user) external view returns (KeyPackage memory) { + return users[user].keyPackages[users[user].keyPackages.length - 1]; + } +} diff --git a/contracts/test/Foo.t.sol b/contracts/test/Foo.t.sol deleted file mode 100644 index 6b15158..0000000 --- a/contracts/test/Foo.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { Test, console } from "forge-std/Test.sol"; - -import { Deploy } from "../script/Deploy.s.sol"; -import { DeploymentConfig } from "../script/DeploymentConfig.s.sol"; -import { Foo } from "../src/Foo.sol"; - -contract FooTest is Test { - Foo internal foo; - DeploymentConfig internal deploymentConfig; - - address internal deployer; - - function setUp() public virtual { - Deploy deployment = new Deploy(); - (foo, deploymentConfig) = deployment.run(); - } - - function test_Example() external { - console.log("Hello World"); - uint256 x = 42; - assertEq(foo.id(x), x, "value mismatch"); - } -} diff --git a/contracts/test/ScKeystore.t.sol b/contracts/test/ScKeystore.t.sol new file mode 100644 index 0000000..f0269cd --- /dev/null +++ b/contracts/test/ScKeystore.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.19 <0.9.0; + +import { Test } from "forge-std/Test.sol"; +import { Deploy } from "../script/Deploy.s.sol"; +import { DeploymentConfig } from "../script/DeploymentConfig.s.sol"; +import "../src/ScKeystore.sol"; // solhint-disable-line + +contract ScKeystoreTest is Test { + ScKeystore internal s; + DeploymentConfig internal deploymentConfig; + address internal deployer; + + function setUp() public virtual { + Deploy deployment = new Deploy(); + (s, deploymentConfig) = deployment.run(); + } + + function addUser() internal { + KeyPackage[] memory keyPackages = new KeyPackage[](1); + keyPackages[0] = KeyPackage({data: new bytes[](0)}); + UserInfo memory userInfo = UserInfo({ + signaturePubKey: "0x", + keyPackages: keyPackages + }); + s.addUser(userInfo); + } + + function test__userExists__returnsFalse__whenUserDoesNotExist() public view { + assert(!s.userExists(address(this))); + } + + function test__addUser__reverts__whenUserInfoIsMalformed() public { + UserInfo memory userInfo; + vm.expectRevert(MalformedUserInfo.selector); + s.addUser(userInfo); + } + + function test__addUser__reverts__whenUserAlreadyExists() public { + addUser(); + vm.expectRevert(UserAlreadyExists.selector); + addUser(); + } + + function test__addUser__addsUser__whenUserInfoIsValid() public { + addUser(); + assert(s.userExists(address(this))); + } + + function test__getUser__returnsUserInfo__whenUserExists() public { + addUser(); + UserInfo memory userInfo = s.getUser(address(this)); + assert(userInfo.signaturePubKey.length == 2); + assert(userInfo.keyPackages.length == 1); + } +}