/** * Mint NFT to Token Bound Account (TBA) Script * * This script mints an NFT directly to a Token Bound Account (ERC-6551 account) * for token ID 1 with a specified salt * * Usage: * 1. Create a .env file and set the following environment variables: * - PRIVATE_KEY: Private key of the NFT holder * * 2. Run the script: * npm run mint-to-tba * or * yarn mint-to-tba */ import { GoTakeSDK, NetworkId, getNetworkById, getNetworkByName } from "../src"; import { getContractAddress } from 'gotake-contracts'; import * as dotenv from 'dotenv'; import { ethers } from 'ethers'; dotenv.config(); // NFT metadata configuration - Customize your NFT here const nftMetadata = { title: "My TBA NFT", // NFT title description: "NFT minted to TBA", // NFT description thumbnailUrl: "", // Thumbnail URL (optional) creator: "", // Will be set to signer's address totalSeasons: 1, // Total seasons totalEpisodes: 1, // Total episodes genres: ["Action", "Drama"], // Genre tags posterUri: "" // Poster URI }; // TBA configuration const tbaConfig = { tokenId: 1, // Target token ID is 1 salt: "0x0000000000000000000000000000000000000000000000000000000000000001" // Custom salt }; async function main() { // Check required environment variables if (!process.env.PRIVATE_KEY) { throw new Error("PRIVATE_KEY is not defined in environment variables. Please set it in your .env file"); } try { // Environment configuration - support network selection const NETWORK = process.env.NETWORK || 'Base Sepolia'; // Resolve network configuration let networkConfig; if (typeof NETWORK === 'string' && !isNaN(Number(NETWORK))) { // Network ID provided const networkId = Number(NETWORK) as NetworkId; networkConfig = getNetworkById(networkId); } else { // Network name provided networkConfig = getNetworkByName(NETWORK); } if (!networkConfig) { throw new Error(`Unsupported network: ${NETWORK}. Supported networks: Base Mainnet, Base Sepolia, Base Goerli, Ethereum Mainnet, Ethereum Sepolia`); } console.log(`Using network: ${networkConfig.name} (ID: ${networkConfig.id})`); // Create Provider and Signer const ethersProvider = new ethers.providers.JsonRpcProvider(networkConfig.rpcUrl); const ethersSigner = new ethers.Wallet(process.env.PRIVATE_KEY, ethersProvider); const signerAddress = await ethersSigner.getAddress(); console.log(`Using address: ${signerAddress}`); // Set creator to signer's address nftMetadata.creator = signerAddress; // Initialize SDK const sdk = new GoTakeSDK({ network: networkConfig.id, provider: ethersProvider, signer: ethersSigner, }); console.log("SDK initialized successfully"); // Get contract addresses from config const networkName = networkConfig.id === 8453 ? 'base' : 'base_sepolia'; const tokenContract = getContractAddress(networkName, 'contentNFT'); const implementation = getContractAddress(networkName, 'accountImplementation'); if (!tokenContract) { throw new Error(`ContentNFT contract address not found for ${networkName} network`); } if (!implementation) { throw new Error(`Account implementation address not found for ${networkName} network`); } console.log(`NFT contract address: ${tokenContract}`); console.log(`Account implementation address: ${implementation}`); console.log(`Target Token ID for TBA: ${tbaConfig.tokenId}`); console.log(`Using salt: ${tbaConfig.salt}`); // Get current gas price recommendations console.log("Getting current gas price recommendations..."); const gasPrices = await sdk.getGasPrice({ multiplier: 1.2, priorityMultiplier: 1.5 }); console.log("Current gas prices:"); if (gasPrices.baseFeePerGas) { console.log(`Base fee: ${ethers.utils.formatUnits(gasPrices.baseFeePerGas, "gwei")} gwei`); } console.log(`Max fee per gas: ${ethers.utils.formatUnits(gasPrices.maxFeePerGas, "gwei")} gwei`); if (gasPrices.maxPriorityFeePerGas) { console.log(`Max priority fee: ${ethers.utils.formatUnits(gasPrices.maxPriorityFeePerGas, "gwei")} gwei`); } // Transaction options including gas configuration const transactionOptions = { gasConfig: { maxFeePerGas: gasPrices.maxFeePerGas, // Use recommended values maxPriorityFeePerGas: gasPrices.maxPriorityFeePerGas // Use recommended values // Let system auto-estimate gas limit } }; console.log("Using transaction options with recommended gas values (auto gas limit)"); // Calculate TBA address console.log("Calculating TBA address..."); const tbaAddress = await sdk.account.computeTBAAddress({ tokenContract, tokenId: tbaConfig.tokenId, salt: tbaConfig.salt }); console.log(`Calculated TBA address: ${tbaAddress}`); // Check if TBA exists const code = await ethersProvider.getCode(tbaAddress); const tbaExists = code !== '0x'; // If TBA doesn't exist, create it if (!tbaExists) { console.log("TBA does not exist, creating..."); const businessParams = { tokenContract: tokenContract, tokenId: tbaConfig.tokenId, salt: tbaConfig.salt }; const createResult = await sdk.account.createTBA(businessParams, transactionOptions); console.log(`TBA creation successful: ${createResult.tbaAddress}`); console.log(`Transaction hash: ${createResult.tx.hash}`); console.log("Waiting for transaction confirmation..."); await ethersProvider.waitForTransaction(createResult.tx.hash); console.log("TBA creation confirmed"); } else { console.log(`TBA already exists: ${tbaAddress}`); } // Mint NFT to TBA address console.log(`Minting NFT to TBA address: ${tbaAddress}...`); const mintResult = await sdk.contentNFT.mint( tbaAddress, nftMetadata, transactionOptions ); console.log(`NFT mint transaction submitted, hash: ${mintResult.tx.hash}`); // Wait for transaction confirmation console.log("Waiting for transaction confirmation..."); await ethersProvider.waitForTransaction(mintResult.tx.hash); console.log(`NFT mint successful! Token ID: ${mintResult.tokenId.toString()}`); // Get NFT details console.log("Fetching NFT details..."); const nftDetails = await sdk.contentNFT.getContentNFTDetails(mintResult.tokenId); console.log("NFT Details:"); console.log(`Token ID: ${nftDetails.tokenId.toString()}`); console.log(`Owner: ${nftDetails.owner}`); console.log(`Series Title: ${nftDetails.seriesTitle}`); console.log(`Description: ${nftDetails.description}`); console.log(`URI: ${nftDetails.uri}`); console.log(`Total Seasons: ${nftDetails.totalSeasons.toString()}`); console.log(`Total Episodes: ${nftDetails.totalEpisodes.toString()}`); console.log(`Genres: ${nftDetails.genres.join(', ')}`); console.log(`Creators: ${nftDetails.creators.join(', ')}`); console.log(`Poster URI: ${nftDetails.posterUri}`); console.log(`Created At: ${new Date(nftDetails.createdAt.toNumber() * 1000).toISOString()}`); console.log("Operation completed successfully!"); } catch (error) { console.error("Error minting NFT to TBA:"); console.error(error); process.exitCode = 1; } } main().catch(error => { console.error("Error executing script:"); console.error(error); process.exitCode = 1; });