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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bvm.network/bvm/bitcoin-dapps/evm-code-tutorials/decentralized-discord.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
