@rareprotocol/rare-cli 0.2.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command10 } from "commander";
4
+ import { Command as Command13 } from "commander";
5
5
 
6
6
  // src/commands/configure.ts
7
7
  import { Command } from "commander";
@@ -55,6 +55,42 @@ var contractAddresses = {
55
55
  auction: "0x1f0c946f0ee87acb268d50ede6c9b4d010af65d2"
56
56
  }
57
57
  };
58
+ var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
59
+ var currencyAddresses = {
60
+ eth: {
61
+ mainnet: ETH_ADDRESS,
62
+ sepolia: ETH_ADDRESS,
63
+ base: ETH_ADDRESS,
64
+ "base-sepolia": ETH_ADDRESS
65
+ },
66
+ rare: {
67
+ mainnet: "0xba5BDe662c17e2aDFF1075610382B9B691296350",
68
+ sepolia: "0x197FaeF3f59eC80113e773Bb6206a17d183F97CB",
69
+ base: "0x691077c8e8de54ea84efd454630439f99bd8c92f",
70
+ "base-sepolia": "0x8b21bC8571d11F7AdB705ad8F6f6BD1deb79cE01"
71
+ },
72
+ usdc: {
73
+ mainnet: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
74
+ sepolia: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
75
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
76
+ "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
77
+ }
78
+ };
79
+ var currencyNames = Object.keys(currencyAddresses);
80
+ function resolveCurrency(input, chain) {
81
+ const lower = input.toLowerCase();
82
+ if (lower in currencyAddresses) {
83
+ const addr = currencyAddresses[lower][chain];
84
+ if (!addr) {
85
+ throw new Error(`Currency "${lower}" is not available on "${chain}".`);
86
+ }
87
+ return addr;
88
+ }
89
+ if (input.startsWith("0x")) {
90
+ return input;
91
+ }
92
+ throw new Error(`Unknown currency "${input}". Supported: ${currencyNames.join(", ")} or a 0x address.`);
93
+ }
58
94
  function getContractAddresses(chain) {
59
95
  const addresses = contractAddresses[chain];
60
96
  if (!addresses) {
@@ -218,6 +254,14 @@ function getWalletClient(chain) {
218
254
  };
219
255
  }
220
256
 
257
+ // src/sdk/client.ts
258
+ import {
259
+ erc20Abi,
260
+ parseEther,
261
+ parseEventLogs,
262
+ maxUint256
263
+ } from "viem";
264
+
221
265
  // src/contracts/abis/factory.ts
222
266
  var factoryAbi = [
223
267
  {
@@ -383,71 +427,6 @@ var factoryAbi = [
383
427
  }
384
428
  ];
385
429
 
386
- // src/commands/deploy.ts
387
- function deployErc721Command() {
388
- const cmd = new Command2("erc721");
389
- cmd.description("Deploy a new ERC-721 NFT contract via the RARE factory");
390
- cmd.argument("<name>", "name of the NFT collection").argument("<symbol>", "symbol of the NFT collection").option("--max-tokens <number>", "maximum number of tokens (optional)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (name, symbol, opts) => {
391
- const chain = getActiveChain(opts.chain);
392
- const { client, account } = getWalletClient(chain);
393
- const publicClient = getPublicClient(chain);
394
- const factoryAddress = getContractAddresses(chain).factory;
395
- console.log(`Deploying ERC-721 contract on ${chain}...`);
396
- console.log(` Factory: ${factoryAddress}`);
397
- console.log(` Name: ${name}`);
398
- console.log(` Symbol: ${symbol}`);
399
- if (opts.maxTokens) console.log(` Max tokens: ${opts.maxTokens}`);
400
- let txHash;
401
- if (opts.maxTokens) {
402
- txHash = await client.writeContract({
403
- address: factoryAddress,
404
- abi: factoryAbi,
405
- functionName: "createSovereignBatchMint",
406
- args: [name, symbol, BigInt(opts.maxTokens)],
407
- account,
408
- chain: void 0
409
- });
410
- } else {
411
- txHash = await client.writeContract({
412
- address: factoryAddress,
413
- abi: factoryAbi,
414
- functionName: "createSovereignBatchMint",
415
- args: [name, symbol],
416
- account,
417
- chain: void 0
418
- });
419
- }
420
- console.log(`Transaction sent: ${txHash}`);
421
- console.log("Waiting for confirmation...");
422
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
423
- const { parseEventLogs } = await import("viem");
424
- const logs = parseEventLogs({
425
- abi: factoryAbi,
426
- logs: receipt.logs,
427
- eventName: "SovereignBatchMintCreated"
428
- });
429
- if (logs.length > 0) {
430
- const deployedAddress = logs[0].args.contractAddress;
431
- console.log(`
432
- ERC-721 contract deployed at: ${deployedAddress}`);
433
- } else {
434
- console.log(`
435
- Transaction confirmed. Block: ${receipt.blockNumber}`);
436
- console.log("Could not parse deployed address from logs.");
437
- }
438
- });
439
- return cmd;
440
- }
441
- function deployCommand() {
442
- const cmd = new Command2("deploy");
443
- cmd.description("Deploy a new contract via the RARE protocol");
444
- cmd.addCommand(deployErc721Command());
445
- return cmd;
446
- }
447
-
448
- // src/commands/mint.ts
449
- import { Command as Command3 } from "commander";
450
-
451
430
  // src/contracts/abis/token.ts
452
431
  var tokenAbi = [
453
432
  {
@@ -1206,290 +1185,30 @@ var tokenAbi = [
1206
1185
  }
1207
1186
  ];
1208
1187
 
1209
- // src/ipfs.ts
1210
- import { basename, extname } from "path";
1211
- import { readFile, stat } from "fs/promises";
1212
- import { isAddress } from "viem";
1213
- var API_BASE_URL = "https://api.superrare.org";
1214
- var MIME_TYPES = {
1215
- ".png": "image/png",
1216
- ".jpg": "image/jpeg",
1217
- ".jpeg": "image/jpeg",
1218
- ".gif": "image/gif",
1219
- ".webp": "image/webp",
1220
- ".svg": "image/svg+xml",
1221
- ".mp4": "video/mp4",
1222
- ".mov": "video/quicktime",
1223
- ".webm": "video/webm",
1224
- ".glb": "model/gltf-binary",
1225
- ".gltf": "model/gltf+json",
1226
- ".html": "text/html"
1227
- };
1228
- function inferMimeType(filename) {
1229
- const ext = extname(filename).toLowerCase();
1230
- return MIME_TYPES[ext] ?? "application/octet-stream";
1231
- }
1232
- function assertPositiveInteger(value, fieldName) {
1233
- if (!Number.isInteger(value) || value <= 0) {
1234
- throw new Error(`${fieldName} must be a positive integer`);
1235
- }
1236
- }
1237
- function assertEvmAddress(value, fieldName) {
1238
- if (!isAddress(value)) {
1239
- throw new Error(`${fieldName} must be a valid EVM address`);
1240
- }
1241
- }
1242
- function parseDimensions(dimensions) {
1243
- if (!dimensions) return void 0;
1244
- const [w, h] = dimensions.split("x");
1245
- if (!w || !h) return void 0;
1246
- const width = parseInt(w, 10);
1247
- const height = parseInt(h, 10);
1248
- if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return void 0;
1249
- return { width, height };
1250
- }
1251
- async function apiPost(path2, payload) {
1252
- const url = `${API_BASE_URL}${path2}`;
1253
- const response = await fetch(url, {
1254
- method: "POST",
1255
- headers: { "Content-Type": "application/json" },
1256
- body: JSON.stringify(payload)
1257
- });
1258
- const text = await response.text();
1259
- const json = text ? JSON.parse(text) : {};
1260
- if (!response.ok) {
1261
- const message = json.error ?? text;
1262
- throw new Error(`API error ${response.status} on ${path2}: ${message}`);
1263
- }
1264
- return json;
1265
- }
1266
- async function uploadParts(fileBuffer, partSize, presignedUrls) {
1267
- const parts = [];
1268
- for (let i = 0; i < presignedUrls.length; i++) {
1269
- const start = i * partSize;
1270
- const end = start + partSize;
1271
- const partBuffer = fileBuffer.subarray(start, end);
1272
- const response = await fetch(presignedUrls[i], {
1273
- method: "PUT",
1274
- body: new Uint8Array(partBuffer)
1275
- });
1276
- if (response.status !== 200 && response.status !== 204) {
1277
- throw new Error(`Part ${i + 1} upload failed with status ${response.status}`);
1278
- }
1279
- const etag = response.headers.get("etag");
1280
- if (!etag) {
1281
- throw new Error(`Missing etag header for part ${i + 1}`);
1282
- }
1283
- parts.push({ ETag: etag, PartNumber: i + 1 });
1284
- }
1285
- return parts;
1286
- }
1287
- async function uploadMedia(filePath, label) {
1288
- const fileStats = await stat(filePath);
1289
- const fileSize = fileStats.size;
1290
- const fileName = basename(filePath);
1291
- const fileBuffer = await readFile(filePath);
1292
- const mimeType = inferMimeType(fileName);
1293
- console.log(`Uploading ${label}: ${fileName} (${fileSize} bytes, ${mimeType})`);
1294
- const init = await apiPost("/api/nft/media-upload-url", {
1295
- fileSize,
1296
- filename: fileName
1297
- });
1298
- console.log(` Multipart upload initialized (${init.presignedUrls.length} parts)`);
1299
- const parts = await uploadParts(fileBuffer, init.partSize, init.presignedUrls);
1300
- console.log(` All parts uploaded`);
1301
- const complete = await apiPost("/api/nft/media-upload-complete", {
1302
- key: init.key,
1303
- uploadId: init.uploadId,
1304
- bucket: init.bucket,
1305
- parts
1306
- });
1307
- console.log(` Upload complete: ${complete.ipfsUrl}`);
1308
- const generated = await apiPost("/api/nft/media-generate", {
1309
- uri: complete.ipfsUrl,
1310
- mimeType
1311
- });
1312
- const dimensions = parseDimensions(generated.media.dimensions);
1313
- const entry = {
1314
- url: generated.media.uri,
1315
- mimeType: generated.media.mimeType,
1316
- size: generated.media.size ?? fileSize,
1317
- ...dimensions ? { dimensions } : {}
1318
- };
1319
- console.log(` Media generated: ${entry.url}`);
1320
- return entry;
1321
- }
1322
- async function importErc721(opts) {
1323
- assertPositiveInteger(opts.chainId, "chainId");
1324
- assertEvmAddress(opts.contractAddress, "contractAddress");
1325
- assertEvmAddress(opts.ownerAddress, "ownerAddress");
1326
- const normalizedContractAddress = opts.contractAddress.toLowerCase();
1327
- const normalizedOwnerAddress = opts.ownerAddress.toLowerCase();
1328
- const result = await apiPost("/api/nft/import-erc721", {
1329
- chainId: opts.chainId,
1330
- contractAddress: normalizedContractAddress,
1331
- ownerAddress: normalizedOwnerAddress
1332
- });
1333
- if (result.ok !== true) {
1334
- throw new Error("Unexpected response from /api/nft/import-erc721");
1335
- }
1336
- }
1337
- async function pinMetadata(opts) {
1338
- const nftMedia = {
1339
- image: opts.image
1340
- };
1341
- if (opts.video) {
1342
- nftMedia.video = opts.video;
1343
- }
1344
- const payload = {
1345
- name: opts.name,
1346
- description: opts.description,
1347
- nftMedia,
1348
- tags: opts.tags ?? []
1349
- };
1350
- if (opts.attributes && opts.attributes.length > 0) {
1351
- payload.attributes = opts.attributes;
1352
- }
1353
- console.log("Pinning metadata to IPFS...");
1354
- const result = await apiPost("/api/nft/metadata", payload);
1355
- console.log(`Metadata pinned: ${result.ipfsUrl}`);
1356
- console.log(`Gateway URL: ${result.gatewayUrl}`);
1357
- return result.ipfsUrl;
1358
- }
1359
-
1360
- // src/commands/mint.ts
1361
- function parseAttribute(raw) {
1362
- if (raw.startsWith("{")) {
1363
- const parsed = JSON.parse(raw);
1364
- if (parsed.value === void 0) {
1365
- throw new Error(`Attribute JSON must include "value": ${raw}`);
1366
- }
1367
- return parsed;
1368
- }
1369
- const eqIndex = raw.indexOf("=");
1370
- if (eqIndex === -1) {
1371
- return { value: raw };
1372
- }
1373
- const trait_type = raw.slice(0, eqIndex);
1374
- const rawValue = raw.slice(eqIndex + 1);
1375
- const numValue = Number(rawValue);
1376
- const value = rawValue.length > 0 && !Number.isNaN(numValue) ? numValue : rawValue;
1377
- return { trait_type, value };
1378
- }
1379
- function mintCommand() {
1380
- const cmd = new Command3("mint");
1381
- cmd.description("Mint a new NFT on a deployed token contract");
1382
- cmd.requiredOption("--contract <address>", "token contract address").option("--token-uri <uri>", "token metadata URI (skip upload if provided)").option("--name <name>", "NFT name").option("--description <description>", "NFT description").option("--image <path>", "path to image file").option("--video <path>", "path to video file").option("--tag <tag>", "tag (repeatable)", (val, acc) => [...acc, val], []).option("--attribute <attr>", 'attribute as "trait=value" or JSON (repeatable)', (val, acc) => [...acc, val], []).option("--to <address>", "recipient address (defaults to caller)").option("--royalty-receiver <address>", "royalty receiver address (defaults to caller)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
1383
- let tokenUri;
1384
- if (opts.tokenUri) {
1385
- tokenUri = opts.tokenUri;
1386
- } else {
1387
- if (!opts.name) {
1388
- console.error("Error: --name is required when not using --token-uri");
1389
- process.exit(1);
1390
- }
1391
- if (!opts.description) {
1392
- console.error("Error: --description is required when not using --token-uri");
1393
- process.exit(1);
1188
+ // src/contracts/abis/auction.ts
1189
+ var auctionAbi = [
1190
+ {
1191
+ "type": "function",
1192
+ "name": "COLDIE_AUCTION",
1193
+ "inputs": [],
1194
+ "outputs": [
1195
+ {
1196
+ "name": "",
1197
+ "type": "bytes32",
1198
+ "internalType": "bytes32"
1394
1199
  }
1395
- if (!opts.image) {
1396
- console.error("Error: --image is required when not using --token-uri");
1397
- process.exit(1);
1398
- }
1399
- const imageMedia = await uploadMedia(opts.image, "image");
1400
- const videoMedia = opts.video ? await uploadMedia(opts.video, "video") : void 0;
1401
- const tags = opts.tag.length > 0 ? opts.tag : void 0;
1402
- const attributes = opts.attribute.length > 0 ? opts.attribute.map(parseAttribute) : void 0;
1403
- tokenUri = await pinMetadata({
1404
- name: opts.name,
1405
- description: opts.description,
1406
- image: imageMedia,
1407
- video: videoMedia,
1408
- tags,
1409
- attributes
1410
- });
1411
- }
1412
- const chain = getActiveChain(opts.chain);
1413
- const { client, account } = getWalletClient(chain);
1414
- const publicClient = getPublicClient(chain);
1415
- const contractAddress = opts.contract;
1416
- const useMintTo = opts.to || opts.royaltyReceiver;
1417
- console.log(`
1418
- Minting NFT on ${chain}...`);
1419
- console.log(` Contract: ${contractAddress}`);
1420
- console.log(` URI: ${tokenUri}`);
1421
- let txHash;
1422
- if (useMintTo) {
1423
- const receiver = opts.to ?? account.address;
1424
- const royaltyReceiver = opts.royaltyReceiver ?? account.address;
1425
- console.log(` To: ${receiver}`);
1426
- console.log(` Royalty receiver: ${royaltyReceiver}`);
1427
- txHash = await client.writeContract({
1428
- address: contractAddress,
1429
- abi: tokenAbi,
1430
- functionName: "mintTo",
1431
- args: [tokenUri, receiver, royaltyReceiver],
1432
- account,
1433
- chain: void 0
1434
- });
1435
- } else {
1436
- txHash = await client.writeContract({
1437
- address: contractAddress,
1438
- abi: tokenAbi,
1439
- functionName: "addNewToken",
1440
- args: [tokenUri],
1441
- account,
1442
- chain: void 0
1443
- });
1444
- }
1445
- console.log(`Transaction sent: ${txHash}`);
1446
- console.log("Waiting for confirmation...");
1447
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
1448
- const { parseEventLogs } = await import("viem");
1449
- const logs = parseEventLogs({
1450
- abi: tokenAbi,
1451
- logs: receipt.logs,
1452
- eventName: "Transfer"
1453
- });
1454
- if (logs.length > 0) {
1455
- console.log(`
1456
- NFT minted! Token ID: ${logs[0].args.tokenId}`);
1457
- } else {
1458
- console.log(`
1459
- Transaction confirmed. Block: ${receipt.blockNumber}`);
1460
- }
1461
- });
1462
- return cmd;
1463
- }
1464
-
1465
- // src/commands/auction.ts
1466
- import { Command as Command4 } from "commander";
1467
- import { parseEther, formatEther } from "viem";
1468
-
1469
- // src/contracts/abis/auction.ts
1470
- var auctionAbi = [
1471
- {
1472
- "type": "function",
1473
- "name": "COLDIE_AUCTION",
1474
- "inputs": [],
1475
- "outputs": [
1476
- {
1477
- "name": "",
1478
- "type": "bytes32",
1479
- "internalType": "bytes32"
1480
- }
1481
- ],
1482
- "stateMutability": "view"
1483
- },
1484
- {
1485
- "type": "function",
1486
- "name": "NO_AUCTION",
1487
- "inputs": [],
1488
- "outputs": [
1489
- {
1490
- "name": "",
1491
- "type": "bytes32",
1492
- "internalType": "bytes32"
1200
+ ],
1201
+ "stateMutability": "view"
1202
+ },
1203
+ {
1204
+ "type": "function",
1205
+ "name": "NO_AUCTION",
1206
+ "inputs": [],
1207
+ "outputs": [
1208
+ {
1209
+ "name": "",
1210
+ "type": "bytes32",
1211
+ "internalType": "bytes32"
1493
1212
  }
1494
1213
  ],
1495
1214
  "stateMutability": "view"
@@ -3037,35 +2756,178 @@ var auctionAbi = [
3037
2756
  }
3038
2757
  ];
3039
2758
 
3040
- // src/errors.ts
3041
- function printContractError(error) {
3042
- if (!(error instanceof Error)) {
3043
- console.error("\nTransaction failed:", error);
3044
- process.exit(1);
2759
+ // src/sdk/api.ts
2760
+ import { isAddress } from "viem";
2761
+ var API_BASE_URL = "https://api.superrare.org";
2762
+ var MIME_TYPES = {
2763
+ ".png": "image/png",
2764
+ ".jpg": "image/jpeg",
2765
+ ".jpeg": "image/jpeg",
2766
+ ".gif": "image/gif",
2767
+ ".webp": "image/webp",
2768
+ ".svg": "image/svg+xml",
2769
+ ".mp4": "video/mp4",
2770
+ ".mov": "video/quicktime",
2771
+ ".webm": "video/webm",
2772
+ ".glb": "model/gltf-binary",
2773
+ ".gltf": "model/gltf+json",
2774
+ ".html": "text/html"
2775
+ };
2776
+ function inferMimeType(filename) {
2777
+ const extIndex = filename.lastIndexOf(".");
2778
+ const ext = extIndex === -1 ? "" : filename.slice(extIndex).toLowerCase();
2779
+ return MIME_TYPES[ext] ?? "application/octet-stream";
2780
+ }
2781
+ function normalizeFilename(filename) {
2782
+ const normalized = filename.replaceAll("\\", "/");
2783
+ const lastSeparator = normalized.lastIndexOf("/");
2784
+ return lastSeparator === -1 ? normalized : normalized.slice(lastSeparator + 1);
2785
+ }
2786
+ function assertPositiveInteger(value, fieldName) {
2787
+ if (!Number.isInteger(value) || value <= 0) {
2788
+ throw new Error(`${fieldName} must be a positive integer`);
3045
2789
  }
3046
- console.error("\nTransaction failed:");
3047
- let current = error;
3048
- let depth = 0;
3049
- while (current instanceof Error) {
3050
- const indent = " ".repeat(depth + 1);
3051
- const msg = current.shortMessage ?? current.message;
3052
- console.error(`${indent}${msg}`);
3053
- if ("reason" in current && current.reason) {
3054
- console.error(`${indent}Revert reason: ${current.reason}`);
2790
+ }
2791
+ function assertEvmAddress(value, fieldName) {
2792
+ if (!isAddress(value)) {
2793
+ throw new Error(`${fieldName} must be a valid EVM address`);
2794
+ }
2795
+ }
2796
+ function parseDimensions(dimensions) {
2797
+ if (!dimensions) return void 0;
2798
+ const [w, h] = dimensions.split("x");
2799
+ if (!w || !h) return void 0;
2800
+ const width = Number.parseInt(w, 10);
2801
+ const height = Number.parseInt(h, 10);
2802
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
2803
+ return void 0;
2804
+ }
2805
+ return { width, height };
2806
+ }
2807
+ async function apiPost(path2, payload) {
2808
+ const url = `${API_BASE_URL}${path2}`;
2809
+ const response = await fetch(url, {
2810
+ method: "POST",
2811
+ headers: { "Content-Type": "application/json" },
2812
+ body: JSON.stringify(payload)
2813
+ });
2814
+ const text = await response.text();
2815
+ const json = text ? JSON.parse(text) : {};
2816
+ if (!response.ok) {
2817
+ const message = json.error ?? text;
2818
+ throw new Error(`API error ${response.status} on ${path2}: ${String(message)}`);
2819
+ }
2820
+ return json;
2821
+ }
2822
+ async function uploadParts(fileBuffer, partSize, presignedUrls) {
2823
+ const parts = [];
2824
+ for (let i = 0; i < presignedUrls.length; i++) {
2825
+ const start = i * partSize;
2826
+ const end = start + partSize;
2827
+ const partBuffer = fileBuffer.subarray(start, end);
2828
+ const response = await fetch(presignedUrls[i], {
2829
+ method: "PUT",
2830
+ body: new Uint8Array(partBuffer)
2831
+ });
2832
+ if (response.status !== 200 && response.status !== 204) {
2833
+ throw new Error(`Part ${i + 1} upload failed with status ${response.status}`);
3055
2834
  }
3056
- if ("metaMessages" in current && Array.isArray(current.metaMessages)) {
3057
- for (const line of current.metaMessages) {
3058
- if (line.trim()) console.error(`${indent}${line.trim()}`);
3059
- }
2835
+ const etag = response.headers.get("etag");
2836
+ if (!etag) {
2837
+ throw new Error(`Missing etag header for part ${i + 1}`);
3060
2838
  }
3061
- current = current.cause;
3062
- depth++;
2839
+ parts.push({ ETag: etag, PartNumber: i + 1 });
3063
2840
  }
3064
- process.exit(1);
2841
+ return parts;
2842
+ }
2843
+ async function uploadMedia(buffer, filename) {
2844
+ const fileSize = buffer.byteLength;
2845
+ const safeFilename = normalizeFilename(filename);
2846
+ const mimeType = inferMimeType(safeFilename);
2847
+ const init = await apiPost("/api/nft/media-upload-url", {
2848
+ fileSize,
2849
+ filename: safeFilename
2850
+ });
2851
+ const parts = await uploadParts(buffer, init.partSize, init.presignedUrls);
2852
+ const complete = await apiPost("/api/nft/media-upload-complete", {
2853
+ key: init.key,
2854
+ uploadId: init.uploadId,
2855
+ bucket: init.bucket,
2856
+ parts
2857
+ });
2858
+ const generated = await apiPost("/api/nft/media-generate", {
2859
+ uri: complete.ipfsUrl,
2860
+ mimeType
2861
+ });
2862
+ const dimensions = parseDimensions(generated.media.dimensions);
2863
+ return {
2864
+ url: generated.media.uri,
2865
+ mimeType: generated.media.mimeType,
2866
+ size: generated.media.size ?? fileSize,
2867
+ ...dimensions ? { dimensions } : {}
2868
+ };
2869
+ }
2870
+ async function pinMetadata(opts) {
2871
+ const nftMedia = {
2872
+ image: opts.image
2873
+ };
2874
+ if (opts.video) {
2875
+ nftMedia.video = opts.video;
2876
+ }
2877
+ const payload = {
2878
+ name: opts.name,
2879
+ description: opts.description,
2880
+ nftMedia,
2881
+ tags: opts.tags ?? []
2882
+ };
2883
+ if (opts.attributes && opts.attributes.length > 0) {
2884
+ payload.attributes = opts.attributes;
2885
+ }
2886
+ const result = await apiPost("/api/nft/metadata", payload);
2887
+ return result.ipfsUrl;
2888
+ }
2889
+ async function importErc721(opts) {
2890
+ assertPositiveInteger(opts.chainId, "chainId");
2891
+ assertEvmAddress(opts.contract, "contract");
2892
+ assertEvmAddress(opts.owner, "owner");
2893
+ const result = await apiPost("/api/nft/import-erc721", {
2894
+ chainId: opts.chainId,
2895
+ contractAddress: opts.contract.toLowerCase(),
2896
+ ownerAddress: opts.owner.toLowerCase()
2897
+ });
2898
+ if (result.ok !== true) {
2899
+ throw new Error("Unexpected response from /api/nft/import-erc721");
2900
+ }
2901
+ }
2902
+ async function searchPost(path2, payload) {
2903
+ return apiPost(path2, payload);
2904
+ }
2905
+ async function searchNfts(params = {}) {
2906
+ return searchPost("/api/search/nfts", {
2907
+ query: params.query ?? "",
2908
+ take: params.take ?? 24,
2909
+ cursor: params.cursor ?? 0,
2910
+ sortBy: params.sortBy ?? "RECENT_ACTIVITY_DESC",
2911
+ ownerAddresses: params.ownerAddresses ?? [],
2912
+ creatorAddresses: params.creatorAddresses ?? [],
2913
+ collectionIds: params.collectionIds ?? [],
2914
+ contractAddresses: params.contractAddresses ?? [],
2915
+ ...params.auctionStates ? { auctionStates: params.auctionStates } : {},
2916
+ ...params.chainIds ? { chainIds: params.chainIds } : {}
2917
+ });
2918
+ }
2919
+ async function searchCollections(params = {}) {
2920
+ return searchPost("/api/search/collections", {
2921
+ query: params.query ?? "",
2922
+ take: params.take ?? 24,
2923
+ cursor: params.cursor ?? 0,
2924
+ sortBy: params.sortBy ?? "NEWEST",
2925
+ ownerAddresses: params.ownerAddresses ?? []
2926
+ });
3065
2927
  }
3066
2928
 
3067
- // src/commands/auction.ts
3068
- var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
2929
+ // src/sdk/client.ts
2930
+ var ETH_ADDRESS2 = "0x0000000000000000000000000000000000000000";
3069
2931
  var approvalAbi = [
3070
2932
  {
3071
2933
  inputs: [{ name: "owner", type: "address" }, { name: "operator", type: "address" }],
@@ -3082,183 +2944,1099 @@ var approvalAbi = [
3082
2944
  type: "function"
3083
2945
  }
3084
2946
  ];
3085
- function auctionCommand() {
3086
- const cmd = new Command4("auction");
3087
- cmd.description("Auction subcommands (create, bid, settle, cancel, status)");
3088
- cmd.command("create").description("Configure and start an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID to auction").requiredOption("--starting-price <amount>", "starting price in ETH (or token units)").requiredOption("--duration <seconds>", "auction duration in seconds").option("--currency <address>", "ERC20 currency address (defaults to ETH)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3089
- const chain = getActiveChain(opts.chain);
3090
- const { client, account } = getWalletClient(chain);
3091
- const publicClient = getPublicClient(chain);
3092
- const auctionAddress = getContractAddresses(chain).auction;
3093
- const currency = opts.currency ?? ETH_ADDRESS;
3094
- console.log(`Creating auction on ${chain}...`);
3095
- console.log(` Auction contract: ${auctionAddress}`);
3096
- console.log(` NFT contract: ${opts.contract}`);
3097
- console.log(` Token ID: ${opts.tokenId}`);
3098
- console.log(` Starting price: ${opts.startingPrice} ETH`);
3099
- console.log(` Duration: ${opts.duration} seconds`);
3100
- const nftAddress = opts.contract;
3101
- const isApproved = await publicClient.readContract({
3102
- address: nftAddress,
3103
- abi: approvalAbi,
3104
- functionName: "isApprovedForAll",
3105
- args: [account.address, auctionAddress]
3106
- });
3107
- if (!isApproved) {
3108
- console.log("\nApproval required. Requesting setApprovalForAll...");
3109
- const approveTxHash = await client.writeContract({
3110
- address: nftAddress,
3111
- abi: approvalAbi,
3112
- functionName: "setApprovalForAll",
3113
- args: [auctionAddress, true],
3114
- account,
3115
- chain: void 0
3116
- });
3117
- console.log(`Approval tx sent: ${approveTxHash}`);
3118
- await publicClient.waitForTransactionReceipt({ hash: approveTxHash });
3119
- console.log("Approval confirmed.\n");
3120
- } else {
3121
- console.log("(Already approved)\n");
3122
- }
3123
- const tokenId = BigInt(opts.tokenId);
3124
- const startingPrice = parseEther(opts.startingPrice);
3125
- const duration = BigInt(opts.duration);
3126
- const auctionType = await publicClient.readContract({
3127
- address: auctionAddress,
3128
- abi: auctionAbi,
3129
- functionName: "COLDIE_AUCTION"
3130
- });
3131
- const splitAddresses = [account.address];
3132
- const splitRatios = [100];
3133
- console.log("\nTransaction details:");
3134
- console.log(` NFT: ${nftAddress}`);
3135
- console.log(` Token ID: ${tokenId}`);
3136
- console.log(` Starting price: ${opts.startingPrice} ETH (${startingPrice}wei)`);
3137
- console.log(` Duration: ${duration}s`);
3138
- console.log(` Currency: ${currency === ETH_ADDRESS ? "ETH" : currency}`);
3139
- let txHash;
3140
- try {
3141
- txHash = await client.writeContract({
3142
- address: auctionAddress,
3143
- abi: auctionAbi,
3144
- functionName: "configureAuction",
3145
- args: [
3146
- auctionType,
3147
- nftAddress,
3148
- tokenId,
3149
- startingPrice,
3150
- currency,
3151
- duration,
3152
- 0n,
3153
- splitAddresses,
3154
- splitRatios
3155
- ],
3156
- account,
3157
- chain: void 0
3158
- });
3159
- } catch (error) {
3160
- printContractError(error);
2947
+ var marketplaceSettingsAbi = [
2948
+ {
2949
+ inputs: [{ name: "_amount", type: "uint256" }],
2950
+ name: "calculateMarketplaceFee",
2951
+ outputs: [{ name: "", type: "uint256" }],
2952
+ stateMutability: "view",
2953
+ type: "function"
2954
+ }
2955
+ ];
2956
+ function resolveChainFromPublicClient(publicClient) {
2957
+ const chainId = publicClient.chain?.id;
2958
+ if (!chainId) {
2959
+ throw new Error("Unable to resolve chain from publicClient.chain.id. Create your public client with an explicit chain.");
2960
+ }
2961
+ for (const [chain, id] of Object.entries(chainIds)) {
2962
+ if (id === chainId) {
2963
+ return chain;
2964
+ }
2965
+ }
2966
+ throw new Error(`Unsupported chain id: ${chainId}. Supported chain ids: ${Object.values(chainIds).join(", ")}`);
2967
+ }
2968
+ function requireWallet(config) {
2969
+ if (!config.walletClient) {
2970
+ throw new Error("walletClient is required for write operations.");
2971
+ }
2972
+ const walletAccount = config.walletClient.account;
2973
+ if (config.account) {
2974
+ if (walletAccount && walletAccount.address.toLowerCase() === config.account.toLowerCase()) {
2975
+ return {
2976
+ walletClient: config.walletClient,
2977
+ account: walletAccount,
2978
+ accountAddress: walletAccount.address
2979
+ };
2980
+ }
2981
+ return {
2982
+ walletClient: config.walletClient,
2983
+ account: config.account,
2984
+ accountAddress: config.account
2985
+ };
2986
+ }
2987
+ if (!walletAccount) {
2988
+ throw new Error("No account available for write operations. Pass config.account or provide walletClient with an account.");
2989
+ }
2990
+ return {
2991
+ walletClient: config.walletClient,
2992
+ account: walletAccount,
2993
+ accountAddress: walletAccount.address
2994
+ };
2995
+ }
2996
+ function toInteger(value, field) {
2997
+ if (typeof value === "bigint") return value;
2998
+ if (typeof value === "number") {
2999
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
3000
+ throw new Error(`${field} must be an integer.`);
3001
+ }
3002
+ return BigInt(value);
3003
+ }
3004
+ try {
3005
+ return BigInt(value);
3006
+ } catch {
3007
+ throw new Error(`${field} must be an integer.`);
3008
+ }
3009
+ }
3010
+ function toWei(value) {
3011
+ if (typeof value === "bigint") {
3012
+ return value;
3013
+ }
3014
+ return parseEther(String(value));
3015
+ }
3016
+ function createRareClient(config) {
3017
+ const { publicClient } = config;
3018
+ const chain = resolveChainFromPublicClient(publicClient);
3019
+ const chainId = chainIds[chain];
3020
+ const addresses = getContractAddresses(chain);
3021
+ return {
3022
+ chain,
3023
+ chainId,
3024
+ contracts: {
3025
+ factory: addresses.factory,
3026
+ auction: addresses.auction
3027
+ },
3028
+ deploy: {
3029
+ async erc721(params) {
3030
+ const { walletClient, account } = requireWallet(config);
3031
+ let txHash;
3032
+ if (params.maxTokens !== void 0) {
3033
+ txHash = await walletClient.writeContract({
3034
+ address: addresses.factory,
3035
+ abi: factoryAbi,
3036
+ functionName: "createSovereignBatchMint",
3037
+ args: [params.name, params.symbol, toInteger(params.maxTokens, "maxTokens")],
3038
+ account,
3039
+ chain: void 0
3040
+ });
3041
+ } else {
3042
+ txHash = await walletClient.writeContract({
3043
+ address: addresses.factory,
3044
+ abi: factoryAbi,
3045
+ functionName: "createSovereignBatchMint",
3046
+ args: [params.name, params.symbol],
3047
+ account,
3048
+ chain: void 0
3049
+ });
3050
+ }
3051
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3052
+ const logs = parseEventLogs({
3053
+ abi: factoryAbi,
3054
+ logs: receipt.logs,
3055
+ eventName: "SovereignBatchMintCreated"
3056
+ });
3057
+ return {
3058
+ txHash,
3059
+ receipt,
3060
+ contract: logs[0]?.args.contractAddress
3061
+ };
3062
+ }
3063
+ },
3064
+ mint: {
3065
+ async mintTo(params) {
3066
+ const { walletClient, account, accountAddress } = requireWallet(config);
3067
+ const useMintTo = Boolean(params.to || params.royaltyReceiver);
3068
+ let txHash;
3069
+ if (useMintTo) {
3070
+ const receiver = params.to ?? accountAddress;
3071
+ const royaltyReceiver = params.royaltyReceiver ?? accountAddress;
3072
+ txHash = await walletClient.writeContract({
3073
+ address: params.contract,
3074
+ abi: tokenAbi,
3075
+ functionName: "mintTo",
3076
+ args: [params.tokenUri, receiver, royaltyReceiver],
3077
+ account,
3078
+ chain: void 0
3079
+ });
3080
+ } else {
3081
+ txHash = await walletClient.writeContract({
3082
+ address: params.contract,
3083
+ abi: tokenAbi,
3084
+ functionName: "addNewToken",
3085
+ args: [params.tokenUri],
3086
+ account,
3087
+ chain: void 0
3088
+ });
3089
+ }
3090
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3091
+ const logs = parseEventLogs({
3092
+ abi: tokenAbi,
3093
+ logs: receipt.logs,
3094
+ eventName: "Transfer"
3095
+ });
3096
+ return {
3097
+ txHash,
3098
+ receipt,
3099
+ tokenId: logs[0]?.args.tokenId
3100
+ };
3101
+ }
3102
+ },
3103
+ auction: {
3104
+ async create(params) {
3105
+ const { walletClient, account, accountAddress } = requireWallet(config);
3106
+ const nftAddress = params.contract;
3107
+ const currency = params.currency ?? ETH_ADDRESS2;
3108
+ const tokenId = toInteger(params.tokenId, "tokenId");
3109
+ const startingPrice = toWei(params.startingPrice);
3110
+ const duration = toInteger(params.duration, "duration");
3111
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3112
+ const splitRatios = params.splitRatios ?? [100];
3113
+ let approvalTxHash;
3114
+ if (params.autoApprove !== false) {
3115
+ const isApproved = await publicClient.readContract({
3116
+ address: nftAddress,
3117
+ abi: approvalAbi,
3118
+ functionName: "isApprovedForAll",
3119
+ args: [accountAddress, addresses.auction]
3120
+ });
3121
+ if (!isApproved) {
3122
+ approvalTxHash = await walletClient.writeContract({
3123
+ address: nftAddress,
3124
+ abi: approvalAbi,
3125
+ functionName: "setApprovalForAll",
3126
+ args: [addresses.auction, true],
3127
+ account,
3128
+ chain: void 0
3129
+ });
3130
+ await publicClient.waitForTransactionReceipt({ hash: approvalTxHash });
3131
+ }
3132
+ }
3133
+ const auctionType = await publicClient.readContract({
3134
+ address: addresses.auction,
3135
+ abi: auctionAbi,
3136
+ functionName: "COLDIE_AUCTION"
3137
+ });
3138
+ const txHash = await walletClient.writeContract({
3139
+ address: addresses.auction,
3140
+ abi: auctionAbi,
3141
+ functionName: "configureAuction",
3142
+ args: [
3143
+ auctionType,
3144
+ nftAddress,
3145
+ tokenId,
3146
+ startingPrice,
3147
+ currency,
3148
+ duration,
3149
+ 0n,
3150
+ splitAddresses,
3151
+ splitRatios
3152
+ ],
3153
+ account,
3154
+ chain: void 0
3155
+ });
3156
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3157
+ return {
3158
+ txHash,
3159
+ receipt,
3160
+ approvalTxHash
3161
+ };
3162
+ },
3163
+ async bid(params) {
3164
+ const { walletClient, account, accountAddress } = requireWallet(config);
3165
+ const currency = params.currency ?? ETH_ADDRESS2;
3166
+ const amount = toWei(params.amount);
3167
+ const isEth = currency === ETH_ADDRESS2;
3168
+ let value = 0n;
3169
+ if (isEth) {
3170
+ const settingsAddress = await publicClient.readContract({
3171
+ address: addresses.auction,
3172
+ abi: auctionAbi,
3173
+ functionName: "marketplaceSettings"
3174
+ });
3175
+ const fee = await publicClient.readContract({
3176
+ address: settingsAddress,
3177
+ abi: marketplaceSettingsAbi,
3178
+ functionName: "calculateMarketplaceFee",
3179
+ args: [amount]
3180
+ });
3181
+ value = amount + fee;
3182
+ } else {
3183
+ try {
3184
+ const allowance = await publicClient.readContract({
3185
+ address: currency,
3186
+ abi: erc20Abi,
3187
+ functionName: "allowance",
3188
+ args: [accountAddress, addresses.auction]
3189
+ });
3190
+ if (BigInt(allowance) < amount) {
3191
+ const approveTx = await walletClient.writeContract({
3192
+ address: currency,
3193
+ abi: erc20Abi,
3194
+ functionName: "approve",
3195
+ args: [addresses.auction, maxUint256],
3196
+ account,
3197
+ chain: void 0
3198
+ });
3199
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3200
+ }
3201
+ } catch {
3202
+ const approveTx = await walletClient.writeContract({
3203
+ address: currency,
3204
+ abi: erc20Abi,
3205
+ functionName: "approve",
3206
+ args: [addresses.auction, maxUint256],
3207
+ account,
3208
+ chain: void 0
3209
+ });
3210
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3211
+ }
3212
+ }
3213
+ const txHash = await walletClient.writeContract({
3214
+ address: addresses.auction,
3215
+ abi: auctionAbi,
3216
+ functionName: "bid",
3217
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount],
3218
+ account,
3219
+ chain: void 0,
3220
+ value
3221
+ });
3222
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3223
+ return { txHash, receipt };
3224
+ },
3225
+ async settle(params) {
3226
+ const { walletClient, account } = requireWallet(config);
3227
+ const txHash = await walletClient.writeContract({
3228
+ address: addresses.auction,
3229
+ abi: auctionAbi,
3230
+ functionName: "settleAuction",
3231
+ args: [params.contract, toInteger(params.tokenId, "tokenId")],
3232
+ account,
3233
+ chain: void 0
3234
+ });
3235
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3236
+ return { txHash, receipt };
3237
+ },
3238
+ async cancel(params) {
3239
+ const { walletClient, account } = requireWallet(config);
3240
+ const txHash = await walletClient.writeContract({
3241
+ address: addresses.auction,
3242
+ abi: auctionAbi,
3243
+ functionName: "cancelAuction",
3244
+ args: [params.contract, toInteger(params.tokenId, "tokenId")],
3245
+ account,
3246
+ chain: void 0
3247
+ });
3248
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3249
+ return { txHash, receipt };
3250
+ },
3251
+ async getStatus(params) {
3252
+ const result = await publicClient.readContract({
3253
+ address: addresses.auction,
3254
+ abi: auctionAbi,
3255
+ functionName: "getAuctionDetails",
3256
+ args: [params.contract, toInteger(params.tokenId, "tokenId")]
3257
+ });
3258
+ const [
3259
+ seller,
3260
+ creationBlock,
3261
+ startingTime,
3262
+ lengthOfAuction,
3263
+ currency,
3264
+ minimumBid,
3265
+ auctionType,
3266
+ splitAddresses,
3267
+ splitRatios
3268
+ ] = result;
3269
+ const started = startingTime > 0n;
3270
+ const endTime = started ? startingTime + lengthOfAuction : null;
3271
+ const now = BigInt(Math.floor(Date.now() / 1e3));
3272
+ let status = "PENDING";
3273
+ if (started) {
3274
+ status = endTime !== null && now >= endTime ? "ENDED" : "RUNNING";
3275
+ }
3276
+ return {
3277
+ seller,
3278
+ creationBlock,
3279
+ startingTime,
3280
+ lengthOfAuction,
3281
+ currency,
3282
+ minimumBid,
3283
+ auctionType,
3284
+ splitAddresses: [...splitAddresses],
3285
+ splitRatios: [...splitRatios],
3286
+ isEth: currency === ETH_ADDRESS2,
3287
+ started,
3288
+ endTime,
3289
+ status
3290
+ };
3291
+ }
3292
+ },
3293
+ offer: {
3294
+ async create(params) {
3295
+ const { walletClient, account, accountAddress } = requireWallet(config);
3296
+ const currency = params.currency ?? ETH_ADDRESS2;
3297
+ const amount = toWei(params.amount);
3298
+ const isEth = currency === ETH_ADDRESS2;
3299
+ const convertible = params.convertible ?? false;
3300
+ let value = 0n;
3301
+ if (isEth) {
3302
+ const settingsAddress = await publicClient.readContract({
3303
+ address: addresses.auction,
3304
+ abi: auctionAbi,
3305
+ functionName: "marketplaceSettings"
3306
+ });
3307
+ const fee = await publicClient.readContract({
3308
+ address: settingsAddress,
3309
+ abi: marketplaceSettingsAbi,
3310
+ functionName: "calculateMarketplaceFee",
3311
+ args: [amount]
3312
+ });
3313
+ value = amount + fee;
3314
+ } else {
3315
+ try {
3316
+ const allowance = await publicClient.readContract({
3317
+ address: currency,
3318
+ abi: erc20Abi,
3319
+ functionName: "allowance",
3320
+ args: [accountAddress, addresses.auction]
3321
+ });
3322
+ if (BigInt(allowance) < amount) {
3323
+ const approveTx = await walletClient.writeContract({
3324
+ address: currency,
3325
+ abi: erc20Abi,
3326
+ functionName: "approve",
3327
+ args: [addresses.auction, maxUint256],
3328
+ account,
3329
+ chain: void 0
3330
+ });
3331
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3332
+ }
3333
+ } catch {
3334
+ const approveTx = await walletClient.writeContract({
3335
+ address: currency,
3336
+ abi: erc20Abi,
3337
+ functionName: "approve",
3338
+ args: [addresses.auction, maxUint256],
3339
+ account,
3340
+ chain: void 0
3341
+ });
3342
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3343
+ }
3344
+ }
3345
+ const txHash = await walletClient.writeContract({
3346
+ address: addresses.auction,
3347
+ abi: auctionAbi,
3348
+ functionName: "offer",
3349
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount, convertible],
3350
+ account,
3351
+ chain: void 0,
3352
+ value
3353
+ });
3354
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3355
+ return { txHash, receipt };
3356
+ },
3357
+ async cancel(params) {
3358
+ const { walletClient, account } = requireWallet(config);
3359
+ const currency = params.currency ?? ETH_ADDRESS2;
3360
+ const txHash = await walletClient.writeContract({
3361
+ address: addresses.auction,
3362
+ abi: auctionAbi,
3363
+ functionName: "cancelOffer",
3364
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency],
3365
+ account,
3366
+ chain: void 0
3367
+ });
3368
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3369
+ return { txHash, receipt };
3370
+ },
3371
+ async accept(params) {
3372
+ const { walletClient, account, accountAddress } = requireWallet(config);
3373
+ const currency = params.currency ?? ETH_ADDRESS2;
3374
+ const amount = toWei(params.amount);
3375
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3376
+ const splitRatios = params.splitRatios ?? [100];
3377
+ const txHash = await walletClient.writeContract({
3378
+ address: addresses.auction,
3379
+ abi: auctionAbi,
3380
+ functionName: "acceptOffer",
3381
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount, splitAddresses, splitRatios],
3382
+ account,
3383
+ chain: void 0
3384
+ });
3385
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3386
+ return { txHash, receipt };
3387
+ },
3388
+ async getStatus(params) {
3389
+ const currency = params.currency ?? ETH_ADDRESS2;
3390
+ const [buyer, amount, timestamp, marketplaceFee, convertible] = await publicClient.readContract({
3391
+ address: addresses.auction,
3392
+ abi: auctionAbi,
3393
+ functionName: "tokenCurrentOffers",
3394
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency]
3395
+ });
3396
+ const hasOffer = amount > 0n;
3397
+ return { buyer, amount, timestamp, marketplaceFee, convertible, hasOffer };
3398
+ }
3399
+ },
3400
+ listing: {
3401
+ async create(params) {
3402
+ const { walletClient, account, accountAddress } = requireWallet(config);
3403
+ const currency = params.currency ?? ETH_ADDRESS2;
3404
+ const price = toWei(params.price);
3405
+ const target = params.target ?? ETH_ADDRESS2;
3406
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3407
+ const splitRatios = params.splitRatios ?? [100];
3408
+ const nftAddress = params.contract;
3409
+ let approvalTxHash;
3410
+ if (params.autoApprove !== false) {
3411
+ const isApproved = await publicClient.readContract({
3412
+ address: nftAddress,
3413
+ abi: approvalAbi,
3414
+ functionName: "isApprovedForAll",
3415
+ args: [accountAddress, addresses.auction]
3416
+ });
3417
+ if (!isApproved) {
3418
+ approvalTxHash = await walletClient.writeContract({
3419
+ address: nftAddress,
3420
+ abi: approvalAbi,
3421
+ functionName: "setApprovalForAll",
3422
+ args: [addresses.auction, true],
3423
+ account,
3424
+ chain: void 0
3425
+ });
3426
+ await publicClient.waitForTransactionReceipt({ hash: approvalTxHash });
3427
+ }
3428
+ }
3429
+ const txHash = await walletClient.writeContract({
3430
+ address: addresses.auction,
3431
+ abi: auctionAbi,
3432
+ functionName: "setSalePrice",
3433
+ args: [nftAddress, toInteger(params.tokenId, "tokenId"), currency, price, target, splitAddresses, splitRatios],
3434
+ account,
3435
+ chain: void 0
3436
+ });
3437
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3438
+ return { txHash, receipt, approvalTxHash };
3439
+ },
3440
+ async cancel(params) {
3441
+ const { walletClient, account } = requireWallet(config);
3442
+ const target = params.target ?? ETH_ADDRESS2;
3443
+ const txHash = await walletClient.writeContract({
3444
+ address: addresses.auction,
3445
+ abi: auctionAbi,
3446
+ functionName: "removeSalePrice",
3447
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), target],
3448
+ account,
3449
+ chain: void 0
3450
+ });
3451
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3452
+ return { txHash, receipt };
3453
+ },
3454
+ async buy(params) {
3455
+ const { walletClient, account, accountAddress } = requireWallet(config);
3456
+ const currency = params.currency ?? ETH_ADDRESS2;
3457
+ const amount = toWei(params.amount);
3458
+ const isEth = currency === ETH_ADDRESS2;
3459
+ let value = 0n;
3460
+ if (isEth) {
3461
+ const settingsAddress = await publicClient.readContract({
3462
+ address: addresses.auction,
3463
+ abi: auctionAbi,
3464
+ functionName: "marketplaceSettings"
3465
+ });
3466
+ const fee = await publicClient.readContract({
3467
+ address: settingsAddress,
3468
+ abi: marketplaceSettingsAbi,
3469
+ functionName: "calculateMarketplaceFee",
3470
+ args: [amount]
3471
+ });
3472
+ value = amount + fee;
3473
+ } else {
3474
+ try {
3475
+ const allowance = await publicClient.readContract({
3476
+ address: currency,
3477
+ abi: erc20Abi,
3478
+ functionName: "allowance",
3479
+ args: [accountAddress, addresses.auction]
3480
+ });
3481
+ if (BigInt(allowance) < amount) {
3482
+ const approveTx = await walletClient.writeContract({
3483
+ address: currency,
3484
+ abi: erc20Abi,
3485
+ functionName: "approve",
3486
+ args: [addresses.auction, maxUint256],
3487
+ account,
3488
+ chain: void 0
3489
+ });
3490
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3491
+ }
3492
+ } catch {
3493
+ const approveTx = await walletClient.writeContract({
3494
+ address: currency,
3495
+ abi: erc20Abi,
3496
+ functionName: "approve",
3497
+ args: [addresses.auction, maxUint256],
3498
+ account,
3499
+ chain: void 0
3500
+ });
3501
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3502
+ }
3503
+ }
3504
+ const txHash = await walletClient.writeContract({
3505
+ address: addresses.auction,
3506
+ abi: auctionAbi,
3507
+ functionName: "buy",
3508
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount],
3509
+ account,
3510
+ chain: void 0,
3511
+ value
3512
+ });
3513
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3514
+ return { txHash, receipt };
3515
+ },
3516
+ async getStatus(params) {
3517
+ const target = params.target ?? ETH_ADDRESS2;
3518
+ const [seller, currencyAddress, amount] = await publicClient.readContract({
3519
+ address: addresses.auction,
3520
+ abi: auctionAbi,
3521
+ functionName: "tokenSalePrices",
3522
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), target]
3523
+ });
3524
+ const hasListing = amount > 0n;
3525
+ const isEth = currencyAddress === ETH_ADDRESS2;
3526
+ return { seller, currencyAddress, amount, hasListing, isEth };
3527
+ }
3528
+ },
3529
+ search: {
3530
+ async nfts(params = {}) {
3531
+ const requestParams = params.chainIds ? params : { ...params, chainIds: [chainId] };
3532
+ return searchNfts(requestParams);
3533
+ },
3534
+ async collections(params = {}) {
3535
+ return searchCollections(params);
3536
+ }
3537
+ },
3538
+ media: {
3539
+ async upload(buffer, filename) {
3540
+ return uploadMedia(buffer, filename);
3541
+ },
3542
+ async pinMetadata(opts) {
3543
+ return pinMetadata(opts);
3544
+ }
3545
+ },
3546
+ import: {
3547
+ async erc721(params) {
3548
+ const owner = params.owner ?? config.account ?? config.walletClient?.account?.address;
3549
+ if (!owner) {
3550
+ throw new Error("No owner available for import. Pass params.owner or provide config.account/walletClient with an account.");
3551
+ }
3552
+ await importErc721({
3553
+ chainId,
3554
+ contract: params.contract,
3555
+ owner
3556
+ });
3557
+ }
3558
+ },
3559
+ token: {
3560
+ async getContractInfo(params) {
3561
+ const [name, symbol, totalSupply] = await Promise.all([
3562
+ publicClient.readContract({
3563
+ address: params.contract,
3564
+ abi: tokenAbi,
3565
+ functionName: "name"
3566
+ }),
3567
+ publicClient.readContract({
3568
+ address: params.contract,
3569
+ abi: tokenAbi,
3570
+ functionName: "symbol"
3571
+ }),
3572
+ publicClient.readContract({
3573
+ address: params.contract,
3574
+ abi: tokenAbi,
3575
+ functionName: "totalSupply"
3576
+ })
3577
+ ]);
3578
+ return {
3579
+ contract: params.contract,
3580
+ chain,
3581
+ name,
3582
+ symbol,
3583
+ totalSupply
3584
+ };
3585
+ },
3586
+ async getTokenInfo(params) {
3587
+ const tokenId = toInteger(params.tokenId, "tokenId");
3588
+ const [owner, tokenUri] = await Promise.all([
3589
+ publicClient.readContract({
3590
+ address: params.contract,
3591
+ abi: tokenAbi,
3592
+ functionName: "ownerOf",
3593
+ args: [tokenId]
3594
+ }),
3595
+ publicClient.readContract({
3596
+ address: params.contract,
3597
+ abi: tokenAbi,
3598
+ functionName: "tokenURI",
3599
+ args: [tokenId]
3600
+ })
3601
+ ]);
3602
+ return {
3603
+ contract: params.contract,
3604
+ tokenId,
3605
+ owner,
3606
+ tokenUri
3607
+ };
3608
+ }
3609
+ }
3610
+ };
3611
+ }
3612
+
3613
+ // src/commands/deploy.ts
3614
+ function deployErc721Command() {
3615
+ const cmd = new Command2("erc721");
3616
+ cmd.description("Deploy a new ERC-721 NFT contract via the RARE factory");
3617
+ cmd.argument("<name>", "name of the NFT collection").argument("<symbol>", "symbol of the NFT collection").option("--max-tokens <number>", "maximum number of tokens (optional)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (name, symbol, opts) => {
3618
+ const chain = getActiveChain(opts.chain);
3619
+ const { client } = getWalletClient(chain);
3620
+ const publicClient = getPublicClient(chain);
3621
+ const rare = createRareClient({ publicClient, walletClient: client });
3622
+ console.log(`Deploying ERC-721 contract on ${chain}...`);
3623
+ console.log(` Factory: ${rare.contracts.factory}`);
3624
+ console.log(` Name: ${name}`);
3625
+ console.log(` Symbol: ${symbol}`);
3626
+ if (opts.maxTokens) console.log(` Max tokens: ${opts.maxTokens}`);
3627
+ console.log("Waiting for confirmation...");
3628
+ const result = await rare.deploy.erc721({
3629
+ name,
3630
+ symbol,
3631
+ maxTokens: opts.maxTokens
3632
+ });
3633
+ console.log(`Transaction sent: ${result.txHash}`);
3634
+ if (result.contract) {
3635
+ console.log(`
3636
+ ERC-721 contract deployed at: ${result.contract}`);
3637
+ } else {
3638
+ console.log(`
3639
+ Transaction confirmed. Block: ${result.receipt.blockNumber}`);
3640
+ console.log("Could not parse deployed address from logs.");
3641
+ }
3642
+ });
3643
+ return cmd;
3644
+ }
3645
+ function deployCommand() {
3646
+ const cmd = new Command2("deploy");
3647
+ cmd.description("Deploy a new contract via the RARE protocol");
3648
+ cmd.addCommand(deployErc721Command());
3649
+ return cmd;
3650
+ }
3651
+
3652
+ // src/commands/mint.ts
3653
+ import { Command as Command3 } from "commander";
3654
+
3655
+ // src/ipfs.ts
3656
+ import { basename, extname } from "path";
3657
+ import { readFile, stat } from "fs/promises";
3658
+ import { isAddress as isAddress2 } from "viem";
3659
+ var API_BASE_URL2 = "https://api.superrare.org";
3660
+ var MIME_TYPES2 = {
3661
+ ".png": "image/png",
3662
+ ".jpg": "image/jpeg",
3663
+ ".jpeg": "image/jpeg",
3664
+ ".gif": "image/gif",
3665
+ ".webp": "image/webp",
3666
+ ".svg": "image/svg+xml",
3667
+ ".mp4": "video/mp4",
3668
+ ".mov": "video/quicktime",
3669
+ ".webm": "video/webm",
3670
+ ".glb": "model/gltf-binary",
3671
+ ".gltf": "model/gltf+json",
3672
+ ".html": "text/html"
3673
+ };
3674
+ function inferMimeType2(filename) {
3675
+ const ext = extname(filename).toLowerCase();
3676
+ return MIME_TYPES2[ext] ?? "application/octet-stream";
3677
+ }
3678
+ function assertPositiveInteger2(value, fieldName) {
3679
+ if (!Number.isInteger(value) || value <= 0) {
3680
+ throw new Error(`${fieldName} must be a positive integer`);
3681
+ }
3682
+ }
3683
+ function assertEvmAddress2(value, fieldName) {
3684
+ if (!isAddress2(value)) {
3685
+ throw new Error(`${fieldName} must be a valid EVM address`);
3686
+ }
3687
+ }
3688
+ function parseDimensions2(dimensions) {
3689
+ if (!dimensions) return void 0;
3690
+ const [w, h] = dimensions.split("x");
3691
+ if (!w || !h) return void 0;
3692
+ const width = parseInt(w, 10);
3693
+ const height = parseInt(h, 10);
3694
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return void 0;
3695
+ return { width, height };
3696
+ }
3697
+ async function apiPost2(path2, payload) {
3698
+ const url = `${API_BASE_URL2}${path2}`;
3699
+ const response = await fetch(url, {
3700
+ method: "POST",
3701
+ headers: { "Content-Type": "application/json" },
3702
+ body: JSON.stringify(payload)
3703
+ });
3704
+ const text = await response.text();
3705
+ const json = text ? JSON.parse(text) : {};
3706
+ if (!response.ok) {
3707
+ const message = json.error ?? text;
3708
+ throw new Error(`API error ${response.status} on ${path2}: ${message}`);
3709
+ }
3710
+ return json;
3711
+ }
3712
+ async function uploadParts2(fileBuffer, partSize, presignedUrls) {
3713
+ const parts = [];
3714
+ for (let i = 0; i < presignedUrls.length; i++) {
3715
+ const start = i * partSize;
3716
+ const end = start + partSize;
3717
+ const partBuffer = fileBuffer.subarray(start, end);
3718
+ const response = await fetch(presignedUrls[i], {
3719
+ method: "PUT",
3720
+ body: new Uint8Array(partBuffer)
3721
+ });
3722
+ if (response.status !== 200 && response.status !== 204) {
3723
+ throw new Error(`Part ${i + 1} upload failed with status ${response.status}`);
3724
+ }
3725
+ const etag = response.headers.get("etag");
3726
+ if (!etag) {
3727
+ throw new Error(`Missing etag header for part ${i + 1}`);
3728
+ }
3729
+ parts.push({ ETag: etag, PartNumber: i + 1 });
3730
+ }
3731
+ return parts;
3732
+ }
3733
+ async function uploadMedia2(filePath, label) {
3734
+ const fileStats = await stat(filePath);
3735
+ const fileSize = fileStats.size;
3736
+ const fileName = basename(filePath);
3737
+ const fileBuffer = await readFile(filePath);
3738
+ const mimeType = inferMimeType2(fileName);
3739
+ console.log(`Uploading ${label}: ${fileName} (${fileSize} bytes, ${mimeType})`);
3740
+ const init = await apiPost2("/api/nft/media-upload-url", {
3741
+ fileSize,
3742
+ filename: fileName
3743
+ });
3744
+ console.log(` Multipart upload initialized (${init.presignedUrls.length} parts)`);
3745
+ const parts = await uploadParts2(fileBuffer, init.partSize, init.presignedUrls);
3746
+ console.log(` All parts uploaded`);
3747
+ const complete = await apiPost2("/api/nft/media-upload-complete", {
3748
+ key: init.key,
3749
+ uploadId: init.uploadId,
3750
+ bucket: init.bucket,
3751
+ parts
3752
+ });
3753
+ console.log(` Upload complete: ${complete.ipfsUrl}`);
3754
+ const generated = await apiPost2("/api/nft/media-generate", {
3755
+ uri: complete.ipfsUrl,
3756
+ mimeType
3757
+ });
3758
+ const dimensions = parseDimensions2(generated.media.dimensions);
3759
+ const entry = {
3760
+ url: generated.media.uri,
3761
+ mimeType: generated.media.mimeType,
3762
+ size: generated.media.size ?? fileSize,
3763
+ ...dimensions ? { dimensions } : {}
3764
+ };
3765
+ console.log(` Media generated: ${entry.url}`);
3766
+ return entry;
3767
+ }
3768
+ async function importErc7212(opts) {
3769
+ assertPositiveInteger2(opts.chainId, "chainId");
3770
+ assertEvmAddress2(opts.contractAddress, "contractAddress");
3771
+ assertEvmAddress2(opts.ownerAddress, "ownerAddress");
3772
+ const normalizedContractAddress = opts.contractAddress.toLowerCase();
3773
+ const normalizedOwnerAddress = opts.ownerAddress.toLowerCase();
3774
+ const result = await apiPost2("/api/nft/import-erc721", {
3775
+ chainId: opts.chainId,
3776
+ contractAddress: normalizedContractAddress,
3777
+ ownerAddress: normalizedOwnerAddress
3778
+ });
3779
+ if (result.ok !== true) {
3780
+ throw new Error("Unexpected response from /api/nft/import-erc721");
3781
+ }
3782
+ }
3783
+ async function pinMetadata2(opts) {
3784
+ const nftMedia = {
3785
+ image: opts.image
3786
+ };
3787
+ if (opts.video) {
3788
+ nftMedia.video = opts.video;
3789
+ }
3790
+ const payload = {
3791
+ name: opts.name,
3792
+ description: opts.description,
3793
+ nftMedia,
3794
+ tags: opts.tags ?? []
3795
+ };
3796
+ if (opts.attributes && opts.attributes.length > 0) {
3797
+ payload.attributes = opts.attributes;
3798
+ }
3799
+ console.log("Pinning metadata to IPFS...");
3800
+ const result = await apiPost2("/api/nft/metadata", payload);
3801
+ console.log(`Metadata pinned: ${result.ipfsUrl}`);
3802
+ console.log(`Gateway URL: ${result.gatewayUrl}`);
3803
+ return result.ipfsUrl;
3804
+ }
3805
+
3806
+ // src/commands/mint.ts
3807
+ function parseAttribute(raw) {
3808
+ if (raw.startsWith("{")) {
3809
+ const parsed = JSON.parse(raw);
3810
+ if (parsed.value === void 0) {
3811
+ throw new Error(`Attribute JSON must include "value": ${raw}`);
3812
+ }
3813
+ return parsed;
3814
+ }
3815
+ const eqIndex = raw.indexOf("=");
3816
+ if (eqIndex === -1) {
3817
+ return { value: raw };
3818
+ }
3819
+ const trait_type = raw.slice(0, eqIndex);
3820
+ const rawValue = raw.slice(eqIndex + 1);
3821
+ const numValue = Number(rawValue);
3822
+ const value = rawValue.length > 0 && !Number.isNaN(numValue) ? numValue : rawValue;
3823
+ return { trait_type, value };
3824
+ }
3825
+ function mintCommand() {
3826
+ const cmd = new Command3("mint");
3827
+ cmd.description("Mint a new NFT on a deployed token contract");
3828
+ cmd.requiredOption("--contract <address>", "token contract address").option("--token-uri <uri>", "token metadata URI (skip upload if provided)").option("--name <name>", "NFT name").option("--description <description>", "NFT description").option("--image <path>", "path to image file").option("--video <path>", "path to video file").option("--tag <tag>", "tag (repeatable)", (val, acc) => [...acc, val], []).option("--attribute <attr>", 'attribute as "trait=value" or JSON (repeatable)', (val, acc) => [...acc, val], []).option("--to <address>", "recipient address (defaults to caller)").option("--royalty-receiver <address>", "royalty receiver address (defaults to caller)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3829
+ let tokenUri;
3830
+ if (opts.tokenUri) {
3831
+ tokenUri = opts.tokenUri;
3832
+ } else {
3833
+ if (!opts.name) {
3834
+ console.error("Error: --name is required when not using --token-uri");
3835
+ process.exit(1);
3836
+ }
3837
+ if (!opts.description) {
3838
+ console.error("Error: --description is required when not using --token-uri");
3839
+ process.exit(1);
3840
+ }
3841
+ if (!opts.image) {
3842
+ console.error("Error: --image is required when not using --token-uri");
3843
+ process.exit(1);
3844
+ }
3845
+ const imageMedia = await uploadMedia2(opts.image, "image");
3846
+ const videoMedia = opts.video ? await uploadMedia2(opts.video, "video") : void 0;
3847
+ const tags = opts.tag.length > 0 ? opts.tag : void 0;
3848
+ const attributes = opts.attribute.length > 0 ? opts.attribute.map(parseAttribute) : void 0;
3849
+ tokenUri = await pinMetadata2({
3850
+ name: opts.name,
3851
+ description: opts.description,
3852
+ image: imageMedia,
3853
+ video: videoMedia,
3854
+ tags,
3855
+ attributes
3856
+ });
3161
3857
  }
3162
- console.log(`
3163
- Transaction sent: ${txHash}`);
3164
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3165
- console.log(`Auction created! Block: ${receipt.blockNumber}`);
3166
- });
3167
- cmd.command("bid").description("Place a bid on an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "bid amount in ETH (or token units)").option("--currency <address>", "ERC20 currency address (defaults to ETH)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3168
3858
  const chain = getActiveChain(opts.chain);
3169
3859
  const { client, account } = getWalletClient(chain);
3170
3860
  const publicClient = getPublicClient(chain);
3171
- const auctionAddress = getContractAddresses(chain).auction;
3172
- const currency = opts.currency ?? ETH_ADDRESS;
3173
- const isEth = currency === ETH_ADDRESS;
3174
- const bidAmount = parseEther(opts.amount);
3861
+ const rare = createRareClient({ publicClient, walletClient: client });
3862
+ const contractAddress = opts.contract;
3863
+ console.log(`
3864
+ Minting NFT on ${chain}...`);
3865
+ console.log(` Contract: ${contractAddress}`);
3866
+ console.log(` URI: ${tokenUri}`);
3867
+ if (opts.to || opts.royaltyReceiver) {
3868
+ const receiver = opts.to ?? account.address;
3869
+ const royaltyReceiver = opts.royaltyReceiver ?? account.address;
3870
+ console.log(` To: ${receiver}`);
3871
+ console.log(` Royalty receiver: ${royaltyReceiver}`);
3872
+ }
3873
+ console.log("Waiting for confirmation...");
3874
+ const result = await rare.mint.mintTo({
3875
+ contract: contractAddress,
3876
+ tokenUri,
3877
+ to: opts.to,
3878
+ royaltyReceiver: opts.royaltyReceiver
3879
+ });
3880
+ console.log(`Transaction sent: ${result.txHash}`);
3881
+ if (result.tokenId !== void 0) {
3882
+ console.log(`
3883
+ NFT minted! Token ID: ${result.tokenId}`);
3884
+ } else {
3885
+ console.log(`
3886
+ Transaction confirmed. Block: ${result.receipt.blockNumber}`);
3887
+ }
3888
+ });
3889
+ return cmd;
3890
+ }
3891
+
3892
+ // src/commands/auction.ts
3893
+ import { Command as Command4 } from "commander";
3894
+ import { formatEther } from "viem";
3895
+
3896
+ // src/errors.ts
3897
+ function printContractError(error) {
3898
+ if (!(error instanceof Error)) {
3899
+ console.error("\nTransaction failed:", error);
3900
+ process.exit(1);
3901
+ }
3902
+ console.error("\nTransaction failed:");
3903
+ let current = error;
3904
+ let depth = 0;
3905
+ while (current instanceof Error) {
3906
+ const indent = " ".repeat(depth + 1);
3907
+ const msg = current.shortMessage ?? current.message;
3908
+ console.error(`${indent}${msg}`);
3909
+ if ("reason" in current && current.reason) {
3910
+ console.error(`${indent}Revert reason: ${current.reason}`);
3911
+ }
3912
+ if ("metaMessages" in current && Array.isArray(current.metaMessages)) {
3913
+ for (const line of current.metaMessages) {
3914
+ if (line.trim()) console.error(`${indent}${line.trim()}`);
3915
+ }
3916
+ }
3917
+ current = current.cause;
3918
+ depth++;
3919
+ }
3920
+ process.exit(1);
3921
+ }
3922
+
3923
+ // src/commands/auction.ts
3924
+ var ETH_ADDRESS3 = "0x0000000000000000000000000000000000000000";
3925
+ function auctionCommand() {
3926
+ const cmd = new Command4("auction");
3927
+ cmd.description("Auction subcommands (create, bid, settle, cancel, status)");
3928
+ cmd.command("create").description("Configure and start an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID to auction").requiredOption("--starting-price <amount>", "starting price in ETH (or token units)").requiredOption("--duration <seconds>", "auction duration in seconds").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3929
+ const chain = getActiveChain(opts.chain);
3930
+ const { client } = getWalletClient(chain);
3931
+ const publicClient = getPublicClient(chain);
3932
+ const rare = createRareClient({ publicClient, walletClient: client });
3933
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS3;
3934
+ console.log(`Creating auction on ${chain}...`);
3935
+ console.log(` Auction contract: ${rare.contracts.auction}`);
3936
+ console.log(` NFT contract: ${opts.contract}`);
3937
+ console.log(` Token ID: ${opts.tokenId}`);
3938
+ console.log(` Starting price: ${opts.startingPrice} ETH`);
3939
+ console.log(` Duration: ${opts.duration} seconds`);
3940
+ console.log(` Currency: ${currency === ETH_ADDRESS3 ? "ETH" : currency}`);
3941
+ try {
3942
+ const result = await rare.auction.create({
3943
+ contract: opts.contract,
3944
+ tokenId: opts.tokenId,
3945
+ startingPrice: opts.startingPrice,
3946
+ duration: opts.duration,
3947
+ currency
3948
+ });
3949
+ if (result.approvalTxHash) {
3950
+ console.log(`Approval tx sent: ${result.approvalTxHash}`);
3951
+ }
3952
+ console.log(`
3953
+ Transaction sent: ${result.txHash}`);
3954
+ console.log(`Auction created! Block: ${result.receipt.blockNumber}`);
3955
+ } catch (error) {
3956
+ printContractError(error);
3957
+ }
3958
+ });
3959
+ cmd.command("bid").description("Place a bid on an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "bid amount in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3960
+ const chain = getActiveChain(opts.chain);
3961
+ const { client } = getWalletClient(chain);
3962
+ const publicClient = getPublicClient(chain);
3963
+ const rare = createRareClient({ publicClient, walletClient: client });
3964
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS3;
3965
+ const isEth = currency === ETH_ADDRESS3;
3175
3966
  console.log(`Placing bid on ${chain}...`);
3176
- console.log(` Auction contract: ${auctionAddress}`);
3967
+ console.log(` Auction contract: ${rare.contracts.auction}`);
3177
3968
  console.log(` NFT contract: ${opts.contract}`);
3178
3969
  console.log(` Token ID: ${opts.tokenId}`);
3179
3970
  console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
3180
- let txHash;
3181
3971
  try {
3182
- txHash = await client.writeContract({
3183
- address: auctionAddress,
3184
- abi: auctionAbi,
3185
- functionName: "bid",
3186
- args: [opts.contract, BigInt(opts.tokenId), currency, bidAmount],
3187
- account,
3188
- chain: void 0,
3189
- value: isEth ? bidAmount : 0n
3972
+ const result = await rare.auction.bid({
3973
+ contract: opts.contract,
3974
+ tokenId: opts.tokenId,
3975
+ amount: opts.amount,
3976
+ currency
3190
3977
  });
3978
+ console.log(`
3979
+ Transaction sent: ${result.txHash}`);
3980
+ console.log(`Bid placed! Block: ${result.receipt.blockNumber}`);
3191
3981
  } catch (error) {
3192
3982
  printContractError(error);
3193
3983
  }
3194
- console.log(`
3195
- Transaction sent: ${txHash}`);
3196
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3197
- console.log(`Bid placed! Block: ${receipt.blockNumber}`);
3198
3984
  });
3199
3985
  cmd.command("settle").description("Settle a completed auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3200
3986
  const chain = getActiveChain(opts.chain);
3201
- const { client, account } = getWalletClient(chain);
3987
+ const { client } = getWalletClient(chain);
3202
3988
  const publicClient = getPublicClient(chain);
3203
- const auctionAddress = getContractAddresses(chain).auction;
3989
+ const rare = createRareClient({ publicClient, walletClient: client });
3204
3990
  console.log(`Settling auction on ${chain}...`);
3205
- const txHash = await client.writeContract({
3206
- address: auctionAddress,
3207
- abi: auctionAbi,
3208
- functionName: "settleAuction",
3209
- args: [opts.contract, BigInt(opts.tokenId)],
3210
- account,
3211
- chain: void 0
3212
- });
3213
- console.log(`Transaction sent: ${txHash}`);
3214
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3215
- console.log(`Auction settled! Block: ${receipt.blockNumber}`);
3991
+ try {
3992
+ const result = await rare.auction.settle({
3993
+ contract: opts.contract,
3994
+ tokenId: opts.tokenId
3995
+ });
3996
+ console.log(`Transaction sent: ${result.txHash}`);
3997
+ console.log(`Auction settled! Block: ${result.receipt.blockNumber}`);
3998
+ } catch (error) {
3999
+ printContractError(error);
4000
+ }
3216
4001
  });
