Skip to content

Commit 75a7a5f

Browse files
committed
initial 2.0 update (before testing)
1 parent d44d272 commit 75a7a5f

17 files changed

+1637
-430
lines changed

package-lock.json

Lines changed: 682 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "10k-collection-video",
3-
"version": "1.2.0",
4-
"description": "Source code from \"How To Create An ENTIRE NFT Collection (10,000+) & MINT In Under 1 Hour Without Coding Knowledge\" video.",
3+
"version": "2.0.0",
4+
"description": "How To Create An ENTIRE NFT Collection (10,000+) & MINT",
55
"main": "index.js",
66
"bin": "index.js",
77
"pkg": {
@@ -14,21 +14,30 @@
1414
"scripts": {
1515
"build": "node index.js",
1616
"generate": "node index.js",
17-
"rarity": "node utils/rarity.js",
18-
"rarity_md": "node utils/getRarity_fromMetadata.js",
17+
"rarity": "node utils/rarity",
18+
"rarity_md": "node utils/getRarity_fromMetadata",
1919
"rarity_rank": "node utils/rarity_rank.js",
2020
"preview": "node utils/preview.js",
2121
"pixelate": "node utils/pixelate.js",
2222
"update_info": "node utils/update_info.js",
23-
"preview_gif": "node utils/preview_gif.js"
23+
"preview_gif": "node utils/preview_gif.js",
24+
"create_generic": "node utils/genericMetas",
25+
"deploy_contract": "node utils/deployContract",
26+
"get_contract": "node utils/retrieveContract",
27+
"mint": "node utils/mint $npm_config_start $npm_config_end",
28+
"check_txns": "node utils/checkTxns $npm_config_dir",
29+
"refresh_os": "node utils/refreshOpensea $npm_config_start $npm_config_end"
2430
},
2531
"author": "Jesse Hall (codeSTACKr)",
2632
"license": "MIT",
2733
"dependencies": {
34+
"async-sema": "^3.1.1",
2835
"canvas": "^2.8.0",
2936
"form-data": "^4.0.0",
3037
"gif-encoder-2": "^1.0.5",
3138
"node-fetch": "^2.6.6",
32-
"sha1": "^1.1.1"
39+
"puppeteer": "^13.4.1",
40+
"sha1": "^1.1.1",
41+
"yesno": "^0.3.1"
3342
}
3443
}

src/config.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,38 @@ const { NETWORK } = require(`${basePath}/constants/network.js`);
44

55
const network = NETWORK.eth;
66

7+
// NFTPort Info
8+
// ** REQUIRED **
9+
const AUTH = 'YOUR API KEY HERE';
10+
const LIMIT = 2; // Your API key rate limit
11+
const CONTRACT_NAME = 'CRYPTOPUNKS';
12+
const CONTRACT_SYMBOL = 'CP';
13+
const CONTRACT_TYPE = 'erc721';
14+
const MINT_TO_ADDRESS = 'YOUR WALLET ADDRESS HERE';
15+
const CHAIN = 'rinkeby';
16+
// ** OPTIONAL **
17+
let CONTRACT_ADDRESS = 'Your Contract Address'; // If you want to manually include it
18+
// Generic Metadata is optional if you want to reveal your NFTs
19+
const GENERIC = false; // Set to true if you want to upload generic metas and reveal the real NFTs in the future
20+
const GENERIC_TITLE = "Unknown" // Replace with what you want the generic titles to say.
21+
const GENERIC_DESCRIPTION = "Unknown" // Replace with what you want the generic descriptions to say.
22+
const GENERIC_IMAGE = ["https://ipfs.io/ipfs/QmUf9tDbkqnfHkQaMdFWSGAeXwVXWA61pFED7ypx4hcsfh"] // Replace with your generic image(s).
23+
const REVEAL_PROMPT = true; // Set to false if you want to disable the prompt to confirm each reveal.
24+
const INTERVAL = 900000; // Milliseconds. This is the interval for it to check for sales and reveal the NFT. 900000 = 15 minutes.
25+
26+
// Automatically set contract address if deployed using the deployContract.js script
27+
try {
28+
const rawContractData = fs.readFileSync(`${basePath}/build/contract/_contract.json`);
29+
const contractData = JSON.parse(rawContractData);
30+
if (contractData.response === "OK" && contractData.error === null) {
31+
CONTRACT_ADDRESS = contractData.contract_address;
32+
} else {
33+
console.log(`Using manual contract address: ${CONTRACT_ADDRESS}`);
34+
}
35+
} catch (error) {
36+
console.log(`Using manual contract address: ${CONTRACT_ADDRESS}`);
37+
}
38+
739
// General metadata for Ethereum
840
const namePrefix = "Your Collection";
941
const description = "Remember to replace this description";
@@ -121,4 +153,18 @@ module.exports = {
121153
solanaMetadata,
122154
gif,
123155
preview_gif,
156+
AUTH,
157+
LIMIT,
158+
CONTRACT_ADDRESS,
159+
MINT_TO_ADDRESS,
160+
CHAIN,
161+
GENERIC,
162+
GENERIC_TITLE,
163+
GENERIC_DESCRIPTION,
164+
GENERIC_IMAGE,
165+
INTERVAL,
166+
CONTRACT_NAME,
167+
CONTRACT_SYMBOL,
168+
CONTRACT_TYPE,
169+
REVEAL_PROMPT,
124170
};

