Skip to content

Add examples using CSL to create simple, metadata, minting tokens/nft transactions #726

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions doc/getting-started/metadata_tx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import * as CSL from "@emurgo/cardano-serialization-lib-nodejs";
import { mnemonicToEntropy } from "bip39";
import { Buffer } from "node:buffer";

const MNEMONIC = "key in your 24 words of your mnemonic here, words separated by spaces";
const INPUT_HASH ="9fc9bb3ea1f2540ae870076e6543b5d804566a548db9da9e16c5271596e8dc9d"
const INPUT_INDEX =1;
const INPUT_AMOUNT = "113185492" ; //Lovelace on your UTXO
const TO_ADDRESS="addr_test1your_address_in_bech32";
const AMOUNT="2000000";

function harden(num: number): number {
return 0x80000000 + num;
}

//Step 1.========= Retrieve root key===============
const entropy = mnemonicToEntropy(MNEMONIC);
// retrieve root key in hex
const rootKey = CSL.Bip32PrivateKey.from_bip39_entropy(
Buffer.from(entropy, "hex"),
Buffer.from("")
);

// Retrieve child private key at m/1852H/1815H/0H/0/0 and m/1852H/1815H/0H/2/0
const accountKey = rootKey
.derive(harden(1852))
.derive(harden(1815))
.derive(harden(0));
const utxoPrivKey = accountKey.derive(0).derive(0);
const stakePrivKey = accountKey.derive(2).derive(0);
const paymentKey = utxoPrivKey.to_raw_key();

// Retrieve payment credential + stake credential
const addr = CSL.BaseAddress.new(
CSL.NetworkInfo.testnet_preprod().network_id(),
CSL.Credential.from_keyhash(utxoPrivKey.to_public().to_raw_key().hash()),
CSL.Credential.from_keyhash(stakePrivKey.to_public().to_raw_key().hash()) ///not need for non-stake tx
);

//Step 2.========= instantiate the tx builder with the Cardano protocol parameters - these may change later on===============
const linearFee = CSL.LinearFee.new(
CSL.BigNum.from_str("44"),
CSL.BigNum.from_str("155381")
);
const txBuilderCfg = CSL.TransactionBuilderConfigBuilder.new()
.fee_algo(linearFee)
.pool_deposit(CSL.BigNum.from_str("500000000"))
.key_deposit(CSL.BigNum.from_str("2000000"))
.max_value_size(5000)
.max_tx_size(16384)
.coins_per_utxo_byte(CSL.BigNum.from_str("4310"))
.build();

const txBuilder = CSL.TransactionBuilder.new(txBuilderCfg);

//Step 3.========= Define and add inputs to transaction=================
const txInputsBuilder = CSL.TxInputsBuilder.new();
txInputsBuilder.add_regular_input(addr.to_address(),
CSL.TransactionInput.new(CSL.TransactionHash.from_hex(INPUT_HASH), INPUT_INDEX),
CSL.Value.new(CSL.BigNum.from_str(INPUT_AMOUNT))
);
txBuilder.set_inputs(txInputsBuilder);

//Step 4.========= Define and add output to the tx to transaction========
const DESTINATION_ADDRESS = CSL.Address.from_bech32(TO_ADDRESS);
txBuilder.add_output(
CSL.TransactionOutput.new(DESTINATION_ADDRESS,
CSL.Value.new(CSL.BigNum.from_str(AMOUNT))
),
);

//Step 5.========= Define and add metadata tx to transaction========
const metadata = CSL.GeneralTransactionMetadata.new();
const metadataKey = CSL.BigNum.from_str("674");
const metadataValue = CSL.encode_json_str_to_metadatum(
JSON.stringify({ message: "hello metadata" }),
CSL.MetadataJsonSchema.BasicConversions
);
metadata.insert(metadataKey, metadataValue);

// add metadata as auxiliary data to tx.
const auxData = CSL.AuxiliaryData.new();
auxData.set_metadata(metadata);
txBuilder.set_auxiliary_data(auxData);

// calculate the min fee required and send any change to an address
txBuilder.add_change_if_needed(addr.to_address());


const tx = txBuilder.build_tx()
const fixedTx = CSL.FixedTransaction.from_bytes(tx.to_bytes());
let txHash = fixedTx.transaction_hash();

// Step 6.=========Make and add vkey witness if it necessary========
const vkeyWitness = CSL.make_vkey_witness(txHash,paymentKey);
fixedTx.add_vkey_witness(vkeyWitness)

// Step 7.=========Serialize Transaction to hex========
const txSerialized = fixedTx.to_hex();
console.log("Transaction serialized:", txSerialized);




