### **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)
:::