src/main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,13 @@ const addMetadata = (_dna, _edition) => {
131131
name: `${namePrefix} #${_edition}`,
132132
description: description,
133133
file_url: `${baseUri}/${_edition}.png`,
134+
image: `${baseUri}/${_edition}.png`,
134135
attributes: attributesList,
135136
custom_fields: {
136137
dna: sha1(_dna),
137138
edition: _edition,
138139
date: dateTime,
139-
compiler: "HashLips Art Engine",
140+
compiler: "HashLips Art Engine - codeSTACKr Modified",
140141
},
141142
...extraMetadata,
142143
};

utils/functions/fetchWithRetry.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const fetch = require("node-fetch");
2+
const { AUTH } = require(`${basePath}/src/config.js`);
3+
4+
function fetchWithRetry(data, url, method) {
5+
return new Promise((resolve, reject) => {
6+
const fetch_retry = (_data) => {
7+
let options = {
8+
method: method,
9+
headers: {
10+
"Content-Type": "application/json",
11+
Authorization: AUTH,
12+
},
13+
body: _data,
14+
};
15+
16+
return fetch(url, options)
17+
.then((res) => {
18+
const status = res.status;
19+
20+
if (status === 200) {
21+
return res.json();
22+
} else {
23+
throw `ERROR STATUS: ${status}`;
24+
}
25+
})
26+
.then((json) => {
27+
if (json.response === "OK") {
28+
return resolve(json);
29+
} else {
30+
throw `NOK: ${json.error}`;
31+
}
32+
})
33+
.catch((error) => {
34+
console.error(`CATCH ERROR: ${error}`);
35+
console.log("Retrying");
36+
fetch_retry(_data);
37+
});
38+
};
39+
return fetch_retry(data);
40+
});
41+
}
42+
43+
module.exports = { fetchWithRetry };

utils/functions/refreshOpensea.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const basePath = process.cwd();
2+
const puppeteer = require("puppeteer");
3+
let [START, END] = process.argv.slice(2);
4+
const { CONTRACT_ADDRESS } = require(`${basePath}/src/config.js`);
5+
6+
if(!START || !END) {
7+
console.log("Please provide a start and end edition number. Example: node refreshOpensea.js 1 100");
8+
process.exit(1);
9+
}
10+
11+
const COLLECTION_BASE_URL = `https://opensea.io/assets/matic/${CONTRACT_ADDRESS}/`;
12+
13+
async function main() {
14+
const browser = await puppeteer.launch({
15+
headless: false,
16+
timeout: 60000,
17+
});
18+
const notFound = [];
19+
const errors = [];
20+
21+
console.log(`Beginning OpenSea Refresh - ${COLLECTION_BASE_URL}`);
22+
const page = await browser.newPage();
23+
24+
for (let i = START; i <= END; i++) {
25+
try {
26+
console.log(`Refreshing Edition: ${i}`);
27+
28+
const url = COLLECTION_BASE_URL + i.toString();
29+
30+
await page.goto(url);
31+
32+
await page.waitForSelector('main');
33+
let pageTitle = await page.$$eval('title', title => title.map(title => title.textContent));
34+
if(pageTitle[0] === "Not Found | OpenSea") {
35+
console.log(`Edition ${i} not found!`);
36+
notFound.push(i);
37+
}
38+
39+
await page.click('button>div>i[value="refresh"]')
40+
await page.waitForTimeout(5000);
41+
42+
console.log(`Refreshed Edition: ${i}`);
43+
} catch (error) {
44+
console.log(`Error refreshing edition ${i}: ${error}`);
45+
errors.push(i);
46+
}
47+
}
48+
49+
await browser.close();
50+
51+
if(notFound.length > 0 || errors.length > 0) {
52+
console.log(`Not Found: ${notFound}`);
53+
console.log(`Errors: ${errors}`);
54+
}
55+
console.log(
56+
`Finished OpenSea Refresh - ${COLLECTION_BASE_URL}`
57+
);
58+
}
59+
60+
main();

utils/functions/txnCheck.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const fetch = require("node-fetch");
2+
3+
async function txnCheck(url) {
4+
return new Promise((resolve, reject) => {
5+
const options = {
6+
method: "GET",
7+
headers: {
8+
"Content-Type": "application/json",
9+
},
10+
};
11+
12+
fetch(url, options)
13+
.then((response) => {
14+
return response.text();
15+
})
16+
.then((text) => {
17+
if (
18+
text.toLowerCase().includes("search not found") ||
19+
text.toLowerCase().includes("</i>fail</span>") ||
20+
text.toLowerCase().includes("</i>failed</span>")
21+
) {
22+
resolve('Failed');
23+
} else if (text.toLowerCase().includes("</i>success</span>")) {
24+
resolve('Success');
25+
} else {
26+
resolve('Unknown');
27+
}
28+
})
29+
.catch((err) => {
30+
console.error("error:" + err);
31+
reject(err);
32+
});
33+
});
34+
}
35+
36+
module.exports = { txnCheck };

