|
|
@@ -93,20 +93,44 @@ This example is going to run through setting up Umi with a `generatedSigner()`.
|
|
|
|
|
|
You can place the umi variable and code block either inside or outside the `createAndMintTokens()` function. All that matters is that your `umi` variable is accessible from the `createAndMintTokens()` function itself.
|
|
|
|
|
|
+### Generating a New Wallet
|
|
|
+
|
|
|
```ts
|
|
|
const umi = createUmi('https://api.devnet.solana.com')
|
|
|
- .use(mplTokenMetadata())
|
|
|
+ .use(mplCore())
|
|
|
.use(irysUploader())
|
|
|
|
|
|
-// Generates a new private key to use with umi.
|
|
|
+// Generate a new keypair signer.
|
|
|
const signer = generateSigner(umi)
|
|
|
|
|
|
-// Assign the private key to be the default Umi identity.
|
|
|
+// Tell umit to use the new signer.
|
|
|
umi.use(signerIdentity(signer))
|
|
|
|
|
|
-// If using a newly generated privatekey/wallet you may
|
|
|
-// need to airdrop (Devnet only) or transfer SOL to the new address.
|
|
|
-await umi.rpc.airdrop(umi.identity.publicKey, sol(1));
|
|
|
+// Airdrop 1 SOL to the identity
|
|
|
+// if you end up with a 429 too many requests error, you may have to use
|
|
|
+// the a different rpc other than the free default one supplied.
|
|
|
+await umi.rpc.airdrop(umi.identity.publickey)
|
|
|
+```
|
|
|
+
|
|
|
+### Use an Existing Wallet Stored Locally
|
|
|
+
|
|
|
+```ts
|
|
|
+const umi = createUmi('https://api.devnet.solana.com')
|
|
|
+ .use(mplTokenMetadata())
|
|
|
+ .use(mplToolbox())
|
|
|
+ .use(irysUploader())
|
|
|
+
|
|
|
+// You will need to us fs and navigate the filesystem to
|
|
|
+// load the wallet you wish to use via relative pathing.
|
|
|
+const walletFile = const imageFile = fs.readFileSync(
|
|
|
+ path.join(__dirname, './keypair.json')
|
|
|
+ )
|
|
|
+
|
|
|
+// Convert your walletFile onto a keypair.
|
|
|
+let keypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(walletFile));
|
|
|
+
|
|
|
+// Load the keypair into umi.
|
|
|
+umi.use(keypairIdentity(umiSigner));
|
|
|
```
|
|
|
|
|
|
|
|
|
@@ -134,7 +158,7 @@ const imageFile = fs.readFileSync(
|
|
|
// otherwise Arweave will not know how to display your image.
|
|
|
|
|
|
const umiImageFile = createGenericFile(imageFile, 'island-dao.jpeg', {
|
|
|
- tags: [{ name: 'Content-Type', value: 'image/jpeg' }],
|
|
|
+ tags: [{ name: 'contentType', value: 'image/jpeg' }],
|
|
|
})
|
|
|
|
|
|
// Here we upload the image to Arweave via Irys and we get returned a uri
|
|
|
@@ -200,21 +224,17 @@ const metadataUri = await umi.uploader.uploadJson(metadata).catch((err) => {
|
|
|
|
|
|
If everything goes as planned, the metadataUri variable should store the URI of the uploaded JSON file.
|
|
|
|
|
|
-### Creating the Token
|
|
|
+### Creating a Token
|
|
|
|
|
|
When creating a new token on the Solana blockchain we need to create a few accounts to accommodate the new data.
|
|
|
|
|
|
-#### Creating the mint account.
|
|
|
-
|
|
|
-If we are minting the Tokens then we need a Token Account (holds the minted tokens in a persons wallet)
|
|
|
-Mint the token.
|
|
|
-When you first create the tokens, the creator will retain the update authority and mint authority. Both update and mint authority will need to be revoked when listing the token on DEXs such as Jupiter and Orca for validation.
|
|
|
+#### Creating The Mint Account and Token Metadata
|
|
|
|
|
|
-#### Mint Account
|
|
|
+While the Mint account of stores initial minting details of Mint such as number of decimals, the total supply, and mint and freeze authorities, the Token Metadata account holds properties of the token such as `name`, off chain metadata `uri`, `description` of the token, and the tokens `symbol`. Together these accounts provide all the information for a SPL Token on Solana.
|
|
|
|
|
|
-To make a mint account and save mint data, we use the createFungible helper method. This method simplifies the process of creating an account for you.
|
|
|
+The `createFungible()` function below creates both the Mint account and the Token Metadata account for use.
|
|
|
|
|
|
-We need to give the function a keypair for the mint address. We also need to provide additional metadata from a JSON file. This metadata includes the token's name and the metadata URI address.
|
|
|
+We need to supply the function a keypair which will become the mint address. We also need to provide additional metadata from a JSON file. This metadata includes the token's name and the metadata URI address.
|
|
|
|
|
|
```ts
|
|
|
const mintSigner = generateSigner(umi)
|
|
|
@@ -232,20 +252,22 @@ const createMintIx = await createFungible(umi, {
|
|
|
|
|
|
#### Token Account
|
|
|
|
|
|
-If we are minting the tokens straight away then we need a place to store the tokens in someones wallet. To do this we mathematically generate an address based on both the wallet and mint address which is called a Associated Token Account (ATA) or sometimes just referred to as just a Token Account.
|
|
|
+If we are minting the tokens straight away then we need a place to store the tokens in someones wallet. To do this we mathematically generate an address based on both the wallet and mint address which is called a Associated Token Account (ATA) or sometimes just referred to as just a Token Account. This Token Account (ATA) belongs to the wallet and stores our tokens for us.
|
|
|
|
|
|
-#### Generating the Token Account Address.
|
|
|
+#### Generating a Token Account.
|
|
|
|
|
|
-The first thing we need to do is figure out what the Token Account address should be. mpl-toolbox has a helper function we can import that does just that.
|
|
|
+The first thing we need to do is figure out what the Token Account address should be. MPL-Toolbox has a helper function we can import that does just that while also creating the Token Account for if it doesn't exist.
|
|
|
|
|
|
```ts
|
|
|
-const createTokenIx = createTokenIfMissing(umi, {
|
|
|
+const createTokenIx = createTokenAccountIfMissing(umi, {
|
|
|
mint: mintSigner.publickey,
|
|
|
owner: umi.identity.publicKey,
|
|
|
ataProgram: getSplAssociatedTokenProgramId(umi),
|
|
|
})
|
|
|
```
|
|
|
|
|
|
+#### Mint Tokens Transaction
|
|
|
+
|
|
|
Now that we have a instruction to create an Token Account we can mint tokens to that account with the `mintTokenTo()` instruction.
|
|
|
|
|
|
```ts
|
|
|
@@ -268,6 +290,7 @@ You can send and arrange the transactions in multiple ways but in this example w
|
|
|
|
|
|
const tx = await createFungibleIx
|
|
|
.add(createTokenIx)
|
|
|
+ .add(createTokenAccountIfMissing)
|
|
|
.add(mintTokensIx)
|
|
|
.sendAndConfirm(umi)
|
|
|
|
|
|
@@ -319,60 +342,63 @@ const createAndMintTokens = async () => {
|
|
|
|
|
|
umi.use(signerIdentity(signer))
|
|
|
|
|
|
- // Airdrop 1 SOL to the identity
|
|
|
+// Airdrop 1 SOL to the identity
|
|
|
// if you end up with a 429 too many requests error, you may have to use
|
|
|
// the filesystem wallet method or change rpcs.
|
|
|
- await umi.rpc.airdrop(umi.identity.publicKey, sol(1))
|
|
|
+ console.log("AirDrop 1 SOL to the umi identity");
|
|
|
+ await umi.rpc.airdrop(umi.identity.publicKey, sol(1));
|
|
|
|
|
|
// use `fs` to read file via a string path.
|
|
|
-
|
|
|
- const imageFile = fs.readFileSync(path.join(__dirname, '/assets/image.png'))
|
|
|
+
|
|
|
+ const imageFile = fs.readFileSync(path.join(__dirname, "../assets/images/1.png"));
|
|
|
|
|
|
// Use `createGenericFile` to transform the file into a `GenericFile` type
|
|
|
- // that Umi can understand. Make sure you set the mimi tag type correctly
|
|
|
+ // that umi can understand. Make sure you set the mimi tag type correctly
|
|
|
// otherwise Arweave will not know how to display your image.
|
|
|
|
|
|
- const umiImageFile = createGenericFile(imageFile, 'image.png', {
|
|
|
- tags: [{ name: 'Content-Type', value: 'image/png' }],
|
|
|
- })
|
|
|
+ const umiImageFile = createGenericFile(imageFile, "1.png", {
|
|
|
+ tags: [{ name: "Content-Type", value: "image/png" }],
|
|
|
+ });
|
|
|
|
|
|
// Here we upload the image to Arweave via Irys and we get returned a uri
|
|
|
// address where the file is located. You can log this out but as the
|
|
|
// uploader can takes an array of files it also returns an array of uris.
|
|
|
// To get the uri we want we can call index [0] in the array.
|
|
|
|
|
|
+ console.log("Uploading image to Arweave via Irys");
|
|
|
const imageUri = await umi.uploader.upload([umiImageFile]).catch((err) => {
|
|
|
- throw new Error(err)
|
|
|
- })
|
|
|
+ throw new Error(err);
|
|
|
+ });
|
|
|
|
|
|
- console.log(imageUri[0])
|
|
|
+ console.log(imageUri[0]);
|
|
|
|
|
|
// Uploading the tokens metadata to Arweave via Irys
|
|
|
|
|
|
const metadata = {
|
|
|
- name: 'The Kitten Coin',
|
|
|
- symbol: 'KITTEN',
|
|
|
- description: 'The Kitten Coin is a token created on the Solana blockchain',
|
|
|
+ name: "The Kitten Coin",
|
|
|
+ symbol: "KITTEN",
|
|
|
+ description: "The Kitten Coin is a token created on the Solana blockchain",
|
|
|
image: imageUri, // Either use variable or paste in string of the uri.
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- // Call upon Umi's `uploadJson` function to upload our metadata to Arweave via Irys.
|
|
|
+ // Call upon umi's uploadJson function to upload our metadata to Arweave via Irys.
|
|
|
|
|
|
+ console.log("Uploading metadata to Arweave via Irys");
|
|
|
const metadataUri = await umi.uploader.uploadJson(metadata).catch((err) => {
|
|
|
- throw new Error(err)
|
|
|
- })
|
|
|
+ throw new Error(err);
|
|
|
+ });
|
|
|
|
|
|
// Creating the mintIx
|
|
|
|
|
|
- const mintSigner = generateSigner(umi)
|
|
|
+ const mintSigner = generateSigner(umi);
|
|
|
|
|
|
const createFungibleIx = createFungible(umi, {
|
|
|
mint: mintSigner,
|
|
|
- name: 'The Kitten Coin',
|
|
|
- uri: metadataUri, // we use the `metadataUri` variable we created earlier that is storing our uri.
|
|
|
+ name: "The Kitten Coin",
|
|
|
+ uri: metadataUri, // we use the `metedataUri` variable we created earlier that is storing our uri.
|
|
|
sellerFeeBasisPoints: percentAmount(0),
|
|
|
- decimals: 9, // set the amount of decimals you want your token to have.
|
|
|
- })
|
|
|
+ decimals: 0, // set the amount of decimals you want your token to have.
|
|
|
+ });
|
|
|
|
|
|
// This instruction will create a new Token Account if required, if one is found then it skips.
|
|
|
|
|
|
@@ -380,7 +406,7 @@ const createAndMintTokens = async () => {
|
|
|
mint: mintSigner.publicKey,
|
|
|
owner: umi.identity.publicKey,
|
|
|
ataProgram: getSplAssociatedTokenProgramId(umi),
|
|
|
- })
|
|
|
+ });
|
|
|
|
|
|
// The final instruction (if required) is to mint the tokens to the token account in the previous ix.
|
|
|
|
|
|
@@ -391,25 +417,30 @@ const createAndMintTokens = async () => {
|
|
|
owner: umi.identity.publicKey,
|
|
|
}),
|
|
|
amount: BigInt(1000),
|
|
|
- })
|
|
|
+ });
|
|
|
|
|
|
// The last step is to send the ix's off in a transaction to the chain.
|
|
|
- // Ix's here can be omitted and added as needed during the chain.
|
|
|
+ // Ix's here can be ommited and added as needed during the transaction chain.
|
|
|
// If for example you just want to create the Token without minting
|
|
|
- // any tokens then you can only submit the `createToken` ix.
|
|
|
-
|
|
|
- // If you want to mint tokens to a different wallet then you can
|
|
|
- // just pull out the `createTokenIx` ix and `mintTokensIx` ix and send
|
|
|
- // them as another tx.
|
|
|
+ // any tokens then you may only want to submit the `createToken` ix.
|
|
|
|
|
|
+ console.log("Sending transaction")
|
|
|
const tx = await createFungibleIx
|
|
|
.add(createTokenIx)
|
|
|
.add(mintTokensIx)
|
|
|
- .sendAndConfirm(umi)
|
|
|
+ .sendAndConfirm(umi);
|
|
|
|
|
|
// finally we can deserialize the signature that we can check on chain.
|
|
|
- console.log(base58.deserialize(tx.signature)[0])
|
|
|
-}
|
|
|
+ const signature = base58.deserialize(tx.signature)[0];
|
|
|
+
|
|
|
+ // Log out the signature and the links to the transaction and the NFT.
|
|
|
+ // Explorer links are for the devnet chain, you can change the clusters to mainnet.
|
|
|
+ console.log('\nTransaction Complete')
|
|
|
+ console.log('View Transaction on Solana Explorer')
|
|
|
+ console.log(`https://explorer.solana.com/tx/${signature}?cluster=devnet`)
|
|
|
+ console.log('View Token on Solana Explorer')
|
|
|
+ console.log(`https://explorer.solana.com/address/${mintSigner.publicKey}?cluster=devnet`)
|
|
|
+};
|
|
|
|
|
|
createAndMintTokens()
|
|
|
```
|