Building a Celo-based social network using 3Box

Building a Celo-based social network using 3Box https://celo.academy/uploads/default/optimized/2X/2/2d3fb2a850b32ee71bb936ce62ad565313f1608f_2_1024x576.png
none 0.0 0

Introduction​

In this tutorial, we will guide developers through the process of building a social network on the Celo blockchain using 3Box. We will introduce 3Box and its features, and demonstrate how to integrate it with a Celo smart contract to create a decentralized social network.
We will also explore best practices for building a scalable and secure social network on Celo Blockchain, including data privacy and user authentication.

Prerequisites​

To build a Celo-Based social network using 3Box you will need the following

  • Javascript, a good knowledge of javascript is needed.
  • Solidity: The programming language we’re going to use to write our smart contract
  • React.js: Javascript library for building user interfaces
  • Web3.js: You’ll need a basic knowledge of web3.

Requirements​

These are going to be required in building a Celo-Based social network using 3Box

  • Node.js
  • Celo cli
  • Truffle
  • contractkit (to connect to the celoblockchain)
  • 3Box
  • React
  • Jest

Procedures for building a Celo-based social network using 3Box

step 1: Understanding Celo and 3Box:

Celo is an open blockchain platform that aims to create a decentralized financial system accessible to anyone with a smartphone. It provides a programmable blockchain where you can deploy smart contracts and interact with the Celo ecosystem.
3Box is a user data management system built on decentralized web principles. It allows users to store and manage their data in a secure and decentralized manner using the InterPlanetary File System (IPFS).

step 2: Designing the Social Network:

The next step is to define the features and functionality of our social network. The data structure and requirements for user profiles, posts, relationships, and messaging.

The Features and Functionality:

User profiles: Allow users to create and manage their profiles with information like username, profile picture, bio, contact details, and social media links.
Posts and interactions: Enable users to create posts, share content (text, images, videos), and interact with posts through likes, comments, and shares.

Relationships and connections: Implement the ability for users to follow or connect with other users, creating a network of relationships. Users should be able to view and manage their followers and followings.

Messaging: Provide users with the ability to send direct messages to each other, fostering private conversations.

Notifications: Implement a notification system to alert users about new interactions, messages, or updates from their connections.

Search functionality: Enable users to search for other users, posts, or specific content within the social network.

Privacy settings: Allow users to manage their privacy settings, such as choosing who can view their profile, posts, and interactions.
Determine the Data Structure and Requirements:

User profiles: Define the necessary fields to store user information, such as username, profile picture URL, bio, contact details, and social media links.

Posts: Determine the fields required for each post, such as the content, author, timestamp, likes count, comments count, and associated comments.

Relationships: Establish a structure to represent user connections, such as a follower/following model or a friend network. Store the relationship information between users.

Messages: Define the fields needed to store messages, including the sender, recipient, content, timestamp, and read/unread status.

Notifications: Identify the information required for notifications, such as the recipient, type of notification, associated post or interaction, and read/unread status.

Data Structure in Solidity:

In our smart contract, you can define data structures to represent user profiles, posts, relationships, messages, and notifications.

// solidity

struct UserProfile {
    string username;
    string profilePictureUrl;
    string bio;
    string contactDetails;
    mapping(string => string) socialMediaLinks;
}

struct Post {
    string content;
    address author;
    uint256 timestamp;
    uint256 likesCount;
    uint256 commentsCount;
}

struct Comment {
    string content;
    address author;
    uint256 timestamp;
}

struct Relationship {
    mapping(address => bool) followers;
    mapping(address => bool) followings;
}

struct Message {
    string content;
    address sender;
    address recipient;
    uint256 timestamp;
    bool isRead;
}

struct Notification {
    address recipient;
    string notificationType;
    uint256 associatedItemId;
    bool isRead;
} 

you can customize the data structure based on your specific requirements and additional fields you may need.

step 3: Smart Contract Development:

Set up your Development Environment:
We will install the Celo CLI and Solidity compiler (Truffle).
On the terminal run the following code (making sure you’re on the project directory):

// Bash
npm install -g truffle
npm install -g @celo/cli

Write and Deploy Smart Contracts:

As earlier stated we are going to use Solidity to write the smart contract code for each functionality. Here’s the smart contract code:

