Decentralized Discord

Let's build Trustless Discord, a decentralized, unstoppable, and open messaging application.
  • create a new server
  • join an existing server
  • create a channel on an existing server
  • post a message to the created channel
  • get all messages posted to a channel

Write the Trustless Discord smart contract

It turns out that writing the Trustless Discord smart contract is very simple. Here is a basic contract to provide a decentralized social application.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Discord {
struct Server {
address creator;
string serverName;
}
struct Channel {
address creator;
string serverName;
string channelName;
}
struct Message {
address sender;
string message;
}
mapping(string => Server) public servers;
mapping(address => mapping(string => uint8)) public joinInfo;
mapping(string => Channel) public channels;
mapping(string => mapping(string => Message[])) public messages;
function createServer(string memory _sname) public {
require(keccak256(abi.encodePacked(servers[_sname].serverName)) == keccak256(abi.encodePacked("")), "The server name is existed already");
servers[_sname] = Server(
msg.sender,
_sname
);
}
function joinServer(string memory _sname) public {
require(keccak256(abi.encodePacked(_sname)) != keccak256(abi.encodePacked("")), "Server name must be not empty");
require(keccak256(abi.encodePacked(servers[_sname].serverName)) != keccak256(abi.encodePacked("")), "The server name is not existed yet");
require(joinInfo[msg.sender][_sname] == 0, "You have joined the server already");
joinInfo[msg.sender][_sname] = 1;
}
function createChannel(string memory _sname, string memory _cname) public {
require(keccak256(abi.encodePacked(_sname)) != keccak256(abi.encodePacked("")), "Server name must be not empty");
require(keccak256(abi.encodePacked(_cname)) != keccak256(abi.encodePacked("")), "Channel name must be not empty");
require(keccak256(abi.encodePacked(servers[_sname].serverName)) != keccak256(abi.encodePacked("")), "The server name is not existed yet");
channels[_cname] = Channel(
msg.sender,
servers[_sname].serverName,
_cname
);
}
function postMessage(string memory _sname, string memory _cname, string memory _message) public {
require(joinInfo[msg.sender][_sname] != 0, "You have not joined the server");
require(keccak256(abi.encodePacked(channels[_cname].channelName)) != keccak256(abi.encodePacked("")), "The channel is not existed yet");
Message memory newMsg = Message(
msg.sender,
_message
);
messages[_sname][_cname].push(newMsg);
}
function getMessages(string memory _sname, string memory _cname) public view returns (string memory, string memory, Message[] memory) {
return (_sname, _cname, messages[_sname][_cname]);
}
}

Clone the smart contract examples

We've prepared a few different examples for you to get started. The Messenger example is located at smart-contract-examples/contracts/Discord.sol.
git clone https://github.com/trustlesscomputer/smart-contract-examples.git

Compile the contracts

To compile your contracts, use the built-in hardhat compile task.
cd smart-contract-examples
npm install
npx hardhat compile

Deploy the contracts

Review config file hardhat.config.ts. The network configs should look like this.
We'll deploy Trustless Discord on Layer 2, because it needs low latency.
networks: {
mynw: {
url: "https://nos-testnet.trustless.computer/",
accounts: {
mnemonic: "<your mnemonic with funds>"
},
timeout: 100_000,
},
blockscoutVerify: {
blockscoutURL: "https://explorer.nos-testnet.trustless.computer",
...
}
}
Run the deploy scripts using hardhat-deploy.
npx hardhat deploy --tags Discord
Make sure the accounts in hardhat.config.ts have some TC.

Interact with the contracts

Once the contracts are deployed, you can interact with them. We've prepared a few hardhat tasks to make it easy for you to interact with the contracts.
# create a new Discord server
npx hardhat createServer --contract <your-contract-address> --sname server1
# join an existing server
npx hardhat joinServer --contract <your-contract-address> --sname server1
# create a new channel on an existing server
npx hardhat createChannel --contract <your-contract-address> --sname server1 --cname channel1
# post a message to a created channel
npx hardhat postMessage --contract <your-contract-address> --sname server1 --cname channel1 --message "The new Bitcoin city"
# get all messages from a channel
npx hardhat getMessages --contract <your-contract-address> --sname server1 --cname channel1