utils/nftport/checkTxns.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const path = require("path");
2+
const basePath = process.cwd();
3+
const fs = require("fs");
4+
const { txnCheck } = require(`${basePath}/utils/functions/txnCheck.js`);
5+
const regex = new RegExp("^([0-9]+).json$");
6+
7+
let [dir] = process.argv.slice(2);
8+
if(dir !== 'minted' || dir !== 'revealed') {
9+
console.log('Please specify the directory to check. Use "minted" or "revealed"');
10+
process.exit(1);
11+
}
12+
13+
let success = [];
14+
let failed = [];
15+
let unknown = [];
16+
17+
async function main() {
18+
console.log("Checking transactions...");
19+
const files = fs.readdirSync(`${basePath}/build/${dir}`);
20+
files.sort(function(a, b){
21+
return a.split(".")[0] - b.split(".")[0];
22+
});
23+
for (const file of files) {
24+
try {
25+
if (regex.test(file)) {
26+
const edition = path.parse(file).name;
27+
let jsonFile = fs.readFileSync(`${basePath}/build/${dir}/${edition}.json`);
28+
let txnData = JSON.parse(jsonFile);
29+
if (
30+
txnData.mintData.response !== "OK" ||
31+
txnData.mintData.error !== null
32+
) {
33+
failed.push(edition);
34+
console.log(
35+
`Edition #${edition}: Transaction failed`
36+
);
37+
} else {
38+
let check = await txnCheck(
39+
txnData.mintData.transaction_external_url
40+
);
41+
if (check === "Failed") {
42+
failed.push(edition);
43+
console.log(
44+
`Edition #${edition}: Transaction failed or not found.`
45+
);
46+
} else if (check === "Unknown") {
47+
unknown.push(edition);
48+
console.log(`Edition #${edition}: Transaction pending..`);
49+
} else if (check === "Success") {
50+
success.push(edition);
51+
console.log(`Edition #${edition}: Transaction success!`);
52+
}
53+
}
54+
}
55+
} catch (error) {
56+
console.log(`Catch: ${error}`);
57+
}
58+
}
59+
if(failed.length > 0) {
60+
console.log(`Failed Txn Count: ${failed.length}`);
61+
console.log(`Failed Txns: ${failed}`);
62+
} else if (unknown.length > 0) {
63+
console.log(`Unknown Txn Count: ${unknown.length}`);
64+
console.log(`Unknown Txns: ${unknown}`);
65+
console.log(`There are some transactions pending.`);
66+
} else if (success.length > 0) {
67+
console.log(`Successful Txn Count: ${success}`);
68+
}
69+
}

utils/nftport/deployContract.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const basePath = process.cwd();
2+
const fs = require("fs");
3+
const yesno = require('yesno');
4+
5+
const ok = await yesno({
6+
question: `Is all REQUIRED contract information correct in config.js?`,
7+
default: null,
8+
});
9+
10+
if(!ok) {
11+
console.log("Exiting...");
12+
process.exit(0);
13+
}
14+
15+
const {
16+
fetchWithRetry,
17+
} = require(`${basePath}/utils/functions/fetchWithRetry.js`);
18+
const {
19+
CHAIN,
20+
CONTRACT_NAME,
21+
CONTRACT_SYMBOL,
22+
CONTRACT_TYPE,
23+
MINT_TO_ADDRESS,
24+
} = require(`${basePath}/src/config.js`);
25+
26+
const contract = {
27+
chain: CHAIN.toLowerCase(),
28+
name: CONTRACT_NAME,
29+
symbol: CONTRACT_SYMBOL,
30+
owner_address: MINT_TO_ADDRESS,
31+
type: CONTRACT_TYPE,
32+
metadata_updatable: true, // set to false if you don't want to allow metadata updates after minting
33+
};
34+
35+
if (!fs.existsSync(path.join(`${basePath}/build`, "/contract"))) {
36+
fs.mkdirSync(path.join(`${basePath}/build`, "contract"));
37+
}
38+
39+
const deployContract = async () => {
40+
try {
41+
const url = `https://api.nftport.xyz/v0/contracts`;
42+
const response = await fetchWithRetry(JSON.stringify(contract), url, "POST");
43+
fs.writeFileSync(`${basePath}/build/contract/_deployContractResponse.json`, JSON.stringify(response, null, 2));
44+
if(response.response === "OK" && response.error === null) {
45+
console.log(`Contract ${CONTRACT_NAME} deployment started.`);
46+
} else {
47+
console.log(`Contract ${CONTRACT_NAME} deployment failed`);
48+
}
49+
} catch (error) {
50+
console.log(`Contract ${CONTRACT_NAME} deployment failed`);
51+
}
52+
};
53+
54+
deployContract();

0 commit comments

Comments
 (0)