From c39a3cd90bd438cdaece891844bd3c23867e8ccf Mon Sep 17 00:00:00 2001 From: "David E. Perez Negron R." Date: Wed, 8 May 2024 19:18:09 -0600 Subject: [PATCH] Addding updated version with library for data conversion used in the tests and scripts --- lib/openzeppelin-contracts | 2 +- script/DappIndexer.s.sol | 49 ++++++++------------------- src/CIDStorage.sol | 32 ++++++++++++++++++ src/DappIndexer.sol | 39 ++++++++++++++++++++- test/DappIndexer.t.sol | 69 ++++++++++++++++++++------------------ 5 files changed, 122 insertions(+), 69 deletions(-) create mode 100644 src/CIDStorage.sol diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 01ef448..52c36d4 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3 +Subproject commit 52c36d412e8681053975396223d0ea39687fe33b diff --git a/script/DappIndexer.s.sol b/script/DappIndexer.s.sol index c96cc4d..4e9459b 100644 --- a/script/DappIndexer.s.sol +++ b/script/DappIndexer.s.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.23; import {Script, console2} from "forge-std/Script.sol"; import { DappIndexer} from "src/DappIndexer.sol"; +import { CIDStorage } from "src/CIDStorage.sol"; contract DappIndexerScript is Script { DappIndexer public dappIdxr; @@ -19,63 +20,41 @@ contract DappIndexerScript is Script { uint256 deployerPrivateKey = vm.envUint("PK0"); // startBroadcast and stopBraodcast will let us execute transactions anything between them vm.startBroadcast(deployerPrivateKey); - // here we just need to deploy a new contractc + // here we just need to deploy a new contract dappIdxr = new DappIndexer(owner, owner); console2.log("The Dapps Indexer contract address is: ", address(dappIdxr)); + // Define a Dapp name + bytes32 dapp_name = bytes32("Dapp01"); + + // Define DappURI splited into two bytes32 CIDs bytes32 CID1; bytes32 CID2; - (CID1, CID2) = stringToBytes32Pair(dappsURI[0]); + (CID1, CID2) = CIDStorage.stringToBytes32Pair(dappsURI[0]); // Add Dapp console2.log("-----Adding Dapp-----"); console2.log("Dapp Name is:"); - console2.logBytes32(bytes32("Dapp01")); + console2.logBytes32(dapp_name); console2.log("Bytes32 first:"); console2.logBytes32(CID1); console2.log("Bytes32 second:"); console2.logBytes32(CID2); - console2.log(Bytes32PairToString(CID1, CID2)); - dappIdxr.addDapp(bytes32("Dapp01"), DappIndexer.PackedCID(CID1, CID2)); + console2.log(CIDStorage.bytes32PairToString(CID1, CID2)); + dappIdxr.addDapp(dapp_name, DappIndexer.PackedCID(CID1, CID2)); // retrive Dapp console2.log("-----retriving Dapp-----"); - DappIndexer.PackedCID memory dapp1 = dappIdxr.getDapp(bytes32("Dapp01")); + DappIndexer.PackedCID memory dapp1 = dappIdxr.getDapp(dapp_name); console2.log("Bytes32 first:"); console2.logBytes32(dapp1.CID1); console2.log("Bytes32 second:"); console2.logBytes32(dapp1.CID2); - console2.log(Bytes32PairToString(dapp1.CID1, dapp1.CID2)); + + // reconstruct the CID and verify + console2.log(CIDStorage.bytes32PairToString(dapp1.CID1, dapp1.CID2)); vm.stopBroadcast(); } - - function Bytes32PairToString(bytes32 part1, bytes32 part2) public pure returns (string memory) { - // Concatenate the two bytes32 variables - bytes memory concatenatedBytes = abi.encodePacked(part1, part2); - - // Truncate the concatenated bytes to 59 bytes - bytes memory truncatedBytes = new bytes(59); - for (uint i = 0; i < 59; i++) { - truncatedBytes[i] = concatenatedBytes[i]; - } - - // Convert the truncated bytes to a string - string memory str = string(truncatedBytes); - - return str; - } - - function stringToBytes32Pair(string memory source) public pure returns (bytes32 part1, bytes32 part2) { - bytes memory sourceBytes = bytes(source); - require(sourceBytes.length == 59, "URI string must equal to 59 bytes"); - - assembly { - // Load the first 32 bytes of the string data - part1 := mload(add(sourceBytes, 32)) - // Load the second 32 bytes of the string data - part2 := mload(add(sourceBytes, 64)) - } - } } diff --git a/src/CIDStorage.sol b/src/CIDStorage.sol new file mode 100644 index 0000000..f0db1c1 --- /dev/null +++ b/src/CIDStorage.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +library CIDStorage { + function bytes32PairToString(bytes32 part1, bytes32 part2) public pure returns (string memory) { + // Concatenate the two bytes32 variables + bytes memory concatenatedBytes = abi.encodePacked(part1, part2); + + // Truncate the concatenated bytes to 59 bytes + bytes memory truncatedBytes = new bytes(59); + for (uint i = 0; i < 59; i++) { + truncatedBytes[i] = concatenatedBytes[i]; + } + + // Convert the truncated bytes to a string + string memory str = string(truncatedBytes); + + return str; + } + + function stringToBytes32Pair(string memory source) public pure returns (bytes32 part1, bytes32 part2) { + bytes memory sourceBytes = bytes(source); + require(sourceBytes.length == 59, "URI string must equal to 59 bytes"); + + assembly { + // Load the first 32 bytes of the string data + part1 := mload(add(sourceBytes, 32)) + // Load the second 32 bytes of the string data + part2 := mload(add(sourceBytes, 64)) + } + } +} diff --git a/src/DappIndexer.sol b/src/DappIndexer.sol index 31f07ab..e90ba1a 100644 --- a/src/DappIndexer.sol +++ b/src/DappIndexer.sol @@ -14,6 +14,8 @@ contract DappIndexer is AccessControl { mapping (bytes32 => PackedCID) private dapps; + bytes32[] public dapp_names; + constructor( address defaultAdmin, address moderator @@ -24,14 +26,49 @@ contract DappIndexer is AccessControl { function addDapp(bytes32 dapp_name, PackedCID calldata cid) external onlyRole(MODERATOR_ROLE) { + //if the struct does not exists trace it on the array + if (dapps[dapp_name].CID1 != 0 && dapps[dapp_name].CID2 != 0) { + dapp_names.push(dapp_name); + } + dapps[dapp_name] = PackedCID(cid.CID1, cid.CID2); } - function removeDapp(bytes32 dapp_name) external onlyRole(MODERATOR_ROLE) { + //@Notice: consider calling getDappIndex internal and pop dapps and dapp_names + //@Notice: Yet requiring index might give extra verification + function removeDapp(uint index, bytes32 dapp_name) + external onlyRole(MODERATOR_ROLE) { + require(index < dapp_names.length, "dapp index out of bounds"); + require(dapp_names[index] == dapp_name); + dapp_names[index] = dapp_names[dapp_names.length - 1]; + dapp_names.pop(); delete dapps[dapp_name]; } function getDapp(bytes32 dapp_name) external view returns (PackedCID memory){ return dapps[dapp_name]; } + + function getDappIndex(bytes32 dapp_name) external view returns (uint256 i) { + require(dappExists(dapp_name)); + for(i; i <= dapp_names.length; i++){ + if(dapp_names[i] == dapp_name){ + return i; + } + } + } + + function listDappNames() external view returns (bytes32[] memory) { + return dapp_names; + } + + function dappExists(bytes32 dapp_name) public view returns (bool) { + for(uint i; i <= dapp_names.length; i++){ + if(dapp_names[i] == dapp_name){ + return true; + } + } + return false; + } + } diff --git a/test/DappIndexer.t.sol b/test/DappIndexer.t.sol index 0c067af..aae00ad 100644 --- a/test/DappIndexer.t.sol +++ b/test/DappIndexer.t.sol @@ -3,64 +3,69 @@ pragma solidity ^0.8.23; import { Test, console2 } from "forge-std/Test.sol"; import { DappIndexer } from "src/DappIndexer.sol"; +import { CIDStorage } from "src/CIDStorage.sol"; contract DappIndexerTest is Test { DappIndexer public dappIdxr; string[] public dappsURI; + address public owner; function setUp() public { dappIdxr = new DappIndexer(address(this), address(this)); dappsURI = vm.envString("dapps", ' '); + owner = vm.envAddress("ACC0"); } + // Test adding a dapp that doesn't exist function testAddDapp() public { + bytes32 dapp_name = bytes32("Dapp01"); bytes32 CID1; bytes32 CID2; - (CID1, CID2) = stringToBytes32Pair(dappsURI[0]); + (CID1, CID2) = CIDStorage.stringToBytes32Pair(dappsURI[0]); // Add Dapp console2.log("Dapp Name is:"); - console2.logBytes32(bytes32("Dapp01")); + console2.logBytes32(dapp_name); console2.log("Bytes32 first:"); console2.logBytes32(CID1); console2.log("Bytes32 second:"); console2.logBytes32(CID2); - console2.log(Bytes32PairToString(CID1, CID2)); - dappIdxr.addDapp(bytes32("Dapp01"), DappIndexer.PackedCID(CID1, CID2)); + console2.log(CIDStorage.bytes32PairToString(CID1, CID2)); + dappIdxr.addDapp(dapp_name, DappIndexer.PackedCID(CID1, CID2)); + // retrive Dapp - DappIndexer.PackedCID memory dapp1 = dappIdxr.getDapp(bytes32("Dapp01")); + DappIndexer.PackedCID memory dapp1 = dappIdxr.getDapp(dapp_name); assertEq(CID1, dapp1.CID1); assertEq(CID2, dapp1.CID2); - string memory retrivedDappURI = Bytes32PairToString(dapp1.CID1, dapp1.CID2); + + // reconstruct the CID and verify + string memory retrivedDappURI = CIDStorage.bytes32PairToString(dapp1.CID1, dapp1.CID2); assertEq(dappsURI[0], retrivedDappURI); } - function Bytes32PairToString(bytes32 part1, bytes32 part2) public pure returns (string memory) { - // Concatenate the two bytes32 variables - bytes memory concatenatedBytes = abi.encodePacked(part1, part2); +//## ToDo ISSUE #2 +// +//### Features testing +// +//- [x] test adding a dapp and retrive it. (addDapp, getDapp) +// +//- [ ] test removing a dapp that exists (verify dapps and dapp_names) +//- [ ] test dappExists (lower, upper, fuzz) +//- [ ] test removing a dapp that doesn't exist +//- [ ] test getting that names (listDappNames) +//- [ ] test getDappIndex (lower, upper, fuzz) +//- [ ] check if dapp name exists +// +//### Library testing +// +//- [ ] test adding longer CID +//- [ ] test adding shorter CID +//- [ ] test fuzz +// +//### Testing Roles Open Zeppelin Module +// +//- [ ] test roles for educational purposes. +// - // Truncate the concatenated bytes to 59 bytes - bytes memory truncatedBytes = new bytes(59); - for (uint i = 0; i < 59; i++) { - truncatedBytes[i] = concatenatedBytes[i]; - } - - // Convert the truncated bytes to a string - string memory str = string(truncatedBytes); - - return str; - } - - function stringToBytes32Pair(string memory source) public pure returns (bytes32 part1, bytes32 part2) { - bytes memory sourceBytes = bytes(source); - require(sourceBytes.length == 59, "URI string must equal to 59 bytes"); - - assembly { - // Load the first 32 bytes of the string data - part1 := mload(add(sourceBytes, 32)) - // Load the second 32 bytes of the string data - part2 := mload(add(sourceBytes, 64)) - } - } }