> For the complete documentation index, see [llms.txt](/llms.txt).

### **1. Understanding the Contract Structure**

This contract defines a new token type, **RuneToken**, based on the **ERC-1155 standard**. It also uses the **Ownable** contract, which restricts certain functions to the contract's owner.

#### **Key Imports:**

```
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
```

- **ERC1155**: This is a token standard that supports both fungible and non-fungible tokens within the same contract.
- **Ownable**: This contract standard restricts certain actions to only the contract's owner (the one who deployed it or someone assigned as the owner).
- **Strings**: A utility library for working with string conversions.

### **Main Components of the Contract**

#### **Events:**

- `TokensFrozen`: Emits an event when tokens are frozen for a specific account.
- `TokensUnfrozen`: Emits an event when tokens are unfrozen.

#### **Data Structures:**

- **Balance**: Holds the account and balance of a token.
- **TokenInfo**: Contains details about a token, such as its URI ( **Uniform Resource Identifier**), name, symbol, maximum supply, current supply, default minting amount, and balance.

#### **Mappings:**

- `_tokenInfos`: Stores the information about each token, keyed by the token ID.
- `_userTokens`: Tracks all tokens held by a user.
- `_frozenTokens`: Keeps track of how many tokens are frozen for each user.

###

### **2. The Constructor**

```
constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {}
```

- **ERC1155 ("")**: This calls the ERC1155 constructor, but the URI is set as an empty string initially.
- **Ownable (initialOwner)**: The `Ownable` contract is initialized with the `initialOwner` as the owner of the contract, allowing only this address to perform certain actions (e.g., minting).

### **3. The `uri` Function**

```
function uri(uint256 tokenId) public view override returns (string memory) {
    return _tokenInfos[tokenId].uri;
}
```

This function returns the URI for a given token ID. The URI typically points to a metadata file that contains additional details about the token (e.g., images, descriptions).

### **4. Minting Fungible Tokens**

```
function mintFungible(
    string memory tokenURI,
    string memory runeName,
    string memory symbol,
    uint256 maxSupply,
    uint256 initialSupply,
    uint256 defaultMintAmount,
    address receiver
) public onlyOwner {
    // Function logic here
}
```

This function allows the owner of the contract to mint fungible tokens.

#### **Steps Involved:**

1. **Check max supply**: Ensure that the initial supply is not greater than the maximum allowed supply.
2. **Generate a token ID**: A unique token ID is created by hashing the `runeName` using `keccak256`.
3. **Token ID uniqueness check**: Ensure that the token ID doesn't already exist.
4. **Save Token Info**: Store details about the token in the `_tokenInfos` mapping.
5. **Mint the token**: Mint the specified amount (`initialSupply`) to the `receiver` address.
6. **Track ownership**: Add the minted token to the user's list of owned tokens using `_addUserToken`.

### **5. Minting Non-Fungible Tokens (NFTs)**

```
function mintNonFungible(
    string memory tokenURI,
    string memory runeName,
    string memory symbol,
    address receiver
) public onlyOwner {
    // Function logic here
}
```

This function is similar to `mintFungible` but for minting non-fungible tokens. A non-fungible token is a unique token, meaning only one exists.

#### **Key Differences:**

- **Max Supply** is always `1` for non-fungible tokens.
- **Current Supply** is also set to `1`.

### **6. Minting More Tokens**

```
function mintMore(
    string memory runeName,
    address receiver
) external onlyOwner {
    // Function logic here
}
```

This function allows the contract owner to mint additional tokens of an existing fungible token, as long as the new supply doesn’t exceed the maximum supply.

#### **Key Steps:**

1. **Check token existence**: Ensure the token exists by checking its `maxSupply`.
2. **Check supply limits**: Ensure the current supply plus the new minting amount doesn’t exceed the max supply.
3. **Mint tokens**: Mint more tokens to the `receiver`.

### **7. Token Freezing and Unfreezing**

#### **Freezing Tokens:**

```
function freezeTokens(string memory runeName, uint256 amount, address owner) external onlyOwner {
    // Function logic here
}
```

- Freezing tokens restricts the user from transferring them.
- The function ensures that the account has sufficient tokens to freeze.
- The frozen amount is added to `_frozenTokens`.

#### **Unfreezing Tokens:**

```
function unfreezeTokens(string memory runeName, uint256 amount, address owner) external onlyOwner {
    // Function logic here
}
```

- This function unfreezes the tokens, allowing the user to transfer them again.
- The frozen amount is reduced from `_frozenTokens`.

### **8. Token Information Queries**

#### **Get Token Information:**

```
function getTokenInfo(uint256 tokenId, address holder) public view returns (TokenInfo memory) {
    // Function logic here
}
```

- This function retrieves the details about a token (such as URI, name, symbol, max supply, etc.).
- It can also include the token balance of a specific `holder` if the `holder` address is provided.

#### **Get Tokens Owned by a User:**

```
function getUserTokens(address user) public view returns (uint256[] memory) {
    return _userTokens[user];
}
```

- This function returns a list of all token IDs owned by a specific user.

### **9. Token Transfer Functions with Freezing Consideration**

ERC1155 includes transfer functions (`safeTransferFrom` and `safeBatchTransferFrom`). These are overridden in this contract to take into account frozen tokens.

```
function safeTransferFrom(
    address from,
    address to,
    uint256 id,
    uint256 amount,
    bytes memory data
) public virtual override {
    require(balanceOf(from, id) >= amount + _frozenTokens[id][from], "Insufficient unlocked balance for transfer");
    super.safeTransferFrom(from, to, id, amount, data);
}
```

This ensures that users cannot transfer frozen tokens. The contract checks that the unlocked balance (total balance minus frozen balance) is sufficient before allowing transfers.

### **10. Overriding `balanceOf` to Consider Frozen Tokens**

```
function balanceOf(address account, uint256 tokenId) public view override returns (uint256) {
    uint256 totalBalance = super.balanceOf(account, tokenId);
    uint256 frozenBalance = _frozenTokens[tokenId][account];
    return totalBalance - frozenBalance;
}
```

This function returns the number of **unfrozen** tokens owned by a user for a specific token ID.

:::info[Complete Codebase on GitHub]
[**Complete RSK-Runes**](https://github.com/rsksmart/rsk-runes/tree/main/contracts)
:::
