This project demonstrates a minimal working example of long-term decentralized data storage using:
- Celestia Rollups (Rollkit + Ethermint execution layer)
- Solidity smart contracts to store IPFS/Filecoin CIDs
- IPFS and Web3.Storage for decentralized content storage
- React + ethers.js to form the client-side application
Users can upload files β store them via IPFS/Filecoin β persist the resulting CID on a Celestia rollup.
This MVP later extends into a DED Learning Session prototype where learning artifacts can be uploaded and validated through on-chain voting.
Before running this project, you must have:
https://docs.celestia.org/nodes/light-node/
This provides the RPC environment used by the contracts.
https://docs.celestia.org/category/ethermint
A minimal contract that stores user β CID mappings:
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.13;
contract Storage {
mapping (address => string) public userFiles;
function setFile(string memory file) external {
userFiles[msg.sender] = file;
}
}Deploy the contract using a standard Foundry script:
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
import {Storage} from "src/Storage.sol";
contract StorageScript is Script {
function run() public {
vm.startBroadcast();
new Storage();
vm.stopBroadcast();
}
}Deployment demo:
Screen.Recording.2022-12-05.at.6.48.46.AM.mov
Record the deployed address for frontend integration.
We bootstrap the frontend using create-eth-app:
https://github.com/paulrberg/create-eth-app
Then:
packages/contracts/src/abis
import erc20Abi from "./abis/erc20.json";
import ownableAbi from "./abis/ownable.json";
import storageAbi from "./abis/Storage.json";
const abis = {
erc20: erc20Abi,
ownable: ownableAbi,
storage: storageAbi,
};
export default abis;const addresses = {
storage: "0xdc64a140aa3e981100a9beca4e685f962f0cf6c9",
};
export default addresses;Initialize the IPFS node:
import IPFS from "ipfs";
async function initIpfs() {
node = await IPFS.create();
const version = await node.version();
console.log("IPFS Node Version:", version.version);
}Read a user's stored CID:
async function readCurrentUserFile() {
const signer = defaultProvider.getSigner();
const userAddress = await signer.getAddress();
return await storageContract.userFiles(userAddress);
}Upload + write the CID on-chain:
async function setFile(hash) {
const withSigner = storageContract.connect(defaultProvider.getSigner());
await withSigner.setFile(hash);
setIpfsHash(hash);
}
async function uploadFile(file) {
const files = [{ path: file.name + file.path, content: file }];
for await (const result of node.add(files)) {
await setFile(result.cid.string);
}
}The UI handles:
- File selection
- IPFS upload
- CID resolution
- Smart contract interaction
See the repo for the complete frontend code.
Set up a custom network for Ethermint using RPC_URL: 9545.
You can import an Anvil private key to fund transactions.
Example screenshot:
Demo video of uploading a file and resolving its CID:
the.two.mov
This MVP forms the basis for Decentralized Education Development (DED) Learning Sessions.
Students upload learning artifacts (videos, comments).
Arbitrators evaluate them using an on-chain voting mechanism.
struct Artifact {
LearningSessionArtifact type;
uint256 id;
uint256 parentId;
address author;
uint256 createdAtBlock;
uint256[] childIds;
string CID; // IPFS/Filecoin content identifier
}enum LearningSessionArtifact {
VIDEO,
COMMENT
}Comments form a tree structure using parentId and childIds.
All content is stored as JSON in IPFS/Filecoin using Web3.Storage.
Arbitrators vote on artifacts:
function vote(uint256 artifactId, int8 voteValue) public { ... }+1= upvote-1= downvote0= withdraw vote
Score retrieval:
function getArtifactScore(uint256 artifactId) public view returns (int256);Author reputation:
function getAuthorReputation(address author) public view returns (int256);// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
import {LearningSession} from "src/LearningSession.sol";
contract LearningSessionScript is Script {
function run() public {
vm.startBroadcast();
new LearningSession();
vm.stopBroadcast();
}
}Deploy:
forge script script/LearningSession.s.sol:LearningSessionScript \
--fork-url $RPC_URL --private-key $ANVIL_KEY --broadcastFile upload:
function getFiles () {
const fileInput = document.querySelector('input[type="file"]')
return fileInput.files
}
async function storeFiles (files) {
const client = makeStorageClient()
const cid = await client.put(files)
console.log('stored files with cid:', cid)
return cid
}Retrieval:
async function retrieveFiles (cid) {
const client = makeStorageClient()
const res = await client.get(cid)
if (!res.ok) {
throw new Error(`failed to get ${cid} - [${res.status}] ${res.statusText}`)
}
const files = await res.files()
for (const file of files) {
console.log(`${file.cid} -- ${file.path} -- ${file.size}`)
}
}-
Foundry Contracts:
https://github.com/DED-EDU/celestia-long-term-data-storage-mvp/tree/main/mvp-contracts -
Frontend (React App):
https://github.com/DED-EDU/celestia-long-term-data-storage-mvp/tree/main/mvp-dapp
Open an issue or PR β this MVP is a foundation for research on sovereign rollups, decentralized storage, and verifiable learning systems within the Celestia ecosystem.
