Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nodejs - Add Irc27Metadata and Irc30Metadata #1261

Merged
merged 14 commits into from
Sep 25, 2023
18 changes: 7 additions & 11 deletions bindings/nodejs/examples/client/15-build-nft-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
SenderFeature,
Ed25519Address,
IssuerFeature,
Irc27Metadata,
} from '@iota/sdk';
require('dotenv').config({ path: '.env' });

Expand All @@ -35,14 +36,11 @@ async function run() {
'rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy',
);

// IOTA NFT Standard - IRC27: https://github.com/iotaledger/tips/blob/main/tips/TIP-0027/tip-0027.md
const tip27ImmutableMetadata = {
standard: 'IRC27',
version: 'v1.0',
type: 'image/jpeg',
uri: 'https://mywebsite.com/my-nft-files-1.jpeg',
name: 'My NFT #0001',
};
const tip27ImmutableMetadata = new Irc27Metadata(
'image/jpeg',
'https://mywebsite.com/my-nft-files-1.jpeg',
'My NFT #0001',
);

const nftOutput = await client.buildNftOutput({
// NftId needs to be null the first time
Expand All @@ -52,9 +50,7 @@ async function run() {
],
immutableFeatures: [
new IssuerFeature(new Ed25519Address(hexAddress)),
new MetadataFeature(
utf8ToHex(JSON.stringify(tip27ImmutableMetadata)),
),
new MetadataFeature(tip27ImmutableMetadata.asHex()),
],
features: [
new SenderFeature(new Ed25519Address(hexAddress)),
Expand Down
10 changes: 8 additions & 2 deletions bindings/nodejs/examples/how_tos/native_tokens/create.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { CreateNativeTokenParams, utf8ToHex } from '@iota/sdk';
import { CreateNativeTokenParams, Irc30Metadata } from '@iota/sdk';

import { getUnlockedWallet } from '../../wallet/common';

Expand Down Expand Up @@ -51,11 +51,17 @@ async function run() {

console.log('Preparing transaction to create native token...');

const metadata = new Irc30Metadata(
'My Native Token',
'MNT',
10,
).withDescription('A native token to test the iota-sdk.');

// If we omit the AccountAddress field the first address of the account is used by default
const params: CreateNativeTokenParams = {
circulatingSupply: CIRCULATING_SUPPLY,
maximumSupply: MAXIMUM_SUPPLY,
foundryMetadata: utf8ToHex('Hello, World!'),
foundryMetadata: metadata.asHex(),
};

const prepared = await account.prepareCreateNativeToken(params);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { MintNftParams, NftId, utf8ToHex, Utils, Wallet } from '@iota/sdk';
import { MintNftParams, NftId, Utils, Wallet, Irc27Metadata } from '@iota/sdk';
require('dotenv').config({ path: '.env' });

// The NFT collection size
Expand Down Expand Up @@ -48,9 +48,7 @@ async function run() {
// Create the metadata with another index for each
for (let index = 0; index < NFT_COLLECTION_SIZE; index++) {
const params: MintNftParams = {
immutableMetadata: utf8ToHex(
getImmutableMetadata(index, issuerNftId),
),
immutableMetadata: getImmutableMetadata(index).asHex(),
// The NFT address from the NFT we minted in mint_issuer_nft example
issuer,
};
Expand Down Expand Up @@ -97,21 +95,18 @@ async function run() {
process.exit(0);
}

function getImmutableMetadata(index: number, issuerNftId: NftId) {
// Note: we use parse and stringify to remove all unnecessary whitespace
return JSON.stringify(
JSON.parse(`{
"standard":"IRC27",
"version":"v1.0",
"type":"video/mp4",
"uri":"ipfs://wrongcVm9fx47YXNTkhpMEYSxCD3Bqh7PJYr7eo5Ywrong",
"name":"Shimmer OG NFT ${index}",
"description":"The Shimmer OG NFT was handed out 1337 times by the IOTA Foundation to celebrate the official launch of the Shimmer Network.",
"issuerName":"IOTA Foundation",
"collectionId":"${issuerNftId}",
"collectionName":"Shimmer OG"
}`),
);
function getImmutableMetadata(index: number) {
return new Irc27Metadata(
'video/mp4',
'https://ipfs.io/ipfs/QmPoYcVm9fx47YXNTkhpMEYSxCD3Bqh7PJYr7eo5YjLgiT',
`Shimmer OG NFT ${index}`,
)
.withDescription(
'The Shimmer OG NFT was handed out 1337 times by the IOTA Foundation \
to celebrate the official launch of the Shimmer Network.',
)
.withIssuerName('IOTA Foundation')
.withCollectionName('Shimmer OG');
}

run();
11 changes: 8 additions & 3 deletions bindings/nodejs/examples/how_tos/nfts/mint_nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
utf8ToHex,
Utils,
Wallet,
Irc27Metadata,
} from '@iota/sdk';
require('dotenv').config({ path: '.env' });

Expand All @@ -18,8 +19,6 @@ const NFT1_OWNER_ADDRESS =
'rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu';
// The metadata of the first minted NFT
const NFT1_METADATA = utf8ToHex('some NFT metadata');
// The immutable metadata of the first minted NFT
const NFT1_IMMUTABLE_METADATA = utf8ToHex('some NFT immutable metadata');
// The tag of the first minted NFT
const NFT1_TAG = utf8ToHex('some NFT tag');
// The base coin amount we sent with the second NFT
Expand Down Expand Up @@ -52,13 +51,19 @@ async function run() {
// We need to unlock stronghold.
await wallet.setStrongholdPassword(process.env.STRONGHOLD_PASSWORD);

const metadata = new Irc27Metadata(
'video/mp4',
'https://ipfs.io/ipfs/QmPoYcVm9fx47YXNTkhpMEYSxCD3Bqh7PJYr7eo5YjLgiT',
'Shimmer OG NFT',
).withDescription('The original Shimmer NFT');

const params: MintNftParams = {
address: NFT1_OWNER_ADDRESS, // Remove or change to senderAddress to send to self
sender: senderAddress,
metadata: NFT1_METADATA,
tag: NFT1_TAG,
issuer: senderAddress,
immutableMetadata: NFT1_IMMUTABLE_METADATA,
immutableMetadata: metadata.asHex(),
};
let transaction = await account.mintNfts([params]);
console.log(`Transaction sent: ${transaction.transactionId}`);
Expand Down
2 changes: 2 additions & 0 deletions bindings/nodejs/lib/types/block/output/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export * from './feature';
export * from './unlock-condition';
export * from './output';
export * from './token-scheme';
export * from './irc-27';
export * from './irc-30';
106 changes: 106 additions & 0 deletions bindings/nodejs/lib/types/block/output/irc-27.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { utf8ToHex } from '../../../utils';

/**
* The IRC27 NFT standard schema.
*/
class Irc27Metadata {
/** The IRC standard */
readonly standard: string = 'IRC27';
/** The current version. */
readonly version: string = 'v1.0';
/** The media type (MIME) of the asset.
*
* ## Examples
* - Image files: `image/jpeg`, `image/png`, `image/gif`, etc.
* - Video files: `video/x-msvideo` (avi), `video/mp4`, `video/mpeg`, etc.
* - Audio files: `audio/mpeg`, `audio/wav`, etc.
* - 3D Assets: `model/obj`, `model/u3d`, etc.
* - Documents: `application/pdf`, `text/plain`, etc.
*/
type: string;
/** URL pointing to the NFT file location. */
uri: string;
/** The human-readable name of the native token. */
name: string;
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
/** The human-readable collection name of the native token. */
collectionName?: string;
/** Royalty payment addresses mapped to the payout percentage. */
royalties: Map<string, number> = new Map();
/** The human-readable name of the native token creator. */
issuerName?: string;
/** The human-readable description of the token. */
description?: string;
/** Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). */
attributes: Attribute[] = [];
abdulmth marked this conversation as resolved.
Show resolved Hide resolved

/**
* @param type The media type (MIME) of the asset.
* @param uri URL pointing to the NFT file location.
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
* @param name The human-readable name of the native token.
*/
constructor(type: string, uri: string, name: string) {
this.type = type;
this.uri = uri;
this.name = name;
}

withCollectionName(collectionName: string): Irc27Metadata {
this.collectionName = collectionName;
return this;
}

addRoyalty(address: string, percentage: number): Irc27Metadata {
this.royalties.set(address, percentage);
return this;
}

withRoyalties(royalties: Map<string, number>): Irc27Metadata {
this.royalties = royalties;
return this;
}

withIssuerName(issuerName: string): Irc27Metadata {
this.issuerName = issuerName;
return this;
}

withDescription(description: string): Irc27Metadata {
this.description = description;
return this;
}

addAttribute(attribute: Attribute): Irc27Metadata {
this.attributes.push(attribute);
return this;
}

withAttributes(attributes: Array<Attribute>): Irc27Metadata {
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
this.attributes = attributes;
return this;
}

asHex(): string {
return utf8ToHex(JSON.stringify(this));
}
}

class Attribute {
trait_type: string;
value: any;
display_type?: string;

constructor(trait_type: string, value: any) {
this.trait_type = trait_type;
this.value = value;
}

withDisplayType(display_type: string): Attribute {
this.display_type = display_type;
return this;
}
}

export { Irc27Metadata, Attribute };
63 changes: 63 additions & 0 deletions bindings/nodejs/lib/types/block/output/irc-30.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { utf8ToHex } from '../../../utils';

/**
* The IRC30 native token metadata standard schema.
*/
class Irc30Metadata {
/** The IRC standard */
readonly standard: string = 'IRC30';
/** The human-readable name of the native token. */
name: string;
/** The symbol/ticker of the token. */
symbol: string;
/** Number of decimals the token uses (divide the token amount by `10^decimals` to get its user representation). */
decimals: number;
/** The human-readable description of the token. */
description?: string;
/** URL pointing to more resources about the token. */
url?: string;
/** URL pointing to an image resource of the token logo. */
logoUrl?: string;
/** The svg logo of the token encoded as a byte string. */
logo?: string;

/**
* @param name The human-readable name of the native token.
* @param symbol The symbol/ticker of the token.
* @param decimals Number of decimals the token uses.
*/
constructor(name: string, symbol: string, decimals: number) {
this.name = name;
this.symbol = symbol;
this.decimals = decimals;
}

withDescription(description: string): Irc30Metadata {
this.description = description;
return this;
}

withUrl(url: string): Irc30Metadata {
this.url = url;
return this;
}

withLogoUrl(logoUrl: string): Irc30Metadata {
this.logoUrl = logoUrl;
return this;
}

withLogo(logo: string): Irc30Metadata {
this.logo = logo;
return this;
}

asHex(): string {
return utf8ToHex(JSON.stringify(this));
}
}

export { Irc30Metadata };
5 changes: 3 additions & 2 deletions sdk/src/types/block/output/feature/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ pub(crate) mod irc_30 {

use super::*;

/// The IRC30 NFT standard schema.
/// The IRC30 native token metadata standard schema.
#[derive(Clone, Debug, Serialize, Deserialize, Getters, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "standard", rename = "IRC30")]
Expand All @@ -322,7 +322,8 @@ pub(crate) mod irc_30 {
name: String,
/// The symbol/ticker of the token.
symbol: String,
/// Number of decimals the token uses (divide the token amount by 10^decimals to get its user representation).
/// Number of decimals the token uses (divide the token amount by `10^decimals` to get its user
/// representation).
decimals: u32,
/// The human-readable description of the token.
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand Down
Loading