> For the complete documentation index, see [llms.txt](https://docs.ghostmarket.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ghostmarket.io/developer-guides/minting-tokens/phantasma-nft-creation.md).

# Phantasma NFT Creation

## Introduction

This page provides step-by-step instructions for deploying GhostMarket compatible NFTs on the Phantasma blockchain.

The NFT creation process requires interaction with the blockchain. For retrieving existing NFT metadata, see [Accessing NFT](/developer-guides/accessing-nft-data.md) data, which uses the GhostMarket APIs.

The code snippets also assume a [node.js](https://nodejs.org) environment.

See our [Metadata Reference](/developer-guides/metadata-specification.md) for full details and requirements of GhostMarket NFT metadata.

## NFT Creation

The NFT creation process on all blockchains broadly consists of the following steps.

1. Prepare Off-Chain Metadata and persist it.
2. Assemble On-Chain Metadata and build a transaction.
3. Sign the transaction.
4. Broadcast to the blockchain.

### 1. Prepare Off-Chain Metadata

The preferred decentralised platform for persisting image/media data for your NFT is [IPFS](https://ipfs.io/).

This guide will use Pinãta to upload and pin your images to IPFS.

Set up a Pinata account and get started [here](https://www.pinata.cloud/).

You can either manually upload you metadata, noting the IPFS hash, or dive into the [Pinata js-sdk](https://docs.pinata.cloud/pinata-node-sdk) to interract with Pinata programatically.

> Note the IPFS hash of the uploaded metadata, you will need it in the next step.

### 2. Assemble On-Chain Metadata

Ghostmarket Phantasma NFT contract stores all metadata on-chain, so you must assemble it into a Phantasma transaction script.

We will use the [phantasma-ts npm](https://github.com/phantasma-io/phantasma-ts) module to work with the Phantasma blockchain.

#### Install the module

```bash
% npm install phantasma-ts
```

#### Import the library

```javascript
const { phantasmaJS } = require("phantasma-ts");
```

The Minting Data is sent to the contract as an array. The following table specifies the contents of the array.

> All elements must be provided.

#### Phantasma "ghost" mint contract parameters

<table><thead><tr><th width="150">index</th><th>name</th><th width="158">type</th><th>descr</th></tr></thead><tbody><tr><td>0</td><td>editionId</td><td>number</td><td>0 for new series // != 0 for existing series</td></tr><tr><td>1</td><td>editionMax</td><td>number</td><td>Maximum number possible</td></tr><tr><td>2</td><td>editionMode</td><td>number</td><td>1 = duplicated, 2 = unique // only allow duplicate for now</td></tr><tr><td>3</td><td>creator</td><td>address</td><td>Address of the creator</td></tr><tr><td>4</td><td>royalties</td><td>number</td><td>Royalties in BPS (0.01%) - must be integer</td></tr><tr><td>5</td><td>mintTicker</td><td>string</td><td></td></tr><tr><td>6</td><td>numOfNfts</td><td>number</td><td>number to mint</td></tr><tr><td>7</td><td>name</td><td>string</td><td>Short name of the NFT</td></tr><tr><td>8</td><td>description</td><td>string</td><td>long descriptive name of the NFT</td></tr><tr><td>9</td><td>type</td><td>number/integer</td><td>Genre of the NFT - see Genre reference</td></tr><tr><td>10</td><td>imageURL</td><td>string</td><td>URL of the image - ipfs://&#x3C;hash></td></tr><tr><td>11</td><td>infoURL</td><td>string</td><td>Currently unused</td></tr><tr><td>12</td><td>attrT1</td><td>string</td><td>First attribute Type/Key, e.g. "Color"</td></tr><tr><td>13</td><td>attrV1</td><td>string</td><td>First attribute Value, e.g. "Red"</td></tr><tr><td>14</td><td>attrT2</td><td>string</td><td>Second attribute Type/Key</td></tr><tr><td>15</td><td>attrV2</td><td>string</td><td>Second attribute Value</td></tr><tr><td>16</td><td>attrT3</td><td>string</td><td>Third attribute Type/Key</td></tr><tr><td>17</td><td>attrV3</td><td>string</td><td>Third attribute Value</td></tr><tr><td>18</td><td>lockedContent</td><td>string</td><td>String containing the encrypted content</td></tr><tr><td>19</td><td>listPrice</td><td>number</td><td>If listing with Mint, the listing price</td></tr><tr><td>20</td><td>listPriceCurrency</td><td>string</td><td>If listing with Mint, the listing currency, e.g. "KCAL"</td></tr><tr><td>21</td><td>listLastEndDate</td><td>timestamp</td><td>If listing with Mint, the Unix Epoch end time of listing</td></tr><tr><td>22</td><td>infusedAsset</td><td>string</td><td>If infusing, the asset being infused e.g. "KCAL", otherwise ""</td></tr><tr><td>23</td><td>infusedAmount</td><td>number</td><td>If infusing , the amount of infusedAsset to infuse, otherwise 0</td></tr><tr><td>24</td><td>hasLocked</td><td>bool</td><td>True if <em>lockedContent</em> is specified, otherwise false</td></tr></tbody></table>

***

#### Assemble the Minting Parameter Array

```javascript
let creatorAdd = "<my Phantasma address>";

mintParamArrayGhost = [
  0, // editionID
  100, // editionMax
  1, // editionMode
  creatorAdd, // creator - address
  2000, // royalties - 20% expressed as BPS (0.01%)
  "GHOST", // mintTicker - string
  1, // numOfNfts - Mint one NFT
  "My Shiny NFT", // name
  "This NFT will be a classic", // description
  1, // type - See Metadata Reference "Genre"
  "ipfs://QmTy8w65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStJb", // imageURL - from step 1
  "", // infoURL - not used
  "color", // attrT1
  "red", // attrV1
  "size", // attrT2
  "small", // attrV2
  "", // attrT3 - empty string if unused
  "", // attrV3 - empty string if unused
  "This is your mystery content", // lockedContent
  0, // listPrice - we can list later, not now
  "", // listPriceCurrency - not listing with mint
  0, // listLastEndDate - not listing
  "", // infusedAsset - string
  0, // infusedAmount - number
  true, // hasLocked - true
];
```

### 3. Build the transaction script

```javascript
//Create a new Script Builder Object
let sb = new phantasmaJS.ScriptBuilder();

// Assemble the Script
sb.callContract("gas", "AllowGas", [
  "fromAddress",
  sb.nullAddress,
  "100000",
  "900",
])
  .callContract("ghost", "mintToken", mintParamArrayGhost)
  .callContract("gas", "SpendGas", ["fromAddress"])
  .endScript();
```

### 3. Construct & Sign the transaction

```javascript
// stringify the script
let script = sb.str;
let privateKey = "Your Private Key";

//build an expiration date for the transaction of 5 minutes
let expiration = 5; //Expiration time, in minutes
let getTime = new Date();
let expDate = new Date(getTime() + expiration * 60000);

//Creating New Transaction Object
let transaction = new phantasmaJS.Transaction(
  "mainnet", //Nexus Name
  "main", //Chain
  script, //In string format
  date, //Expiration Date
  ""
); //Extra Info to attach to Transaction in Serialized Hex - not needed

//Sign's Transaction with Private Key
await transaction.sign(privateKey);
```

### 4. Broadcast to the blockchain

Finally, broadcast the transaction

```javascript
//Send Transaction
let txHash = await RPC.sendRawTransaction(transaction.toString(true));
```

Congratulations! you have successfully deployed a GhostMarket compatible NFT to the "ghost" contract on the Phantasma blockchain.

> For clarity, all of the above snippets exclude error and promise handling for clarity. Production code should include thorough exception management and handle promises appropriately.