3217
4002
  cmd.command("cancel").description("Cancel an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3218
4003
  const chain = getActiveChain(opts.chain);
3219
- const { client, account } = getWalletClient(chain);
4004
+ const { client } = getWalletClient(chain);
3220
4005
  const publicClient = getPublicClient(chain);
3221
- const auctionAddress = getContractAddresses(chain).auction;
4006
+ const rare = createRareClient({ publicClient, walletClient: client });
3222
4007
  console.log(`Cancelling auction on ${chain}...`);
3223
- const txHash = await client.writeContract({
3224
- address: auctionAddress,
3225
- abi: auctionAbi,
3226
- functionName: "cancelAuction",
3227
- args: [opts.contract, BigInt(opts.tokenId)],
3228
- account,
3229
- chain: void 0
3230
- });
3231
- console.log(`Transaction sent: ${txHash}`);
3232
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3233
- console.log(`Auction cancelled! Block: ${receipt.blockNumber}`);
4008
+ try {
4009
+ const result = await rare.auction.cancel({
4010
+ contract: opts.contract,
4011
+ tokenId: opts.tokenId
4012
+ });
4013
+ console.log(`Transaction sent: ${result.txHash}`);
4014
+ console.log(`Auction cancelled! Block: ${result.receipt.blockNumber}`);
4015
+ } catch (error) {
4016
+ printContractError(error);
4017
+ }
3234
4018
  });
