May 2, 2019 Knowledge Center

How decentralized reputation works: Monetha’s reputation widget

This article is technical: it assumes some programming and blockchain knowledge.

The article is based on our reputation-widget-example app which lets you build the Monetha widget by yourself using our Reputation JS SDK.


Behold our humble reputation widget:

It’s a visual representation of our users’ basic identification and reputation info. The widget can be used by anyone with a Monetha account to share their online reputation built with our products. For now, that would be the dealmaking app and the payment gateway.

Behind the pretty veneer there’s a short snippet of code. Ideally, you should be able to paste it on any website:

<div
  id="banner-no-badges-uyXBeAJcMucIMotrSEKWK5mMCceN6YGsSdGshRqbRDL"
  class="monetha-reputation-snippet"
  data-profile-hash="uyXBeAJcMucIMotrSEKWK5mMCceN6YGsSdGshRqbRDL"
  data-snippet-name="banner-no-badges"
  data-version="1.0.0">
</div>
<script defer src="https://www.monetha.io/reputation-snippet.js?v=11"></script>

But where does this data come from?

While outwardly they might look the same, our user profiles actually have two states. In the first state, all data is stored and retrieved from a central database via Monetha’s API. This is the default option for Monetha users. In other words, no one prevents us from censoring that data, tampering with it, or removing access to it on a whim to lock you into the platform. Not good. 

The second state is different: is stores all of the important user information on a distributed ledger. To enable it, we have a pretty blue prompt on the app and website, offering our users to upgrade their profile into a portable Reputational Identity:

A few words about the Reputational Identity

The Reputational Identity is our term for a smart contract that acts as data storage for information about the Reputational Identity’s owner. It is accompanied by auxiliary contracts responsible for tasks like Reputational Identity creation and data reading/writing logic. Through these contracts, various facts providers are able to store information in the user’s Reputational Identity without any centralized mechanism.

When a user agrees to update their profile into a Reputational Identity, several things take place:

  1. A designated Reputational Identity factory contract deploys a new Reputational Identity.
  2. The Reputational Identity contract gets linked to the Reputational Identity logic registry which stores models describing how the Reputational Identity can behave. These models are upgradeable and controlled by Monetha.
  3. After the Reputational Identity is created, the user confirms its ownership.
  4. Monetha starts provisioning information on a scheduled basis. Only public information such as the first name, avatar image, number of deals made and the person’s reputation score is stored in the Reputational Identity.

More information on providing facts to a Reputational Identity can be found here (Golang SDK) and here (Javascript SDK). But enough about data entry for now. Instead, let’s investigate how the widget gets its contents from the blockchain.

Reading data from the Reputational Identity

To retrieve the necessary data, Monetha’s reputation widget makes use of our Reputation JS SDK. Three things are necessary to initialize the SDK:

  1. JSON RPC URL of the Ethereum node that will be used to retrieve our data.
  2. Ethereum address of the fact provider who is provisioning the data to the Reputational Identity. In our case that would be Monetha.
  3. Ethereum address of the Reputational Identity where the data is kept.

At the moment, Monetha’s reputation framework doesn’t limit fact providers on how facts should be stored. They are free to choose between data types such as integer, string, or file. In order to read the data, information about the data storage schema is needed.

In our case, we access the necessary data by aggregating three different keys. You can see how it is retrieved in the getDataFromPassport() method from our reputation widget example:

  • profile – this is the user’s name, nickname, and verification status.
  • deal_stats – the user’s star score, reputation score, and signed deal count.
  • profile_image – the user’s hopefully happy face.

The first two keys are stored directly on the blockchain. The third one, however, is an image. Because Ethereum is not suited for large chunks of data (the gas fees are no joke!), we put the file on IPFS and only write its hash to the distributed ledger.