//solidity

contract UserRegistry {
    mapping(address => bool) public registeredUsers;

    function registerUser() public {
        require(!registeredUsers[msg.sender], "User already registered.");
        registeredUsers[msg.sender] = true;
    }
}

contract PostStorage {
    struct Post {
        string content;
        address author;
        uint256 timestamp;
    }

    mapping(uint256 => Post) public posts;
    uint256 public postCount;

    function createPost(string memory _content) public {
        postCount++;
        posts[postCount] = Post(_content, msg.sender, block.timestamp);
    }
}
// Additional contracts for relationship management, messaging, and notifications can also be added here.

Implement User Authentication Mechanisms:
Use Celo account addresses and signatures for user authentication within your smart contracts and application.

Verify the authenticity of user actions by validating the provided signatures against the user’s Celo account address.

Here’s how to interact with the smart contracts for user registration and post creation using web3.js:

//javascript

import Web3 from 'web3';

const web3 = new Web3('https://alfajores-forno.celo-testnet.org');

const userRegistryContractAddress = '0x123456789...'; // Address of deployed UserRegistry contract
const postStorageContractAddress = '0x987654321...'; // Address of deployed PostStorage contract

async function registerUser() {
    const userRegistryContract = new web3.eth.Contract(UserRegistryABI, userRegistryContractAddress);
    await userRegistryContract.methods.registerUser().send({ from: userAddress });
    console.log('User registered successfully!');
}

async function createPost(content) {
    const postStorageContract = new web3.eth.Contract(PostStorageABI, postStorageContractAddress);
    await postStorageContract.methods.createPost(content).send({ from: userAddress });
    console.log('Post created successfully!');
}

Replace UserRegistryABI, PostStorageABI, userAddress, userRegistryContractAddress, and postStorageContractAddress with the appropriate contract ABIs, user address, and contract addresses.

step 4: Connect to Celo Blockchain:

Connect to Celo Blockchain:

To connect to the Celo blockchain, we’ll need to use a library like ContractKit, which provides a JavaScript API for interacting with the Celo blockchain.

Install ContractKit by running the following command on our terminal:

npm install @celo/contractkit

Import the necessary modules and connect to the Celo network.

const ContractKit = require('@celo/contractkit');

async function connectToCelo() {
  const kit = ContractKit.newKit('https://alfajores-forno.celo-testnet.org');
  // Other connection setup code
}

Step 5: Design User Profiles and Data Model:

User Profile Design:

Determine the information you want to display on user profiles, such as username, profile picture, bio, contact details, and social media links.
Decide on the privacy settings for different profile fields, allowing users to control the visibility of their information.
Consider additional features for user profiles, such as follower/following counts, post counts, and user activity.

Data Model for User Profiles:

Define the data structure and fields needed to store user profile information.
Decide whether to store profile data on the Celo blockchain, in 3Box, or a combination of both, based on your requirements for data privacy, scalability, and usability.
We’ll be using IPFS (InterPlanetary File System) to store profile pictures and other media assets associated with user profiles.

Data Model for Posts and Interactions:

Determine the data structure and fields required to store posts and their associated interactions, such as likes, comments, and shares.
Identify the relationships between users and posts, such as the author of a post and the users who interacted with it.

Data Model:
Here’s the data model for user profiles and posts using a combination of Celo blockchain and 3Box

//solidity

struct Profile {
    string username;
    string profilePictureCID; // IPFS content identifier for the profile picture
    string bio;
    string contactDetails;
    mapping(string => string) socialMediaLinks;
    // Other profile fields as needed
}

struct Post {
    uint256 postId;
    string content;
    address author;
    uint256 timestamp;
    uint256 likesCount;
    uint256 commentsCount;
    // Other post fields as needed
}

Here the user profiles are stored in 3Box, and the user’s Celo account address can be used as a key to retrieve the profile data. The Profile struct contains fields such as username, profile picture CID (content identifier), bio, contact details, and social media links.

step 6: Implement User Authentication:

We will use Celo accounts for user authentication. Users can sign in using their Celo wallet addresses, and you can verify their ownership by asking them to sign a message with their private key.

We will be utilizing Web3.js to handle user authentication. Here’s an example:

