Comment on page
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
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]);
}
}
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
To compile your contracts, use the built-in
hardhat compile
task.cd smart-contract-examples
npm install
npx hardhat compile
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.
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