Compare commits

...

4 Commits

Author SHA1 Message Date
p1r0 d97ed8f4e3 Merge pull request 'develop' (#5) from develop into main
Reviewed-on: #5
2024-05-09 01:26:55 +00:00
David E. Perez Negron R. c39a3cd90b Addding updated version with library for data conversion used in the tests and scripts 2024-05-08 19:18:09 -06:00
David E. Perez Negron R. ac149f7865 Some Updates 2024-05-08 19:16:34 -06:00
David E. Perez Negron R. de3b87bc0b Adding deployment scripts and README Update usage. 2024-05-08 19:15:25 -06:00
11 changed files with 236 additions and 153 deletions

View File

@ -11,9 +11,9 @@ The goal is to use this as an alternative for ssl to web3 to verify its the corr
- [x] Keep it as simple as posible.
## ToDo and wanted features:
- [ ] Integrate CIDStorage library to the Dapp Indexer smart contract
- [ ] Create an event for metadata information about the CID.
- [ ] Support other type of hashes or structure storage
- [ ] Support of the [CID Specification](https://github.com/multiformats/cid?tab=readme-ov-file)
## Usage
@ -41,11 +41,44 @@ $ forge snapshot
$ anvil
```
### Enviorment Variables
### Deploy
#### Option1: Deployment script (recommended)
```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
$ ./deploy.sh
```
> IMPORTANT: verify .env information before executing the deployment script
**verify by attaching the deployed contract test:**
Once you deployed the contract with the previous script execution you can test
the correct smartcontract operations by running the `DeployedDappIndexer.s.sol`
script
should set after deploying the smart contract in the .env named after
DAPPINDEXERADDRS, once you update the address you can run the following
script to verify it was deployed correctly.
```shell
$source .env
$forge script script/DeployedDappIndexer.s.sol:DappIndexerScript --fork-url $PROVIDER_URL --private-key $PK0 --broadcast
```
#### Option2: Script deployment and test
using the script follows diferent verifications first before deploying the
contract, more about it here.
```shell
$source .env
$forge script script/DappIndexer.s.sol:DappIndexerScript --fork-url $PROVIDER_URL --private-key $PK0 --broadcast
```
> where:
> PROVIDER_URL can be either the anvil fork or a blockchain RPC
> $PK0
### Cast

11
deploy.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
. ./.env
forge create --rpc-url $PROVIDER_URL \
--constructor-args $ACC0 $ACC0 \
--private-key $PK0 \
src/DappIndexer.sol:DappIndexer
#forge create --rpc-url $PROVIDER_URL \
# --constructor-args $ACC0 $ACC0 \
# --private-key $PK0 \
# src/CIDStorage.sol:CIDStorage

View File

@ -2,6 +2,7 @@
src = "src"
out = "out"
libs = ["lib"]
evm_version = "cancun"
[rpc_endpoints]
sepolia = "${PROVIDER_URL}"

@ -1 +1 @@
Subproject commit 36c303b7ffdd842d06b1ec2744c9b9b5fb3083f3
Subproject commit 5475f852e3f530d7e25dfb4596aa1f9baa8ffdfc

@ -1 +1 @@
Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3
Subproject commit 52c36d412e8681053975396223d0ea39687fe33b

View File

@ -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))
}
}
}

View File

@ -0,0 +1,65 @@
// SPDX-License-Identifier: UNLICENSED
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 {
address public dappIndexerAddr;
address public CIDStorageAddr;
DappIndexer public dappIdxr;
string[] public dappsURI;
address public owner;
function setUp() public {
dappIndexerAddr = vm.envAddress("DAPPINDEXERADDRS");
dappsURI = vm.envString("dapps", ' ');
// Deployed contract must have Owner as ACC0)
owner = vm.envAddress("ACC0");
}
// run is the entry point
function run() public {
uint256 deployerPrivateKey = vm.envUint("PK0");
// startBroadcast and stopBraodcast will let us execute transactions anything between them
vm.startBroadcast(deployerPrivateKey);
// connect to the DappIndexer already deployed address
dappIdxr = DappIndexer(dappIndexerAddr);
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) = CIDStorage.stringToBytes32Pair(dappsURI[0]);
// Add Dapp
console2.log("-----Adding Dapp-----");
console2.log("Dapp Name is:");
console2.logBytes32(dapp_name);
console2.log("Bytes32 first:");
console2.logBytes32(CID1);
console2.log("Bytes32 second:");
console2.logBytes32(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(dapp_name);
console2.log("Bytes32 first:");
console2.logBytes32(dapp1.CID1);
console2.log("Bytes32 second:");
console2.logBytes32(dapp1.CID2);
// reconstruct the CID and verify
console2.log(CIDStorage.bytes32PairToString(dapp1.CID1, dapp1.CID2));
vm.stopBroadcast();
}
}

32
src/CIDStorage.sol Normal file
View File

@ -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))
}
}
}

View File

@ -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;
}
}

View File

@ -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))
}
}
}

View File

@ -1,80 +0,0 @@
// 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]);
string memory dapp= "bafkreibc6p3y36yjmeqqnttqfrpb2yttxa6aonoywxwdxl7nqym4jj3jwa";
(CID1, CID2) = stringToBytes32Pair(dapp);
// 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);
assertEq(dappsURI[0], Bytes32PairToString(dapp1.CID1, dapp1.CID2));
}
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, "Source string must be 59 bytes");
assembly {
// Load the first 32 bytes of the string data
part1 := mload(add(sourceBytes, 32))
// Load the next 32 bytes of the string data, then shift right by 3 bytes (24 bits) to remove unwanted bytes
part2 := mload(add(sourceBytes, 64))
part2 := shl(24, part2) // Shift left to remove the last 5 bytes
part2 := shr(24, part2) // Shift right to align back to the least significant bits
}
}
//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, 58))
// }
//}
}
// function stringToBytes32Pair(string calldata str) external pure returns(bytes32 part1, bytes32 part2) {
// bytes memory sourceBytes = bytes(str);
// require(sourceBytes.length == 59, "Source string must be 59 bytes");
// part1 = bytes(str[0:32]);
// part2 = bytes(str[32:59]);
//
// return (part1, part2);
// }