import assert from "node:assert/strict"; * Test helpers. The byte-level pieces (chunking, keys, decoding tokenURIs) come * from scripts/_lib.js on purpose: the tests then exercise the exact code the * upload/deploy/redeem scripts run against Sepolia and mainnet. } from "../scripts/_lib.js"; import { artworkKey, base64Chunks, rawChunks } from "../scripts/_lib.js"; * Assert two byte sequences are identical, whatever container they arrive in * (Buffer from eth_getCode, Uint8Array from a fixture, hex from a view call). export function sameBytes(actual, expected, message) { const a = Buffer.from(typeof actual === "string" ? actual.replace(/^0x/, "") : actual, "hex"); const b = Buffer.from(typeof expected === "string" ? expected.replace(/^0x/, "") : expected, "hex"); message ?? `bytes differ: ${a.length} B actual vs ${b.length} B expected`, /** Deterministic pseudo-random bytes — stands in for AVIF data. */ export function fakeImage(len, seed = 1) { const out = Buffer.alloc(len); for (let i = 0; i < len; i++) { x = (x * 1664525 + 1013904223) >>> 0; * A metadata fragment in the shape scripts/fetch-metadata.js produces: the * token's original JSON minus the image fields, without surrounding braces. export function fragment(id, extra = {}) { name: `COLORGASM #${String(id).padStart(3, "0")}`, created_by: "FelixFelixFelix", description: "Databent colour field, stored onchain.", attributes: [{ trait_type: "Series", value: "COLORGASM" }], * Deploy storage + extension + renderer and wire them — the same three steps * scripts/deploy.js performs onchain. export async function deployStack( { firstId = 1, editionSize = 100, preEncoded = true } = {}, const blobs = await ethers.deployContract("ColorgasmStorage"); await blobs.waitForDeployment(); const ext = await ethers.deployContract("ColorgasmRedeemExtension", [ await ext.waitForDeployment(); const renderer = await ethers.deployContract("ColorgasmRendererV3", [ await blobs.getAddress(), await renderer.waitForDeployment(); await (await ext.setBlobStorage(await blobs.getAddress())).wait(); await (await ext.setRenderer(await renderer.getAddress())).wait(); return { blobs, ext, renderer }; * Upload an artwork the way the offchain script does: one chunk per * transaction, then seal. Returns the storage key and the gas it cost. export async function upload(blobs, id, image, { preEncoded = true, seal = true } = {}) { const key = artworkKey(id); const chunks = preEncoded ? base64Chunks(image) : rawChunks(image); for (const chunk of chunks) { gas += (await (await blobs.append(key, chunk)).wait()).gasUsed; if (seal) gas += (await (await blobs.seal(key)).wait()).gasUsed; return { key, chunks: chunks.length, gas };