# 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ghostmarket.io/developer-guides/minting-tokens/phantasma-nft-creation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
