This repo is a forkable Foundry workspace for artists building render contracts for Liquid Editions.
It is meant to help artists get from idea to first render quickly, even if they are mostly vibe coding.
A Liquid Edition is an ERC20 token with a live on-chain market.
That market state, including things like price, liquidity, supply, balances, and burn progress, can be used as input for generative art.
A Liquid Edition can be presented in two ways:
- as a single artwork attached directly to the ERC20 via
tokenURI() - as that same ERC20 plus an optional companion ERC721 collection, where each NFT is a different lens over the same state
The ERC721 is optional. Some Liquid Editions will only exist as the ERC20 artwork. Others may also include an ERC721 collection.
This is still a living prototype. Features may evolve over time. Reach out to support@superrare.com if you have any questions.
Liquid Editions can technically support plain NFT patterns. An artist could point tokenURI() at IPFS and ship a static image, animation, or webpage. That is valid.
But the protocol is most interesting when the market is treated as artistic material, not just as commerce around the work.
In Liquid Editions:
- price can be part of the picture
- liquidity can be part of the composition
- supply, burns, transfers, and balances can become inputs, thresholds, rhythms, or narrative beats
- one market object can support multiple visual interpretations without fragmenting the underlying edition
The ambition is not just to attach art to a token and let people trade it. The ambition is to let artists use market behavior itself as a medium.
So while the sky is the limit, or even static metadata is technically allowed, the spirit of the protocol is generative art that reads, interprets, and responds to live on-chain state.
That does not mean every project needs to be hyper-reactive. A strong Liquid Edition can be quiet, sparse, slow-moving, or highly constrained. What matters is that the relationship between the visual surface and the market surface feels intentional.
ERC20: the Liquid Edition token itselfERC721: an optional companion NFT collectionrender contract: a contract that returns metadata fromtokenURI()tokenURI: the metadata endpoint clients fetch
This repo includes reusable AI workflow guides under skills/:
skills/liquid-render-builder/SKILL.mdfor designing and implementing render contractsskills/liquid-render-deployer/SKILL.mdfor deploying and registering them
They are written as shared repo guidance, not as a feature tied to any one model provider.
Different agent tools may load or reference them in different ways, but the underlying skill content is intentionally provider-neutral and tuned to this starter kit's examples, interfaces, scripts, and current product constraints.
A Liquid Edition can register only one render contract address.
That means there are two main patterns artists should think about:
- a render-only contract that returns
tokenURI()and has no ERC721 minting features - a single contract that is both the registered render contract and an ERC721, returning both
tokenURI()andtokenURI(uint256)
This starter kit demonstrates both:
LiquidLensHTMLExample.solis the render-only patternLiquidLensMintable721SVGExample.solis the combined renderer-plus-ERC721 pattern
A Liquid render contract is a read-only observer of the Liquid token state, not a live process running beside it.
- the Liquid token reaches the renderer by exposing its
tokenURI()output - during that read, the renderer can only inspect the current onchain state and current block context for that call
tokenURI()is aviewmetadata read, not a lifecycle hook- it cannot persist new state, receive automatic callbacks from market activity, or keep running between reads
If a concept depends on mechanics like "one move per day," "buy extra moves," "claim influence," or any other stored rights, those mechanics must live in explicit transaction functions and usually need their own UI, site, or script. The metadata can display the results of those transactions, but it does not create them.
This starter keeps the example surface intentionally small:
src/examples/LiquidLensHTMLExample.solsrc/examples/LiquidLensMintable721SVGExample.sol
Single-artwork example.
- exposes
tokenURI() - intended to be registered directly on a Liquid token
- returns standard NFT metadata JSON
- uses
animation_urlfor HTML output - includes an SVG preview in
image
Use this when you want one dynamic artwork attached to the Liquid Edition itself.
Mintable ERC721 example.
- exposes
tokenURI()for Liquid Edition passthrough - exposes
tokenURI(uint256 tokenId)for the companion collection - supportsInterface for ERC721
- returns standard NFT metadata JSON
- outputs SVG
- supports minting NFTs from the same contract
Use this when you want the Liquid token plus a companion collectible lens collection.
Your Liquid token's tokenURI() can point at a render contract you control.
That render contract can be a simple render-only contract. It can return standard NFT metadata JSON with:
imageasdata:image/svg+xml;base64,...imageas a normal URLanimation_urlfor HTML artifacts- optional
attributes
This is enough for the Liquid token itself to be "the work."
Because only one render contract can be registered, the clearest ERC20 + ERC721 pattern is to make that same registered contract also implement ERC721 and expose tokenURI(uint256 tokenId).
If it does, we can treat that contract as both:
- the Liquid render contract for
tokenURI() - the companion ERC721 collection for
tokenURI(uint256 tokenId)
In that case:
tokenURI()is the Liquid passthrough viewtokenURI(tokenId)is the NFT lens view
Each NFT can be a different lens over the same state:
- different mappings
- different thresholds
- different narratives
- different visual systems
- different mint or access rules
The output should be standard NFT metadata JSON.
In practice, that means fields like:
namedescriptionimage- optional
animation_url - optional
external_url - optional
attributes
Supported media, in spirit and in product, include:
- SVG
- HTML
- images
- video
- GIFs
These are still just standard NFTs. The main difference is that the metadata can be generated from on-chain Liquid state at read time.
This starter leans toward HTML and SVG because the project is most interesting when the work is rendered directly from on-chain state.
The reserve currency is RARE. The Liquid Edition will be paired with RARE as its base token in the liquidity pool.
Useful canonical addresses for this starter kit:
RARE:0xba5BDe662c17e2aDFF1075610382B9B691296350Liquid Factory:0xd3D8Ca76E8c5547694106378B6e471B4AC8EFC63
RARE:0x197FaeF3f59eC80113e773Bb6206a17d183F97CBLiquid Factory:0xfD18C0D99e5b6F89F3538806241C2C0d6FD728Ac
Guaranteed:
- the Liquid Edition contracts onchain
- the state exposed by the contracts
- the fact that render contracts are fetched via
tokenURI()
Evolving:
- UI / UX
- how artwork is surfaced in product
- how balances, collections, and views are presented
The safe assumption for artists is: the blockchain is the durable layer, and the UI is a rapidly evolving interpretation layer.
The example contracts in this repo read directly from ILiquid.
Most useful dynamic values:
balanceOf(address)totalSupply()maxTotalSupply()getCurrentPrice()getMarketState()quoteBuy()quoteSell()lpLiquidity()totalLiquidity()lpTickLower()lpTickUpper()tokenCreator()
Fixed / identity values:
name()symbol()tokenCreator()baseToken()
The example contracts focus on the simplest current surface:
name()symbol()tokenCreator()maxTotalSupply()getMarketState()
That is the core state surface artists should design against first.
quoteBuy() and quoteSell() are optional. They are mainly useful when you want quote-at-size behavior, spread proxies, or slippage-aware render logic.
Updates are pull-based.
- clients fetch metadata via
tokenURI() - our systems refresh metadata on every relevant Liquid Edition state change
- metadata is also refreshed if the companion ERC721 emits
MetadataUpdated - there is no push-based rendering path from Liquid into the render contract
- the renderer only sees the current state for that fetch; it is not notified in-place when the market changes
The easiest dynamic behavior is pure view logic:
- state changes onchain
- metadata is refetched
- the artwork changes because the view logic reads the new state
If you want stateful behavior such as:
- minting
- claiming
- unlocking
- freezing
- revoking
- changing custom ERC721 state
someone still has to submit a transaction. Nothing stateful happens automatically just because the market moved.
Time-based behavior still follows the same rule. You can derive visuals from block.timestamp or block.number at read time, but that only gives you the current block context for the fetch. It does not mean the contract is autonomously evolving onchain between reads.
We support the normal market actions around the system:
- buying and selling the Liquid Edition
- buying and selling ERC721 tokens through standard marketplace flows
Artists are still free to add custom functions and mechanics to their contracts.
That might include:
- special mint flows
- claims
- burns
- unlocks
- freezes
- transfer restrictions
- other project-specific behaviors
But those custom mechanics are not automatically supported in the SuperRare UI.
For example, if an artist creates a mechanic like "burn your Liquid Edition Tokens to mint an NFT," that can absolutely exist onchain, but it would need to be triggered somewhere outside the current SuperRare UI unless we explicitly build support for it.
So the practical rule is:
- custom mechanics are welcome
- standard metadata and standard trading flows are what the platform guarantees today
- anything beyond that should be exposed by the artist through their own site, script, app, or contract interface
Strong custom patterns are still useful. If artists develop mechanics that are compelling and legible, they may inform future product support or become standard UI flows later.
From the current surface, artists can derive more expressive signals such as:
- market cap
- fully diluted value
- burned supply
- burn rate
- spread proxies
- price impact estimates
- distance to LP bounds
- bonding-curve progress
- holder concentration
- artist holdings value
The examples in this repo are intentionally literal. They are demos, not limits.
Artists control their ERC721 lens contracts.
That can include:
- custom mint logic
- distribution pathways
- unlock rules
- transfer restrictions
- decay
- revocation
- finish states
- multiple visual interpretations over the same market state
The main caveat is collector legibility. Surprise is useful; confusion is expensive. Highly nonstandard behavior may also run into UI limitations.
Baseline assumption: the work can continue evolving as state changes.
But artists can encode a terminal condition entirely in render logic, for example:
- stop changing after a burn threshold
- stop changing after a tick threshold
- freeze after supply drops below a line
Nothing breaks if the work stops changing. That is still a valid authored choice.
Before you build a render contract in this repo, the easiest path is to create your Liquid Edition in the SuperRare dev UI:
This starter kit is primarily for the render contract that you attach afterward. In practice, the easiest flow is:
- Create the Liquid Edition on Sepolia in the dev UI.
- Copy the deployed Liquid Edition contract address.
- Put that address into
LIQUID_EDITION_ADDRESSin this repo. - Build, deploy, and register your render contract from this repo.
Once your render contract is registered, you can immediately inspect how the Liquid Edition renders in the UI at:
https://dev.superrare.com/liquid-editions/11155111/<liquidEditionContractAddress>
Replace <liquidEditionContractAddress> with your Sepolia Liquid Edition address. 11155111 is the Sepolia chain ID in the URL.
cp .env.eth.sepolia .envAt minimum set:
DEPLOYER_PRIVATE_KEY=
RPC_URL=
LIQUID_EDITION_ADDRESS=When you are ready for production:
cp .env.eth.mainnet .envThen set:
DEPLOYER_PRIVATE_KEY=
RPC_URL=
LIQUID_EDITION_ADDRESS=For LiquidLensHTMLExample:
LENS_NAME="Liquid Lens HTML Example"
LENS_DESCRIPTION="Single artwork Liquid lens example using HTML metadata."
LENS_EXTERNAL_URL=
AUTO_REGISTER_RENDER=trueFor LiquidLensMintable721SVGExample:
NFT_NAME="Liquid Lens Mintable 721 SVG Example"
NFT_SYMBOL=LL721
NFT_DESCRIPTION="Mintable ERC721 Liquid lens example using SVG metadata."
NFT_EXTERNAL_URL=
NFT_MAX_SUPPLY=128forge build
forge test -vvIf you are not sure where to start:
- pick
LiquidLensHTMLExample.solif you want one dynamic artwork attached to the Liquid token - pick
LiquidLensMintable721SVGExample.solif you want a companion collectible NFT series
If you are less technical, you can ignore most of the system at first and just focus on:
getMarketState()- color
- composition
- text
- whether the work changes over time
This repo assumes you already have a Liquid Edition address to target.
For Sepolia, the recommended setup is:
- Create the Liquid Edition at
dev.superrare.com/create/liquid-edition. - Set
LIQUID_EDITION_ADDRESSin.envto that deployed Liquid Edition address. - Deploy your render contract from this repo.
- Register the render contract on the Liquid Edition.
- Open
https://dev.superrare.com/liquid-editions/11155111/<liquidEditionContractAddress>to verify the render in the UI.
If you prefer, you can still create Liquid Editions through lower-level contract workflows, but that is not the easiest starting path for most users of this starter kit.
source .env
forge script script/DeployLiquidLensHTMLExample.s.sol:DeployLiquidLensHTMLExample --rpc-url $RPC_URL --broadcastsource .env
forge script script/DeployLiquidLensMintable721SVGExample.s.sol:DeployLiquidLensMintable721SVGExample --rpc-url $RPC_URL --broadcastsource .env
forge script script/RegisterRenderContract.s.sol:RegisterRenderContract --rpc-url $RPC_URL --broadcastIf AUTO_REGISTER_RENDER=true and the broadcaster is also the Liquid token creator, the deploy scripts will register automatically.
Only the token creator can set the render contract.
Minimum requirement:
tokenURI()must return standard NFT metadata JSON
Optional companion collection:
tokenURI(uint256 tokenId)for ERC721 lens metadata if the registered render contract also implements ERC721
Using cast:
cast send $LIQUID_TOKEN_ADDRESS \
"setRenderContract(address)" \
$RENDER_CONTRACT_ADDRESS \
--rpc-url $RPC_URL \
--private-key $DEPLOYER_PRIVATE_KEYTo verify:
cast call $LIQUID_TOKEN_ADDRESS \
"renderContract()(address)" \
--rpc-url $RPC_URLTo clear the render contract and fall back to static metadata:
cast send $LIQUID_TOKEN_ADDRESS \
"setRenderContract(address)" \
0x0000000000000000000000000000000000000000 \
--rpc-url $RPC_URL \
--private-key $DEPLOYER_PRIVATE_KEYFor the HTML example, start inside:
tokenURI()_renderPreviewSvg_renderHtmlPage
For the mintable 721 SVG example, start inside:
tokenURI()tokenURI(uint256)_renderSvg_bars_copy
Because the contracts are intentionally standalone, the simplest workflow is to pick one file and edit it directly.
If you are vibe coding, a good first prompt is:
"Treat the Liquid token as a market-driven art input. Read getMarketState() and getLaunchState() directly. Return standard NFT metadata JSON. Keep the first version simple and legible."
Another good first prompt is:
"Map one or two market variables to visible changes first. Do not invent extra mechanics until the base artwork already works."
Use MockLiquid for quick iteration in tests. It lets you:
- change market state
- change launch state
- register a render contract
- verify Liquid passthrough behavior
Starter coverage lives in:
test/LiquidLensExamples.t.sol
The examples themselves are focused on ILiquid, but ILiquidFactory is still useful for:
- reference
- scripts
- creators who want lower-level token creation workflows from the same repo
- local tests that create a Liquid Edition before attaching a renderer
- end-to-end automation where token creation and render deployment happen in one flow
For most users, the easiest way to get a Sepolia Liquid Edition is still:
- create it first in
dev.superrare.com/create/liquid-edition - then use this repo to build and register the render contract
- Fork the repo.
- Create your Liquid Edition on Sepolia at
dev.superrare.com/create/liquid-edition. - Copy that Liquid Edition contract address into
LIQUID_EDITION_ADDRESS. - Pick the closer example contract.
- Rename the contract to your project name.
- Keep the relevant metadata entrypoints intact.
- Update or add tests.
- Deploy the renderer to Sepolia first.
- Register the renderer on the target Liquid token.
- Verify the result in
https://dev.superrare.com/liquid-editions/11155111/<liquidEditionContractAddress>. - Move to mainnet after validating output.