Intermediate
Gas Optimisation Basics — Kudos build — optimization pass
Write cheaper, cleaner code.
Developer Intermediate
5/6 — Gas Optimisation Basics — Kudos build — optimization pass
Objective Make the Kudos badge/token flows cheaper without losing clarity.
Blockchains solve coordination problems, not just financial ones.
Flow Add batch minting for badges, cache lengths, and keep unchecked blocks documented. Snapshot gas before/after.
What to write
- Batch mint
Loop with cached length and documented unchecked increment.function batchMint(address[] calldata tos, string[] calldata uris) external onlyRole(MINTER_ROLE) { uint256 len = tos.length; require(len == uris.length, "len mismatch"); uint256 id = _nextId; unchecked { for (uint256 i; i < len; i++) { _safeMint(tos[i], id); _setTokenURI(id, uris[i]); id++; } } _nextId = id; }Caching length + unchecked increment trims gas while remaining safe.
- Pack + cache storage
Pack small fields; cache SLOADs in memory.struct BadgeMeta { uint64 minted; uint64 burned; uint128 reserved; } mapping(uint256 => BadgeMeta) internal _meta; function stats(uint256 id) external view returns (uint64 minted, uint64 burned) { BadgeMeta memory m = _meta[id]; // single SLOAD return (m.minted, m.burned); }Packing and caching reduce SLOADs; keep types documented to avoid layout mistakes.
- Measure
Record before/after gas for hot paths.Keep only optimizations with meaningful savings.
Why Batching reduces gas per badge; documenting unchecked math and measuring deltas keeps optimizations safe and defensible.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract KudosBadge is ERC721URIStorage, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
uint256 private _nextId = 1;
string private _base;
struct BadgeMeta { uint64 minted; uint64 burned; uint128 reserved; }
mapping(uint256 => BadgeMeta) internal _meta;
constructor(string memory base) ERC721("Kudos Badge", "KBDG") {
_base = base;
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
}
function batchMint(address[] calldata tos, string[] calldata uris) external onlyRole(MINTER_ROLE) {
uint256 len = tos.length;
require(len == uris.length, "len mismatch");
uint256 id = _nextId;
unchecked {
for (uint256 i; i < len; i++) {
_safeMint(tos[i], id);
_setTokenURI(id, uris[i]);
_meta[id].minted++;
id++;
}
}
_nextId = id;
}
function _baseURI() internal view override returns (string memory) { return _base; }
}
Next You now have a full intermediate-grade Kudos stack—ship, monitor, and iterate.