diff --git a/packages/cli/src/CliSetup.ts b/packages/cli/src/CliSetup.ts index a738169..77a41e2 100644 --- a/packages/cli/src/CliSetup.ts +++ b/packages/cli/src/CliSetup.ts @@ -48,7 +48,7 @@ function resolveBuildToolsPath(buildToolsPath: string | undefined) { function latestReleaseMessage() { showMessage( `Publishing Tools Version ${ Constants.CLI_VERSION }`, - "- priority fee has been updated to handle network congestion\n- short_description value reduced to 30 character limit", + `- priority fee has been updated to ${Constants.DEFAULT_PRIORITY_FEE} lamports = ${Constants.DEFAULT_PRIORITY_FEE/1000000000} SOL. To adjust this value use param "-p or --priority-fee-lamports"`, "warning" ); } @@ -94,14 +94,15 @@ export const createPublisherCliCmd = createCliCmd .option("-u, --url ", "RPC URL", Constants.DEFAULT_RPC_DEVNET) .option("-d, --dry-run", "Flag for dry run. Doesn't mint an NFT") .option("-s, --storage-config ", "Provide alternative storage configuration details") - .action(async ({ keypair, url, dryRun, storageConfig }) => { + .option("-p, --priority-fee-lamports ", "Priority Fee lamports") + .action(async ({ keypair, url, dryRun, storageConfig, priorityFeeLamports }) => { await tryWithErrorMessage(async () => { latestReleaseMessage(); await checkForSelfUpdate(); const signer = parseKeypair(keypair); if (signer) { - const result: { publisherAddress: string } = await createPublisherCommand({ signer, url, dryRun, storageParams: storageConfig }); + const result: { publisherAddress: string } = await createPublisherCommand({ signer, url, dryRun, storageParams: storageConfig, priorityFeeLamports }); const displayUrl = `https://solscan.io/token/${result.publisherAddress}${generateNetworkSuffix(url)}`; const resultText = `Publisher NFT successfully minted:\n${displayUrl}`; @@ -125,7 +126,8 @@ export const createAppCliCmd = createCliCmd .option("-u, --url ", "RPC URL", Constants.DEFAULT_RPC_DEVNET) .option("-d, --dry-run", "Flag for dry run. Doesn't mint an NFT") .option("-s, --storage-config ", "Provide alternative storage configuration details") - .action(async ({ publisherMintAddress, keypair, url, dryRun, storageConfig }) => { + .option("-p, --priority-fee-lamports ", "Priority Fee lamports") + .action(async ({ publisherMintAddress, keypair, url, dryRun, storageConfig, priorityFeeLamports }) => { await tryWithErrorMessage(async () => { latestReleaseMessage(); await checkForSelfUpdate(); @@ -143,7 +145,8 @@ export const createAppCliCmd = createCliCmd signer, url, dryRun, - storageParams: storageConfig + storageParams: storageConfig, + priorityFeeLamports: priorityFeeLamports, }); const displayUrl = `https://solscan.io/token/${result.appAddress}${generateNetworkSuffix(url)}`; @@ -172,7 +175,8 @@ export const createReleaseCliCmd = createCliCmd "Path to Android build tools which contains AAPT2" ) .option("-s, --storage-config ", "Provide alternative storage configuration details") - .action(async ({ appMintAddress, keypair, url, dryRun, buildToolsPath, storageConfig }) => { + .option("-p, --priority-fee-lamports ", "Priority Fee lamports") + .action(async ({ appMintAddress, keypair, url, dryRun, buildToolsPath, storageConfig, priorityFeeLamports }) => { await tryWithErrorMessage(async () => { latestReleaseMessage(); await checkForSelfUpdate(); @@ -196,6 +200,7 @@ export const createReleaseCliCmd = createCliCmd url, dryRun, storageParams: storageConfig, + priorityFeeLamports: priorityFeeLamports }); const displayUrl = `https://solscan.io/token/${result?.releaseAddress}${generateNetworkSuffix(url)}`; diff --git a/packages/cli/src/CliUtils.ts b/packages/cli/src/CliUtils.ts index fc65700..f5de769 100644 --- a/packages/cli/src/CliUtils.ts +++ b/packages/cli/src/CliUtils.ts @@ -21,6 +21,7 @@ export class Constants { static CLI_VERSION = "0.7.3"; static CONFIG_FILE_NAME = "config.yaml"; static DEFAULT_RPC_DEVNET = "https://api.devnet.solana.com"; + static DEFAULT_PRIORITY_FEE = 500000; static getConfigFilePath = () => { return `${process.cwd()}/${Constants.CONFIG_FILE_NAME}`; diff --git a/packages/cli/src/__tests__/CliSetupTest.ts b/packages/cli/src/__tests__/CliSetupTest.ts index 80e62f1..99919ff 100644 --- a/packages/cli/src/__tests__/CliSetupTest.ts +++ b/packages/cli/src/__tests__/CliSetupTest.ts @@ -175,11 +175,12 @@ Commands: Create a publisher Options: - -k, --keypair Path to keypair file - -u, --url RPC URL (default: "https://api.devnet.solana.com") - -d, --dry-run Flag for dry run. Doesn't mint an NFT - -s, --storage-config Provide alternative storage configuration details - -h, --help display help for command + -k, --keypair Path to keypair file + -u, --url RPC URL (default: "https://api.devnet.solana.com") + -d, --dry-run Flag for dry run. Doesn't mint an NFT + -s, --storage-config Provide alternative storage configuration details + -p, --priority-fee-lamports Priority Fee lamports + -h, --help display help for command `; const createAppHelp = `Usage: dapp-store create app [options] @@ -192,6 +193,7 @@ Options: -u, --url RPC URL (default: "https://api.devnet.solana.com") -d, --dry-run Flag for dry run. Doesn't mint an NFT -s, --storage-config Provide alternative storage configuration details + -p, --priority-fee-lamports Priority Fee lamports -h, --help display help for command `; @@ -200,13 +202,14 @@ Options: Create a release Options: - -k, --keypair Path to keypair file - -a, --app-mint-address The mint address of the app NFT - -u, --url RPC URL (default: "https://api.devnet.solana.com") - -d, --dry-run Flag for dry run. Doesn't mint an NFT - -b, --build-tools-path Path to Android build tools which contains AAPT2 - -s, --storage-config Provide alternative storage configuration details - -h, --help display help for command + -k, --keypair Path to keypair file + -a, --app-mint-address The mint address of the app NFT + -u, --url RPC URL (default: "https://api.devnet.solana.com") + -d, --dry-run Flag for dry run. Doesn't mint an NFT + -b, --build-tools-path Path to Android build tools which contains AAPT2 + -s, --storage-config Provide alternative storage configuration details + -p, --priority-fee-lamports Priority Fee lamports + -h, --help display help for command `; }); \ No newline at end of file diff --git a/packages/cli/src/commands/create/CreateCliApp.ts b/packages/cli/src/commands/create/CreateCliApp.ts index ea92a8b..c6e6a80 100644 --- a/packages/cli/src/commands/create/CreateCliApp.ts +++ b/packages/cli/src/commands/create/CreateCliApp.ts @@ -8,6 +8,7 @@ import { } from "@solana/web3.js"; import { + Constants, getMetaplexInstance, } from "../../CliUtils.js"; import { loadPublishDetailsWithChecks, writeToPublishDetails } from "../../config/PublishDetails.js"; @@ -19,12 +20,14 @@ const createAppNft = async ( publisherMintAddress, publisher, storageParams, + priorityFeeLamports, }: { appDetails: App; connection: Connection; publisherMintAddress: string; publisher: Keypair; storageParams: string; + priorityFeeLamports: number; }, { dryRun }: { dryRun?: boolean } ) => { @@ -35,6 +38,7 @@ const createAppNft = async ( publisherMintAddress: new PublicKey(publisherMintAddress), mintAddress, appDetails, + priorityFeeLamports }, { metaplex, publisher } ); @@ -62,6 +66,7 @@ type CreateAppCommandInput = { url: string; dryRun?: boolean; storageParams: string; + priorityFeeLamports: number; }; export const createAppCommand = async ({ @@ -70,6 +75,7 @@ export const createAppCommand = async ({ dryRun, publisherMintAddress, storageParams, + priorityFeeLamports = Constants.DEFAULT_PRIORITY_FEE, }: CreateAppCommandInput) => { const connection = new Connection(url); @@ -83,6 +89,7 @@ export const createAppCommand = async ({ publisherMintAddress: publisherDetails.address ?? publisherMintAddress, appDetails, storageParams, + priorityFeeLamports }, { dryRun } ); diff --git a/packages/cli/src/commands/create/CreateCliPublisher.ts b/packages/cli/src/commands/create/CreateCliPublisher.ts index 2b5b640..e5e0c05 100644 --- a/packages/cli/src/commands/create/CreateCliPublisher.ts +++ b/packages/cli/src/commands/create/CreateCliPublisher.ts @@ -7,6 +7,7 @@ import { } from "@solana/web3.js"; import { + Constants, getMetaplexInstance, } from "../../CliUtils.js"; import { loadPublishDetailsWithChecks, writeToPublishDetails } from "../../config/PublishDetails.js"; @@ -17,11 +18,13 @@ const createPublisherNft = async ( publisher, publisherDetails, storageParams, + priorityFeeLamports, }: { connection: Connection; publisher: Keypair; publisherDetails: Publisher; storageParams: string; + priorityFeeLamports: number; }, { dryRun }: { dryRun: boolean } ) => { @@ -31,7 +34,7 @@ const createPublisherNft = async ( `Creating publisher at address: ${mintAddress.publicKey.toBase58()}` ); const txBuilder = await createPublisher( - { mintAddress, publisherDetails }, + { mintAddress, publisherDetails, priorityFeeLamports }, { metaplex, publisher } ); @@ -57,11 +60,13 @@ export const createPublisherCommand = async ({ url, dryRun, storageParams, + priorityFeeLamports = Constants.DEFAULT_PRIORITY_FEE, }: { signer: Keypair; url: string; dryRun: boolean; storageParams: string; + priorityFeeLamports: number; }) => { const connection = new Connection(url); @@ -73,6 +78,7 @@ export const createPublisherCommand = async ({ publisher: signer, publisherDetails, storageParams: storageParams, + priorityFeeLamports: priorityFeeLamports, }, { dryRun } ); diff --git a/packages/cli/src/commands/create/CreateCliRelease.ts b/packages/cli/src/commands/create/CreateCliRelease.ts index 71887ae..2707cc4 100644 --- a/packages/cli/src/commands/create/CreateCliRelease.ts +++ b/packages/cli/src/commands/create/CreateCliRelease.ts @@ -11,6 +11,7 @@ import { sendAndConfirmTransaction, } from "@solana/web3.js"; import { + Constants, getMetaplexInstance, showMessage } from "../../CliUtils.js"; @@ -23,6 +24,7 @@ type CreateReleaseCommandInput = { url: string; dryRun?: boolean; storageParams: string; + priorityFeeLamports: number; }; const createReleaseNft = async ({ @@ -33,6 +35,7 @@ const createReleaseNft = async ({ connection, publisher, storageParams, + priorityFeeLamports, }: { appMintAddress: string; releaseDetails: Release; @@ -41,6 +44,7 @@ const createReleaseNft = async ({ connection: Connection; publisher: Keypair; storageParams: string; + priorityFeeLamports: number; }) => { const releaseMintAddress = Keypair.generate(); @@ -53,6 +57,7 @@ const createReleaseNft = async ({ releaseDetails, appDetails, publisherDetails, + priorityFeeLamports }, { metaplex, publisher } ); @@ -94,6 +99,7 @@ export const createReleaseCommand = async ({ url, dryRun = false, storageParams, + priorityFeeLamports = Constants.DEFAULT_PRIORITY_FEE, }: CreateReleaseCommandInput) => { const connection = new Connection(url); @@ -110,6 +116,7 @@ export const createReleaseCommand = async ({ appDetails: app, publisherDetails: publisher, storageParams: storageParams, + priorityFeeLamports: priorityFeeLamports, }); await writeToPublishDetails({ release: { address: releaseAddress }, }); diff --git a/packages/core/src/CoreUtils.ts b/packages/core/src/CoreUtils.ts index 1e945b7..6c433d1 100644 --- a/packages/core/src/CoreUtils.ts +++ b/packages/core/src/CoreUtils.ts @@ -24,10 +24,16 @@ type JsonMetadataMetaplexFile = Omit & { export const mintNft = async ( metaplex: Metaplex, json: JsonMetadataMetaplexFile, - createNftInput: Omit + createNftInput: Omit, + priorityFeeLamports: number, ): Promise => { console.info({ json }); const { uri } = await metaplex.nfts().uploadMetadata(json); + const computeBudget = 250000 + + if (priorityFeeLamports < 0) { + throw new Error("Priority fees cannot be negative") + } const txBuilder = await metaplex .nfts() @@ -42,14 +48,16 @@ export const mintNft = async ( txBuilder.prepend({ instruction: ComputeBudgetProgram.setComputeUnitLimit({ - units: 250000, + units: computeBudget, }), signers: [], }); + const microLamportsPerCU = 1000000 * priorityFeeLamports / computeBudget + txBuilder.prepend({ instruction: ComputeBudgetProgram.setComputeUnitPrice({ - microLamports: 2000000, + microLamports: microLamportsPerCU, }), signers: [], }); diff --git a/packages/core/src/create/AppCore.ts b/packages/core/src/create/AppCore.ts index 622560d..c3780e4 100644 --- a/packages/core/src/create/AppCore.ts +++ b/packages/core/src/create/AppCore.ts @@ -38,10 +38,11 @@ type CreateAppInput = { publisherMintAddress: PublicKey; mintAddress: Signer; appDetails: App; + priorityFeeLamports: number; }; export const createApp = async ( - { publisherMintAddress, mintAddress, appDetails }: CreateAppInput, + { publisherMintAddress, mintAddress, appDetails, priorityFeeLamports }: CreateAppInput, { metaplex, publisher }: Context ) => { debug(`Minting app NFT for publisher: ${publisherMintAddress.toBase58()}`); @@ -49,14 +50,19 @@ export const createApp = async ( const appJson = createAppJson(appDetails, publisher.publicKey); validateApp(appJson); - const txBuilder = await mintNft(metaplex, appJson, { - useNewMint: mintAddress, - collection: publisherMintAddress, - collectionAuthority: publisher, - isCollection: true, - isMutable: true, - creators: [{ address: publisher.publicKey, share: 100 }], - }); + const txBuilder = await mintNft( + metaplex, + appJson, + { + useNewMint: mintAddress, + collection: publisherMintAddress, + collectionAuthority: publisher, + isCollection: true, + isMutable: true, + creators: [{ address: publisher.publicKey, share: 100 }], + }, + priorityFeeLamports + ); txBuilder.append( metaplex.nfts().builders().verifyCreator({ diff --git a/packages/core/src/create/PublisherCore.ts b/packages/core/src/create/PublisherCore.ts index 0bb8d3b..9f52647 100644 --- a/packages/core/src/create/PublisherCore.ts +++ b/packages/core/src/create/PublisherCore.ts @@ -42,10 +42,11 @@ export const createPublisherJson = ( type CreatePublisherInput = { mintAddress: Signer; publisherDetails: Publisher; + priorityFeeLamports: number; }; export const createPublisher = async ( - { mintAddress, publisherDetails }: CreatePublisherInput, + { mintAddress, publisherDetails, priorityFeeLamports }: CreatePublisherInput, { metaplex }: Context ): Promise => { debug(`Minting publisher NFT`); @@ -53,11 +54,16 @@ export const createPublisher = async ( const publisherJson = createPublisherJson(publisherDetails); validatePublisher(publisherJson); - const txBuilder = await mintNft(metaplex, publisherJson, { - isCollection: true, - isMutable: true, - useNewMint: mintAddress, - }); + const txBuilder = await mintNft( + metaplex, + publisherJson, + { + isCollection: true, + isMutable: true, + useNewMint: mintAddress, + }, + priorityFeeLamports + ); return txBuilder; }; diff --git a/packages/core/src/create/ReleaseCore.ts b/packages/core/src/create/ReleaseCore.ts index 7e6864f..6b3aff7 100644 --- a/packages/core/src/create/ReleaseCore.ts +++ b/packages/core/src/create/ReleaseCore.ts @@ -161,6 +161,7 @@ type CreateReleaseInput = { releaseDetails: Release; publisherDetails: Publisher; appDetails: App; + priorityFeeLamports: number; }; export const createRelease = async ( @@ -170,6 +171,7 @@ export const createRelease = async ( releaseDetails, appDetails, publisherDetails, + priorityFeeLamports, }: CreateReleaseInput, { publisher, metaplex }: Context ) => { @@ -183,13 +185,17 @@ export const createRelease = async ( const suppressedJson = JSON.stringify(releaseJson, metaplexFileReplacer, 2); validateRelease(JSON.parse(suppressedJson)); - const txBuilder = await mintNft(metaplex, releaseJson, { - useNewMint: releaseMintAddress, - collection: appMintAddress, - collectionAuthority: publisher, - creators: [{ address: publisher.publicKey, share: 100 }], - isMutable: false, - }); + const txBuilder = await mintNft( + metaplex, + releaseJson, { + useNewMint: releaseMintAddress, + collection: appMintAddress, + collectionAuthority: publisher, + creators: [{ address: publisher.publicKey, share: 100 }], + isMutable: false, + }, + priorityFeeLamports + ); // TODO(jon): Enable a case where the signer is not the publisher // TODO(jon): Allow this to be unverified and to verify later