@solana-mobile/dapp-store-cli 0.9.5 → 0.11.0

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.
Files changed (36) hide show
  1. package/lib/CliSetup.js +470 -569
  2. package/lib/CliUtils.js +19 -34
  3. package/lib/__tests__/CliSetupTest.js +4 -27
  4. package/lib/commands/ValidateCommand.js +16 -41
  5. package/lib/commands/create/CreateCliApp.js +19 -31
  6. package/lib/commands/create/CreateCliRelease.js +17 -27
  7. package/lib/commands/create/index.js +0 -1
  8. package/lib/commands/publish/PublishCliRemove.js +12 -20
  9. package/lib/commands/publish/PublishCliSubmit.js +12 -20
  10. package/lib/commands/publish/PublishCliSupport.js +12 -20
  11. package/lib/commands/publish/PublishCliUpdate.js +12 -20
  12. package/lib/commands/scaffolding/ScaffoldInit.js +1 -1
  13. package/lib/commands/utils.js +6 -14
  14. package/lib/config/PublishDetails.js +219 -220
  15. package/lib/generated/config_obj.json +1 -1
  16. package/lib/generated/config_schema.json +1 -1
  17. package/lib/index.js +6 -14
  18. package/lib/package.json +2 -2
  19. package/lib/prebuild_schema/publishing_source.yaml +4 -4
  20. package/lib/prebuild_schema/schemagen.js +4 -4
  21. package/lib/upload/CachedStorageDriver.js +13 -19
  22. package/package.json +2 -2
  23. package/src/CliSetup.ts +5 -53
  24. package/src/CliUtils.ts +5 -11
  25. package/src/__tests__/CliSetupTest.ts +8 -43
  26. package/src/commands/ValidateCommand.ts +0 -20
  27. package/src/commands/create/CreateCliApp.ts +1 -8
  28. package/src/commands/create/index.ts +0 -1
  29. package/src/commands/publish/PublishCliRemove.ts +1 -2
  30. package/src/commands/publish/PublishCliSubmit.ts +1 -2
  31. package/src/commands/publish/PublishCliSupport.ts +1 -2
  32. package/src/commands/publish/PublishCliUpdate.ts +1 -2
  33. package/src/config/PublishDetails.ts +58 -61
  34. package/src/prebuild_schema/publishing_source.yaml +4 -4
  35. package/lib/commands/create/CreateCliPublisher.js +0 -237
  36. package/src/commands/create/CreateCliPublisher.ts +0 -87