//javascript

const Web3 = require('web3');
const web3 = new Web3('https://alfajores-forno.celo-testnet.org');

async function authenticateUser(walletAddress, privateKey) {
  const signedMessage = await web3.eth.accounts.sign(walletAddress, privateKey);
  // Verify the signed message and authenticate the user
}

step 7 Integrate 3Box:

3Box allows users to store and retrieve data in a decentralized manner using IPFS.
Install the 3Box library by running the following command:

npm install 3box

Initialize 3Box and authenticate the user.

//javascript

const Box = require('3box');

async function authenticateWith3Box() {
  const box = await Box.create(web3.currentProvider);
  await box.auth(['social-network:read', 'social-network:write']);
  // Other 3Box setup code
}

Step 8: Implement Social Network Functionality

User Profile Creation and Editing:

Provide a user interface for users to create and edit their profiles.
Implement a form where users can enter their profile information, such as username, profile picture, bio, contact details, and social media links.
Utilize the 3Box SDK and APIs to store and retrieve profile data from the user’s 3Box space.
Post Creation and Display:

Implement a feature that allows users to create and publish posts.
Provide an interface where users can enter the content of their posts.
Use the Celo blockchain to store the necessary data for posts, such as the post content, author address, timestamp, and any associated metadata.
Retrieve and display posts from the Celo blockchain in the user interface.
Following and Followers:

Implement functionality for users to follow or unfollow other users within the social network.
Maintain a list of followers and the users being followed for each user.
Use smart contracts to manage the relationships between users and update the follower/following counts.

Likes and Comments:

Allow users to like and comment on posts.
Store the number of likes and comments for each post using the Celo blockchain or an external storage solution.
Implement functions to update the like and comment counts and display them in the user interface.

Privacy Settings:

Develop mechanisms to manage privacy settings for user profiles, posts, and interactions.
Enable users to control the visibility of their profile information and choose who can see their posts and interact with them.
Implement privacy-related functions in the smart contracts and utilize the 3Box SDK to store and retrieve privacy settings from the user’s 3Box space.
Example Code for Post Creation:

Here’s an example of how you can implement the functionality for creating a post using web3.js and interacting with the Celo blockchain:

//javascript

import Web3 from 'web3';

const web3 = new Web3('https://alfajores-forno.celo-testnet.org');
const postStorageContractAddress = '0x987654321...'; 
// Address of deployed PostStorage contract

async function createPost(content) {
    try {
        const accounts = await web3.eth.requestAccounts();
        const userAddress = accounts[0];
        const postStorageContract = new web3.eth.Contract(PostStorageABI, postStorageContractAddress);
        await postStorageContract.methods.createPost(content).send({ from: userAddress });
        console.log('Post created successfully!');
    } catch (error) {
        console.error('Failed to create post:', error);
        // Handle post creation errors
    }
}

Here, the createPost function allows a user to create a post by calling the createPost function in the PostStorage smart contract deployed on the Celo blockchain.

Step 9: Implement User Interface:

Using React.js we would design and build an intuitive user interface (UI)
and integrate with the Celo and 3Box functionalities, and provide a seamless user experience.

Design the user interface:
We’ll Design our social network user interface, including components for user profiles, post feeds, comment sections, and messaging.

Implement web3.js and Celo integration:
Use the web3.js library to interact with the Celo blockchain, including retrieving user account addresses, sending transactions, and interacting with smart contracts.

retrieving the current user’s account address using web3.js:

//javascript

import Web3 from 'web3';

const web3 = new Web3(Web3.givenProvider);

const getAccountAddress = async () => {
  const accounts = await web3.eth.getAccounts();
  return accounts[0];
}

Integrate the 3Box SDK:
We are going to use the 3Box SDK to interact with the user profiles and data storage.

//javascript

import Box from '3box';

const loadProfileData = async (address) => {
  const box = await Box.openBox(address, window.ethereum);
  const profile = await box.public.get('profile');
  return profile;
}

Implement social network functionality:
Using Celo smart contracts and the 3Box SDK to implement social network functionality, such as creating user profiles, posting content, following other users, and commenting on posts.
Here’s the code:

//javascript

