Skip to content

Commit

Permalink
Merge branch 'main' of github.com:0xCipherCoder/developer-content int…
Browse files Browse the repository at this point in the history
…o fix-deserialize-instruction-data-native-onchain
  • Loading branch information
0xCipherCoder committed Sep 9, 2024
2 parents e859709 + 3655b0a commit 24c8dde
Show file tree
Hide file tree
Showing 47 changed files with 2,151 additions and 1,429 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,7 @@ typings/
package-lock.json

# translations are stored in the `i18n` via crowdin
i18n
i18n

# vscode configuration
.vscode
184 changes: 184 additions & 0 deletions content/cookbook/tokens/create-nft.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
title: How to create an NFT
sidebarSortOrder: 15
description: "Learn how to create an NFT on Solana, using Arweave and Metaplex."
---

To create an NFT you have to:

1. Upload the image to IPFS like Arweave
2. Upload the JSON metadata to Arweave or similar storage service.
3. Call metaplex to create an account for the NFT

### Upload to Arweave

```typescript filename="upload-to-arweave.ts"
import fs from "node:fs";
import Arweave from "arweave";

(async () => {
const arweave = Arweave.init({
host: "localhost",
port: 1984,
protocol: "http",
timeout: 20000,
logging: false,
});

const host = arweave.getConfig().api.host;
const port = arweave.getConfig().api.port;
const protocol = arweave.getConfig().api.protocol;

// Upload image to Arweave
const data = fs.readFileSync("./code/nfts/upload-arweave/lowres-dog.png");

const transaction = await arweave.createTransaction({
data: data,
});

transaction.addTag("Content-Type", "image/png");

// Instead of generating a new wallet, you can use an existing one from your file system
// useful in production environments
// const wallet = JSON.parse(fs.readFileSync("./code/nfts/upload-arweave/wallet.json", "utf-8"))
const wallet = await arweave.wallets.generate();
const address = await arweave.wallets.getAddress(wallet);
console.log("address:, ", address);

await arweave.api.get(`/mint/${encodeURI(addr)}/10000000000000000`);
await arweave.transactions.sign(transaction, wallet);

const response = await arweave.transactions.post(transaction);
console.log(response);

const id = transaction.id;
const imageUrl = id ? `${protocol}://${host}:${port}/${id}` : null;
console.log("imageUrl", imageUrl);

// Upload metadata to Arweave

const metadata = {
name: "Custom NFT #1",
symbol: "CNFT",
description: "A description about my custom NFT #1",
seller_fee_basis_points: 500,
external_url: "https://www.customnft.com/",
attributes: [
{
trait_type: "NFT type",
value: "Custom",
},
],
collection: {
name: "Test Collection",
family: "Custom NFTs",
},
properties: {
files: [
{
uri: imageUrl,
type: "image/png",
},
],
category: "image",
maxSupply: 0,
creators: [
{
address: "CBBUMHRmbVUck99mTCip5sHP16kzGj3QTYB8K3XxwmQx",
share: 100,
},
],
},
image: imageUrl,
};

const metadataString = JSON.stringify(metadata);

const metadataTransaction = await arweave.createTransaction({
data: metadataString,
});

metadataTransaction.addTag("Content-Type", "application/json");

await arweave.transactions.sign(metadataTransaction, wallet);

console.log("metadata txid", metadataTransaction.id);

const txnResult = await arweave.transactions.post(metadataTransaction);

console.log(txnResult);
})();
```

### Mint the NFT

```typescript filename="mint-nft.ts"
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import {
generateSigner,
percentAmount,
keypairIdentity,
} from "@metaplex-foundation/umi";
import { clusterApiUrl } from "@solana/web3.js";
import {
createNft,
fetchDigitalAsset,
mplTokenMetadata,
} from "@metaplex-foundation/mpl-token-metadata";
import "dotenv/config";

