Skip to content

Instantly share code, notes, and snippets.

@melnikaite
Created February 27, 2022 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melnikaite/58bbff5448cde3fd98dd2f40814d4914 to your computer and use it in GitHub Desktop.
Save melnikaite/58bbff5448cde3fd98dd2f40814d4914 to your computer and use it in GitHub Desktop.
Onchain Metadata

This technic I used only for private networks because it's expensive in Ethereum Mainnet, however, once cheap L2 solutions are so popular now, I decided to share this. Blockchain explorers understand very well what is going on only in standard well-known types of contracts and show data in a human-readable way. But all other contracts unfortunately are not readable in the explorer interface. To fix this we can save formatting options inside a smart contract.

Metadata can also keep some other important messages, descriptions, instructions, or even advertizement. Third-party applications can implement subscription to metadata changes you are interested in or just show actual ones. If your contract ABI is intuitively understandable then you might not even need any UI and your application will be truly decentralized.

// SPDX-License-Identifier: MIT
pragma solidity 0.8;
contract owned {
constructor() { owner = msg.sender; }
address owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
}
contract withMetadata is owned {
mapping(bytes32 => string) public metadata;
bytes32[] public metadataKeys;
function find(bytes32 key) public view returns (bool, uint) {
for (uint i = 0; i < metadataKeys.length; i++) {
if (metadataKeys[i] == key) return (true, i);
}
return (false, 0);
}
function updateMetadata(bytes32 key, string memory value) onlyOwner public {
metadata[key] = value;
(bool keyExists, uint keyIndex) = find(key);
if (keyExists && keccak256(abi.encodePacked(value)) == keccak256(abi.encodePacked(""))) {
metadataKeys[keyIndex] = metadataKeys[metadataKeys.length - 1];
metadataKeys.pop();
} else if (!keyExists) metadataKeys.push(key);
}
function metadataKeysList() public view returns (bytes32[] memory) {
return metadataKeys;
}
}
contract YourContract is withMetadata {
// your logic
}
youContract.updateMetadata.sendTransaction(web3.utils.asciiToHex('abi'), JSON.stringify([
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint32",
"name": "day",
"type": "uint32",
"format": {
"multiplier": 1000,
"locale": "YYYY-MM-DD"
}
},
{
"indexed": false,
"internalType": "uint64",
"name": "energy",
"type": "uint64",
"format": {
"multiplier": 0.01,
"precision": 2,
"measurement": "kWh"
}
}
],
"name": "Deal",
"type": "event"
}
]));
abi.inputs.filter(i => i.format).forEach(i => {
if (i.format.multiplier) decodedEvent[i.name] = decodedEvent[i.name] * i.format.multiplier;
if (i.format.precision) decodedEvent[i.name] = decodedEvent[i.name].toFixed(i.format.precision);
if (i.format.locale) decodedEvent[i.name] = moment.utc(decodedEvent[i.name]).format(i.format.locale);
if (i.format.measurement) decodedEvent[i.name] = `${decodedEvent[i.name]} ${i.format.measurement}`;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment