diff --git a/env.example b/env.example new file mode 100644 index 0000000..83529ee --- /dev/null +++ b/env.example @@ -0,0 +1,23 @@ +# Foundry default testing private keys +PK0="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +PK1="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" +PK2="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" +PK3="0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" +PK4="0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" +PK5="0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" +PK6="0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e" +PK7="0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356" +PK8="0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97" +PK9="0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" + +# some IPFS URIs to test +dapps="bafkreibc6p3y36yjmeqqnttqfrpb2yttxa6aonoywxwdxl7nqym4jj3jwa +bafkreidcf5baqb5wevs6avyd7dtd3j7rzrq65uyqasj4dbkcy6na4ig3ay +bafkreibffiehtv4ntajq5vjwpl7q44i6cjbg54lm5hkoa665ue2taspiyu +bafkreifqztiwfutjik4wfs3gyfdyrff7cugi4mcctluunrrbp5cgareisq +bafybeiepujtyev5ett75mxd5eazjlqor7loibey5exbmoal6teivnrrkwi" + +# https://book.getfoundry.sh/tutorials/solidity-scripting?highlight=Private%20key#environment-configuration +# GOERLI_RPC_URL= +# PRIVATE_KEY= +# ETHERSCAN_API_KEY= diff --git a/script/DappIndexer.s.sol b/script/DappIndexer.s.sol new file mode 100644 index 0000000..48a662a --- /dev/null +++ b/script/DappIndexer.s.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +import {Script, console2} from "forge-std/Script.sol"; +import { DappIndexer} from "src/DappIndexer.sol"; + +contract DappIndexerScript is Script { + DappIndexer public dappIdxr; + string[] public dappsURI; + + function setUp() public { + dappIdxr = new DappIndexer(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + console2.log("The Dapps Indexer contract address is: ", address(dappIdxr)); + dappsURI = vm.envString("dapps", ' '); + } + + // run is the entry point + function run() public { + // startBroadcast and stopBraodcast will let us execute transactions anything between them + vm.startBroadcast(); + // here we just need to deploy a new contractc + + bytes32 CID1; + bytes32 CID2; + + (CID1, CID2) = stringToBytes32Pair(dappsURI[0]); + + // Add Dapp + console2.log("-----Adding Dapp-----"); + 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)); + + // retrive Dapp + console2.log("-----retriving Dapp-----"); + DappIndexer.PackedCID memory dapp1 = dappIdxr.getCID(bytes32("Dapp01")); + console2.log("Bytes32 first:"); + console2.logBytes32(dapp1.CID1); + console2.log("Bytes32 second:"); + console2.logBytes32(dapp1.CID2); + console2.log(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); + + // Convert the concatenated bytes to a string + string memory str = string(concatenatedBytes); + + return str; + } + + function stringToBytes32Pair(string memory source) public pure returns (bytes32 part1, bytes32 part2) { + bytes memory sourceBytes = bytes(source); + require(sourceBytes.length <= 64, "String must be less than or equal to 64 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/Counter.sol b/src/Counter.sol deleted file mode 100644 index aded799..0000000 --- a/src/Counter.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -contract Counter { - uint256 public number; - - function setNumber(uint256 newNumber) public { - number = newNumber; - } - - function increment() public { - number++; - } -} diff --git a/src/DappIndexer.sol b/src/DappIndexer.sol index 5917e86..9888e39 100644 --- a/src/DappIndexer.sol +++ b/src/DappIndexer.sol @@ -4,10 +4,34 @@ pragma solidity ^0.8.23; import "@openzeppelin/contracts/access/AccessControl.sol"; contract DappIndexer is AccessControl { + // Moderator adds/updates and removes DAPPs + bytes32 public constant MODERATOR_ROLE = keccak256("MODERATOR_ROLE"); - constructor(){ - _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + struct PackedCID { + bytes32 CID1; + bytes32 CID2; } + mapping (bytes32 => PackedCID) private dapps; + constructor( + address defaultAdmin, + address moderator + ){ + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MODERATOR_ROLE, moderator); + } + + function addDapp(bytes32 dapp_name, PackedCID calldata cid) + external onlyRole(MODERATOR_ROLE) { + dapps[dapp_name] = PackedCID(cid.CID1, cid.CID2); + } + + function removeDapp(bytes32 dapp_name) external onlyRole(MODERATOR_ROLE) { + delete dapps[dapp_name]; + } + + function getCID(bytes32 dapp_name) external view returns (PackedCID memory){ + return dapps[dapp_name]; + } } diff --git a/test/DappIndexer.t.sol b/test/DappIndexer.t.sol new file mode 100644 index 0000000..002aa79 --- /dev/null +++ b/test/DappIndexer.t.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +import { Test, console2 } from "forge-std/Test.sol"; +import { DappIndexer } from "src/DappIndexer.sol"; + +contract DappIndexerTest is Test { + DappIndexer public dappIdxr; + string[] public dappsURI; + + function setUp() public { + dappIdxr = new DappIndexer(address(this), address(this)); + dappsURI = vm.envString("dapps", ' '); + } + + function testAddDapp() public { + bytes32 CID1; + bytes32 CID2; + + (CID1, CID2) = stringToBytes32Pair(dappsURI[0]); + + // Add Dapp + 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)); + // retrive Dapp + DappIndexer.PackedCID memory dapp1 = dappIdxr.getCID(bytes32("Dapp01")); + assertEq(CID1, dapp1.CID1); + assertEq(CID2, dapp1.CID2); + //string memory retrivedDapp = Bytes32PairToString(dapp1.CID1, dapp1.CID2); + //assertEq(dappsURI[0], retrivedDapp[0:59]); + } + + function Bytes32PairToString(bytes32 part1, bytes32 part2) public pure returns (string memory) { + // Concatenate the two bytes32 variables + bytes memory concatenatedBytes = abi.encodePacked(part1, part2); + + // Convert the concatenated bytes to a string + string memory str = string(concatenatedBytes); + + 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)) + } + } +}