UNPKG

@boxfish-studio/candymachine-client-sdk

Version:
1,295 lines (1,281 loc) 48.1 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/update.ts import { PublicKey } from "@solana/web3.js"; // src/cache/actions.ts import fileDownloader from "js-file-download"; function saveCache(cacheName, env, cacheContent) { cacheContent.env = env; cacheContent.cacheName = cacheName; fileDownloader(JSON.stringify(cacheContent), cacheName); } // src/update.ts function updateV2(_0) { return __async(this, arguments, function* ({ newSettings, candyMachinePubkey, publicKey, treasuryWallet, anchorProgram, cache, newAuthority }) { try { const cacheContent = JSON.parse(cache); const env = cacheContent.env; const cacheName = cacheContent.cacheName; const tx = yield anchorProgram.methods.updateCandyMachine(newSettings).accounts({ candyMachine: new PublicKey(candyMachinePubkey), authority: publicKey, wallet: treasuryWallet }).signers([]).rpc(); cacheContent.startDate = newSettings.goLiveDate; console.log("update_candy_machine finished", tx); if (newAuthority) { const tx2 = yield anchorProgram.methods.updateAuthority(new PublicKey(newAuthority)).accounts({ candyMachine: new PublicKey(candyMachinePubkey), authority: publicKey, wallet: treasuryWallet }).rpc(); cacheContent.authority = new PublicKey(newAuthority).toBase58(); console.log(` - updated authority: ${cacheContent.authority}`); console.log("update_authority finished", tx2); } saveCache(cacheName, env, cacheContent); } catch (err) { console.error(err); throw new Error(); } }); } // src/upload/arweave.ts import { calculate } from "@metaplex/arweave-cost"; import * as anchor2 from "@project-serum/anchor"; // src/constants.ts import { PublicKey as PublicKey2 } from "@solana/web3.js"; var SUPPORTED_IMAGE_TYPES = ["image/png", "image/gif", "image/jpeg"]; var SUPPORTED_ANIMATION_TYPES = [ "video/mp4", "video/quicktime", "audio/mpeg", "audio/x-flac", "audio/wav", "model/gltf-binary", "text/html" ]; var DEFAULT_GATEKEEPER = { gatekeeperNetwork: "ignREusXmGrscGNUesoU9mxfds9AiYTezUKex2PsZV6", expireOnUse: true }; var JSON_EXTENSION = "application/json"; var DEFAULT_TIMEOUT = 3e4; var NOTIFICATION_TIMEOUT_NEVER = -1; var NOTIFICATION_TIMEOUT_DEFAULT = 5e3; var CANDY_MACHINE = "candy_machine"; var AUCTION_HOUSE = "auction_house"; var TOKEN_ENTANGLER = "token_entangler"; var ESCROW = "escrow"; var A = "A"; var B = "B"; var FEE_PAYER = "fee_payer"; var TREASURY = "treasury"; var MAX_NAME_LENGTH = 32; var MAX_URI_LENGTH = 200; var MAX_SYMBOL_LENGTH = 10; var MAX_CREATOR_LEN = 32 + 1 + 1; var MAX_CREATOR_LIMIT = 5; var ARWEAVE_PAYMENT_WALLET = new PublicKey2("6FKvsq4ydWFci6nGq9ckbjYMtnmaqAoatz5c9XWjiDuS"); var CANDY_MACHINE_PROGRAM_ID = new PublicKey2("cndyAnrLdpjq1Ssp1z8xxDsB8dxe7u4HL5Nxi2K5WXZ"); var CANDY_MACHINE_PROGRAM_V2_ID = new PublicKey2("cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ"); var TOKEN_METADATA_PROGRAM_ID = new PublicKey2("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"); var SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = new PublicKey2("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); var TOKEN_PROGRAM_ID = new PublicKey2("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); var FAIR_LAUNCH_PROGRAM_ID = new PublicKey2("faircnAB9k59Y4TXmLabBULeuTLgV7TkGMGNkjnA15j"); var AUCTION_HOUSE_PROGRAM_ID = new PublicKey2("hausS13jsjafwWwGqZTUQRmWyvyxn9EQpqMwV1PBBmk"); var TOKEN_ENTANGLEMENT_PROGRAM_ID = new PublicKey2("qntmGodpGkrM42mN68VCZHXnKqDCT8rdY23wFcXCLPd"); var WRAPPED_SOL_MINT = new PublicKey2("So11111111111111111111111111111111111111112"); var ARWEAVE_UPLOAD_ENDPOINT = "https://us-central1-metaplex-studios.cloudfunctions.net/uploadFile"; var CONFIG_ARRAY_START = 32 + 4 + 6 + 4 + 10 + 2 + 1 + 4 + 5 * 34 + 8 + 1 + 1 + 4; var CONFIG_ARRAY_START_V2 = 8 + 32 + 32 + 33 + 4 + 6 + 8 + 8 + 9 + 10 + 4 + MAX_SYMBOL_LENGTH + 2 + 4 + MAX_CREATOR_LIMIT * MAX_CREATOR_LEN + 8 + 1 + 1 + 1 + 4 + MAX_NAME_LENGTH + 4 + MAX_URI_LENGTH + 32 + 4 + 8 + 1 + 1 + 1 + 9 + 32 + 1 + 32 + 1; var CONFIG_LINE_SIZE_V2 = 4 + 32 + 4 + 200; var CONFIG_LINE_SIZE = 4 + 32 + 4 + 200; var CACHE_PATH = "./.cache"; // src/upload/helpers.ts import * as anchor from "@project-serum/anchor"; import { Keypair, SystemProgram } from "@solana/web3.js"; function parseDate(date) { if (date === "now") { return Date.now() / 1e3; } return Date.parse(date) / 1e3; } function sleep(milliseconds) { return new Promise((resolve) => setTimeout(resolve, milliseconds)); } function uuidFromConfigPubkey(configAccount) { return configAccount.toBase58().slice(0, 6); } var createCandyMachineV2 = function(anchorProgram, payerWallet, treasuryWallet, candyData) { return __async(this, null, function* () { const candyAccount = Keypair.generate(); candyData.uuid = uuidFromConfigPubkey(candyAccount.publicKey); if (!candyData.symbol) { throw new Error("Invalid config, there must be a symbol."); } if (!candyData.creators || candyData.creators.length === 0) { throw new Error("Invalid config, there must be at least one creator."); } const totalShare = (candyData.creators || []).reduce((acc, curr) => acc + curr.share, 0); if (totalShare !== 100) { throw new Error("Invalid config, creators shares must add up to 100"); } const remainingAccounts = []; const cmCreation = { candyMachine: candyAccount.publicKey, uuid: candyData.uuid, txId: yield anchorProgram.methods.initializeCandyMachine(candyData).accounts({ candyMachine: candyAccount.publicKey, wallet: treasuryWallet, authority: payerWallet.publicKey, payer: payerWallet.publicKey, systemProgram: SystemProgram.programId, rent: anchor.web3.SYSVAR_RENT_PUBKEY }).signers([candyAccount]).remainingAccounts(remainingAccounts).preInstructions([ yield createCandyMachineV2Account(anchorProgram, candyData, payerWallet.publicKey, candyAccount.publicKey) ]).rpc() }; console.log("cmCreation", cmCreation); return cmCreation; }); }; function createCandyMachineV2Account(anchorProgram, candyData, payerWallet, candyAccount) { return __async(this, null, function* () { console.log("creating v2 account"); const size = CONFIG_ARRAY_START_V2 + 4 + candyData.itemsAvailable.toNumber() * CONFIG_LINE_SIZE_V2 + 8 + 2 * (Math.floor(candyData.itemsAvailable.toNumber() / 8) + 1); const candyMachineAccount = anchor.web3.SystemProgram.createAccount({ fromPubkey: payerWallet, newAccountPubkey: candyAccount, space: size, lamports: yield anchorProgram.provider.connection.getMinimumBalanceForRentExemption(size), programId: CANDY_MACHINE_PROGRAM_V2_ID }); console.log("account created", candyMachineAccount); return candyMachineAccount; }); } var getUnixTs = () => new Date().getTime() / 1e3; var getFileName = (fileName) => fileName.split(".")[0]; var getFileExtension = (fileName) => fileName.split(".")[1]; // src/upload/transactions.ts import { Transaction } from "@solana/web3.js"; var sendTransactionWithRetryWithKeypair = (connection, wallet, instructions, commitment = "singleGossip", block, beforeSend) => __async(void 0, null, function* () { const transaction = new Transaction(); instructions.forEach((instruction) => transaction.add(instruction)); transaction.recentBlockhash = (block || (yield connection.getLatestBlockhash(commitment))).blockhash; transaction.feePayer = wallet.publicKey; yield wallet.signTransaction(transaction); if (beforeSend) { beforeSend(); } const { txid, slot } = yield sendSignedTransaction({ connection, signedTransaction: transaction }); return { txid, slot }; }); function sendSignedTransaction(_0) { return __async(this, arguments, function* ({ signedTransaction, connection, timeout = DEFAULT_TIMEOUT }) { const rawTransaction = signedTransaction.serialize(); const startTime = getUnixTs(); let slot = 0; let txid = yield connection.sendRawTransaction(rawTransaction, { skipPreflight: true }); console.log("Started awaiting confirmation for", txid); let done = false; (() => __async(this, null, function* () { while (!done && getUnixTs() - startTime < timeout) { connection.sendRawTransaction(rawTransaction, { skipPreflight: true }); yield sleep(500); } }))(); try { const confirmation = yield awaitTransactionSignatureConfirmation(txid, timeout, connection, "confirmed", true); if (!confirmation) throw new Error("Timed out awaiting confirmation on transaction"); if (confirmation.err) { console.error(confirmation.err); throw new Error("Transaction failed: Custom instruction error"); } slot = (confirmation == null ? void 0 : confirmation.slot) || 0; } catch (err) { console.error("Timeout Error caught", err); if (err.timeout) { throw new Error("Timed out awaiting confirmation on transaction"); } let simulateResult = null; try { simulateResult = (yield simulateTransaction(connection, signedTransaction, "single")).value; } catch (e) { console.error("Simulate Transaction error", e); } if (simulateResult && simulateResult.err) { if (simulateResult.logs) { for (let i = simulateResult.logs.length - 1; i >= 0; --i) { const line = simulateResult.logs[i]; if (line.startsWith("Program log: ")) { throw new Error("Transaction failed: " + line.slice("Program log: ".length)); } } } throw new Error(JSON.stringify(simulateResult.err)); } console.error("Got this far."); txid = simulateResult == null ? void 0 : simulateResult.err; } finally { done = true; } console.log("Latency (ms)", txid, getUnixTs() - startTime); return { txid, slot }; }); } function simulateTransaction(connection, transaction, commitment) { return __async(this, null, function* () { transaction.recentBlockhash = (yield connection.getLatestBlockhash()).blockhash; const signData = transaction.serializeMessage(); const encodedTransaction = signData.toString("base64"); const config = { encoding: "base64", commitment }; const args = [encodedTransaction, config]; const res = yield connection._rpcRequest("simulateTransaction", args); if (res.error) { throw new Error("failed to simulate transaction: " + res.error.message); } return res.result; }); } function awaitTransactionSignatureConfirmation(txid, timeout, connection, commitment = "recent", queryStatus = false) { return __async(this, null, function* () { let done = false; let status = { slot: 0, confirmations: 0, err: null }; let subId = 0; status = yield new Promise((resolve, reject) => __async(this, null, function* () { setTimeout(() => { if (done) { return; } done = true; console.warn("Rejecting for timeout..."); reject({ timeout: true }); }, timeout); try { subId = connection.onSignature( txid, (result, context) => { done = true; status = { err: result.err, slot: context.slot, confirmations: 0 }; if (result.err) { console.warn("Rejected via websocket", result.err); reject(status); } else { console.log("Resolved via websocket", result); resolve(status); } }, commitment ); } catch (e) { done = true; console.error("WS error in setup", txid, e); } while (!done && queryStatus) { ; (() => __async(this, null, function* () { try { const signatureStatuses = yield connection.getSignatureStatuses([txid]); status = signatureStatuses && signatureStatuses.value[0]; if (!done) { if (!status) { console.log("REST null result for", txid, status); } else if (status.err) { console.error("REST error for", txid, status); done = true; reject(status.err); } else if (!status.confirmations) { console.log("REST no confirmations for", txid, status); } else { console.log("REST confirmation for", txid, status); done = true; resolve(status); } } } catch (e) { if (!done) { console.error("REST connection error: txid", txid, e); } } }))(); yield sleep(2e3); } })); connection.removeSignatureListener(subId); done = true; console.log("Returning status", status); return status; }); } var SequenceType = /* @__PURE__ */ ((SequenceType2) => { SequenceType2[SequenceType2["Sequential"] = 0] = "Sequential"; SequenceType2[SequenceType2["Parallel"] = 1] = "Parallel"; SequenceType2[SequenceType2["StopOnFailure"] = 2] = "StopOnFailure"; return SequenceType2; })(SequenceType || {}); var sendTransactions = (_0, _1, _2, _3, ..._4) => __async(void 0, [_0, _1, _2, _3, ..._4], function* (connection, wallet, instructionSet, signersSet, sequenceType = 1 /* Parallel */, commitment = "singleGossip", successCallback = (txid, ind) => { }, failCallback = (txid, ind) => false, block, beforeTransactions = [], afterTransactions = []) { if (!wallet.publicKey) throw new Error("Wallet not connected"); const unsignedTxns = beforeTransactions; if (!block) { block = yield connection.getLatestBlockhash(commitment); } for (let i = 0; i < instructionSet.length; i++) { const instructions = instructionSet[i]; const signers = signersSet[i]; if (instructions.length === 0) { continue; } const transaction = new Transaction(); instructions.forEach((instruction) => transaction.add(instruction)); transaction.recentBlockhash = block.blockhash; transaction.setSigners( wallet.publicKey, ...signers.map((s) => s.publicKey) ); if (signers.length > 0) { transaction.partialSign(...signers); } unsignedTxns.push(transaction); } unsignedTxns.push(...afterTransactions); const partiallySignedTransactions = unsignedTxns.filter( (t) => t.signatures.find((sig) => sig.publicKey.equals(wallet.publicKey)) ); const fullySignedTransactions = unsignedTxns.filter( (t) => !t.signatures.find((sig) => sig.publicKey.equals(wallet.publicKey)) ); let signedTxns = yield wallet.signAllTransactions(partiallySignedTransactions); signedTxns = fullySignedTransactions.concat(signedTxns); const pendingTxns = []; console.log("Signed txns length", signedTxns.length, "vs handed in length", instructionSet.length); for (let i = 0; i < signedTxns.length; i++) { const signedTxnPromise = sendSignedTransaction({ connection, signedTransaction: signedTxns[i] }); if (sequenceType !== 1 /* Parallel */) { try { yield signedTxnPromise.then(({ txid, slot }) => successCallback(txid, i)); pendingTxns.push(signedTxnPromise); } catch (e) { console.log("Failed at txn index:", i); console.log("Caught failure:", e); failCallback(signedTxns[i], i); if (sequenceType === 2 /* StopOnFailure */) { return { number: i, txs: yield Promise.all(pendingTxns) }; } } } else { pendingTxns.push(signedTxnPromise); } } if (sequenceType !== 1 /* Parallel */) { const result = yield Promise.all(pendingTxns); return { number: signedTxns.length, txs: result }; } return { number: signedTxns.length, txs: yield Promise.all(pendingTxns) }; }); // src/upload/arweave.ts function fetchAssetCostToStore(fileSizes) { return __async(this, null, function* () { const result = yield calculate(fileSizes); console.log("Arweave cost estimates:", result); return result.solana * anchor2.web3.LAMPORTS_PER_SOL; }); } function upload(data, manifest, index) { return __async(this, null, function* () { console.log(`trying to upload image ${index}: ${manifest.name}`); const res = yield (yield fetch(ARWEAVE_UPLOAD_ENDPOINT, { method: "POST", body: data })).json(); return res; }); } function estimateManifestSize(filenames) { const paths = {}; for (const name of filenames) { console.log("name", name); paths[name] = { id: "artestaC_testsEaEmAGFtestEGtestmMGmgMGAV438", ext: getFileExtension(name) }; } const manifest = { manifest: "arweave/paths", version: "0.1.0", paths, index: { path: "metadata.json" } }; const data = Buffer.from(JSON.stringify(manifest), "utf8"); console.log("Estimated manifest size:", data.length); return data.length; } function arweaveUpload(walletKeyPair, anchorProgram, env, image, manifestBuffer, manifest, index) { return __async(this, null, function* () { var _a, _b; const imageExt = image.type; const estimatedManifestSize = estimateManifestSize([image.name, "metadata.json"]); const storageCost = yield fetchAssetCostToStore([image.size, manifestBuffer.length, estimatedManifestSize]); console.log(`lamport cost to store ${image.name}: ${storageCost}`); const instructions = [ anchor2.web3.SystemProgram.transfer({ fromPubkey: walletKeyPair.publicKey, toPubkey: ARWEAVE_PAYMENT_WALLET, lamports: Math.round(storageCost) }) ]; const tx = yield sendTransactionWithRetryWithKeypair( anchorProgram.provider.connection, walletKeyPair, instructions, "confirmed" ); console.log(`solana transaction (${env}) for arweave payment:`, tx); const data = new FormData(); const manifestBlob = new Blob([manifestBuffer], { type: JSON_EXTENSION }); data.append("transaction", tx["txid"]); data.append("env", env); data.append("file[]", image, image.name); data.append("file[]", manifestBlob, "metadata.json"); const result = yield upload(data, manifest, index); console.log("result", result); const metadataFile = (_a = result.messages) == null ? void 0 : _a.find((m) => m.filename === "manifest.json"); const imageFile = (_b = result.messages) == null ? void 0 : _b.find((m) => m.filename === image.name); if (metadataFile == null ? void 0 : metadataFile.transactionId) { const link = `https://arweave.net/${metadataFile.transactionId}`; const imageLink = `https://arweave.net/${imageFile.transactionId}?ext=${imageExt.replace(".", "")}`; console.log(`File uploaded: ${link}`); console.log(`imageLink uploaded: ${imageLink}`); return [link, imageLink]; } else { throw new Error(`No transaction ID for upload: ${index}`); } }); } // src/upload/config.ts import * as anchor3 from "@project-serum/anchor"; import { getAccount, getMint, TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID2 } from "@solana/spl-token"; import { PublicKey as PublicKey4 } from "@solana/web3.js"; // src/enums.ts var StorageType = /* @__PURE__ */ ((StorageType2) => { StorageType2["ArweaveBundle"] = "arweave-bundle"; StorageType2["ArweaveSol"] = "arweave-sol"; StorageType2["Arweave"] = "arweave"; StorageType2["Ipfs"] = "ipfs"; StorageType2["Aws"] = "aws"; StorageType2["NftStorage"] = "nft-storage"; StorageType2["Pinata"] = "pinata"; return StorageType2; })(StorageType || {}); // src/mint/helpers.ts import { web3 as web33 } from "@project-serum/anchor"; var getAtaForMint = (mint, buyer) => __async(void 0, null, function* () { return yield web33.PublicKey.findProgramAddress( [buyer.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID ); }); var getMetadata = (mint) => __async(void 0, null, function* () { return (yield web33.PublicKey.findProgramAddress( [Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer()], TOKEN_METADATA_PROGRAM_ID ))[0]; }); var getMasterEdition = (mint) => __async(void 0, null, function* () { return (yield web33.PublicKey.findProgramAddress( [Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer(), Buffer.from("edition")], TOKEN_METADATA_PROGRAM_ID ))[0]; }); var getCandyMachineCreator = (candyMachine) => __async(void 0, null, function* () { return yield web33.PublicKey.findProgramAddress([Buffer.from("candy_machine"), candyMachine.toBuffer()], CANDY_MACHINE_PROGRAM_V2_ID); }); // src/upload/config.ts function loadCandyProgramV2(provider, customRpcUrl) { return __async(this, null, function* () { if (customRpcUrl) console.log("USING CUSTOM URL", customRpcUrl); const idl = yield anchor3.Program.fetchIdl(CANDY_MACHINE_PROGRAM_V2_ID, provider); const program = new anchor3.Program(idl, CANDY_MACHINE_PROGRAM_V2_ID, provider); console.log("program id from anchor", program.programId.toBase58()); return program; }); } function getCandyMachineV2Config(walletKeyPair, configForm, anchorProgram) { return __async(this, null, function* () { var _a, _b, _c; if (configForm === void 0) { throw new Error("The configForm is undefined"); } const config = configForm; const { storage, nftStorageKey, ipfsInfuraProjectId, number, ipfsInfuraSecret, pinataJwt, pinataGateway, awsS3Bucket, noRetainAuthority, noMutable, batchSize, price, splToken, splTokenAccount, solTreasuryAccount, gatekeeper, endSettings, hiddenSettings, whitelistMintSettings, goLiveDate, uuid, arweaveJwk } = config; let wallet; let parsedPrice = price; const splTokenAccountFigured = splTokenAccount ? splTokenAccount : splToken ? (yield getAtaForMint(new PublicKey4(splToken), walletKeyPair))[0] : null; if (splToken) { if (solTreasuryAccount) { throw new Error("If spl-token-account or spl-token is set then sol-treasury-account cannot be set"); } if (!splToken) { throw new Error("If spl-token-account is set, spl-token must also be set"); } const splTokenKey = new PublicKey4(splToken); const splTokenAccountKey = new PublicKey4(splTokenAccountFigured); if (!splTokenAccountFigured) { throw new Error("If spl-token is set, spl-token-account must also be set"); } console.log("anchor program loaded", anchorProgram); const mintInfo = yield getMint(anchorProgram.provider.connection, splTokenKey, void 0, TOKEN_PROGRAM_ID2); if (!mintInfo.isInitialized) { throw new Error("The specified spl-token is not initialized"); } const tokenAccount = yield getAccount(anchorProgram.provider.connection, splTokenAccountKey, void 0, TOKEN_PROGRAM_ID2); if (!tokenAccount.isInitialized) { throw new Error("The specified spl-token-account is not initialized"); } if (!tokenAccount.mint.equals(splTokenKey)) { throw new Error( `The spl-token-account's mint (${tokenAccount.mint.toString()}) does not match specified spl-token ${splTokenKey.toString()}` ); } wallet = new PublicKey4(splTokenAccountKey); parsedPrice = price * 10 ** mintInfo.decimals; if (whitelistMintSettings && (whitelistMintSettings == null ? void 0 : whitelistMintSettings.discountPrice) || whitelistMintSettings && ((_a = whitelistMintSettings == null ? void 0 : whitelistMintSettings.discountPrice) == null ? void 0 : _a.toNumber()) === 0) { ; whitelistMintSettings.discountPrice *= 10 ** mintInfo.decimals; } } else { parsedPrice = price * 10 ** 9; if ((whitelistMintSettings == null ? void 0 : whitelistMintSettings.discountPrice) || ((_b = whitelistMintSettings == null ? void 0 : whitelistMintSettings.discountPrice) == null ? void 0 : _b.toNumber()) === 0) { ; whitelistMintSettings.discountPrice *= 10 ** 9; } wallet = solTreasuryAccount ? new PublicKey4(solTreasuryAccount) : walletKeyPair; } if (whitelistMintSettings) { whitelistMintSettings.mint = new PublicKey4(whitelistMintSettings.mint); if ((whitelistMintSettings == null ? void 0 : whitelistMintSettings.discountPrice) || ((_c = whitelistMintSettings == null ? void 0 : whitelistMintSettings.discountPrice) == null ? void 0 : _c.toNumber()) === 0) { whitelistMintSettings.discountPrice = new anchor3.BN(whitelistMintSettings.discountPrice); } } if (endSettings) { if (endSettings.endSettingType.date) { endSettings.number = new anchor3.BN(parseDate(endSettings.value)); } else if (endSettings.endSettingType.amount) { endSettings.number = new anchor3.BN(endSettings.value); } delete endSettings.value; } if (hiddenSettings) { const utf8Encode = new TextEncoder(); hiddenSettings.hash = utf8Encode.encode(hiddenSettings.hash.toString()); } console.log("correct config"); return { storage, nftStorageKey, ipfsInfuraProjectId, number, ipfsInfuraSecret, pinataJwt, pinataGateway: pinataGateway ? pinataGateway : null, awsS3Bucket, retainAuthority: !noRetainAuthority, mutable: !noMutable, batchSize, price: new anchor3.BN(parsedPrice), treasuryWallet: wallet, splToken: splToken ? new PublicKey4(splToken) : null, gatekeeper: gatekeeper ? { gatekeeperNetwork: new PublicKey4(gatekeeper.gatekeeperNetwork), expireOnUse: gatekeeper.expireOnUse } : null, endSettings, hiddenSettings, whitelistMintSettings, goLiveDate: goLiveDate ? new anchor3.BN(parseDate(goLiveDate)) : null, uuid, arweaveJwk }; }); } function verifyAssets(files, storage, number) { let imageFileCount = 0; let animationFileCount = 0; let jsonFileCount = 0; const supportedFiles = files.filter((it) => { if (SUPPORTED_IMAGE_TYPES.some((e) => e === it.type)) { imageFileCount++; } else if (SUPPORTED_ANIMATION_TYPES.some((e) => e === it.type)) { animationFileCount++; } else if (it.type == JSON_EXTENSION) { jsonFileCount++; } else { console.warn(`WARNING: Skipping unsupported file type ${it}`); return false; } return true; }); if (animationFileCount !== 0 && storage === "arweave" /* Arweave */) { throw new Error( 'The "arweave" storage option is incompatible with animation files. Please try again with another storage option using `--storage <option>`.' ); } if (animationFileCount !== 0 && animationFileCount !== jsonFileCount) { throw new Error( `number of animation files (${animationFileCount}) is different than the number of json files (${jsonFileCount})` ); } else if (imageFileCount !== jsonFileCount) { throw new Error(`number of img files (${imageFileCount}) is different than the number of json files (${jsonFileCount})`); } const elemCount = number ? number : imageFileCount; if (elemCount < imageFileCount) { throw new Error( `max number (${elemCount}) cannot be smaller than the number of images in the source folder (${imageFileCount})` ); } if (animationFileCount === 0) { console.info(`Beginning the upload for ${elemCount} (img+json) pairs`); } else { console.info(`Beginning the upload for ${elemCount} (img+animation+json) sets`); } console.log("supportedFiles", supportedFiles); return { supportedFiles, elemCount }; } // src/upload/upload.ts import { BN as BN2 } from "@project-serum/anchor"; import { PublicKey as PublicKey5 } from "@solana/web3.js"; import { PromisePool } from "@supercharge/promise-pool"; function uploadV2(_0) { return __async(this, arguments, function* ({ files, cacheName, env, totalNFTs, storage, retainAuthority, mutable, batchSize, price, treasuryWallet, gatekeeper, goLiveDate, endSettings, whitelistMintSettings, hiddenSettings, walletKeyPair, anchorProgram, rateLimit }) { var _a, _b, _c; const cacheContent = { program: { uuid: "", candyMachine: "" }, items: {} }; const filesNames = files.map((file) => file.name); const dedupedAssetKeys = getAssetKeysNeedingUpload(cacheContent.items, filesNames); console.log("dedupedAssetKeys", dedupedAssetKeys); let candyMachine = void 0; if (!((_a = cacheContent == null ? void 0 : cacheContent.program) == null ? void 0 : _a.uuid)) { const firstManifestFile = files.find((file) => file.name === "0.json"); if (!firstManifestFile) throw new Error("0.json must be present"); const firstAssetManifest = JSON.parse(yield firstManifestFile.text()); try { if (!((_c = (_b = firstAssetManifest.properties) == null ? void 0 : _b.creators) == null ? void 0 : _c.every((creator) => creator.address !== void 0))) { throw new Error("Creator address is missing"); } console.info("initializing candy machine"); const res = yield createCandyMachineV2( anchorProgram, walletKeyPair, treasuryWallet, { itemsAvailable: new BN2(totalNFTs), uuid: null, symbol: firstAssetManifest.symbol, sellerFeeBasisPoints: firstAssetManifest.seller_fee_basis_points, isMutable: mutable, maxSupply: new BN2(0), retainAuthority, gatekeeper, goLiveDate, price, endSettings, whitelistMintSettings, hiddenSettings, creators: firstAssetManifest.properties.creators.map((creator) => ({ address: new PublicKey5(creator.address), verified: true, share: creator.share })) } ); console.log("res", res); cacheContent.program.uuid = res.uuid; cacheContent.program.candyMachine = res.candyMachine.toBase58(); cacheContent.startDate = goLiveDate; candyMachine = res.candyMachine; console.info(`initialized config for a candy machine with publickey: ${res.candyMachine.toBase58()}`); } catch (exx) { console.error("Error deploying config to Solana network.", exx); throw exx; } } else { console.info( `config for a candy machine with publickey: ${cacheContent == null ? void 0 : cacheContent.program.candyMachine} has been already initialized` ); } const uploadedItems = Object.values(cacheContent.items).filter((f) => !!f.link).length; console.info(`[${uploadedItems}] out of [${totalNFTs}] items have been uploaded`); if (dedupedAssetKeys.length) { console.info(`Starting upload for [${dedupedAssetKeys.length}] items, format ${JSON.stringify(dedupedAssetKeys[0])}`); } if (dedupedAssetKeys.length) { yield PromisePool.withConcurrency(batchSize || 1).for(dedupedAssetKeys).handleError((err, asset) => __async(this, null, function* () { console.error(` Error uploading ${JSON.stringify(asset)} asset (skipping)`, err.message); yield sleep(5e3); })).process((asset) => __async(this, null, function* () { console.log("processing asset: ", asset); const jsonFile = files.find((file) => getFileName(file.name) === asset.index && file.type === JSON_EXTENSION); const imageFile = files.find((file) => getFileName(file.name) === asset.index && file.type.startsWith("image/")); if (!jsonFile) { throw new Error(`JSON file ${asset.index}.json is missing`); } const manifest = getAssetManifest(asset.index, JSON.parse(yield jsonFile == null ? void 0 : jsonFile.text())); const manifestBuffer = Buffer.from(JSON.stringify(manifest)); if (!imageFile) throw new Error(`Image file ${asset.index} is missing`); let link, imageLink, animationLink; try { switch (storage) { case "arweave" /* Arweave */: default: ; [link, imageLink] = yield arweaveUpload( walletKeyPair, anchorProgram, env, imageFile, manifestBuffer, manifest, Number(asset.index) ); if (link && imageLink) { cacheContent.items[asset.index] = { link, imageLink, name: manifest.name, onChain: false }; } } } catch (err) { saveCache(cacheName, env, cacheContent); console.error(err); } })); } let uploadSuccessful = true; try { if (!hiddenSettings && candyMachine) { uploadSuccessful = yield writeIndices({ anchorProgram, cacheContent, cacheName, env, candyMachine, walletKeyPair, rateLimit }); console.log("cache content: ", cacheContent); const uploadedItems2 = Object.values(cacheContent.items).filter((f) => !!f.link).length; console.log("uploadedItems: ", uploadedItems2); console.log("totalNFTs: ", totalNFTs); console.log("uploadSuccessful: ", uploadSuccessful); uploadSuccessful = uploadSuccessful && uploadedItems2 == totalNFTs; } else { console.log("Skipping upload to chain as this is a hidden Candy Machine"); } console.log(`Done. Successful = ${uploadSuccessful}.`); return cacheContent.program.candyMachine; } catch (err) { console.error(err); return false; } }); } function getAssetKeysNeedingUpload(items, files) { const all = [.../* @__PURE__ */ new Set([...Object.keys(items), ...files])]; const keyMap = {}; const assets = all.filter((k) => !k.includes(".json")).reduce((acc, assetKey) => { var _a; const key = getFileName(assetKey); const ext = getFileExtension(assetKey); if (!((_a = items[key]) == null ? void 0 : _a.link) && !keyMap[key]) { keyMap[key] = true; acc.push({ mediaExt: ext, index: key }); } return acc; }, []).sort((a, b) => Number.parseInt(a.index, 10) - Number.parseInt(b.index, 10)); console.log(assets); return assets; } function getAssetManifest(assetIndex, manifest) { manifest.image = manifest.image.replace("image", assetIndex); if ("animation_url" in manifest) { manifest.animation_url = manifest.animation_url.replace("animation_url", assetIndex); } return manifest; } function writeIndices(_0) { return __async(this, arguments, function* ({ anchorProgram, cacheContent, cacheName, env, candyMachine, walletKeyPair, rateLimit }) { let uploadSuccessful = true; const keys = Object.keys(cacheContent.items); const poolArray = []; const allIndicesInSlice = Array.from(Array(keys.length).keys()); let offset = 0; while (offset < allIndicesInSlice.length) { let length = 0; let lineSize = 0; let configLines = allIndicesInSlice.slice(offset, offset + 16); while (length < 850 && lineSize < 16 && configLines[lineSize] !== void 0) { length += cacheContent.items[keys[configLines[lineSize]]].link.length + cacheContent.items[keys[configLines[lineSize]]].name.length; if (length < 850) lineSize++; } configLines = allIndicesInSlice.slice(offset, offset + lineSize); offset += lineSize; const onChain = configLines.filter((i) => { var _a; return ((_a = cacheContent.items[keys[i]]) == null ? void 0 : _a.onChain) || false; }); const index = keys[configLines[0]]; if (onChain.length != configLines.length) { poolArray.push({ index, configLines }); } } console.info(`Writing all indices in ${poolArray.length} transactions...`); const addConfigLines = (_02) => __async(this, [_02], function* ({ index, configLines }) { const response = yield anchorProgram.methods.addConfigLines( index, configLines.map((i) => ({ uri: cacheContent.items[keys[i]].link, name: cacheContent.items[keys[i]].name })) ).accounts({ candyMachine, authority: walletKeyPair.publicKey }).signers([]).rpc(); console.log(response); configLines.forEach((i) => { cacheContent.items[keys[i]] = __spreadProps(__spreadValues({}, cacheContent.items[keys[i]]), { onChain: true, verifyRun: false }); }); }); yield PromisePool.withConcurrency(rateLimit || 5).for(poolArray).handleError((_02, _1) => __async(this, [_02, _1], function* (err, { index, configLines }) { console.error(` Failed writing indices ${index}-${keys[configLines[configLines.length - 1]]}: ${err.message}`); yield sleep(5e3); uploadSuccessful = false; })).process((_02) => __async(this, [_02], function* ({ index, configLines }) { yield addConfigLines({ index, configLines }); })); saveCache(cacheName, env, cacheContent); return uploadSuccessful; }); } // src/mint/mint.ts import { web3 as web35 } from "@project-serum/anchor"; import { SYSVAR_SLOT_HASHES_PUBKEY, SystemProgram as SystemProgram2 } from "@solana/web3.js"; import { createInitializeMintInstruction, createMintToInstruction, createAssociatedTokenAccountInstruction, MintLayout } from "@solana/spl-token"; var getCollectionPDA = (candyMachineAddress) => __async(void 0, null, function* () { return yield web35.PublicKey.findProgramAddress( [Buffer.from("collection"), candyMachineAddress.toBuffer()], CANDY_MACHINE_PROGRAM_V2_ID ); }); var getCollectionAuthorityRecordPDA = (mint, newAuthority) => __async(void 0, null, function* () { return (yield web35.PublicKey.findProgramAddress( [ Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer(), Buffer.from("collection_authority"), newAuthority.toBuffer() ], TOKEN_METADATA_PROGRAM_ID ))[0]; }); var createAccountsForMint = (candyMachine, payer) => __async(void 0, null, function* () { const mint = web35.Keypair.generate(); const userTokenAccountAddress = (yield getAtaForMint(mint.publicKey, payer))[0]; const signers = [mint]; if (!candyMachine) return; const instructions = [ web35.SystemProgram.createAccount({ fromPubkey: payer, newAccountPubkey: mint.publicKey, space: MintLayout.span, lamports: yield candyMachine.program.provider.connection.getMinimumBalanceForRentExemption(MintLayout.span), programId: TOKEN_PROGRAM_ID }), createInitializeMintInstruction(mint.publicKey, 0, payer, payer, TOKEN_PROGRAM_ID), createAssociatedTokenAccountInstruction(payer, userTokenAccountAddress, payer, mint.publicKey), createMintToInstruction(mint.publicKey, userTokenAccountAddress, payer, 1, [], TOKEN_PROGRAM_ID) ]; const sendTx = yield sendTransactions( candyMachine.program.provider.connection, candyMachine.program.provider.wallet, [instructions], [signers], 2 /* StopOnFailure */, "singleGossip", () => { }, () => false, void 0, [], [] ); console.log(sendTx); const txid = sendTx.txs[0].txid; return { mint, userTokenAccount: userTokenAccountAddress, transaction: txid }; }); var mintOneNft = (_0, _1, ..._2) => __async(void 0, [_0, _1, ..._2], function* (candyMachine, payer, beforeTransactions = [], afterTransactions = [], setupState) { var _a; const mint = (_a = setupState == null ? void 0 : setupState.mint) != null ? _a : web35.Keypair.generate(); const userTokenAccountAddress = (yield getAtaForMint(mint.publicKey, payer))[0]; if (!candyMachine) return null; const userPayingAccountAddress = candyMachine.state.tokenMint ? (yield getAtaForMint(candyMachine.state.tokenMint, payer))[0] : payer; const candyMachineAddress = candyMachine.id; const remainingAccounts = []; const instructions = []; const signers = []; if (!setupState) { signers.push(mint); instructions.push( ...[ web35.SystemProgram.createAccount({ fromPubkey: payer, newAccountPubkey: mint.publicKey, space: MintLayout.span, lamports: yield candyMachine.program.provider.connection.getMinimumBalanceForRentExemption(MintLayout.span), programId: TOKEN_PROGRAM_ID }), createInitializeMintInstruction(mint.publicKey, 0, payer, payer, TOKEN_PROGRAM_ID), createAssociatedTokenAccountInstruction(payer, userTokenAccountAddress, payer, mint.publicKey), createMintToInstruction(mint.publicKey, userTokenAccountAddress, payer, 1, [], TOKEN_PROGRAM_ID) ] ); } if (candyMachine.state.whitelistMintSettings) { const mint2 = new web35.PublicKey(candyMachine.state.whitelistMintSettings.mint); const whitelistToken = (yield getAtaForMint(mint2, payer))[0]; remainingAccounts.push({ pubkey: whitelistToken, isWritable: true, isSigner: false }); if (candyMachine.state.whitelistMintSettings.mode.burnEveryTime) { remainingAccounts.push({ pubkey: mint2, isWritable: true, isSigner: false }); remainingAccounts.push({ pubkey: payer, isWritable: false, isSigner: true }); } } if (candyMachine.state.tokenMint) { remainingAccounts.push({ pubkey: userPayingAccountAddress, isWritable: true, isSigner: false }); remainingAccounts.push({ pubkey: payer, isWritable: false, isSigner: true }); } const metadataAddress = yield getMetadata(mint.publicKey); const masterEdition = yield getMasterEdition(mint.publicKey); const [candyMachineCreator, creatorBump] = yield getCandyMachineCreator(candyMachineAddress); instructions.push( yield candyMachine.program.instruction.mintNft(creatorBump, { accounts: { candyMachine: candyMachineAddress, candyMachineCreator, payer, wallet: candyMachine.state.treasury, mint: mint.publicKey, metadata: metadataAddress, masterEdition, mintAuthority: payer, updateAuthority: payer, tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID, tokenProgram: TOKEN_PROGRAM_ID, systemProgram: SystemProgram2.programId, rent: web35.SYSVAR_RENT_PUBKEY, clock: web35.SYSVAR_CLOCK_PUBKEY, recentBlockhashes: SYSVAR_SLOT_HASHES_PUBKEY, instructionSysvarAccount: web35.SYSVAR_INSTRUCTIONS_PUBKEY }, remainingAccounts: remainingAccounts.length > 0 ? remainingAccounts : void 0 }) ); const [collectionPDA] = yield getCollectionPDA(candyMachineAddress); const collectionPDAAccount = yield candyMachine.program.provider.connection.getAccountInfo(collectionPDA); if (collectionPDAAccount && candyMachine.state.retainAuthority) { try { const collectionData = yield candyMachine.program.account.collectionPda.fetch(collectionPDA); const collectionMint = collectionData.mint; const collectionAuthorityRecord = yield getCollectionAuthorityRecordPDA(collectionMint, collectionPDA); if (collectionMint) { const collectionMetadata = yield getMetadata(collectionMint); const collectionMasterEdition = yield getMasterEdition(collectionMint); instructions.push( yield candyMachine.program.instruction.setCollectionDuringMint({ accounts: { candyMachine: candyMachineAddress, metadata: metadataAddress, payer, collectionPda: collectionPDA, tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID, instructions: web35.SYSVAR_INSTRUCTIONS_PUBKEY, collectionMint, collectionMetadata, collectionMasterEdition, authority: candyMachine.state.authority, collectionAuthorityRecord } }) ); } } catch (error) { console.error(error); } } try { const txns = (yield sendTransactions( candyMachine.program.provider.connection, candyMachine.program.provider.wallet, [instructions], [signers], 2 /* StopOnFailure */, "singleGossip", () => { }, () => false, void 0, beforeTransactions, afterTransactions )).txs.map((t) => t.txid); const mintTxn = txns[0]; return { mintTxId: mintTxn, metadataKey: metadataAddress }; } catch (e) { console.log(e); } return null; }); export { A, ARWEAVE_PAYMENT_WALLET, ARWEAVE_UPLOAD_ENDPOINT, AUCTION_HOUSE, AUCTION_HOUSE_PROGRAM_ID, B, CACHE_PATH, CANDY_MACHINE, CANDY_MACHINE_PROGRAM_ID, CANDY_MACHINE_PROGRAM_V2_ID, CONFIG_ARRAY_START, CONFIG_ARRAY_START_V2, CONFIG_LINE_SIZE, CONFIG_LINE_SIZE_V2, DEFAULT_GATEKEEPER, DEFAULT_TIMEOUT, ESCROW, FAIR_LAUNCH_PROGRAM_ID, FEE_PAYER, JSON_EXTENSION, MAX_CREATOR_LEN, MAX_CREATOR_LIMIT, MAX_NAME_LENGTH, MAX_SYMBOL_LENGTH, MAX_URI_LENGTH, NOTIFICATION_TIMEOUT_DEFAULT, NOTIFICATION_TIMEOUT_NEVER, SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, SUPPORTED_ANIMATION_TYPES, SUPPORTED_IMAGE_TYPES, SequenceType, StorageType, TOKEN_ENTANGLEMENT_PROGRAM_ID, TOKEN_ENTANGLER, TOKEN_METADATA_PROGRAM_ID, TOKEN_PROGRAM_ID, TREASURY, WRAPPED_SOL_MINT, arweaveUpload, awaitTransactionSignatureConfirmation, createAccountsForMint, createCandyMachineV2, createCandyMachineV2Account, getAssetManifest, getAtaForMint, getCandyMachineCreator, getCandyMachineV2Config, getCollectionPDA, getFileExtension, getFileName, getMasterEdition, getMetadata, getUnixTs, loadCandyProgramV2, mintOneNft, parseDate, saveCache, sendSignedTransaction, sendTransactionWithRetryWithKeypair, sendTransactions, sleep, updateV2, uploadV2, uuidFromConfigPubkey, verifyAssets }; //# sourceMappingURL=index.mjs.map