src/content/post/how-to-mint-on-sui.mdx 14.1 K raw
1
---
2
title: "How to Mint an NFT on Sui using Pinata and the Sui JS SDK"
3
publishDate: "27 Feb 2023"
4
description: "Learn how to use the Sui SDK and Pinata to mint an NFT"
5
tags: ["web3", "ipfs", "nfts", "tutorials", "web development"]
6
ogImage: "https://miro.medium.com/v2/resize:fit:4800/format:webp/1*JbX3kWI20G3EaKJNgXfQiQ.png"
7
---
8
import { Image } from "@astrojs/image/components";
9
import medium from "../../assets/medium.png"
10
import OutLinkButton from "../../components/OutLinkButton.astro"
11
12
<OutLinkButton link="https://medium.com/pinata/how-to-mint-an-nft-on-sui-using-pinata-and-the-sui-js-sdk-4386655e403" site="Medium" image={medium} />
13
14
15
One of my favorite pastimes is playing around with new blockchains and seeing what they’re like, what they offer, and how easy they are to build on. Recently I stumbled upon Sui and some of its unique features, such as dynamic metadata and goals to help onboard everyday people. After playing with it myself I was impressed with its speed and smoothness, which is saying something as it’s still in development!
16
17
The only thing I found lacking was some basic explanations of how to mint NFTs on Sui and some of the things you might have to tackle, so I thought I would share that experience and demonstrate this!
18
19
To get started, you should only need the basics such as NodeJS and a text editor like VSCode, as well as some fundamental knowledge about Javascript.
20
21
## Setting up your NFT with Pinata
22
23
While Sui features dynamic metadata, you will still want to use a service to store images, video, or any other kind of content you want to turn into an NFT! Pinata is ideal as it uses IPFS which prevents tampering with content which you can read more about here.
24
25
Getting started with Pinata is easy! Just visit the signup page here and start out with a free account. Now all you have to do is upload the image you want to use. Do that by visiting the main files page and clicking “Upload” and “Select File.”
26
27
<Image
28
src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*TF200pv3qCMx41dHZoE_kg@2x.png"
29
alt="pinata files page"
30
width={1920}
31
aspectRatio={16/9}
32
/>
33
34
After that just follow the steps of selecting your file, give it a name, then upload! Once done it should show up in your files page as seen below, and we will want to copy the CID for later.
35
36
<Image
37
src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*68MMViE3btD8hHuxaTbEzg@2x.png"
38
alt="pinata files page"
39
width={1920}
40
aspectRatio={16/9}
41
/>
42
43
## Code Setup with the Sui JS SDK
44
45
First let’s make a new directory where the project will live using the following terminal command:
46
47
```bash
48
mkdir sui-nft && cd sui-nft
49
```
50
51
Now let’s install the Sui Javascript SDK:
52
53
```bash
54
npm init -y && npm install @mysten/sui.js
55
```
56
57
One small change we need to make to the package.json file is adding the module type, so make sure your package.json looks like this.
58
59
```json
60
{
61
  "name": "sui-nft",
62
  "type": "module",
63
  "version": "1.0.0",
64
  "description": "",
65
  "main": "index.js",
66
  "scripts": {
67
    "test": "echo \"Error: no test specified\" && exit 1"
68
  },
69
  "keywords": [],
70
  "author": "",
71
  "license": "ISC",
72
  "dependencies": {
73
    "@mysten/sui.js": "^0.26.1"
74
  }
75
}
76
```
77
78
Lastly, we will want to make a file to run our code which we’ll call mint-nft.js
79
80
```bash
81
touch mint-nft.js
82
```
83
84
Now we can get into good stuff — writing the code to mint our NFT!
85
86
## Minting the NFT
87
88
Go ahead and open up your mint-nft.js file in your text editor of choice, and the first thing we’re gonna do is import the following methods at the top of the page.
89
90
```javascript
91
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from '@mysten/sui.js';
92
```
93
94
All we really need are four things, and you’ll see how they play a part as we start building. Next thing we need to do is create a wallet and get the public address for that wallet, which we can do like so.
95
96
```javascript
97
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from '@mysten/sui.js';
98
99
const keypair = new Ed25519Keypair()
100
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString()
101
console.log(address)
102
```
103
104
Accessing the keypair object makes it super simple to either get the public key or private key, and then turn it into usable data. The Sui address from the public key doesn’t include the leading “0x” so I’m adding that manually here. If you go into the terminal now and run “node mint-nft.js” then you should see an address like this!
105
106
```
107
0x8f7671eedff42d6dde8c365a6b641bb9769ea02e
108
```
109
110
Now that we have a wallet address, it’s time to connect to the Sui network and get some test Sui coin! First we’ll declare a new provider and use the JsonRpcProvider, and pass in the Network “DEVNET.”
111
112
```javascript
113
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from '@mysten/sui.js';
114
115
//Create keypair
116
const keypair = new Ed25519Keypair()
117
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString()
118
console.log(address)
119
120
//Create network connection 
121
const provider = new JsonRpcProvider(Network.DEVNET);
122
```
123
124
Then we’ll use the provider to request some test Sui from the Devnet faucet and use our new address as the receiver like so.
125
126
```javascript
127
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from '@mysten/sui.js';
128
129
//Create keypair
130
const keypair = new Ed25519Keypair()
131
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString()
132
console.log(address)
133
134
//Create network connection 
135
const provider = new JsonRpcProvider(Network.DEVNET);
136
137
// Get Sui from faucet
138
const fund = await provider.requestSuiFromFaucet(address)
139
console.log(fund)
140
```
141
142
Let’s run the node mint-nft.js command now and see what we get!
143
144
```
145
0xf64640227ff94ba762252c15f2adbcedb6d3aaab
146
{
147
  transferred_gas_objects: [
148
    {
149
      amount: 10000000,
150
      id: '0x39c25c3885c2cccea957c26219de9c7e58a33a21',
151
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
152
    },
153
    {
154
      amount: 10000000,
155
      id: '0x3bdad5c729495d9d152cfd03b0e44e8549972d53',
156
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
157
    },
158
    {
159
      amount: 10000000,
160
      id: '0x4a748f4e928b974dd46913e2cc069a21fecaad86',
161
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
162
    },
163
    {
164
      amount: 10000000,
165
      id: '0x66d601ef1811cbdea82d2eb97a0994afdbbc888a',
166
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
167
    },
168
    {
169
      amount: 10000000,
170
      id: '0xee8668e7c2fcd60047992f170da075dafd955f48',
171
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
172
    }
173
  ],
174
  error: null
175
}
176
```
177
178
Nice! Through this we can see the Sui we received which equals out to 0.05 Sui. Something you might be wondering is why we have 5 different items here with different ids, and that’s actually a very important piece of the Sui model that isn’t natural. Every coin in Sui has its own unique object id. These are all of the same type of currency which is the default Sui type, but our five pieces are in their own camp. This can cause a problem when we try to use our Sui to mint an NFT because its gonna try to pull from just one of these objects when ideally we want to pull from all of them like a normal blockchain (huge shoutout to [Paul Fidika](https://twitter.com/PaulFidika) for helping me understand this bit!).
179
180
Think of it like this. Let’s say you have a farm with five cow fields, and each field is separated by the type of cow: short haired, long haired, etc. Each field has 10 cows so you technically have 50 cows, but in order to trade for some goats you need 20 cows. You would have to empty two of those cow fields and combine them to trade them. That’s essentially what we’re doing in Sui with coins.
181
182
With that said, in order for us to mint, we need to combine some of our recently acquired Sui drop. We’re gonna do that with the following code.
183
184
```javascript
185
// Merge two of the Sui coin objects 
186
const coin1 = fund.transferred_gas_objects[0].id
187
const coin2 = fund.transferred_gas_objects[1].id
188
const signer = new RawSigner(keypair, provider);
189
const mergeTxn = await signer.mergeCoin({
190
  primaryCoin: coin1,
191
  coinToMerge: coin2,
192
  gasBudget: 1000,
193
});
194
console.log('MergeCoin txn', mergeTxn);
195
```
196
There’s quite a bit going on here so let’s break it down.
197
198
First we declare coin1 and coin2 from the airdrop we just received by accessing those object ids from our fund result. Then we need to declare our signer! This is what lets us use our private key from our keypair to transfer or mint on the chain, and we do that by declaring a new RawSigner and passing in our previously made keypair and provider to connect. Finally we use the mergeCoin method and pass in our two coins, along with a gas budget.
199
200
Before we run this, there is one small thing we’re missing. If you try to run this code now, you will likely get an error that it could not find the object id for the coin. That’s because its was just freshly created and we’re trying to access an object id that isn’t quite discoverable yet. To fix that we’re gonna make a small little helper function called “wait” like so.
201
202
```javascript
203
// Pause function
204
const wait = async (time) => {
205
  return new Promise((resolve, reject) => {
206
    setTimeout(() => {
207
      resolve();
208
    }, time)
209
  });
210
}
211
```
212
213
This is really simple and just lets us pass in how many milliseconds we want to wait before continuing our function! Let’s use it after getting our airdrop and passing in 3 seconds. You code should look something like this now.
214
215
```javascript
216
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from '@mysten/sui.js';
217
218
// Generate a new Keypair
219
const keypair = new Ed25519Keypair();
220
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString()
221
console.log(address)
222
223
// Create Network Connection and receive airdrop 
224
const provider = new JsonRpcProvider(Network.DEVNET);
225
226
// Get Sui from faucet
227
const fund = await provider.requestSuiFromFaucet(address)
228
console.log(fund)
229
230
// Pause function
231
const wait = async (time) => {
232
  return new Promise((resolve, reject) => {
233
    setTimeout(() => {
234
      resolve();
235
    }, time)
236
  });
237
}
238
239
await wait(3000)
240
241
// Merge two of the Sui coin objects 
242
const coin1 = fund.transferred_gas_objects[1].id
243
const coin2 = fund.transferred_gas_objects[2].id
244
const signer = new RawSigner(keypair, provider);
245
const mergeTxn = await signer.mergeCoin({
246
  primaryCoin: coin1,
247
  coinToMerge: coin2,
248
  gasBudget: 1000,
249
});
250
console.log('MergeCoin txn', mergeTxn);
251
```
252
253
If you run this code you should see the result of the airdrop, a pause before merging the coins, and the successful coin merge! Now that we have all our cows in one heard, we can mint an NFT successfully. Let’s take a look!
254
255
```javascript
256
// Call to Mint NFT
257
const mintTxn = await signer.executeMoveCall({
258
  packageObjectId: '0x2',
259
  module: 'devnet_nft',
260
  function: 'mint',
261
  typeArguments: [],
262
  arguments: [
263
    'gm',
264
    'A nice gm brought to you by Pinata and Sui',
265
    'ipfs://QmZhnkimthxvL32vin2mrQvnhN8ZbWFMvKMxRqHEq7dPz3',
266
  ],
267
  gasBudget: 10000
268
});
269
console.log('mint transaction:', mintTxn);
270
```
271
272
Our minting function is simply accessing a pre-built smart contract called ‘devnet_nft’ and we’re using the ‘mint’ function. All we have to pass into the arguments is the name of the NFT, the description, and then the asset link!
273
274
Before we mint, I’m gonna do one last console log that will let us take a look at the NFT in the browser. To do that , we need to access the results of the NFT mint and get the object id of the NFT, and then just pass that into a Sui explorer link like so.
275
276
```javascript
277
// View NFT
278
const nftId = mintTxn.effects.effects.created[0].reference.objectId.toString()
279
console.log(`View NFT: https://explorer.sui.io/object/${nftId}?network=devnet`)
280
```
281
282
Now let’s look at our full code to make sure everything is good, then run it!
283
284
```javascript
285
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from '@mysten/sui.js';
286
287
// Generate a new Keypair
288
const keypair = new Ed25519Keypair();
289
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString()
290
console.log(address)
291
292
// Create Network Connection and receive airdrop 
293
const provider = new JsonRpcProvider(Network.DEVNET);
294
295
// Get Sui from faucet
296
const fund = await provider.requestSuiFromFaucet(address)
297
console.log(fund)
298
299
// Pause function
300
const wait = async (time) => {
301
  return new Promise((resolve, reject) => {
302
    setTimeout(() => {
303
      resolve();
304
    }, time)
305
  });
306
}
307
308
await wait(3000)
309
310
// Merge two of the Sui coin objects 
311
const coin1 = fund.transferred_gas_objects[1].id
312
const coin2 = fund.transferred_gas_objects[2].id
313
const signer = new RawSigner(keypair, provider);
314
const mergeTxn = await signer.mergeCoin({
315
  primaryCoin: coin1,
316
  coinToMerge: coin2,
317
  gasBudget: 1000,
318
});
319
console.log('MergeCoin txn', mergeTxn);
320
321
// Call to Mint NFT
322
const mintTxn = await signer.executeMoveCall({
323
  packageObjectId: '0x2',
324
  module: 'devnet_nft',
325
  function: 'mint',
326
  typeArguments: [],
327
  arguments: [
328
    'gm',
329
    'A nice gm brought to you by Pinata and Sui',
330
    'ipfs://QmZhnkimthxvL32vin2mrQvnhN8ZbWFMvKMxRqHEq7dPz3',
331
  ],
332
  gasBudget: 10000
333
});
334
console.log('mint transaction:', mintTxn);
335
336
// View NFT
337
const nftId = mintTxn.effects.effects.created[0].reference.objectId.toString()
338
console.log(`View NFT: https://explorer.sui.io/object/${nftId}?network=devnet`)
339
```
340
341
If all works as it should you’ll get a link and then you should see your final NFT!
342
343
<Image
344
src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*oCtNaZK3LOx807tA8IEldg@2x.png"
345
alt="pinata files page"
346
width={1920}
347
aspectRatio={16/9}
348
/>
349
350
## You did it!! 🎉
351
352
You successfully minted an NFT on Sui!! Of course this is only the beginning of what’s possible. Maybe a nice next step is transferring the NFT to another wallet, or maybe even trying to build a Sui marketplace 👀
353
354
With whatever you’re trying to do, Pinata is here to help with tools like [our API](https://docs.pinata.cloud/pinata-api?utm_source=medium&utm_medium=referral), [Dedicated Gateways](https://www.pinata.cloud/dedicated-gateways?utm_source=medium&utm_medium=referral) to quickly stream images or video content for a marketplace, or token gated solutions using Submarine!
355
356
If you have any questions or want to learn more, feel free to join our [Discord](https://discord.gg/pianta) and say hi! :)