171 changes: 171 additions & 0 deletions doc/getting-started/minint_nft.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import {
LinearFee,
PrivateKey,
BigNum,
TransactionBuilderConfigBuilder,
TransactionBuilder,
NativeScripts,
NativeScript,
ScriptPubkey,
ScriptAll,
AssetName,
Int,
TransactionOutputBuilder,
TransactionWitnessSet,
Vkeywitnesses,
make_vkey_witness,
Transaction,
Bip32PrivateKey,
BaseAddress,
NetworkInfo,
Credential,
FixedTransaction,
TransactionInput,
TransactionHash,
Value,
} from "@emurgo/cardano-serialization-lib-nodejs-gc";
import { mnemonicToEntropy } from "bip39";
import { Buffer } from "node:buffer";
import cbor from "cbor";

const mintNft = async (
privateKey,
policyPrivateKey,
assetName,
description,
imageUrl,
mediaType,
tx_hash,
tx_index,
amount
) =>
{
//==============Retrieve publicKey, addr, policyPubKey, PolicyAddr from private keys ===============
const publicKey = privateKey.to_public();
const addr = BaseAddress.new(
NetworkInfo.testnet_preprod().network_id(),
Credential.from_keyhash(publicKey.hash()),
Credential.from_keyhash(publicKey.hash())
).to_address();

const policyPubKey = policyPrivateKey.to_public();
const policyKeyHash = policyPubKey.hash();
const policyAddr = BaseAddress.new(
NetworkInfo.testnet_preprod().network_id(),
Credential.from_keyhash(policyPubKey),
Credential.from_keyhash(policyPubKey)
).to_address();



//==============Sets transaction parameters like fees, deposits, and size limits================
const linearFee = LinearFee.new(
BigNum.from_str("44"),
BigNum.from_str("155381")
);
const txBuilderCfg = TransactionBuilderConfigBuilder.new()
.fee_algo(linearFee)
.pool_deposit(BigNum.from_str("500000000"))
.key_deposit(BigNum.from_str("2000000"))
.max_value_size(5000)
.max_tx_size(16384)
.coins_per_utxo_byte(BigNum.from_str("4310"))
.build();
const txBuilder = TransactionBuilder.new(txBuilderCfg);
const scripts = NativeScripts.new();

//==============add key hash script so only people with policy key can mint assets using this policyId
const keyHashScript = NativeScript.new_script_pubkey(
ScriptPubkey.new(policyKeyHash)
);
scripts.add(keyHashScript);

const mintScript = NativeScript.new_script_all(
ScriptAll.new(scripts)
);

const paymentKeyHash = BaseAddress.from_address(addr)
.payment_cred()
.to_keyhash();

txBuilder.add_key_input(
paymentKeyHash,
TransactionInput.new(
TransactionHash.from_hex(tx_hash),
tx_index
),
Value.new(BigNum.from_str(amount))
);

txBuilder.add_mint_asset_and_output_min_required_coin(
mintScript,
AssetName.new(Buffer.from(assetName)),
Int.new_i32(1),
TransactionOutputBuilder.new().with_address(addr).next()
);
const policyId = Buffer.from(mintScript.hash().to_bytes()).toString("hex");
const metadata = {
[policyId]: {
[assetName]: {
name: assetName,
description,
image: imageUrl,
mediaType,
},
},
};

console.log(`METADATA: ${JSON.stringify(metadata, null, 4)}`);

txBuilder.add_json_metadatum(
BigNum.from_str("721"),
JSON.stringify(metadata)
);

txBuilder.add_change_if_needed(addr);

const tx = txBuilder.build_tx();
const fixedTx = FixedTransaction.from_bytes(tx.to_bytes());
let txHash = fixedTx.transaction_hash();

console.log(`TX_HASH: ${txHash.to_hex()}`);

//==============Add signatures=====================
fixedTx.sign_and_add_vkey_signature(privateKey);
fixedTx.sign_and_add_vkey_signature(policyPrivateKey);

const unsignedTx = txBuilder.build_tx();

const signedTx = fixedTx.to_hex();
console.log(`Minting NFT siged tx: ${signedTx}`)
};