import Web3 from 'web3';
import MySocialNetwork from './MySocialNetwork.json';

const web3 = new Web3(Web3.givenProvider);

const createPost = async (content) => {
  const mySocialNetwork = new web3.eth.Contract(MySocialNetwork.abi, MySocialNetwork.address);
  const account = await getAccountAddress();
  const result = await mySocialNetwork.methods.createPost(content).send({from: account});
  return result;
}

Build the user interface components:
Build React components for your social network user interface, including those for user profiles, post feeds, comment sections, and messaging.
Here’s an example of a post feed component that displays posts from the smart contract and allows users to like and comment:

//javascript

import React, { useState, useEffect } from 'react';
import Web3 from 'web3';
import MySocialNetwork from './MySocialNetwork.json';

const web3 = new Web3(Web3.givenProvider);

const PostFeed = () => {
  const [posts, setPosts] = useState([]);

  const loadPosts = async () => {
    const mySocialNetwork = new web3.eth.Contract(MySocialNetwork.abi, MySocialNetwork.address);
    const result = await mySocialNetwork.methods.getPosts().call();
    setPosts(result);
  }

  useEffect(() => {
    loadPosts();
  }, []);

  const handleLike = async (postId) => {
    const mySocialNetwork = new web3.eth.Contract(MySocialNetwork.abi, MySocialNetwork.address);
    const account = await getAccountAddress();
    await mySocialNetwork.methods.likePost(postId).send({from: account});
    loadPosts();
  }

  const handleComment = async (postId, comment) => {
    const mySocialNetwork = new web3.eth.Contract(MySocialNetwork.abi, MySocialNetwork.address);
    const account = await getAccountAddress();
    await mySocialNetwork.methods.commentOnPost(postId, comment).send({from:
account});
loadPosts();
}

return (
<div>
{posts.map(post => (
<div key={post.id}>
<p>{post.content}</p>
<button onClick={() => handleLike(post.id)}>Like</button>
<input type="text" onChange={(e) => setComment(e.target.value)} />
<button onClick={() => handleComment(post.id, comment)}>Comment</button>
</div>
))}
</div>
);
}

Step 10: Test and Debug:

Thoroughly test your application to ensure all functionalities are working as expected.
Use testing frameworks like Jest or Mocha to write unit tests and simulate user interactions.
Debug any issues that arise during the testing phase.

Writing Test Cases with Jest:

// Test case for user registration
import { render, fireEvent } from '@testing-library/react';
import RegistrationForm from './RegistrationForm';

test('registers a new user', () => {
  // Render the registration form
  const { getByLabelText, getByText } = render(<RegistrationForm />);

  // Fill in the form fields
  fireEvent.change(getByLabelText('Username'), { target: { value: 'testuser' } });
  fireEvent.change(getByLabelText('Email'), { target: { value: 'testuser@example.com' } });
  fireEvent.change(getByLabelText('Password'), { target: { value: 'test123' } });

  // Submit the form
  fireEvent.click(getByText('Register'));

  // Assert that the user is registered successfully
  expect(getByText('Welcome, testuser!')).toBeInTheDocument();
});

Testing Smart Contracts with Truffle:

//javascript

//test case for creating a post
const MySocialNetwork = artifacts.require('MySocialNetwork');

contract('MySocialNetwork', (accounts) => {
  it('creates a new post', async () => {
    const mySocialNetwork = await MySocialNetwork.deployed();
    const content = 'Hello, world!';
    const result = await mySocialNetwork.createPost(content, { from: accounts[0] });
    const postId = result.logs[0].args.postId.toNumber();
    
    // Assert that the post is created successfully
    assert.equal(await mySocialNetwork.getPostContent(postId), content);
  });
});
//Debugging with console.log:

// Example of adding console.log statements for debugging
const createPost = async (content) => {
  console.log('Creating post:', content);
  const mySocialNetwork = new web3.eth.Contract(MySocialNetwork.abi, MySocialNetwork.address);
  const account = await getAccountAddress();
  const result = await mySocialNetwork.methods.createPost(content).send({ from: account });
  console.log('Post created:', result);
  return result;
};
//Mocking API Responses for Integration Testing:

