Protocol Review: Aavegotchi’s `SvgFacet.sol` The On-Chain Rendering Engine
Nursca2 min read·Just now--
Aavegotchi is a DeFi-powered NFT game built on Polygon, where each gotchi is fully on-chain ghost-like creature with numeric traits, equipped wearables, and a collateral type that determines its visual identity. What makes Aavegotchi technically remarkable is that the NFT’s appearance, its SVG artwork is assembled entirely on-chain, inside the contract, at query time.
SvgFacet.sol is the contract responsible for this feat. It is the rendering engine of the Aavegotchi protocol: given a token ID, it reads raw SVG data stored in contract storage, combines multiple visual layers (body, collateral, eye shape, wearables), injects CSS styles derived from the token’s traits, and returns a complete, valid SVG string without a single pixel sourced from off-chain storage.
This article performs a thorough code-level review of SvgFacet.sol , covering it’s architectural context, every import, all public and internal function, design decisions, and potential areas of improvement.
1. Architectural Context: The Diamond Standard (EIP-2535)
Before diving into the contract itself, understanding where SvgFacet.sol lives in the system is essential.
Aavegotchi is implemented using the Diamond Standard (EIP-2535). Rather than deploying a single monolithic contract, the protocol deploys one central AavegotchiDiamond contract found in InitDiamond.sol that routes all external function call to a set of smaller, specialized contracts called facets. Each facet holds a subset of the protocol’s logic.
SvgFacet.sol is one of the facets. Its functions getAavegotchiSvg , previewAavegotchi , storeSvg , etc. are exposed through the diamond’s address. When a user calls getAavegotchiSvg(tokenId) on the diamond, the diamond’s fallback function delegatecall ‘s into SvgFacet , which then runs in the context of the diamond’s storage.
This is why SvgFacet can access the diamond’s full state (all gotchis, all item types, all SVG data) via the shared AppStorage struct, even thoough SvgFacet itself holds no state.
2. Imports What They Are and Why They Matter
import {AppStorage, SvgLayer, Dimensions} from "../libraries/LibAppStorage.sol";
import {LibAavegotchi, PortalAavegotchiTraitsIO, EQUIPPED_WEARABLE_SLOTS, PORTAL_AAVEGOTCHIS_NUM, NUMERIC_TRAITS_NUM} from "../libraries/LibAavegotchi.sol";
import {LibItems} from "../libraries/LibItems.sol";
import {Modifiers, ItemType} from "../libraries/LibAppStorage.sol";
import {LibSvg} from "../libraries/LibSvg.sol";
import {LibStrings} from "../../shared/libraries/LibStrings.sol";2.1 AppStorage , SvgLayer , Dimensions from LibAppStorage.sol
LibAppStorage defines the single storage struct used by the entire Diamond. In the Diamond pattern, all facets share the same storage layout because delegatecall into the diamond’s storage space. By having all state in one AppStorage struct stored at a fixed slot, every facet reads and writes the same data safely.
AppStorage : The master state struct. It holds everything the mapping of the token IDs to Aavegotchi structs, items types, SVG layer data, collateral type info, sleeve mappings, and more. SvgFacet accesses it via the inherited s variables from Modifiers .
SvgLayer : A struct representing one chunk of on-chain SVG data. SVG images are stored in the contract as raw byte arrays, split into layers, associated with a bytes32 type key (e.g. , aavegotchi , wearaables , collaterals ).
Dimensions : A struct containing x , y , width , and height fields. Using when positioning wearables SVGs inside the 64x64 coordinate space of the final image.