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
9
import { Image } from "@astrojs/image/components";
10
import medium from "../../assets/medium.png";
11
import OutLinkButton from "../../components/OutLinkButton.astro";
12
13
<OutLinkButton
14
	link="https://medium.com/pinata/how-to-mint-an-nft-on-sui-using-pinata-and-the-sui-js-sdk-4386655e403"
15
	site="Medium"
16
	image={medium}
17
/>
18
19
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!
20
21
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!
22
23
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.
24
25
## Setting up your NFT with Pinata
26
27
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.
28
29
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.”
30
31
<Image
32
	src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*TF200pv3qCMx41dHZoE_kg@2x.png"
33
	alt="pinata files page"
34
	width={1920}
35
	aspectRatio={16 / 9}
36
/>
37
38
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.
39
40
<Image
41
	src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*68MMViE3btD8hHuxaTbEzg@2x.png"
42
	alt="pinata files page"
43
	width={1920}
44
	aspectRatio={16 / 9}
45
/>
46
47
## Code Setup with the Sui JS SDK
48
49
First let’s make a new directory where the project will live using the following terminal command:
50
51
```bash
52
mkdir sui-nft && cd sui-nft
53
```
54
55
Now let’s install the Sui Javascript SDK:
56
57
```bash
58
npm init -y && npm install @mysten/sui.js
59
```
60
61
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.
62
63
```json
64
{
65
	"name": "sui-nft",
66
	"type": "module",
67
	"version": "1.0.0",
68
	"description": "",
69
	"main": "index.js",
70
	"scripts": {
71
		"test": "echo \"Error: no test specified\" && exit 1"
72
	},
73
	"keywords": [],
74
	"author": "",
75
	"license": "ISC",
76
	"dependencies": {
77
		"@mysten/sui.js": "^0.26.1"
78
	}
79
}
80
```
81
82
Lastly, we will want to make a file to run our code which we’ll call mint-nft.js
83
84
```bash
85
touch mint-nft.js
86
```
87
88
Now we can get into good stuff — writing the code to mint our NFT!
89
90
## Minting the NFT
91
92
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.
93
94
```javascript
95
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from "@mysten/sui.js";
96
```
97
98
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.
99
100
```javascript
101
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from "@mysten/sui.js";
102
103
const keypair = new Ed25519Keypair();
104
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString();
105
console.log(address);
106
```
107
108
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!
109
110
```
111
0x8f7671eedff42d6dde8c365a6b641bb9769ea02e
112
```
113
114
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.”
115
116
```javascript
117
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from "@mysten/sui.js";
118
119
//Create keypair
120
const keypair = new Ed25519Keypair();
121
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString();
122
console.log(address);
123
124
//Create network connection
125
const provider = new JsonRpcProvider(Network.DEVNET);
126
```
127
128
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.
129
130
```javascript
131
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from "@mysten/sui.js";
132
133
//Create keypair
134
const keypair = new Ed25519Keypair();
135
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString();
136
console.log(address);
137
138
//Create network connection
139
const provider = new JsonRpcProvider(Network.DEVNET);
140
141
// Get Sui from faucet
142
const fund = await provider.requestSuiFromFaucet(address);
143
console.log(fund);
144
```
145
146
Let’s run the node mint-nft.js command now and see what we get!
147
148
```
149
0xf64640227ff94ba762252c15f2adbcedb6d3aaab
150
{
151
  transferred_gas_objects: [
152
    {
153
      amount: 10000000,
154
      id: '0x39c25c3885c2cccea957c26219de9c7e58a33a21',
155
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
156
    },
157
    {
158
      amount: 10000000,
159
      id: '0x3bdad5c729495d9d152cfd03b0e44e8549972d53',
160
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
161
    },
162
    {
163
      amount: 10000000,
164
      id: '0x4a748f4e928b974dd46913e2cc069a21fecaad86',
165
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
166
    },
167
    {
168
      amount: 10000000,
169
      id: '0x66d601ef1811cbdea82d2eb97a0994afdbbc888a',
170
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
171
    },
172
    {
173
      amount: 10000000,
174
      id: '0xee8668e7c2fcd60047992f170da075dafd955f48',
175
      transfer_tx_digest: '4ETS2rGNzRYZ95SsLrUsQf8ckfZWQSSqTEpGi32RqKbk'
176
    }
177
  ],
178
  error: null
179
}
180
```
181
182
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!).
183
184
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.
185
186
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.
187
188
```javascript
189
// Merge two of the Sui coin objects
190
const coin1 = fund.transferred_gas_objects[0].id;
191
const coin2 = fund.transferred_gas_objects[1].id;
192
const signer = new RawSigner(keypair, provider);
193
const mergeTxn = await signer.mergeCoin({
194
	primaryCoin: coin1,
195
	coinToMerge: coin2,
196
	gasBudget: 1000,
197
});
198
console.log("MergeCoin txn", mergeTxn);
199
```
200
201
There’s quite a bit going on here so let’s break it down.
202
203
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.
204
205
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.
206
207
```javascript
208
// Pause function
209
const wait = async (time) => {
210
	return new Promise((resolve, reject) => {
211
		setTimeout(() => {
212
			resolve();
213
		}, time);
214
	});
215
};
216
```
217
218
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.
219
220
```javascript
221
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from "@mysten/sui.js";
222
223
// Generate a new Keypair
224
const keypair = new Ed25519Keypair();
225
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString();
226
console.log(address);
227
228
// Create Network Connection and receive airdrop
229
const provider = new JsonRpcProvider(Network.DEVNET);
230
231
// Get Sui from faucet
232
const fund = await provider.requestSuiFromFaucet(address);
233
console.log(fund);
234
235
// Pause function
236
const wait = async (time) => {
237
	return new Promise((resolve, reject) => {
238
		setTimeout(() => {
239
			resolve();
240
		}, time);
241
	});
242
};
243
244
await wait(3000);
245
246
// Merge two of the Sui coin objects
247
const coin1 = fund.transferred_gas_objects[1].id;
248
const coin2 = fund.transferred_gas_objects[2].id;
249
const signer = new RawSigner(keypair, provider);
250
const mergeTxn = await signer.mergeCoin({
251
	primaryCoin: coin1,
252
	coinToMerge: coin2,
253
	gasBudget: 1000,
254
});
255
console.log("MergeCoin txn", mergeTxn);
256
```
257
258
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!
259
260
```javascript
261
// Call to Mint NFT
262
const mintTxn = await signer.executeMoveCall({
263
	packageObjectId: "0x2",
264
	module: "devnet_nft",
265
	function: "mint",
266
	typeArguments: [],
267
	arguments: [
268
		"gm",
269
		"A nice gm brought to you by Pinata and Sui",
270
		"ipfs://QmZhnkimthxvL32vin2mrQvnhN8ZbWFMvKMxRqHEq7dPz3",
271
	],
272
	gasBudget: 10000,
273
});
274
console.log("mint transaction:", mintTxn);
275
```
276
277
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!
278
279
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.
280
281
```javascript
282
// View NFT
283
const nftId = mintTxn.effects.effects.created[0].reference.objectId.toString();
284
console.log(`View NFT: https://explorer.sui.io/object/${nftId}?network=devnet`);
285
```
286
287
Now let’s look at our full code to make sure everything is good, then run it!
288
289
```javascript
290
import { Ed25519Keypair, JsonRpcProvider, Network, RawSigner } from "@mysten/sui.js";
291
292
// Generate a new Keypair
293
const keypair = new Ed25519Keypair();
294
const address = "0x" + keypair.getPublicKey().toSuiAddress().toString();
295
console.log(address);
296
297
// Create Network Connection and receive airdrop
298
const provider = new JsonRpcProvider(Network.DEVNET);
299
300
// Get Sui from faucet
301
const fund = await provider.requestSuiFromFaucet(address);
302
console.log(fund);
303
304
// Pause function
305
const wait = async (time) => {
306
	return new Promise((resolve, reject) => {
307
		setTimeout(() => {
308
			resolve();
309
		}, time);
310
	});
311
};
312
313
await wait(3000);
314
315
// Merge two of the Sui coin objects
316
const coin1 = fund.transferred_gas_objects[1].id;
317
const coin2 = fund.transferred_gas_objects[2].id;
318
const signer = new RawSigner(keypair, provider);
319
const mergeTxn = await signer.mergeCoin({
320
	primaryCoin: coin1,
321
	coinToMerge: coin2,
322
	gasBudget: 1000,
323
});
324
console.log("MergeCoin txn", mergeTxn);
325
326
// Call to Mint NFT
327
const mintTxn = await signer.executeMoveCall({
328
	packageObjectId: "0x2",
329
	module: "devnet_nft",
330
	function: "mint",
331
	typeArguments: [],
332
	arguments: [
333
		"gm",
334
		"A nice gm brought to you by Pinata and Sui",
335
		"ipfs://QmZhnkimthxvL32vin2mrQvnhN8ZbWFMvKMxRqHEq7dPz3",
336
	],
337
	gasBudget: 10000,
338
});
339
console.log("mint transaction:", mintTxn);
340
341
// View NFT
342
const nftId = mintTxn.effects.effects.created[0].reference.objectId.toString();
343
console.log(`View NFT: https://explorer.sui.io/object/${nftId}?network=devnet`);
344
```
345
346
If all works as it should you’ll get a link and then you should see your final NFT!
347
348
<Image
349
	src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*oCtNaZK3LOx807tA8IEldg@2x.png"
350
	alt="pinata files page"
351
	width={1920}
352
	aspectRatio={16 / 9}
353
/>
354
355
## You did it!! 🎉
356
357
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 👀
358
359
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!
360
361
If you have any questions or want to learn more, feel free to join our [Discord](https://discord.gg/pianta) and say hi! :)