jest.mock('3box', () => ({
  openBox: jest.fn().mockImplementation(() => ({
    public: {
      get: jest.fn().mockResolvedValue({ name: 'John Doe' }),
    },
  })),
}));

test('displays user profile', async () => {
  // Render the user profile component
  const { getByText } = render(<UserProfile address={userAddress} />);

  // Wait for the profile data to load
  await waitFor(() => expect(getByText('John Doe')).toBeInTheDocument());
});

step 11: Deploy and Launch:

Choose a hosting platform: Select a hosting platform that meets your needs and deploy your smart contracts and user interface to the chosen platform. You can use services like Heroku, AWS, or Azure.

Deploy smart contracts: Deploy your smart contracts to the Celo network. We are going to be using Truffle to deploy our smart contracts.

Configure and deploy user interface: Once our smart contracts are deployed, configure your user interface to interact with them.

Test: After deploying your application, thoroughly test it to ensure it’s working as expected. You can use tools like Ganache or the Celo Testnet to test your application.

Here is the sample code for deploying smart contracts using Truffle:
Create a new Truffle project:

mkdir my-project
cd my-project
truffle init

Write your smart contracts:

// SimpleStorage.sol

contract SimpleStorage {
    uint256 private _value;

    function getValue() public view returns (uint256) {
        return _value;
    }

    function setValue(uint256 value) public {
        _value = value;
    }
}

//Compile your smart contracts:
truffle compile

//Configure your deployment network:

// truffle-config.js
module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*", // Match any network id
    },
    celo: {
      provider: () =>
        new HDWalletProvider(mnemonic, "https://forno.celo.org"),
      network_id: 42220,
      gas: 8000000,
      gasPrice: 1000000000, // 1 gwei
    },
  },
};

Deploy your smart contracts:

truffle migrate --network celo

Here is some sample code for deploying a user interface using Create React App:

Install Create React App:

npm install -g create-react-app
Create a new React project:
create-react-app my-app
cd my-app

Install required dependencies:

npm install @celo/contractkit web3
Configure your Web3 provider:
//javascript

import Web3 from 'web3';
import { newKit } from '@celo/contractkit';

const provider = window.ethereum;
await provider.enable();

const web3 = new Web3(provider);
const kit = newKit('https://forno.celo.org', web3);

//Interact with your smart contracts:
import SimpleStorage from './contracts/SimpleStorage.json';

const contract = new kit.web3.eth.Contract(
  SimpleStorage.abi,
  SimpleStorage.networks['42220'].address
);
const value = await contract.methods.getValue().call();
await contract.methods.setValue(42).send({ from: kit.defaultAccount });

Conclusion​

This tutorial has taught us how to Build a Celo-based social network using 3Box on the Celo Blockchain. Understanding Celo and 3Box was the first step, installing and setting up the 3Box was the next step, Connecting to Celo Blockchain, Designing User Profiles and Data Model, Implementing User Authentication, Integrating 3Box, Implementing Social Network Functionality, Implementing User Interface, Testing, Debugging and Deployment were the steps taken accordingly during creation.

Next Steps​

Now we have a good knowledge of how to build a celo-based social network using 3Box, we can now go ahead to customize our user Interface, touch other areas and expand on making a fully optimized and responsive UI and making sure it suits the blockchain standard.
Here is the source code for our project

About the Author​

Ernest Nnamdi is a Web3, Solidity, Python developer and content creator with over 5 years of experience in the tech industry. He has always been fascinated by emerging technologies and have a strong passion for blockchain and its potential to change the world.
Connect with me on Twitter

References​

4 Likes

@erniest i will be reviewing this

1 Like

Hi @erniest , maybe you can be reviewed by @4undRaiser

1 Like

@erniest Interesting tutorial

Can you make subheadings like this bold?

1 Like

@erniest also a github repository containing all the code used in this tutorial is needed

2 Likes

If you have any question, let me know

1 Like

@4undRaiser here

1 Like

@erniest you can make this sub heading and others bold by putting them in between a double asterik ** **

good job with the github repo

1 Like

@erniest any update yet?

1 Like

@4undRaiser Yes, I have made the corrections.

3 Likes

@erniest you can move to publish now

1 Like

@4undRaiser Alright moved

2 Likes

Very Insightful, welldone.

1 Like