Here’s how data retrieval looks in code:

    // Monetha stores facts in multiple keys in order to optimize the costs of updating the data
    // 'profile' a json object containing the following
    /*
    {
      "name": "",
      "nickname": "",
      "is_verified": ""
    }
    */
    const FACT_KEY_PROFILE = 'profile';

    // 'deal_stats' a json object containing the following
    /*
    {
      "star_score": 0,
      "reputation_score": 0,
      "signed_deals_count": 0
    }
    */
    const FACT_KEY_DEAL_STATS = 'deal_stats';

    // 'profile_image' a string value of the IPFS blob reference
    const FACT_KEY_PROFILE_IMAGE = 'profile_image';

    // Retrieval of `profile` data
    const profileResponse = await reader.getTxdata(FACT_PROVIDER_ADDRESS, FACT_KEY_PROFILE);
    const profile = JSON.parse(profileResponse);

    if (profile) {
      data.name = profile.name;
      data.nickname = profile.nickname;
    }

    // Retrieval of `deal_stats` data
    const dealStatsResponse = await reader.getTxdata(FACT_PROVIDER_ADDRESS, FACT_KEY_DEAL_STATS);
    const dealStats = JSON.parse(dealStatsResponse);

    if (dealStats) {
      data.reputationScore = dealStats.reputation_score;
      data.starScore = Number((parseFloat(dealStats.star_score) / 100).toFixed(2));
      data.signedDealsCount = dealStats.signed_deals_count;
    }

    // Retrieval of `profile_image`
    const ipfsClient = await getIPFSClient();
    const profileImgUrl = await reader.getIPFSData(FACT_PROVIDER_ADDRESS, FACT_KEY_PROFILE_IMAGE, ipfsClient);

    if (profileImgUrl) {
      data.avatarUrl = profileImgUrl;
    }

    return data;

Giving the widget form

However, the job is not done yet. We were able to get the data, but it in this form it’s nothing more than some numbers and a picture. We need to give it the familiar Monetha flair. This time we’ll use two methods from our SDK to complete the task: renderReputationWidget() and renderProfileImage().

And now for the code:

private renderReputationWidget() {
        const { profile } = this.state;

        if (!profile) {
        return null;
        }

        return (
            <div className='reputation-widget-wrapper'>
                <div className='reputation-widget'>

                    {profile.nickname && <a className='profile-link' href={`https://www.monetha.io/profile/${profile.nickname}`} target='_blank' rel='noopener noreferrer' />}

                    <div className='profile-info'>
                        <div>
                            {this.renderProfileImage()}
                        </div>

                        <h4 className='profile-name'>{profile.name}</h4>

                        {profile.nickname &&
                            <a className='share-icon' href={`https://www.monetha.io/profile/${profile.nickname}`} target='_blank' rel='noopener noreferrer'>
                                <img src={`https://www.monetha.io/assets/snippets/share.png`} alt='share' />
                            </a>
                        }
                    </div>

                    <div className='deal-stats'>
                        <div className='reputation-score'>
                            <div>{profile.reputationScore}</div>
                            <img src={`https://www.monetha.io/assets/snippets/mth.png`} alt='mth' />
                        </div>
                        <div>
                            <img src={`https://www.monetha.io/assets/snippets/star.png`} alt='star' />
                            <div>{profile.starScore}</div>
                        </div>
                    </div>
                </div>

                <div className='powered-by'>
                    <h5 className='powered-by-text'>Powered by</h5>
                    <a href={`https://www.monetha.io`} target='_blank' rel='noopener noreferrer'>
                        <img src={`https://www.monetha.io/assets/snippets/logo.png`} alt='logo' />
                    </a>
                </div>
            </div>
        );
    }

    private renderProfileImage() {
        const { profile } = this.state;

        if (!profile) {
            return null;
        }

        let profileImage = null;
        if (profile.avatarUrl) {
            profileImage = <div className='profile-image' style={{ backgroundImage: `url('${profile.avatarUrl}')` }} />
        }

        return (
            <div className='profile-image-wrapper'>
                <div className='profile-first-letters'>
                    {getFirstLetters(profile.name, 3)}
                </div>

                {profileImage}
            </div>
        );
    }

Just like that, we’ve made Monetha’s reputation widget! Let’s take another look at our accomplishment:

In the same way, any service can become a fact provider and use the Reputational Identity to store data they consider important or think that it should be available to everyone. The Reputational Identity’s owner can then share this information for his or her benefit, similarly to how our users do with the Monetha widget. We cannot censor this data, we cannot tamper with it, and we certainly can’t prevent from using it anywhere the Reputational Identity owner wishes to.

This, in our eyes, makes for a reputation that is truly decentralized.

Thank you for reading!


If you would like to play around with the widget by yourself, have a look at our example app which will let you run through the process from start to finish.

Feel free to read more about Monetha’s Decentralized Reputation Framework and contribute to its development.

If you have any questions or would like to collaborate, shoot us an email at [email protected].


Share