(async () => {
try {
console.log("Loading keypair from environment...");
const privateKey = JSON.parse(process.env.SOLANA_PRIVATE_KEY || "[]");
if (privateKey.length === 0) {
throw new Error("SOLANA_PRIVATE_KEY is not set in .env file");
}

console.log("Creating Umi instance...");
const umi = createUmi(clusterApiUrl("devnet"));

const keypair = umi.eddsa.createKeypairFromSecretKey(
new Uint8Array(privateKey),
);

// Use keypairIdentity to set the keypair as the signer
const signer = keypairIdentity(keypair);
umi.use(signer);
umi.use(mplTokenMetadata());

console.log("Keypair loaded. Public key:", keypair.publicKey);

console.log("Generating new mint address...");
const mint = generateSigner(umi);

console.log("Creating NFT...");
const { signature } = await createNft(umi, {
mint,
name: "My NFT",
// Replace this with your Arweave metadata URI
uri: "https://ffaaqinzhkt4ukhbohixfliubnvpjgyedi3f2iccrq4efh3s.arweave.net/KUAIIbk6p8oo4XHRcq0U__C2r0mwQaNl0gQow4Qp9yk",
maxSupply: 1,
sellerFeeBasisPoints: percentAmount(0),
creators: [
{
address: keypair.publicKey,
share: 100,
verified: true,
},
],
}).sendAndConfirm(umi);

console.log("NFT created successfully!");
console.log("Mint address:", mint.publicKey);
console.log("Transaction signature:", signature);

console.log("Fetching digital asset...");
const asset = await fetchDigitalAsset(umi, mint.publicKey);
console.log("Digital Asset:", asset);
} catch (error) {
console.error("Error:", error);
console.error("Stack trace:", error.stack);
}
})();
```
50 changes: 50 additions & 0 deletions content/cookbook/tokens/fetch-all-nfts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: How to get all NFTs from a wallet?
sidebarSortOrder: 18
description:
"Learn how to fetch all non-fungible tokens (NFTs) from a wallet on Solana."
---

```typescript filename="get-nfts-by-wallet.ts"
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { publicKey } from "@metaplex-foundation/umi";
import { fetchAllDigitalAssetWithTokenByOwner } from "@metaplex-foundation/mpl-token-metadata";
import { clusterApiUrl } from "@solana/web3.js";

BigInt.prototype.toJSON = function () {
return this.toString();
};

(async () => {
try {
// Create a UMI instance
const umi = createUmi(clusterApiUrl("devnet"));

// The owner's public key
const ownerPublicKey = publicKey(
"2R4bHmSBHkHAskerTHE6GE1Fxbn31kaD5gHqpsPySVd7",
);

console.log("Fetching NFTs...");
const allNFTs = await fetchAllDigitalAssetWithTokenByOwner(
umi,
ownerPublicKey,
);

console.log(`Found ${allNFTs.length} NFTs for the owner:`);
allNFTs.forEach((nft, index) => {
console.log(`\nNFT #${index + 1}:`);
console.log("Mint Address:", nft.publicKey);
console.log("Name:", nft.metadata.name);
console.log("Symbol:", nft.metadata.symbol);
console.log("URI:", nft.metadata.uri);
});

// If you need the full NFT data
console.log("\nFull NFT data:");
console.log(JSON.stringify(allNFTs, null, 2));
} catch (error) {
console.error("Error:", error);
}
})();
```
59 changes: 59 additions & 0 deletions content/cookbook/tokens/fetch-nft-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: How to Fetch the NFT Metadata
sidebarSortOrder: 16
description:
"Learn how to fetch the metadata of a non-fungible token (NFT) on Solana."
---

```typescript filename="get-nft-metadata.ts"
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import {
createSignerFromKeypair,
generateSigner,
signerIdentity,
} from "@metaplex-foundation/umi";
import {
fetchDigitalAsset,
mplTokenMetadata,
} from "@metaplex-foundation/mpl-token-metadata";
import { PublicKey } from "@metaplex-foundation/js";

