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: MITpragmasolidity ^0.8.17;contract Discord {structServer { address creator;string serverName; }structChannel { address creator;string serverName;string channelName; }structMessage { 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;functioncreateServer(stringmemory_sname) public { require(keccak256(abi.encodePacked(servers[_sname].serverName)) == keccak256(abi.encodePacked("")), "The server name is existed already");
servers[_sname] =Server( msg.sender, _sname ); }functionjoinServer(stringmemory_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; }functioncreateChannel(stringmemory_sname,stringmemory_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 ); }functionpostMessage(stringmemory_sname,stringmemory_cname,stringmemory_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.
Make sure the accounts in hardhat.config.ts have some $BVM.
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 servernpxhardhatcreateServer--contract<your-contract-address>--snameserver1# join an existing servernpxhardhatjoinServer--contract<your-contract-address>--snameserver1# create a new channel on an existing servernpxhardhatcreateChannel--contract<your-contract-address>--snameserver1--cnamechannel1# post a message to a created channelnpx hardhat postMessage --contract <your-contract-address> --sname server1 --cname channel1 --message "The new Bitcoin city"
# get all messages from a channelnpxhardhatgetMessages--contract<your-contract-address>--snameserver1--cnamechannel1