@@ -47,11 +47,10 @@ export const publishSupportCommand = async ({
47
47
  const sign = ((buf: Buffer) =>
48
48
  nacl.sign(buf, signer.secretKey)) as SignWithPublisherKeypair;
49
49
 
50
- const pubAddr = publisherDetails.address;
51
50
  const appAddr = appMintAddress ?? appDetails.address;
52
51
  const releaseAddr = releaseMintAddress ?? releaseDetails.address;
53
52
 
54
- await checkMintedStatus(connection, pubAddr, appAddr, releaseAddr);
53
+ await checkMintedStatus(connection, appAddr, releaseAddr);
55
54
 
56
55
  await publishSupport(
57
56
  { connection, sign },
@@ -69,7 +69,6 @@ export const publishUpdateCommand = async ({
69
69
  const sign = ((buf: Buffer) =>
70
70
  nacl.sign(buf, signer.secretKey)) as SignWithPublisherKeypair;
71
71
 
72
- const pubAddr = publisherDetails.address;
73
72
  const appAddr = appMintAddress ?? appDetails.address;
74
73
  const releaseAddr = releaseMintAddress ?? releaseDetails.address;
75
74
 
@@ -77,7 +76,7 @@ export const publishUpdateCommand = async ({
77
76
  throw new Error(`You've already submitted this version for review.`);
78
77
  }
79
78
 
80
- await checkMintedStatus(connection, pubAddr, appAddr, releaseAddr);
79
+ await checkMintedStatus(connection, appAddr, releaseAddr);
81
80
 
82
81
  await publishUpdate(
83
82
  { connection, sign },
@@ -90,18 +90,6 @@ export const loadPublishDetailsWithChecks = async (
90
90
  );
91
91
  }
92
92
 
93
- const publisherIcon = config.publisher.media?.find(
94
- (asset: any) => asset.purpose === "icon"
95
- )?.uri;
96
-
97
- if (publisherIcon) {
98
- const iconPath = path.join(process.cwd(), publisherIcon);
99
- await checkIconCompatibility(iconPath, "Publisher");
100
-
101
- const iconBuffer = await fs.promises.readFile(iconPath);
102
- config.publisher.icon = toMetaplexFile(iconBuffer, publisherIcon);
103
- }
104
-
105
93
  const appIcon = config.app.media?.find(
106
94
  (asset: any) => asset.purpose === "icon"
107
95
  )?.uri;
@@ -127,6 +115,26 @@ export const loadPublishDetailsWithChecks = async (
127
115
  throw new Error("Please specify at least one media entry of type icon in your configuration file");
128
116
  }
129
117
 
118
+ const banner = config.release.media?.find(
119
+ (asset: any) => asset.purpose === "banner"
120
+ )?.uri;
121
+
122
+ if (banner) {
123
+ const bannerPath = path.join(process.cwd(), banner);
124
+ await checkBannerCompatibility(bannerPath);
125
+ } else {
126
+ throw new Error("Please specify banner image of size 1200x600 in your configuration file");
127
+ }
128
+
129
+ const featureGraphic = config.release.media?.find(
130
+ (asset: any) => asset.purpose === "featureGraphic"
131
+ )?.uri;
132
+
133
+ if (featureGraphic) {
134
+ const featureGraphicPath = path.join(process.cwd(), featureGraphic);
135
+ await checkFeatureGraphicCompatibility(featureGraphicPath);
136
+ }
137
+
130
138
  config.release.media.forEach((item: PublishDetails["release"]["media"][0]) => {
131
139
  const mediaPath = path.join(process.cwd(), item.uri);
132
140
  if (!fs.existsSync(mediaPath)) {
@@ -149,7 +157,7 @@ export const loadPublishDetailsWithChecks = async (
149
157
 
150
158
  for (const item of screenshots) {
151
159
  const mediaPath = path.join(process.cwd(), item.uri);
152
- if (await checkScreenshotSize(mediaPath)) {
160
+ if (await checkScreenshotDimensions(mediaPath)) {
153
161
  throw new Error(`Screenshot ${mediaPath} must be at least 1080px in width and height.`);
154
162
  }
155
163
  }
@@ -160,7 +168,7 @@ export const loadPublishDetailsWithChecks = async (
160
168
 
161
169
  for (const video of videos) {
162
170
  const mediaPath = path.join(process.cwd(), video.uri);
163
- if (await checkVideoSize(mediaPath)) {
171
+ if (await checkVideoDimensions(mediaPath)) {
164
172
  throw new Error(`Video ${mediaPath} must be at least 720px in width and height.`);
165
173
  }
166
174
  }
@@ -208,6 +216,26 @@ const checkIconCompatibility = async (path: string, typeString: string) => {
208
216
  }
209
217
  };
210
218
 
219
+ const checkBannerCompatibility = async (path: string) => {
220
+ if (!fs.existsSync(path) || !checkImageExtension(path)) {
221
+ throw new Error(`Please check the path to your banner image and ensure the file is a jpeg, png, or webp file.`);
222
+ }
223
+
224
+ if (await checkBannerDimensions(path)) {
225
+ throw new Error("Banner must be 1200px by 600px.");
226
+ }
227
+ };
228
+
229
+ const checkFeatureGraphicCompatibility = async (path: string) => {
230
+ if (!fs.existsSync(path) || !checkImageExtension(path)) {
231
+ throw new Error(`Please check the path to your featureGraphic image and ensure the file is a jpeg, png, or webp file.`);
232
+ }
233
+
234
+ if (await checkFeatureGraphicDimensions(path)) {
235
+ throw new Error("Feature Graphic must be 1200px by 1200px.");
236
+ }
237
+ };
238
+
211
239
  const checkImageExtension = (uri: string): boolean => {
212
240
  const fileExt = path.extname(uri).toLowerCase();
213
241
  return (
@@ -257,13 +285,25 @@ const checkIconDimensions = async (iconPath: string): Promise<boolean> => {
257
285
  return size?.width != size?.height || (size?.width ?? 0) != 512;
258
286
  };
259
287
 
260
- const checkScreenshotSize = async (imagePath: string): Promise<boolean> => {
288
+ const checkScreenshotDimensions = async (imagePath: string): Promise<boolean> => {
261
289
  const size = await runImgSize(imagePath);
262
290
 
263
291
  return (size?.width ?? 0) < 1080 || (size?.height ?? 0) < 1080;
264
292
  }
265
293
 
266
- const checkVideoSize = async (imagePath: string): Promise<boolean> => {
294
+ const checkBannerDimensions = async (imagePath: string): Promise<boolean> => {
295
+ const size = await runImgSize(imagePath);
296
+
297
+ return (size?.width ?? 0) != 1200 || (size?.height ?? 0) != 600;
298
+ }
299
+
300
+ const checkFeatureGraphicDimensions = async (imagePath: string): Promise<boolean> => {
301
+ const size = await runImgSize(imagePath);
302
+
303
+ return (size?.width ?? 0) != 1200 || (size?.height ?? 0) != 1200;
304
+ }
305
+
306
+ const checkVideoDimensions = async (imagePath: string): Promise<boolean> => {
267
307
  const size = await getVideoDimensions(imagePath);
268
308
 
269
309
  return (size?.width ?? 0) < 720 || (size?.height ?? 0) < 720;
@@ -323,7 +363,7 @@ const getAndroidDetails = async (
323
363
  );
324
364
  }
325
365
 
326
- if (permissions.includes("com.solanamobile.seedvault.ACCESS_SEED_VAULT")) {
366
+ if (permissions.includes("com.solanamobile.seedvault.ACCESS_SEED_VAULT") || permissions.includes("com.solanamobile.seedvault.ACCESS_SEED_VAULT_PRIVILEGED")) {
327
367
  showMessage(
328
368
  "App requests Seed Vault permission",
329
369
  "If this is not a wallet application, your app maybe rejected from listing on Solana dApp Store.",
@@ -331,19 +371,6 @@ const getAndroidDetails = async (
331
371
  );
332
372
  }
333
373
 
334
- if (localeArray.length >= 60) {
335
- showMessage(
336
- "The bundle apk claims supports for following locales",
337
- "Claim for supported locales::\n" +
338
- localeArray +
339
- "\nIf this release does not support all these locales the release may be rejected" +
340
- "\nSee details at https://developer.android.com/guide/topics/resources/multilingual-support#design for configuring the supported locales",
341
- "warning"
342
- );
343
- }
344
-
345
- checkAbis(apkPath);
346
-
347
374
  return {
348
375
  android_package: appPackage?.[1] ?? "",
349
376
  min_sdk: parseInt(minSdk?.[1] ?? "0", 10),
@@ -362,35 +389,6 @@ const getAndroidDetails = async (
362
389
  }
363
390
  };
364
391
 
365
- const checkAbis = async (apkPath: string) => {
366
- try {
367
- const { stdout } = await runExec(`zipinfo -s ${apkPath} | grep \.so$`);
368
- const amV7libs = [...stdout.matchAll(/lib\/armeabi-v7a\/(.*)/g)].flatMap(permission => permission[1]);
369
- const x86libs = [...stdout.matchAll(/lib\/x86\/(.*)/g)].flatMap(permission => permission[1]);
370
- const x8664libs = [...stdout.matchAll(/lib\/x86_64\/(.*)/g)].flatMap(permission => permission[1]);
371
- if (amV7libs.length > 0 || x86libs.length > 0 || x8664libs.length > 0) {
372
-
373
- const messages = [
374
- `Solana dApp Store only supports arm64-v8a abi.`,
375
- `Your apk file contains following unsupported abis`,
376
- ... amV7libs.length > 0 ? [`\narmeabi-v7a:\n` + amV7libs] : [],
377
- ... x86libs.length > 0 ? [`\nx86:\n` + x86libs] : [],
378
- ... x8664libs.length > 0 ? [`\nx86_64:\n` + x8664libs] : [],
379
- `\n\nAlthough your app works fine on Saga, these library files are unused and increase the size of apk file making the download and update time longer for your app.`,
380
- `\n\nSee https://developer.android.com/games/optimize/64-bit#build-with-64-bit for how to optimize your app.`,
381
- ].join('\n')
382
-
383
- showMessage(
384
- `Unsupported files found in apk`,
385
- messages,
386
- `warning`
387
- )
388
- }
389
- } catch (e) {
390
- // Ignore this error.
391
- }
392
- }
393
-
394
392
  export const extractCertFingerprint = async (aaptDir: string, apkPath: string): Promise<string> => {
395
393
  const { stdout } = await runExec(`${aaptDir}/apksigner verify --print-certs -v "${apkPath}"`);
396
394
 
@@ -404,7 +402,7 @@ export const extractCertFingerprint = async (aaptDir: string, apkPath: string):
404
402
  }
405
403
  }
406
404
 
407
- export const writeToPublishDetails = async ({ publisher, app, release, lastSubmittedVersionOnChain, lastUpdatedVersionOnStore }: SaveToConfigArgs) => {
405
+ export const writeToPublishDetails = async ({ app, release, lastSubmittedVersionOnChain, lastUpdatedVersionOnStore }: SaveToConfigArgs) => {
408
406
  const currentConfig = await loadPublishDetailsWithChecks();
409
407
 
410
408
  delete currentConfig.publisher.icon;
@@ -413,7 +411,6 @@ export const writeToPublishDetails = async ({ publisher, app, release, lastSubmi
413
411
  const newConfig: PublishDetails = {
414
412
  publisher: {
415
413
  ...currentConfig.publisher,
416
- address: publisher?.address ?? currentConfig.publisher.address
417
414
  },
418
415
  app: {
419
416
  ...currentConfig.app,
@@ -1,11 +1,7 @@
1
1
  publisher:
2
2
  name: <<YOUR_PUBLISHER_NAME>>
3
- address: ""
4
3
  website: <<URL_OF_PUBLISHER_WEBSITE>>
5
4
  email: <<EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>
6
- media:
7
- - purpose: icon
8
- uri: <<RELATIVE_PATH_TO_PUBLISHER_ICON>>
9
5
  app:
10
6
  name: <<APP_NAME>>
11
7
  address: ""
@@ -23,6 +19,10 @@ release:
23
19
  media:
24
20
  - purpose: icon
25
21
  uri: <<RELATIVE_PATH_TO_RELEASE_ICON>>
22
+ - purpose: banner
23
+ uri: <<RELATIVE_PATH_TO_BANNER>>
24
+ - purpose: featureGraphic
25
+ uri: <<RELATIVE_PATH_TO_FEATURE_GRAPHIC>>
26
26
  - purpose: screenshot
27
27
  uri: <<RELATIVE_PATH_TO_SCREENSHOT1>>
28
28
  - purpose: screenshot
@@ -1,237 +0,0 @@
1
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
- try {
3
- var info = gen[key](arg);
4
- var value = info.value;
5
- } catch (error) {
6
- reject(error);
7
- return;
8
- }
9
- if (info.done) {
10
- resolve(value);
11
- } else {
12
- Promise.resolve(value).then(_next, _throw);
13
- }
14
- }
15
- function _async_to_generator(fn) {
16
- return function() {
17
- var self = this, args = arguments;
18
- return new Promise(function(resolve, reject) {
19
- var gen = fn.apply(self, args);
20
- function _next(value) {
21
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
22
- }
23
- function _throw(err) {
24
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
25
- }
26
- _next(undefined);
27
- });
28
- };
29
- }
30
- function _ts_generator(thisArg, body) {
31
- var f, y, t, g, _ = {
32
- label: 0,
33
- sent: function() {
34
- if (t[0] & 1) throw t[1];
35
- return t[1];
36
- },
37
- trys: [],
38
- ops: []
39
- };
40
- return(g = {
41
- next: verb(0),
42
- "throw": verb(1),
43
- "return": verb(2)
44
- }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
45
- return this;
46
- }), g);
47
- function verb(n) {
48
- return function(v) {
49
- return step([
50
- n,
51
- v
52
- ]);
53
- };
54
- }
55
- function step(op) {
56
- if (f) throw new TypeError("Generator is already executing.");
57
- while(_)try {
58
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
59
- if (y = 0, t) op = [
60
- op[0] & 2,
61
- t.value
62
- ];
63
- switch(op[0]){
64
- case 0:
65
- case 1:
66
- t = op;
67
- break;
68
- case 4:
69
- _.label++;
70
- return {
71
- value: op[1],
72
- done: false
73
- };
74
- case 5:
75
- _.label++;
76
- y = op[1];
77
- op = [
78
- 0
79
- ];
80
- continue;
81
- case 7:
82
- op = _.ops.pop();
83
- _.trys.pop();
84
- continue;
85
- default:
86
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
87
- _ = 0;
88
- continue;
89
- }
90
- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
91
- _.label = op[1];
92
- break;
93
- }
94
- if (op[0] === 6 && _.label < t[1]) {
95
- _.label = t[1];
96
- t = op;
97
- break;
98
- }
99
- if (t && _.label < t[2]) {
100
- _.label = t[2];
101
- _.ops.push(op);
102
- break;
103
- }
104
- if (t[2]) _.ops.pop();
105
- _.trys.pop();
106
- continue;
107
- }
108
- op = body.call(thisArg, _);
109
- } catch (e) {
110
- op = [
111
- 6,
112
- e
113
- ];
114
- y = 0;
115
- } finally{
116
- f = t = 0;
117
- }
118
- if (op[0] & 5) throw op[1];
119
- return {
120
- value: op[0] ? op[1] : void 0,
121
- done: true
122
- };
123
- }
124
- }
125
- import { createPublisher } from "@solana-mobile/dapp-store-publishing-tools";
126
- import { Connection, Keypair } from "@solana/web3.js";
127
- import { Constants, getMetaplexInstance } from "../../CliUtils.js";
128
- import { loadPublishDetailsWithChecks, writeToPublishDetails } from "../../config/PublishDetails.js";
129
- import { sendAndConfirmTransaction } from "../utils.js";
130
- var createPublisherNft = function() {
131
- var _ref = _async_to_generator(function(param) {
132
- var connection, publisher, publisherDetails, storageParams, priorityFeeLamports, mintAddress, metaplex, txBuilder, response;
133
- return _ts_generator(this, function(_state) {
134
- switch(_state.label){
135
- case 0:
136
- connection = param.connection, publisher = param.publisher, publisherDetails = param.publisherDetails, storageParams = param.storageParams, priorityFeeLamports = param.priorityFeeLamports;
137
- console.info("Creating Publisher NFT");
138
- mintAddress = Keypair.generate();
139
- metaplex = getMetaplexInstance(connection, publisher, storageParams);
140
- return [
141
- 4,
142
- createPublisher({
143
- mintAddress: mintAddress,
144
- publisherDetails: publisherDetails,
145
- priorityFeeLamports: priorityFeeLamports
146
- }, {
147
- metaplex: metaplex,
148
- publisher: publisher
149
- })
150
- ];
151
- case 1:
152
- txBuilder = _state.sent();
153
- console.info("Publisher NFT data upload complete\nSigning transaction now");
154
- return [
155
- 4,
156
- sendAndConfirmTransaction(metaplex, txBuilder)
157
- ];
158
- case 2:
159
- response = _state.sent().response;
160
- return [
161
- 2,
162
- {
163
- publisherAddress: mintAddress.publicKey.toBase58(),
164
- transactionSignature: response.signature
165
- }
166
- ];
167
- }
168
- });
169
- });
170
- return function createPublisherNft(_) {
171
- return _ref.apply(this, arguments);
172
- };
173
- }();
174
- export var createPublisherCommand = function() {
175
- var _ref = _async_to_generator(function(param) {
176
- var signer, url, dryRun, storageParams, _param_priorityFeeLamports, priorityFeeLamports, connection, _ref, publisherDetails, _ref1, publisherAddress, transactionSignature;
177
- return _ts_generator(this, function(_state) {
178
- switch(_state.label){
179
- case 0:
180
- signer = param.signer, url = param.url, dryRun = param.dryRun, storageParams = param.storageParams, _param_priorityFeeLamports = param.priorityFeeLamports, priorityFeeLamports = _param_priorityFeeLamports === void 0 ? Constants.DEFAULT_PRIORITY_FEE : _param_priorityFeeLamports;
181
- connection = new Connection(url, {
182
- commitment: "confirmed"
183
- });
184
- return [
185
- 4,
186
- loadPublishDetailsWithChecks()
187
- ];
188
- case 1:
189
- _ref = _state.sent(), publisherDetails = _ref.publisher;
190
- if (!!dryRun) return [
191
- 3,
192
- 4
193
- ];
194
- return [
195
- 4,
196
- createPublisherNft({
197
- connection: connection,
198
- publisher: signer,
199
- publisherDetails: publisherDetails,
200
- storageParams: storageParams,
201
- priorityFeeLamports: priorityFeeLamports
202
- })
203
- ];
204
- case 2:
205
- _ref1 = _state.sent(), publisherAddress = _ref1.publisherAddress, transactionSignature = _ref1.transactionSignature;
206
- return [
207
- 4,
208
- writeToPublishDetails({
209
- publisher: {
210
- address: publisherAddress
211
- }
212
- })
213
- ];
214
- case 3:
215
- _state.sent();
216
- return [
217
- 2,
218
- {
219
- publisherAddress: publisherAddress,
220
- transactionSignature: transactionSignature
221
- }
222
- ];
223
- case 4:
224
- return [
225
- 2,
226
- {
227
- publisherAddress: "",
228
- transactionSignature: ""
229
- }
230
- ];
231
- }
232
- });
233
- });
234
- return function createPublisherCommand(_) {
235
- return _ref.apply(this, arguments);
236
- };
237
- }();
@@ -1,87 +0,0 @@
1
- import type { Publisher } from "@solana-mobile/dapp-store-publishing-tools";
2
- import { createPublisher } from "@solana-mobile/dapp-store-publishing-tools";
3
- import {
4
- Connection,
5
- Keypair,
6
- } from "@solana/web3.js";
7
-
8
- import {
9
- Constants,
10
- getMetaplexInstance,
11
- } from "../../CliUtils.js";
12
- import { loadPublishDetailsWithChecks, writeToPublishDetails } from "../../config/PublishDetails.js";
13
- import { sendAndConfirmTransaction } from "../utils.js";
14
-
15
- const createPublisherNft = async (
16
- {
17
- connection,
18
- publisher,
19
- publisherDetails,
20
- storageParams,
21
- priorityFeeLamports,
22
- }: {
23
- connection: Connection;
24
- publisher: Keypair;
25
- publisherDetails: Publisher;
26
- storageParams: string;
27
- priorityFeeLamports: number;
28
- },
29
- ) => {
30
- console.info(`Creating Publisher NFT`);
31
- const mintAddress = Keypair.generate();
32
- const metaplex = getMetaplexInstance(connection, publisher, storageParams);
33
- const txBuilder = await createPublisher(
34
- { mintAddress, publisherDetails, priorityFeeLamports },
35
- { metaplex, publisher }
36
- );
37
-
38
- console.info(`Publisher NFT data upload complete\nSigning transaction now`);
39
-
40
- const { response } = await sendAndConfirmTransaction(metaplex, txBuilder);
41
-
42
- return {
43
- publisherAddress: mintAddress.publicKey.toBase58(),
44
- transactionSignature: response.signature,
45
- };
46
- };
47
-
48
- export const createPublisherCommand = async ({
49
- signer,
50
- url,
51
- dryRun,
52
- storageParams,
53
- priorityFeeLamports = Constants.DEFAULT_PRIORITY_FEE,
54
- }: {
55
- signer: Keypair;
56
- url: string;
57
- dryRun: boolean;
58
- storageParams: string;
59
- priorityFeeLamports: number;
60
- }) => {
61
- const connection = new Connection(
62
- url,
63
- {
64
- commitment: "confirmed",
65
- }
66
- );
67
-
68
- const { publisher: publisherDetails } = await loadPublishDetailsWithChecks();
69
-
70
- if (!dryRun) {
71
- const { publisherAddress, transactionSignature } = await createPublisherNft(
72
- {
73
- connection,
74
- publisher: signer,
75
- publisherDetails,
76
- storageParams: storageParams,
77
- priorityFeeLamports: priorityFeeLamports,
78
- },
79
- );
80
-
81
- await writeToPublishDetails({ publisher: { address: publisherAddress } });
82
-
83
- return { publisherAddress, transactionSignature };
84
- }
85
-
86
- return { publisherAddress: "", transactionSignature: "" };
87
- };