3235
4019
  cmd.command("status").description("Get auction details (read-only)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3236
4020
  const chain = getActiveChain(opts.chain);
3237
4021
  const publicClient = getPublicClient(chain);
3238
- const auctionAddress = getContractAddresses(chain).auction;
3239
- const result = await publicClient.readContract({
3240
- address: auctionAddress,
3241
- abi: auctionAbi,
3242
- functionName: "getAuctionDetails",
3243
- args: [opts.contract, BigInt(opts.tokenId)]
4022
+ const rare = createRareClient({ publicClient });
4023
+ const result = await rare.auction.getStatus({
4024
+ contract: opts.contract,
4025
+ tokenId: opts.tokenId
3244
4026
  });
3245
- const [seller, creationBlock, startingTime, lengthOfAuction, currency, minimumBid, auctionType] = result;
3246
- const isEth = currency === ETH_ADDRESS;
3247
- const started = Number(startingTime) > 0;
3248
- const endTime = started ? Number(startingTime) + Number(lengthOfAuction) : null;
3249
- const endDate = endTime ? new Date(endTime * 1e3) : null;
4027
+ const endDate = result.endTime ? new Date(Number(result.endTime) * 1e3) : null;
3250
4028
  console.log("\nAuction Details:");
3251
- console.log(` Seller: ${seller}`);
3252
- console.log(` Minimum bid: ${formatEther(minimumBid)} ${isEth ? "ETH" : currency}`);
3253
- console.log(` Currency: ${isEth ? "ETH" : currency}`);
3254
- console.log(` Duration: ${lengthOfAuction}s`);
3255
- console.log(` Status: ${started ? "RUNNING" : "PENDING"}`);
3256
- if (started) {
3257
- console.log(` Started at: ${new Date(Number(startingTime) * 1e3).toISOString()}`);
4029
+ console.log(` Seller: ${result.seller}`);
4030
+ console.log(` Minimum bid: ${formatEther(result.minimumBid)} ${result.isEth ? "ETH" : result.currency}`);
4031
+ console.log(` Currency: ${result.isEth ? "ETH" : result.currency}`);
4032
+ console.log(` Duration: ${result.lengthOfAuction}s`);
4033
+ console.log(` Status: ${result.status}`);
4034
+ if (result.started) {
4035
+ console.log(` Started at: ${new Date(Number(result.startingTime) * 1e3).toISOString()}`);
3258
4036
  console.log(` Ends at: ${endDate.toISOString()}`);
3259
4037
  }
3260
- console.log(` Creation block: ${creationBlock}`);
3261
- console.log(` Auction type: ${auctionType}`);
4038
+ console.log(` Creation block: ${result.creationBlock}`);
4039
+ console.log(` Auction type: ${result.auctionType}`);
3262
4040
  });
3263
4041
  return cmd;
3264
4042
  }
@@ -3271,51 +4049,25 @@ function statusCommand() {
3271
4049
  cmd.requiredOption("--contract <address>", "token contract address").option("--token-id <id>", "token ID to query (optional)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3272
4050
  const chain = getActiveChain(opts.chain);
3273
4051
  const publicClient = getPublicClient(chain);
4052
+ const rare = createRareClient({ publicClient });
3274
4053
  const contractAddress = opts.contract;
3275
- const [name, symbol, totalSupply] = await Promise.all([
3276
- publicClient.readContract({
3277
- address: contractAddress,
3278
- abi: tokenAbi,
3279
- functionName: "name"
3280
- }),
3281
- publicClient.readContract({
3282
- address: contractAddress,
3283
- abi: tokenAbi,
3284
- functionName: "symbol"
3285
- }),
3286
- publicClient.readContract({
3287
- address: contractAddress,
3288
- abi: tokenAbi,
3289
- functionName: "totalSupply"
3290
- })
3291
- ]);
4054
+ const contractInfo = await rare.token.getContractInfo({ contract: contractAddress });
3292
4055
  console.log("\nContract Info:");
3293
- console.log(` Address: ${contractAddress}`);
3294
- console.log(` Chain: ${chain}`);
3295
- console.log(` Name: ${name}`);
3296
- console.log(` Symbol: ${symbol}`);
3297
- console.log(` Total Supply: ${totalSupply}`);
4056
+ console.log(` Address: ${contractInfo.contract}`);
4057
+ console.log(` Chain: ${contractInfo.chain}`);
4058
+ console.log(` Name: ${contractInfo.name}`);
4059
+ console.log(` Symbol: ${contractInfo.symbol}`);
4060
+ console.log(` Total Supply: ${contractInfo.totalSupply}`);
3298
4061
  if (opts.tokenId !== void 0) {
3299
- const tokenId = BigInt(opts.tokenId);
3300
4062
  try {
3301
- const [owner, uri] = await Promise.all([
3302
- publicClient.readContract({
3303
- address: contractAddress,
3304
- abi: tokenAbi,
3305
- functionName: "ownerOf",
3306
- args: [tokenId]
3307
- }),
3308
- publicClient.readContract({
3309
- address: contractAddress,
3310
- abi: tokenAbi,
3311
- functionName: "tokenURI",
3312
- args: [tokenId]
3313
- })
3314
- ]);
4063
+ const tokenInfo = await rare.token.getTokenInfo({
4064
+ contract: contractAddress,
4065
+ tokenId: opts.tokenId
4066
+ });
3315
4067
  console.log(`
3316
- Token #${opts.tokenId}:`);
3317
- console.log(` Owner: ${owner}`);
3318
- console.log(` URI: ${uri}`);
4068
+ Token #${tokenInfo.tokenId}:`);
4069
+ console.log(` Owner: ${tokenInfo.owner}`);
4070
+ console.log(` URI: ${tokenInfo.tokenUri}`);
3319
4071
  } catch (err) {
3320
4072
  console.log(`
3321
4073
  Token #${opts.tokenId}: not found or error reading token`);
@@ -3369,9 +4121,9 @@ Private key saved to config for chain: ${chain}`);
3369
4121
  import { Command as Command7 } from "commander";
3370
4122
 
3371
4123
  // src/search.ts
3372
- var API_BASE_URL2 = "https://api.superrare.org";
3373
- async function searchPost(path2, payload) {
3374
- const url = `${API_BASE_URL2}${path2}`;
4124
+ var API_BASE_URL3 = "https://api.superrare.org";
4125
+ async function searchPost2(path2, payload) {
4126
+ const url = `${API_BASE_URL3}${path2}`;
3375
4127
  const response = await fetch(url, {
3376
4128
  method: "POST",
3377
4129
  headers: { "Content-Type": "application/json" },
@@ -3385,8 +4137,8 @@ async function searchPost(path2, payload) {
3385
4137
  }
3386
4138
  return json;
3387
4139
  }
3388
- async function searchNfts(params) {
3389
- return searchPost("/api/search/nfts", {
4140
+ async function searchNfts2(params) {
4141
+ return searchPost2("/api/search/nfts", {
3390
4142
  query: params.query ?? "",
3391
4143
  take: params.take ?? 24,
3392
4144
  cursor: params.cursor ?? 0,
@@ -3399,8 +4151,8 @@ async function searchNfts(params) {
3399
4151
  ...params.chainIds ? { chainIds: params.chainIds } : {}
3400
4152
  });
3401
4153
  }
3402
- async function searchCollections(params) {
3403
- return searchPost("/api/search/collections", {
4154
+ async function searchCollections2(params) {
4155
+ return searchPost2("/api/search/collections", {
3404
4156
  query: params.query ?? "",
3405
4157
  take: params.take ?? 24,
3406
4158
  cursor: params.cursor ?? 0,
@@ -3449,7 +4201,7 @@ function searchCommand() {
3449
4201
  const ownerAddresses = opts.mine ? [getWalletAddress(chain)] : opts.owner ? [opts.owner] : [];
3450
4202
  const label = opts.mine ? `NFTs owned by ${ownerAddresses[0]}` : opts.owner ? `NFTs owned by ${opts.owner}` : "NFTs";
3451
4203
  console.log(`Searching ${label} on ${chain}...`);
3452
- const page = await searchNfts({
4204
+ const page = await searchNfts2({
3453
4205
  query: opts.query,
3454
4206
  take: parseInt(opts.take, 10),
3455
4207
  cursor: parseInt(opts.cursor, 10),
@@ -3461,7 +4213,7 @@ function searchCommand() {
3461
4213
  cmd.command("auctions").description("List NFTs with active or configured auctions").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").option("--state <states...>", "auction states to filter (PENDING, RUNNING, SETTLED, UNSETTLED)", ["PENDING", "RUNNING"]).option("--owner <address>", "filter by owner address (optional)").option("--query <text>", "text search query", "").option("--take <n>", "number of results per page", "24").option("--cursor <n>", "pagination cursor", "0").action(async (opts) => {
3462
4214
  const chain = getActiveChain(opts.chain);
3463
4215
  console.log(`Searching auctions (${opts.state.join(", ")}) on ${chain}...`);
3464
- const page = await searchNfts({
4216
+ const page = await searchNfts2({
3465
4217
  query: opts.query,
3466
4218
  take: parseInt(opts.take, 10),
3467
4219
  cursor: parseInt(opts.cursor, 10),
@@ -3475,7 +4227,7 @@ function searchCommand() {
3475
4227
  const chain = getActiveChain(opts.chain);
3476
4228
  const address = getWalletAddress(chain);
3477
4229
  console.log(`Searching collections owned by ${address}...`);
3478
- const page = await searchCollections({
4230
+ const page = await searchCollections2({
3479
4231
  query: opts.query,
3480
4232
  take: parseInt(opts.take, 10),
3481
4233
  cursor: parseInt(opts.cursor, 10),
@@ -3503,7 +4255,7 @@ function listCollectionsCommand() {
3503
4255
  let cursor = 0;
3504
4256
  let hasMore = true;
3505
4257
  while (hasMore) {
3506
- const page = await searchCollections({
4258
+ const page = await searchCollections2({
3507
4259
  query: opts.query,
3508
4260
  take: 100,
3509
4261
  cursor,
@@ -3546,7 +4298,7 @@ function importCommand() {
3546
4298
  console.log(` Chain: ${chain} (${chainId})`);
3547
4299
  console.log(` Contract: ${contractAddress}`);
3548
4300
  console.log(` Owner: ${ownerAddress}`);
3549
- await importErc721({
4301
+ await importErc7212({
3550
4302
  chainId,
3551
4303
  contractAddress,
3552
4304
  ownerAddress
@@ -3557,9 +4309,236 @@ Contract imported successfully.`);
3557
4309
  return cmd;
3558
4310
  }
3559
4311
 
4312
+ // src/commands/offer.ts
4313
+ import { Command as Command10 } from "commander";
4314
+ import { formatEther as formatEther2 } from "viem";
4315
+ var ETH_ADDRESS4 = "0x0000000000000000000000000000000000000000";
4316
+ function offerCommand() {
4317
+ const cmd = new Command10("offer");
4318
+ cmd.description("Offer subcommands (create, cancel, accept, status)");
4319
+ cmd.command("create").description("Create an offer on a token").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "offer amount in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--convertible", "mark offer as convertible").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4320
+ const chain = getActiveChain(opts.chain);
4321
+ const { client } = getWalletClient(chain);
4322
+ const publicClient = getPublicClient(chain);
4323
+ const rare = createRareClient({ publicClient, walletClient: client });
4324
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4325
+ const isEth = currency === ETH_ADDRESS4;
4326
+ console.log(`Creating offer on ${chain}...`);
4327
+ console.log(` Marketplace contract: ${rare.contracts.auction}`);
4328
+ console.log(` NFT contract: ${opts.contract}`);
4329
+ console.log(` Token ID: ${opts.tokenId}`);
4330
+ console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
4331
+ console.log(` Convertible: ${opts.convertible ? "yes" : "no"}`);
4332
+ try {
4333
+ const result = await rare.offer.create({
4334
+ contract: opts.contract,
4335
+ tokenId: opts.tokenId,
4336
+ amount: opts.amount,
4337
+ currency,
4338
+ convertible: opts.convertible ?? false
4339
+ });
4340
+ console.log(`
4341
+ Transaction sent: ${result.txHash}`);
4342
+ console.log(`Offer created! Block: ${result.receipt.blockNumber}`);
4343
+ } catch (error) {
4344
+ printContractError(error);
4345
+ }
4346
+ });
4347
+ cmd.command("cancel").description("Cancel an existing offer").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4348
+ const chain = getActiveChain(opts.chain);
4349
+ const { client } = getWalletClient(chain);
4350
+ const publicClient = getPublicClient(chain);
4351
+ const rare = createRareClient({ publicClient, walletClient: client });
4352
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4353
+ console.log(`Cancelling offer on ${chain}...`);
4354
+ try {
4355
+ const result = await rare.offer.cancel({
4356
+ contract: opts.contract,
4357
+ tokenId: opts.tokenId,
4358
+ currency
4359
+ });
4360
+ console.log(`Transaction sent: ${result.txHash}`);
4361
+ console.log(`Offer cancelled! Block: ${result.receipt.blockNumber}`);
4362
+ } catch (error) {
4363
+ printContractError(error);
4364
+ }
4365
+ });
4366
+ cmd.command("accept").description("Accept an offer on a token you own").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "offer amount to accept in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4367
+ const chain = getActiveChain(opts.chain);
4368
+ const { client } = getWalletClient(chain);
4369
+ const publicClient = getPublicClient(chain);
4370
+ const rare = createRareClient({ publicClient, walletClient: client });
4371
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4372
+ const isEth = currency === ETH_ADDRESS4;
4373
+ console.log(`Accepting offer on ${chain}...`);
4374
+ console.log(` NFT contract: ${opts.contract}`);
4375
+ console.log(` Token ID: ${opts.tokenId}`);
4376
+ console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
4377
+ try {
4378
+ const result = await rare.offer.accept({
4379
+ contract: opts.contract,
4380
+ tokenId: opts.tokenId,
4381
+ amount: opts.amount,
4382
+ currency
4383
+ });
4384
+ console.log(`
4385
+ Transaction sent: ${result.txHash}`);
4386
+ console.log(`Offer accepted! Block: ${result.receipt.blockNumber}`);
4387
+ } catch (error) {
4388
+ printContractError(error);
4389
+ }
4390
+ });
4391
+ cmd.command("status").description("Get current offer details (read-only)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4392
+ const chain = getActiveChain(opts.chain);
4393
+ const publicClient = getPublicClient(chain);
4394
+ const rare = createRareClient({ publicClient });
4395
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4396
+ const isEth = currency === ETH_ADDRESS4;
4397
+ const result = await rare.offer.getStatus({
4398
+ contract: opts.contract,
4399
+ tokenId: opts.tokenId,
4400
+ currency
4401
+ });
4402
+ console.log("\nOffer Details:");
4403
+ if (!result.hasOffer) {
4404
+ console.log(" No active offer found.");
4405
+ } else {
4406
+ console.log(` Buyer: ${result.buyer}`);
4407
+ console.log(` Amount: ${formatEther2(result.amount)} ${isEth ? "ETH" : currency}`);
4408
+ console.log(` Timestamp: ${new Date(Number(result.timestamp) * 1e3).toISOString()}`);
4409
+ console.log(` Marketplace fee: ${result.marketplaceFee}%`);
4410
+ console.log(` Convertible: ${result.convertible ? "yes" : "no"}`);
4411
+ }
4412
+ });
4413
+ return cmd;
4414
+ }
4415
+
4416
+ // src/commands/listing.ts
4417
+ import { Command as Command11 } from "commander";
4418
+ import { formatEther as formatEther3 } from "viem";
4419
+ var ETH_ADDRESS5 = "0x0000000000000000000000000000000000000000";
4420
+ function listingCommand() {
4421
+ const cmd = new Command11("listing");
4422
+ cmd.description("Listing subcommands (create, cancel, buy, status)");
4423
+ cmd.command("create").description("Create a listing (set sale price) for a token").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--price <amount>", "listing price in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--target <address>", "target buyer address (defaults to public listing)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4424
+ const chain = getActiveChain(opts.chain);
4425
+ const { client } = getWalletClient(chain);
4426
+ const publicClient = getPublicClient(chain);
4427
+ const rare = createRareClient({ publicClient, walletClient: client });
4428
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS5;
4429
+ const isEth = currency === ETH_ADDRESS5;
4430
+ const target = opts.target ?? ETH_ADDRESS5;
4431
+ console.log(`Creating listing on ${chain}...`);
4432
+ console.log(` Marketplace contract: ${rare.contracts.auction}`);
4433
+ console.log(` NFT contract: ${opts.contract}`);
4434
+ console.log(` Token ID: ${opts.tokenId}`);
4435
+ console.log(` Price: ${opts.price} ${isEth ? "ETH" : currency}`);
4436
+ console.log(` Target: ${target === ETH_ADDRESS5 ? "public" : target}`);
4437
+ try {
4438
+ const result = await rare.listing.create({
4439
+ contract: opts.contract,
4440
+ tokenId: opts.tokenId,
4441
+ price: opts.price,
4442
+ currency,
4443
+ target
4444
+ });
4445
+ if (result.approvalTxHash) {
4446
+ console.log(`Approval tx sent: ${result.approvalTxHash}`);
4447
+ }
4448
+ console.log(`
4449
+ Transaction sent: ${result.txHash}`);
4450
+ console.log(`Listing created! Block: ${result.receipt.blockNumber}`);
4451
+ } catch (error) {
4452
+ printContractError(error);
4453
+ }
4454
+ });
4455
+ cmd.command("cancel").description("Cancel a listing (remove sale price)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--target <address>", "target buyer address (defaults to public listing)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4456
+ const chain = getActiveChain(opts.chain);
4457
+ const { client } = getWalletClient(chain);
4458
+ const publicClient = getPublicClient(chain);
4459
+ const rare = createRareClient({ publicClient, walletClient: client });
4460
+ const target = opts.target ?? ETH_ADDRESS5;
4461
+ console.log(`Cancelling listing on ${chain}...`);
4462
+ try {
4463
+ const result = await rare.listing.cancel({
4464
+ contract: opts.contract,
4465
+ tokenId: opts.tokenId,
4466
+ target
4467
+ });
4468
+ console.log(`Transaction sent: ${result.txHash}`);
4469
+ console.log(`Listing cancelled! Block: ${result.receipt.blockNumber}`);
4470
+ } catch (error) {
4471
+ printContractError(error);
4472
+ }
4473
+ });
4474
+ cmd.command("buy").description("Buy a listed token").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "purchase amount in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4475
+ const chain = getActiveChain(opts.chain);
4476
+ const { client } = getWalletClient(chain);
4477
+ const publicClient = getPublicClient(chain);
4478
+ const rare = createRareClient({ publicClient, walletClient: client });
4479
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS5;
4480
+ const isEth = currency === ETH_ADDRESS5;
4481
+ console.log(`Buying token on ${chain}...`);
4482
+ console.log(` Marketplace contract: ${rare.contracts.auction}`);
4483
+ console.log(` NFT contract: ${opts.contract}`);
4484
+ console.log(` Token ID: ${opts.tokenId}`);
4485
+ console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
4486
+ try {
4487
+ const result = await rare.listing.buy({
4488
+ contract: opts.contract,
4489
+ tokenId: opts.tokenId,
4490
+ amount: opts.amount,
4491
+ currency
4492
+ });
4493
+ console.log(`
4494
+ Transaction sent: ${result.txHash}`);
4495
+ console.log(`Token purchased! Block: ${result.receipt.blockNumber}`);
4496
+ } catch (error) {
4497
+ printContractError(error);
4498
+ }
4499
+ });
4500
+ cmd.command("status").description("Get listing details (read-only)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--target <address>", "target buyer address (defaults to public listing)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4501
+ const chain = getActiveChain(opts.chain);
4502
+ const publicClient = getPublicClient(chain);
4503
+ const rare = createRareClient({ publicClient });
4504
+ const target = opts.target ?? ETH_ADDRESS5;
4505
+ const result = await rare.listing.getStatus({
4506
+ contract: opts.contract,
4507
+ tokenId: opts.tokenId,
4508
+ target
4509
+ });
4510
+ console.log("\nListing Details:");
4511
+ if (!result.hasListing) {
4512
+ console.log(" No active listing found.");
4513
+ } else {
4514
+ console.log(` Seller: ${result.seller}`);
4515
+ console.log(` Amount: ${formatEther3(result.amount)} ${result.isEth ? "ETH" : result.currencyAddress}`);
4516
+ console.log(` Currency: ${result.isEth ? "ETH" : result.currencyAddress}`);
4517
+ }
4518
+ });
4519
+ return cmd;
4520
+ }
4521
+
4522
+ // src/commands/currencies.ts
4523
+ import { Command as Command12 } from "commander";
4524
+ function currenciesCommand() {
4525
+ const cmd = new Command12("currencies");
4526
+ cmd.description("List supported currencies and their addresses").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action((opts) => {
4527
+ const chain = getActiveChain(opts.chain);
4528
+ console.log(`
4529
+ Supported currencies on ${chain}:
4530
+ `);
4531
+ for (const name of currencyNames) {
4532
+ const address = resolveCurrency(name, chain);
4533
+ console.log(` ${name.toUpperCase().padEnd(6)} ${address}`);
4534
+ }
4535
+ });
4536
+ return cmd;
4537
+ }
4538
+
3560
4539
  // src/index.ts
3561
- var program = new Command10();
3562
- program.name("rare").description("CLI tool for interacting with the RARE protocol smart contracts").version("0.2.2");
4540
+ var program = new Command13();
4541
+ program.name("rare").description("CLI tool for interacting with the RARE protocol smart contracts").version("0.4.1");
3563
4542
  program.addCommand(configureCommand());
3564
4543
  program.addCommand(deployCommand());
3565
4544
  program.addCommand(mintCommand());
@@ -3569,6 +4548,9 @@ program.addCommand(walletCommand());
3569
4548
  program.addCommand(searchCommand());
3570
4549
  program.addCommand(listCollectionsCommand());
3571
4550
  program.addCommand(importCommand());
4551
+ program.addCommand(offerCommand());
4552
+ program.addCommand(listingCommand());
4553
+ program.addCommand(currenciesCommand());
3572
4554
  program.parseAsync(process.argv).catch((err) => {
3573
4555
  console.error("Error:", err.message ?? err);
3574
4556
  process.exit(1);