Uh oh! Looks like JavaScript is disabled.

Bitman requires JavaScript to fuel his thirst to end bad UX and lazy design, which is necessary to give you the best viewing experience possible. Please enable it to continue to our website.

/web - 5 min read

Blockchain as public ledger

Rahul Nitin Padalkar

Rahul Nitin Padalkar

Developer

Blockchain FTW

Using smart contracts to efficiently store information on the blockchain

We recently completed a project in the IP protection and copyright space. The core idea of the product was to use blockchain as a ledger to record information on ownership of artwork and it's metadata. Artwork here, is used in the more broader sense covering various media formats like images, videos, text, code, audio etc.

The product was a quasi-social-media application with options to like, share and collaborate on an artwork. As far as tech is concerned, we developed a mobile application with Flutter as a frontend. The backend was NodeJS with AdonisJS on top. Adonis provides features like ORM (Lucid ORM), request validators, authentication and database migration tool.

The Problem

The foundations of the product lay in the idea of being able to prove ownership of a piece of artwork. Along with that we also wanted to record interactions like viewing, liking, sharing and collaborating on the artwork. This requirement was particularly challenging since we had to record the interaction data (which is generated frequently) in the blockchain. Writing to the blockchain can take time depending on the traffic and also get expensive. So we had to find a fast yet cost effective way to store information on the blockchain even when the application scales to hundreds of thousands of users.

The Solution

We decided to use a tool, Metakeep, rather than interacting with the blockchain directly. Metakeep provides a Node SDK along with the REST endpoints to interact with the polygon blockchain. For recording ownership of an artwork we decided to use NFTs. All artwork uploaded to the platform would be minted as an NFT using Metakeep along with the owner and collaborators (if any) wallet addresses as metadata information. One thing we observed is Metakeep lists the minted NFTs in the OpenSea marketplace. There was no way atleast from the API to tweak this. Since the platform demanded exclusivity we replaced the actual artwork with a placeholder/default image and recorded the file hash along with other metadata information.

To mint an NFT we used the mint endpoint made available by Metakeep. The pseudocode would look like below

export default function mint({auth, request, response}) {
    const payload = request.validate(MintValidator)
    let file_hash = FileHelper.getFileHash(payload.file)

    axios.post({
        url: MINT_URL,
        headers: {
          'accept': 'application/json',
          'Idempotency-Key': `some-random-string`,
          'content-type': 'application/json',
          'x-api-key': METAKEEP_API_KEY,
        },
        data: {
            nft: { collection: COLLECTION_ADDRESS },
            to: { email: EMAIL },
            metadata: {
                name,
                description,
                image
                attributes: {
                    collaborators: ['wallet-address-1','wallet-address-2']
                    creators: ['wallet-address-3','wallet-address-4']
                    file_hash
                }
            }
        }
    })

}

With this we were successfully able to mint an NFT and see it appear in the blockchain. For the next part ie. storing interaction information in the blockchain, required us to write a smart contract and then deploy it to Metakeep's infrastructure. We used Solidity to write a smart contract and Hardhat to compile it. The abi from the compilation step was then used to deploy it to the Metakeep infrastructure.

Intially we decided to create a state variable and then store the interaction information in it. But we quickly realised that as the application scales, storing information in the blockchain will get expensive and slow. Events to the rescue! Rather than storing the information on the chain we decided to emit that information using an event. The data emitted by an event is not stored in the state of a smart contract. It is recorded in a transaction receipt and stored in the block. This can then be accessed and queried using Metakeep API or blockchain explorers like polyscan.

To implement this we first had to write a simple smart contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "metakeep-lambda/ethereum/contracts/MetaKeepLambda.sol";

contract InteractionsData is MetaKeepLambda {

    constructor(address lambdaOwner, string memory lambdaName) MetaKeepLambda(lambdaOwner, lambdaName) {}

    event SaveInteractionData(string interactionData);

    function logInteractionData(string calldata eventData) public {
      emit SaveInteractionData(eventData);
    }
}

To compile this smart contract we setup a hardhat project and placed this under contracts folder. To compile we ran,

npx hardhat compile

The abi from the compiled contract generated in the artifacts/contracts folder was then passed to Metakeep for creating a lambda.

To register a lambda we used the lambda/create endpoint,

async function registerLambda() {
  const { ethAddress } = await getDeveloperWalletAddress()
  const body = {
    constructor: { args: [ethAddress, "StoreArkData"] },
    abi: contractData["abi"],
    bytecode: contractData["bytecode"]
  }
  const res = await fetch(`${METAKEEP_LAMBDA_BASE_URL}/create`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(body)
  })
  const data = await res.json()
  return data
}

To trigger a lambda we used lambda/invoke endpoint,

async function triggerLambda(resData: string, transaction_type: string) {
  const body = {
    lambda: `${process.env.METAKEEP_LAMBDA_ADDRESS}`,
    function: { name: "triggerEvent", args: [resData] },
    description: { text: `Store data in blockchain for ${transaction_type}` }
  }

  const res = await fetch(`${METAKEEP_LAMBDA_BASE_URL}/invoke`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(body)
  })
  const data = await res.json()
}

With this we were able to store the artwork in the blockhain and the interaction data in the blockchain with fast and cost-effective way.

Key Takeaways

  1. Storing data in a state variable in a smart contract is not cost effective. Storing it in transaction receipt at fraction of the cost is a better alternative.
  2. Metakeep provides user friendly apis and abstracts away the complexity of dealing with blockchains.
  3. Since Truffle is being sunset and will no longer receive updates, Hardhat serves as a strong alternative.

Conclusion

We were not only able to meet the client's requirements but also helped them save money in the long run. The client was happy with our implementation and the platform is now live for artists and creators.


Rahul Nitin Padalkar

Rahul Nitin Padalkar

Developer

He is still thinking what to write about him


Let’s build digital solutions together.
Get in touch
->
Lenny Face