(async () => {
try {
// Create a UMI instance
const umi = createUmi("https://api.mainnet-beta.solana.com");

// Use the mplTokenMetadata plugin
umi.use(mplTokenMetadata());

// Generate a new keypair (you can replace this with your own keypair if needed)
const keypair = generateSigner(umi);
umi.use(signerIdentity(createSignerFromKeypair(umi, keypair)));

// The mint address of the NFT you want to fetch
const mintAddress = new PublicKey(
"Ay1U9DWphDgc7hq58Yj1yHabt91zTzvV2YJbAWkPNbaK",
);

console.log("Fetching NFT metadata...");
const asset = await fetchDigitalAsset(umi, mintAddress);

console.log("NFT Metadata:");

// If you want to access specific metadata fields:
console.log("\nName:", asset.metadata.name);
console.log("Symbol:", asset.metadata.symbol);
console.log("URI:", asset.metadata.uri);

// Fetch and log the JSON metadata
if (asset.metadata.uri) {
const response = await fetch(asset.metadata.uri);
const jsonMetadata = await response.json();
console.log("\nJSON Metadata:");
console.log(JSON.stringify(jsonMetadata, null, 2));
}
} catch (error) {
console.error("Error:", error);
}
})();
```
35 changes: 35 additions & 0 deletions content/cookbook/tokens/get-nft-owner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: How to get the owner of an NFT
sidebarSortOrder: 17
description:
"Learn how to get the owner of a non-fungible token (NFT) on Solana."
---

If you have the mint key of an NFT, you can find its current owner by
sneak-peeking at the largest token account for that mint key.

Remember that NFTs have a supply of 1, and they are indivisible, meaning that
only one token account will hold that token at any point in time, whilst all
other token accounts for that mint key will have a balance of 0.

Once the largest token account is identified, we can retrieve its owner.

```typescript filename="get-nft-owner.ts"
import { Connection, PublicKey } from "@solana/web3.js";

(async () => {
const connection = new Connection("https://api.mainnet-beta.solana.com");
const tokenMint = "9ARngHhVaCtH5JFieRdSS5Y8cdZk2TMF4tfGSWFB9iSK";

const largestAccounts = await connection.getTokenLargestAccounts(
new PublicKey(tokenMint),
);
const largestAccountInfo = await connection.getParsedAccountInfo(
largestAccounts.value[0].address,
);
console.log(largestAccountInfo?.value?.data);

const owner = largestAccountInfo?.value?.data?.parsed.info.owner;
console.log("NFT owner :", owner);
})();
```
10 changes: 5 additions & 5 deletions content/courses/connecting-to-offchain-data/oracles.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Oracles can provide just about any type of data onchain. Examples include:
While the exact implementation may differ from blockchain to blockchain,
generally Oracles work as follows:

1. Data is sourced off-chain.
1. Data is sourced offchain.
2. That data is published onchain via a transaction, and stored in an account.
3. Programs can read the data stored in the account and use that data in the
program's logic.
Expand Down Expand Up @@ -82,7 +82,7 @@ On the other hand, you may be less willing to trust a centralized oracle
providing price information for trading applications.

You may end up creating many standalone oracles for your own applications simply
as a way to get access to off-chain information that you need. However, those
as a way to get access to offchain information that you need. However, those
oracles are unlikely to be used by the broader community where decentralization
is a core tenet. You should also be hesitant to use centralized, third-party
oracles yourself.
Expand Down Expand Up @@ -138,7 +138,7 @@ verify each oracle’s software to allow participation in the network. If an
oracle operator acts maliciously and attempts to change the operation of the
approved code, a data quote verification will fail. This allows Switchboard
oracles to operate beyond quantitative value reporting, such as functions --
running off-chain custom and confidential computations.
running offchain custom and confidential computations.

### Switchboard Oracles

Expand All @@ -158,7 +158,7 @@ understand how Switchboard works:
Each data source should correspond to a job account. The job account is a
collection of Switchboard tasks used to instruct the oracles on how to fetch
and transform data. In other words, it stores the blueprints for how data is
fetched off-chain for a particular data source.
fetched offchain for a particular data source.
- **Oracle** - A separate program that sits between the internet and the
blockchain and facilitates the flow of information. An oracle reads a feed’s
job definitions, calculates the result, and submits its response onchain.
Expand Down Expand Up @@ -235,7 +235,7 @@ data is published onchain:

#### How to use Switchboard Oracles

To use Switchboard oracles and incorporate off-chain data into a Solana program,
To use Switchboard oracles and incorporate offchain data into a Solana program,
you first have to find a feed that provides the data you need. Switchboard feeds
are public and there are many
[already available that you can choose from](https://app.switchboard.xyz/solana/devnet/explore).
Expand Down
Loading

0 comments on commit 24c8dde

Please sign in to comment.