try {
const privateKey = PrivateKey.from_bech32(
"ed25519e_sk1your_key"
);
const policyPrivateKey = PrivateKey.from_bech32(
"ed25519e_sk1your_key"
);

//==============Select UTXO that is probably big enough to pay the tx fee===============
const tx_hash="5a4925b330916e62307766802f5af4ce8b234c27de8271a901086c08733da0f1";
const tx_index="1";
const amount="31009807";
await mintNft(
privateKey,
{
privateKey: policyPrivateKey
},
"CSL_101", // assetName
"Description about NFT", // description
"ipfs://QmSUfz3aeFjufYo9RnQauBaoQhGD27BwMYzZSvtsJ714BP", // image url
"image/jpeg", // mediaType
tx_hash,
tx_index,
amount
);
}
catch (err) {
console.error(`failed to mint nft: ${err.toString()}`);
}
122 changes: 122 additions & 0 deletions doc/getting-started/minting_tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {
LinearFee,
PrivateKey,
BigNum,
TransactionBuilderConfigBuilder,
TransactionBuilder,
NativeScripts,
NativeScript,
ScriptPubkey,
ScriptAll,
AssetName,
Int,
TransactionOutputBuilder,
TransactionWitnessSet,
Vkeywitnesses,
make_vkey_witness,
Transaction,
Bip32PrivateKey,
BaseAddress,
NetworkInfo,
Credential,
FixedTransaction,
TransactionInput,
TransactionHash,
Value,
} from "@emurgo/cardano-serialization-lib-nodejs-gc";
import { mnemonicToEntropy } from "bip39";
import { Buffer } from "node:buffer";


const MNEMONIC = "fill in 24 words of your mnemonic here";
const INPUT_HASH ="9171d747c58f1f582c0973d7d5c832e2ef5dd9738c208e0b72a10481ce187e45"
const INPUT_INDEX =1; //tx_ix of your utxo
const INPUT_AMOUNT = "41611646" ; //Lovelace on your UTXO
const TOKEN_NAME ="TOKEN_ABC";
const AMOUNT="2000000";

function harden(num: number): number {
return 0x80000000 + num;
}

//==============Retrieve hierarchical deterministic (HD) root key ===============
const entropy = mnemonicToEntropy(MNEMONIC);
// retrieve root key in hex
const rootKey = Bip32PrivateKey.from_bip39_entropy(
Buffer.from(entropy, "hex"),
Buffer.from("")
);

//==============Derives child private keys from the root key using the CIP-1852 derivation path=====
const accountKey = rootKey
.derive(harden(1852))
.derive(harden(1815))
.derive(harden(0));
const utxoPrivKey = accountKey.derive(0).derive(0);
const stakePrivKey = accountKey.derive(2).derive(0);

const payment_skey = utxoPrivKey.to_raw_key();
const payment_vkey = payment_skey.to_public();
const publicKeyHash = payment_vkey.hash();

//==============Creates a Cardano BaseAddress using the payment public key hash and staking public key hash====
const addr = BaseAddress.new(
NetworkInfo.testnet_preprod().network_id(),
Credential.from_keyhash(publicKeyHash),
Credential.from_keyhash(stakePrivKey.to_raw_key().to_public().hash())
).to_address();

//==============Sets transaction parameters like fees, deposits, and size limits================
const linearFee = LinearFee.new(
BigNum.from_str("44"),
BigNum.from_str("155381")
);
const txBuilderCfg = TransactionBuilderConfigBuilder.new()
.fee_algo(linearFee)
.pool_deposit(BigNum.from_str("500000000"))
.key_deposit(BigNum.from_str("2000000"))
.max_value_size(5000)
.max_tx_size(16384)
.coins_per_utxo_byte(BigNum.from_str("4310"))
.build();
const txBuilder = TransactionBuilder.new(txBuilderCfg);

//==============Creates a minting policy script by using the payment public key hash================
const policyScript = NativeScript.new_script_pubkey(
ScriptPubkey.new(publicKeyHash)); // you could use other keys instead of using publickey
const scripts = NativeScripts.new();
scripts.add(policyScript);
const mintScript = NativeScript.new_script_all(
ScriptAll.new(scripts)
);

//==============Specify assesst name and amount of token=============
const assetName = AssetName.new(Buffer.from(TOKEN_NAME, 'utf8'));
txBuilder.add_mint_asset_and_output_min_required_coin(
mintScript,assetName,
Int.new_i32(AMOUNT),
TransactionOutputBuilder.new().with_address(addr).next()
);

//==============Adds an input to the transaction=====================
txBuilder.add_key_input(
publicKeyHash,
TransactionInput.new(
TransactionHash.from_bytes(Buffer.from(INPUT_HASH, "hex")),
INPUT_INDEX
),Value.new(BigNum.from_str(INPUT_AMOUNT))
);

txBuilder.add_change_if_needed(addr);

const tx = txBuilder.build_tx();
const fixedTx = FixedTransaction.from_bytes(tx.to_bytes());
let txHash = fixedTx.transaction_hash();
console.log(`Tx_hash of transaction: ${txHash.to_hex()}`);

//==============Sign transaction=====================
fixedTx.sign_and_add_vkey_signature(payment_skey);

const signedTx = fixedTx.to_hex();

console.log(`CBOR of signed transaction: ${signedTx}`);
Loading