EVM × Sui Walrus GitHub
Showcase 01 · implemented

Mint an NFT whose image lives on Walrus, not IPFS.

A 200-line dApp that shows how to swap the storage layer behind a vanilla OpenZeppelin ERC-721. The Solidity contract stores a plain tokenURI string — identical in shape to an IPFS-backed NFT. Two write paths drop the same kind of string in; the EVM side never knows which one was used.

Source: showcases/01-evmwal-nft/ Stack: Foundry · Next.js 16 · viem · wagmi · @mysten/walrus Local chain: Anvil 31337
01 · the pain

NFT.Storage's quiet collapse left every drop on borrowed time.

trust shock
ipfs-pain.md · §4
"Don't trust free decentralized storage to outlive your project. Bankless's Metaversal newsletter now routinely frames IPFS as 'data must be pinned through services like ClubNFT or Pinata to be maintained.'"
— 2026 builder-sentiment survey
02 · the shape

One mint, two write paths, one read path.

The contract is an OpenZeppelin ERC721 + ERC721URIStorage. mint(string) assigns a token id and stores the string verbatim. There is no Walrus-specific code on chain.

The browser uploads bytes to either a local Next.js API route that signs Sui transactions with an operator keypair (default), or directly to the public Walrus testnet publisher (set NEXT_PUBLIC_WALRUS_UPLOAD_MODE=publisher). Both paths return the same 32-byte blobId and lead to the same aggregator URL.

The migration cost from IPFS is changing one URL prefix. The Solidity side does not move.

// the entire EVM-side contract surface
function mint(string tokenURI_)
  external returns (uint256);
function mintTo(address to, string tokenURI_)
  external returns (uint256);
event Minted(
  uint256 indexed tokenId,
  address indexed minter,
  string tokenURI_
);
file picker
walrus write
mint(uri)
03 · try it locally

Five terminal commands and a wallet popup.

01

Prerequisites

Node 22, pnpm 10, Foundry, and an injected EVM wallet (MetaMask / Rabby / Coinbase Wallet extension). No real ETH needed — the deploy script funds itself from Anvil dev-0.

  • nvm use (or install node@22 any other way)
  • corepack enable && corepack prepare pnpm@10.32.1 --activate
  • curl -L https://foundry.paradigm.xyz | bash && foundryup

Backend (default) upload mode also needs a Sui testnet keypair plus testnet SUI and testnet WAL. Publisher mode skips all Sui-side setup.

02

Clone and install

git clone git@github.com:MystenLabs/evm-sui.git
cd evm-sui
pnpm install
cp showcases/01-evmwal-nft/web/.env.local.example showcases/01-evmwal-nft/web/.env.local

Edit web/.env.local: paste SUI_PRIVATE_KEY=suiprivkey… for backend mode, or set NEXT_PUBLIC_WALRUS_UPLOAD_MODE=publisher to skip the Sui side entirely.

03

Start a local chain

# terminal A — repo root
pnpm dev:chain    # anvil on 127.0.0.1:8545

Anvil pre-funds 10 deterministic wallets; the first one is what deploy:local uses below.

04

Deploy + sync the ABI into the web app

# terminal B — inside showcase 01
cd showcases/01-evmwal-nft
pnpm deploy:local
# → forge script DeployEvmWalNFT.s.sol  → broadcast
# → write-deployed-address.ts            → .deployed-address
# → extract-abi.ts                       → web/lib/contract.ts + web/.env.local

The script reads the Foundry broadcast artifact, captures the deployed address, and patches it into the web app's env + ABI. Re-run any time you redeploy.

05

Start the dev server, connect MetaMask, mint

pnpm dev:web        # http://localhost:3000

In MetaMask: add the Anvil network (chain id 31337, RPC http://127.0.0.1:8545), switch to it, then open http://localhost:3000. Hit the Mint tab, pick an image, watch the upload + mint flow. The card appears in All NFTs and My NFTs within seconds of confirmation.

04 · verify

What "good" looks like.

05 · what this is NOT

Limits to set expectations.

  • Not production-deployable as-is. The backend upload route at /api/walrus/upload is unauthenticated. It spends operator WAL on every successful request. Run on a local dev server only.
  • Not a Walrus pricing oracle. epochs: 5 (~14 days) is the default; operator picks the retention window and pays upfront.
  • Not infinite scale. The gallery scans 1..totalSupply on every render — snappy below ~100 tokens; for real scale you'd want a subgraph or a Transfer event indexer.
  • Not a hash verifier. Trust in the bytes served by the aggregator is identical to trust in an IPFS gateway. For trustless retrieval, add a Reed-Solomon recompute via @mysten/walrus on top.
06 · source files

Where to look in the repo.