Monorepo for Aesthetic.Computer
aesthetic.computer
1/**
2 * Keeps FA2 v4 Contract - Read-Only Tests
3 *
4 * These tests verify the production contract via TzKT API without making any transactions.
5 * Safe to run against mainnet contract: KT1ER1GyoeRNhkv6E57yKbBbEKi5ynKbaH3W
6 */
7
8import { getContract, CONTRACTS, EXPECTED_STORAGE, stringToBytes } from './helpers/keeps-test-helper.mjs';
9import {
10 getContractStorage,
11 getContractEntrypoints,
12 getTokenMetadata,
13 getAllTokens,
14 getOperations,
15 getBigMapKeys
16} from './helpers/tzkt-helper.mjs';
17
18const RUN_KEEPS_NETWORK_TESTS =
19 process.env.RUN_KEEPS_NETWORK_TESTS === 'true' ||
20 process.env.RUN_KEEPS_V4_NETWORK_TESTS === 'true';
21const describeIfNetworkEnabled = RUN_KEEPS_NETWORK_TESTS ? describe : xdescribe;
22
23if (!RUN_KEEPS_NETWORK_TESTS) {
24 console.log(
25 '⏭️ Skipping keeps network read-only tests (set RUN_KEEPS_NETWORK_TESTS=true to enable)'
26 );
27}
28
29describeIfNetworkEnabled("🔐 Keeps FA2 v4 Contract - Read-Only Tests", () => {
30 let contract, address;
31 const network = 'mainnet';
32
33 beforeAll(async () => {
34 console.log('\n🧪 Starting Keeps v4 read-only test suite...\n');
35 console.log(`🎯 Target contract: ${CONTRACTS.mainnet}`);
36 console.log(`🎯 Expected admin: ${EXPECTED_STORAGE.mainnet.administrator}`);
37 ({ contract, address } = await getContract(network, false));
38 });
39
40 afterAll(() => {
41 console.log('\n✅ Read-only test suite complete!\n');
42 });
43
44 describe("📋 Contract Configuration", () => {
45 it("should have correct contract address", () => {
46 expect(address).toBe(CONTRACTS.mainnet);
47 });
48
49 it("should have correct administrator", async () => {
50 const storage = await getContractStorage(address, network);
51 expect(storage.administrator).toBe(EXPECTED_STORAGE.mainnet.administrator);
52 });
53
54 it("should have default royalty of 10%", async () => {
55 const storage = await getContractStorage(address, network);
56 expect(parseInt(storage.default_royalty_bps)).toBe(EXPECTED_STORAGE.mainnet.default_royalty_bps);
57 });
58
59 it("should not be paused", async () => {
60 const storage = await getContractStorage(address, network);
61 expect(storage.paused).toBe(EXPECTED_STORAGE.mainnet.paused);
62 });
63
64 it("should have keep_fee configured", async () => {
65 const storage = await getContractStorage(address, network);
66 expect(storage.keep_fee).toBeDefined();
67 console.log(` 📊 Current keep fee: ${storage.keep_fee} mutez`);
68 });
69
70 it("should have contract metadata", async () => {
71 const storage = await getContractStorage(address, network);
72 expect(storage.metadata).toBeDefined();
73 });
74
75 it("should have contract_metadata_locked flag", async () => {
76 const storage = await getContractStorage(address, network);
77 expect(typeof storage.contract_metadata_locked).toBe('boolean');
78 });
79 });
80
81 describe("🎯 Contract Entrypoints", () => {
82 let entrypoints;
83
84 beforeAll(async () => {
85 entrypoints = await getContractEntrypoints(address, network);
86 });
87
88 it("should have all 12 custom Keeps entrypoints", () => {
89 const customEntrypoints = [
90 'keep',
91 'edit_metadata',
92 'lock_metadata',
93 'set_contract_metadata',
94 'lock_contract_metadata',
95 'set_keep_fee',
96 'withdraw_fees',
97 'burn_keep',
98 'pause',
99 'unpause',
100 'set_default_royalty',
101 'admin_transfer'
102 ];
103
104 const entrypointNames = entrypoints.map(ep => ep.name);
105 customEntrypoints.forEach(name => {
106 expect(entrypointNames).toContain(name);
107 });
108
109 console.log(` ✅ Found ${customEntrypoints.length} custom entrypoints`);
110 });
111
112 it("should have all 6 FA2 standard entrypoints", () => {
113 const fa2Entrypoints = [
114 'transfer',
115 'update_operators',
116 'balance_of',
117 'mint',
118 'burn',
119 'set_administrator'
120 ];
121
122 const entrypointNames = entrypoints.map(ep => ep.name);
123 fa2Entrypoints.forEach(name => {
124 expect(entrypointNames).toContain(name);
125 });
126
127 console.log(` ✅ Found ${fa2Entrypoints.length} FA2 standard entrypoints`);
128 });
129
130 it("should have v4 entrypoints (pause, unpause, set_default_royalty, admin_transfer)", () => {
131 const v4Entrypoints = ['pause', 'unpause', 'set_default_royalty', 'admin_transfer'];
132 const entrypointNames = entrypoints.map(ep => ep.name);
133
134 v4Entrypoints.forEach(name => {
135 expect(entrypointNames).toContain(name);
136 });
137
138 console.log(` ✅ Found all 4 v4-specific entrypoints`);
139 });
140 });
141
142 describe("🪙 Token Metadata", () => {
143 it("should have minted tokens", async () => {
144 const storage = await getContractStorage(address, network);
145 const nextTokenId = parseInt(storage.next_token_id);
146
147 expect(nextTokenId).toBeGreaterThan(0);
148 console.log(` 📊 Total tokens minted: ${nextTokenId}`);
149 });
150
151 it("should fetch token metadata from TzKT", async () => {
152 const storage = await getContractStorage(address, network);
153 const nextTokenId = parseInt(storage.next_token_id);
154
155 if (nextTokenId > 0) {
156 // Fetch first token
157 const tokens = await getTokenMetadata(address, 0, network);
158
159 expect(tokens.length).toBeGreaterThan(0);
160 expect(tokens[0].metadata).toBeDefined();
161 console.log(` ✅ Token #0 metadata: ${tokens[0].metadata.name}`);
162 } else {
163 console.log(` ⚠️ No tokens minted yet, skipping metadata test`);
164 }
165 });
166
167 it("should have proper token metadata structure (TZIP-21)", async () => {
168 const storage = await getContractStorage(address, network);
169 const nextTokenId = parseInt(storage.next_token_id);
170
171 if (nextTokenId > 0) {
172 const tokens = await getTokenMetadata(address, 0, network);
173 const metadata = tokens[0].metadata;
174
175 // Check TZIP-21 required fields
176 expect(metadata.name).toBeDefined();
177 expect(metadata.symbol).toBeDefined();
178 expect(metadata.decimals).toBeDefined();
179
180 // Check Keeps-specific fields
181 expect(metadata.artifactUri).toBeDefined();
182 expect(metadata.displayUri).toBeDefined();
183 expect(metadata.thumbnailUri).toBeDefined();
184
185 console.log(` ✅ Token metadata follows TZIP-21 standard`);
186 }
187 });
188 });
189
190 describe("💾 Storage BigMaps", () => {
191 it("should have content_hashes bigmap", async () => {
192 const storage = await getContractStorage(address, network);
193 expect(storage.content_hashes).toBeDefined();
194 console.log(` 📊 Content hashes bigmap ID: ${storage.content_hashes}`);
195 });
196
197 it("should have token_creators bigmap", async () => {
198 const storage = await getContractStorage(address, network);
199 expect(storage.token_creators).toBeDefined();
200 console.log(` 📊 Token creators bigmap ID: ${storage.token_creators}`);
201 });
202
203 it("should have metadata_locked bigmap", async () => {
204 const storage = await getContractStorage(address, network);
205 expect(storage.metadata_locked).toBeDefined();
206 console.log(` 📊 Metadata locked bigmap ID: ${storage.metadata_locked}`);
207 });
208
209 it("should have ledger bigmap", async () => {
210 const storage = await getContractStorage(address, network);
211 expect(storage.ledger).toBeDefined();
212 console.log(` 📊 Ledger bigmap ID: ${storage.ledger}`);
213 });
214
215 it("should have token_metadata bigmap", async () => {
216 const storage = await getContractStorage(address, network);
217 expect(storage.token_metadata).toBeDefined();
218 console.log(` 📊 Token metadata bigmap ID: ${storage.token_metadata}`);
219 });
220
221 it("should have operators bigmap", async () => {
222 const storage = await getContractStorage(address, network);
223 expect(storage.operators).toBeDefined();
224 console.log(` 📊 Operators bigmap ID: ${storage.operators}`);
225 });
226 });
227
228 describe("📜 Operation History", () => {
229 it("should have mint operations (keep entrypoint)", async () => {
230 const operations = await getOperations(address, 'keep', network, 5);
231
232 if (operations.length > 0) {
233 console.log(` ✅ Found ${operations.length} mint operations`);
234 console.log(` 📊 Latest mint: ${operations[0].hash} (block ${operations[0].level})`);
235 } else {
236 console.log(` ⚠️ No mint operations found yet`);
237 }
238 });
239
240 it("should verify all operations were successful", async () => {
241 const operations = await getOperations(address, 'keep', network, 10);
242
243 operations.forEach(op => {
244 expect(op.status).toBe('applied');
245 });
246
247 if (operations.length > 0) {
248 console.log(` ✅ All ${operations.length} operations successful`);
249 }
250 });
251
252 it("should have operation sender information", async () => {
253 const operations = await getOperations(address, 'keep', network, 1);
254
255 if (operations.length > 0) {
256 const op = operations[0];
257 expect(op.sender).toBeDefined();
258 expect(op.sender.address).toBeDefined();
259 console.log(` 📊 Latest mint sender: ${op.sender.address}`);
260 }
261 });
262 });
263
264 describe("🔍 Contract Verification", () => {
265 it("should be a valid FA2 contract", async () => {
266 const storage = await getContractStorage(address, network);
267
268 // Check FA2 required storage
269 expect(storage.ledger).toBeDefined();
270 expect(storage.operators).toBeDefined();
271 expect(storage.token_metadata).toBeDefined();
272
273 console.log(` ✅ Contract has FA2 storage structure`);
274 });
275
276 it("should have v4-specific storage (pause, royalty)", async () => {
277 const storage = await getContractStorage(address, network);
278
279 // v4 specific fields
280 expect(storage.paused).toBeDefined();
281 expect(storage.default_royalty_bps).toBeDefined();
282
283 console.log(` ✅ Contract has v4-specific storage fields`);
284 });
285
286 it("should have creator tracking (v3 feature)", async () => {
287 const storage = await getContractStorage(address, network);
288 expect(storage.token_creators).toBeDefined();
289 console.log(` ✅ Contract has creator tracking (v3 feature)`);
290 });
291
292 it("should have content hash deduplication (v3 feature)", async () => {
293 const storage = await getContractStorage(address, network);
294 expect(storage.content_hashes).toBeDefined();
295 console.log(` ✅ Contract has content hash deduplication (v3 feature)`);
296 });
297
298 it("should have metadata locking support (v3 feature)", async () => {
299 const storage = await getContractStorage(address, network);
300 expect(storage.metadata_locked).toBeDefined();
301 expect(storage.contract_metadata_locked).toBeDefined();
302 console.log(` ✅ Contract has metadata locking support (v3 feature)`);
303 });
304 });
305});