DistributedTown is a multicomponent system, designed to work in a modular way. The platform is based on the idea of a public distributed user-driven blockchain-agnostic architecture.
The technical stack of the application is the following:
Smart contracts for achieving the distributed immutable trusted execution. The smart contracts are implemented in Solidity and are deployed on top of several blockchain networks - Matic, Ethereum, RSK.
Off-chain service - backend API implemented with NodeJS and expressJS.
Off-chain storage - threadDB designed to have secure threads per community. The data of the different communities are separated on different threads which ensures the privacy and independence of the communities.
Off-chain messaging system - Mailbox API is used for intercommunication between the communities.
Frontend - ReactJS application for the UI.
DistributedTown is build to be blockchain-agnostic. The addresses of the smart contracts of each community are stored securely in the off-chain storage. The FrontEnd queries those addresses and calls the smart contracts accordingly.
In order to achieve easy and free access of the user to the platform, DistributedTown abstracts away gas to minimize onboarding by using GSN. DistributedTown currently uses openGSN.
The DistributedTown's off-chain vs on-chain sync is crucial for the correct behavior of the network. In order to achieve this reliability, DistributedTown uses Chainlink for verification of the data.
Chainlink is used in the following cases:
Calculation and assigning DiTo credits on user creation
When a SkillWallet is created, the user gets assigned a certain amount of credits, depending on their skills. This calculation is made in the DistributedTown's backend. Then a smart contract is called for storing these credits. The smart contract calls the backend in order to get the calculated DiTo credits, instead of passing them as a parameter of the smart contract. This way we ensure that the platform doesn't have security flaws such as calling the join function with the credits as a parameter.
Verifying Gig when taking/accepting/completing
The backend server generates a hash for each gig. When taking/accepting/completing a gig this hash gets verified. The request is sent by the oracle to ensure that the off-chain data hasn't been modified.
Community.sol smart contract is the backbone of the DistributedTown on-chain logic. It is responsible for the community management and also for deploying the new community, treasury, and token contracts when a new community is created. For more information about these flows refer to the Community docs.
The user can either use their own wallet and authenticate with Metamask or can generate a brain wallet, by registering with a username and password. The requests to the smart contracts are signed with the user certificates, with either ethers.js or Metamask.
In order to ensure secure requests from the Frontend to the Backend, we generate an authentication token when the user logs in. The diagram below describes the flow. A nonce is generated for each user, the user signs a request with this nonce and sends it back to the backend. The backend generates a JWT token out of this and changes the nonce. The nonce is always unique, which ensures that nobody can guess or reuse an old user token.
DistributedTown is OWASP compliant. Moving forward we'll focus on implementing end-to-end tests for the most common security flaws.
Rate limits - in order to protect you against slow performance and denial-of-service (DoS) attacks, we have rate limits per request
Injections - frameworks such as react don't allow the most common injections such as SQL injection.
Deployment and networking