> For the complete documentation index, see [llms.txt](https://sevenheaven.gitbook.io/sevenheaven/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sevenheaven.gitbook.io/sevenheaven/tokenization/eternal-tokens.md).

# Eternal-Tokens

Eternal Tokens Suggest Enhancements Introduction Eternal tokens represent a distinct category of blockchain assets adhering to the SPL 1 standard. Notably, these tokens exhibit an inherent characteristic: they are impervious to transfers between different wallet addresses. Once an Eternal token is crafted for a specific wallet address, any attempt to transfer or exchange it to another address is categorically restricted. This unique feature finds utility in scenarios where the creation of exclusive digital items or rewards for designated users is paramount.

Benefits of Employing Eternal Tokens Several advantages accompany the utilization of Eternal tokens:

1. Unparalleled Rewards: The creation of Eternal tokens ensures that each reward or item remains exclusively tied to a particular user. This exclusivity enhances the perceived value of the item, rendering it more meaningful to the user.
2. Enhanced Security: By curbing the transferability of tokens to alternative wallet addresses, the risk of token theft or misuse is effectively mitigated.
3. Unmatched Control: Eternal tokens furnish an elevated level of control over token distribution and utilization. This control ensures that tokens are strictly employed for their intended purpose and by their designated recipients.

Creating an Eternal Token via the Co:Create API To initiate the creation of an Eternal token using the Co:Create API, familiar methods for crafting SPL tokens are employed. However, distinct configurations must be applied to enforce the Eternal nature of the token.

Follow these steps to fabricate an Eternal token:

1. Initiate a New SPL  Token

   * Dispatch a POST request to the SPL  API. Essential parameters include:

     * `name`: The designated name of your token.
     * `symbol`: The symbol representing your token, conventionally in uppercase.
     * `base_uri`: The off-chain file corresponding to your token (further details available here).
     * `transfer_restricted`: Set to true to inhibit token transfers, the defining characteristic of an Eternal token.
     * `transfer_allowlist` : Facilitates the addition of a comma-separated list of addresses authorized to engage in transfers of the token.<br>

     **Bulk distribute NFT items to holders**

   `import { Commitment, Keypair, LAMPORTS_PER_SOL, PublicKey, Signer, } from "@solana/web3.js"; import { ConnectionManager, TransactionWrapper, Logger, TransactionBuilder, } from "@solworks/soltoolkit-sdk"; import { getAssociatedTokenAddress, createTransferCheckedInstruction, createAssociatedTokenAccountInstruction } from "@solana/spl-token"; import { Metaplex } from "@metaplex-foundation/js"; import * as fs from "fs";`

   `// This script will: // 1. Iterate through a list of mint addresses // 2. Create an associated token account for each mint address // 3. Transfer 1 NFT to each associated token account // 4. Confirm the transaction // 5. Log the transaction hash and result along with any errors const rpcEndpoint = 'https://api.mainnet-beta.solana.com'; const commitment: Commitment = "max"; const skipSending = false; const sender = Keypair.fromSecretKey(Uint8Array.from([...])); const minters = [{ "address": "...", "items": 3 }, { "address": "...", "items": 3 }, { "address": "...", "items": 12 }];`

   `(async () => { const logger = new Logger("nft-transfer"); const cm = await ConnectionManager.getInstance({ commitment, endpoint: rpcEndpoint, mode: "single", network: "mainnet-beta", }); const mp = new Metaplex(cm._connection);`

   `// get SOL balance of sender logger.debug("Fetching SOL balance of", sender.publicKey.toBase58()); let senderSOLBal = await cm .connSync({ changeConn: false }) .getBalance(sender.publicKey, commitment); logger.debug(Sender balance: ${senderSOLBal / LAMPORTS_PER_SOL} SOL);`

   `let results: IResults = { success: [], failure: [], }; // iterate through mints for (let i = 0; i < minters.length; i++) { // get NFTs owned by sender const nftsOwnedBySender = await mp .nfts() .findAllByOwner({ owner: sender.publicKey }); logger.debug("NFTs owned by sender:", nftsOwnedBySender.length); const receivingOwner = new PublicKey(minters[i].address); const nftsToSend = minters[i].items;`

   ```
   // find minted nfts to send
   for (let k = 0; k < nftsToSend; k++) {
     if (nftsOwnedBySender.length === 0) {
       logger.debug("No more NFTs to send");
       break;
     }

     const nftToSend = nftsOwnedBySender[k];
     logger.debug("NFT to send:", nftToSend);
     const sendingMint = (nftToSend as any).mintAddress;
     logger.debug("Sending mint:", sendingMint.toBase58());

     try {    
       let sendingAta = await getAssociatedTokenAddress(sendingMint, sender.publicKey);
       logger.debug("Sending ATA:", sendingAta.toBase58());

       let receivingAta = await getAssociatedTokenAddress(sendingMint, receivingOwner);
       logger.debug("Receiving ATA:", receivingAta.toBase58());

       // generate tx to transfer NFT to ATA
       // create associated token account
       const tx = TransactionBuilder
         .create()
         .addIx([
             createAssociatedTokenAccountInstruction(
               sender.publicKey,
               receivingAta,
               receivingOwner,
               sendingMint
             ),
             createTransferCheckedInstruction(
               sendingAta,
               sendingMint,
               receivingAta,
               sender.publicKey,
               1,
               0
             )
           ])
         .build();


       if (!skipSending) {
         // feed transaction into TransactionWrapper
         const wrapper = await TransactionWrapper
           .create({
             connectionManager: cm,
             transaction: tx,
             signer: sender.publicKey,
           })
           .addBlockhashAndFeePayer(sender.publicKey);

         // sign the transaction
         logger.debug(`Signing transaction ${i + 1}`);
         const signedTx = await wrapper.sign({ signer: sender as Signer });

         // send and confirm the transaction
         logger.debug(`Sending transaction ${i + 1}`);
         const transferSig = await wrapper.sendAndConfirm({ 
           serialisedTx: signedTx.serialize(), 
           commitment 
         });
         logger.debug("Transaction sent:", transferSig.toString());

         results.success.push({
           sentTicketMint: sendingMint.toBase58(),
           ticketHeldMint: receivingOwner,
         });

         await sleep(3_000);
       }
     } catch (e: any) {
       logger.error(e);
       results.failure.push({
         sentTicketMint: sendingMint.toBase58(),
         ticketHeldMint: receivingOwner.toBase58()
       });
     }
   }
   ```

   }

   fs.writeFileSync("results.json", JSON.stringify(results)); })();

   interface IResults { success: Array; failure: Array; } function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); }


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sevenheaven.gitbook.io/sevenheaven/tokenization/eternal-tokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
