跳到正文
DEV Community· mujin·· 4 小時前AI 評分55

mujin 用 4GB GPU 發佈 22 個動漫 NFT,拆解耗時一天的三個故障

I shipped 22 anime NFTs from a 4GB GPU — three things that cost me a full day

AI 導讀

mujin 使用配備 4GB VRAM 的 GTX 1650 生成 22 張動漫肖像,以 Python 編寫 ERC-721 和 Seaport 上架層,並將項目部署到 Base。

正文

I generated 22 anime portraits on a GTX 1650 with 4GB of VRAM, wrote my own ERC-721 and Seaport listing layer in Python, and put the whole thing on Base.

This is not a "look at my NFT" post. It's the three bugs that ate a day, because none of them throw an error that points at the real cause.


1. fp16 silently produces NaN on GTX 16-series cards

First run: 20 images came out completely black. Not dark — pixel mean 0.0, non-black pixel ratio 0%.

pipe = StableDiffusionPipeline.from_single_file(ckpt, torch_dtype=torch.float16)
img = pipe(prompt, num_inference_steps=10).images[0]
# np.asarray(img).mean() -> 0.0

Nothing in the pipeline warns. The diffusers call returns successfully, and only when you inspect the tensor do you see invalid value encountered in cast.

Fix: run fp32 on small/consumer cards and offload modules instead of quantizing:

pipe = StableDiffusionPipeline.from_single_file(ckpt, torch_dtype=torch.float32)
pipe.enable_model_cpu_offload()   # 4GB card, ~2.5 min per 512x768 image

If you keep fp16, at minimum pipe.upcast_vae() — but on 4GB that still left me with NaN in the UNet. fp32 + offload was the only thing that worked.


2. Seaport's order typehash depends on EIP-712 type ordering

I built Seaport OrderComponents by hand. The signature was rejected by OpenSea with Signature invalid, and my locally computed order hash didn't match Seaport.getOrderHash() on-chain.

The cause: EIP-712 encodeType(primaryType) appends referenced types in alphabetical order. My type string had OfferItem before ConsiderationItem. Alphabetically, ConsiderationItem comes first.

OrderComponents(address offerer,address zone,OfferItem[] offer,ConsiderationItem[] consideration,...)
+ ConsiderationItem(uint8 itemType,address token,uint256 identifierOrCriteria,uint256 startAmount,uint256 endAmount,address recipient)
+ OfferItem(uint8 itemType,address token,uint256 identifierOrCriteria,uint256 startAmount,uint256 endAmount)

Get the order wrong and you get a different typehash — a valid-looking signature that the contract rejects.

How I found it: I read the immutable ORDER_TYPEHASH out of the deployed Seaport runtime bytecode and compared it against keccak256 of candidate strings until one matched. If you're debugging something similar, Seaport.getOrderHash() is a free oracle — it takes the same components and costs nothing to call.


3. If conduitKey != 0, the Conduit transfers the NFT — not Seaport

I approved Seaport and my listings still couldn't be filled. OpenSea's error was explicit once I read it:

Seaport order validation failed: errors=[ERC721 not owner of token, ERC721 conduit not approved]

With OpenSea's default conduitKey, the transfer is executed by the Conduit contract. isApprovedForAll(owner, seaport) is irrelevant.

Fix: resolve the conduit for the key and approve that too.

conduit, exists = conduit_controller.functions.getConduit(conduit_key).call()
# -> 0x1E0049783F008A0085193E00003D00cd54003c71 on Base
nft.functions.setApprovalForAll(conduit, True)

Also worth knowing: Seaport.validate() does not verify signatures. I fed it 65 random bytes and it passed. Don't use it as a signature oracle.


What it actually costs

Measured on Base at ~0.006 gwei:

Operation Gas Cost
Deploy ERC-721 + ERC-2981 1.5M 0.0000093 ETH
Write metadata URI (per piece) ~120k 0.0000008 ETH
Buyer mint ~190k paid by buyer
List on Seaport 0 off-chain signature

22 pieces cost under 0.0001 ETH in total. The expensive part was my time, not the chain.


If you're doing this too

  1. Test np.asarray(img).mean() right after your first generation — it catches the fp16 NaN immediately.
  2. Call Seaport.getOrderHash() and compare with your local implementation before you sign anything.
  3. Before listing, check conduitKey and approve the conduit, not just Seaport.

The collection is live at charming-llama-47b816.netlify.app if you want to see what 4GB gets you.

Happy to answer questions about any of the three.

來源:DEV Community · dev.to