# 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.

```solidity
// 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**.

```bash
git clone https://github.com/trustlesscomputer/smart-contract-examples.git
```

## Compile the contracts

To compile your contracts, use the built-in `hardhat compile` task.

```bash
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.&#x20;

We'll deploy Trustless Discord on Layer 2, because it needs low latency.

```js
  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`.

```bash
npx hardhat deploy --tags Discord
```

{% hint style="warning" %}
Make sure the accounts in hardhat.config.ts have some $BVM.
{% endhint %}

## 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.

```bash
# 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
```
