a manifold extension to port fully onchain an existing collection minted with offchain content
clgsms/test/helpers.js
JavaScript · 106 lines · 3 KBRAWDOWNLOAD
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.
*/
export {
CHUNK,
CLGSM_MAINNET as CLGSM,
CREATOR_ABI,
artworkKey,
base64Chunks,
creatorAt,
decodeTokenURI,
deployCreator,
rawChunks,
toChunks,
} 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");
assert.equal(
a.equals(b),
true,
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);
let x = seed >>> 0;
for (let i = 0; i < len; i++) {
x = (x * 1664525 + 1013904223) >>> 0;
out[i] = x & 0xff;
}
return out;
}
/**
* 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 = {}) {
return JSON.stringify({
name: `COLORGASM #${String(id).padStart(3, "0")}`,
created_by: "FelixFelixFelix",
description: "Databent colour field, stored onchain.",
attributes: [{ trait_type: "Series", value: "COLORGASM" }],
...extra,
}).slice(1, -1);
}
/**
* Deploy storage + extension + renderer and wire them — the same three steps
* scripts/deploy.js performs onchain.
*/
export async function deployStack(
ethers,
creator,
{ firstId = 1, editionSize = 100, preEncoded = true } = {},
) {
const blobs = await ethers.deployContract("ColorgasmStorage");
await blobs.waitForDeployment();
const ext = await ethers.deployContract("ColorgasmRedeemExtension", [
creator,
firstId,
editionSize,
]);
await ext.waitForDeployment();
const renderer = await ethers.deployContract("ColorgasmRendererV3", [
await ext.getAddress(),
await blobs.getAddress(),
preEncoded,
]);
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);
let gas = 0n;
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 };
}