-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #118 from wise4rmgodroot/runes-series
Docs: Add Runes complete series
- Loading branch information
Showing
14 changed files
with
624 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
--- | ||
sidebar_position: 1 | ||
title: Introduction to Runes | ||
sidebar_label: Introduction to Runes | ||
tags: [rsk, rootstock, resources, tutorials, runes, nft, Ethereum, dApps, smart contracts] | ||
description: "The Rootstock Runes Mock Bridge opens up exciting opportunities for developers to build Runes-focused applications within the Rootstock ecosystem. This bridge introduces three core solutions: Mock Bridge, Marketplace, Giveaway Engine" | ||
--- | ||
|
||
The Rootstock Runes Mock Bridge opens up exciting opportunities for developers to build Runes-focused applications within the Rootstock ecosystem. This bridge introduces three core solutions: | ||
|
||
Here’s the table in a list format in Markdown: | ||
|
||
- **Mock Bridge** | ||
- Description: Facilitates transferring Runes between different blockchain networks. | ||
- Repo: [Link](https://github.com/rsksmart/rsk-runes) | ||
|
||
- **Marketplace** | ||
- Description: A platform for trading and exchanging Runes tokens. | ||
- Repo: N/A | ||
|
||
- **Giveaway Engine** | ||
- Description: A system for distributing tokens in a structured or promotional manner. | ||
- Repo: [Link](https://github.com/rsksmart/airdrop-ui.git) | ||
|
||
|
||
These tools allow developers to create diverse Runes-based applications, further expanding the Rootstock ecosystem and promoting innovation. | ||
|
||
In this guide, you will explore the exciting possibilities the Rootstock Runes Mock Bridge presents for developing Runes-focused applications within the Rootstock ecosystem. | ||
|
||
You will gain an understanding of Bitcoin Runes, including how they operate on the Bitcoin blockchain using the Unspent Transaction Output (UTXO) model and the OP\_RETURN opcode. | ||
|
||
**Expect to learn:** | ||
|
||
| **Component** | **Description** | | ||
|----------------------|--------------------------------------------------------------------------------------------------------------| | ||
| Core Components | Insight into the Mock Bridge and how they facilitate Runes token interactions. | | ||
| Technical Concepts | A clear explanation of the UTXO model and OP_RETURN. | | ||
| Practical Examples | Step-by-step examples demonstrating how to send Runes, accompanied by visual diagrams to aid understanding. | | ||
|
||
|
||
By the end of this article, you will be able to build and deploy the Runes Mock Bridge and connect it to a frontend, equipping you with the foundational knowledge and technical skills necessary to start building innovative applications using Bitcoin Runes within the Rootstock ecosystem. | ||
|
||
### **Who Is This Guide For?** | ||
|
||
This guide is aimed at developers interested in working with Bitcoin Runes, particularly within the Rootstock ecosystem. You’ll need some basic knowledge of blockchain technology, Bitcoin, and Ethereum, but we’ll also provide step-by-step instructions for setting up your environment. | ||
|
||
### **Understanding Bitcoin Runes** | ||
|
||
**What Are Runes?** | ||
Bitcoin Runes is a protocol for creating fungible tokens directly on the blockchain. Developed by Casey Rodarmor, the mind behind Ordinals, Runes offers a more efficient way to issue tokens. | ||
|
||
Unlike [BRC-20 and SRC-20 tokens](https://academy.binance.com/en/glossary/src-20-tokens), Runes operate independently and are not dependent on the Ordinals protocol but operate on Bitcoin. Built on [Bitcoin’s Unspent Transaction Output (UTXO) model](https://www.kraken.com/learn/what-is-bitcoin-unspent-transaction-output-utxo), Runes is fully on-chain, offering a simpler and more efficient token system. | ||
|
||
This UTXO-based structure gives Runes an edge over other token models, like those on Ethereum, by ensuring that all data remains on the blockchain without needing external input. | ||
|
||
## **How Runes Work** | ||
|
||
Bitcoin Runes is a protocol for creating and managing tokens on the Bitcoin blockchain. It leverages two key features: Bitcoin's UTXO (Unspent Transaction Output) model and the OP\_RETURN opcode. | ||
|
||
### **Understanding UTXO and How Runes Use It** | ||
|
||
Bitcoin's UTXO model tracks Bitcoin's movement by breaking each transaction into outputs, called UTXOs. When you spend Bitcoin, you're using these UTXOs as inputs for your transaction. | ||
|
||
Think of a UTXO like a digital coin in your wallet—each UTXO can represent a specific amount of Bitcoin, and when you spend it, the remaining "change" becomes a new UTXO. | ||
|
||
In the case of Bitcoin Runes, each UTXO can hold not just Bitcoin, but also different tokens or Runes. For example, let's say you have 2 Bitcoin Runes and want to transfer 1 Rune to a friend. | ||
|
||
Your UTXO will be split into one that transfers 1 Rune to your friend and another that keeps 1 Rune for you. The UTXO model helps track these tokens across the network, making it easy to know how many Runes each address owns. | ||
|
||
### **OP\_RETURN: Attaching Information to Transactions** | ||
|
||
Bitcoin transactions typically transfer currency from one address to another. However, the OP\_RETURN opcode allows for more than just currency transfer—it lets users attach extra information (up to 80 bytes) to a transaction. | ||
|
||
This added data is important because it’s how Runes store essential details like: | ||
|
||
* The token's name (e.g., "Rune of Power") | ||
* The token’s ID (a unique identifier) | ||
* Commands for specific actions (like transferring or minting tokens) | ||
|
||
This extra information is written into the blockchain in a part of the transaction called a "Runestone." When a Bitcoin transaction containing a Rune occurs, the data stored in the OP\_RETURN field tells the network what kind of Rune is involved and what should happen to it (e.g., transfer 1 Rune from John to Kate). | ||
|
||
### **Example: Sending Runes on Bitcoin** | ||
|
||
Let’s break this down with an example: | ||
|
||
1. **John owns 3 Runes** stored in a Bitcoin UTXO. | ||
2. He wants to send 2 Runes to Kate. | ||
3. John creates a Bitcoin transaction that uses his UTXO as input and attaches the Rune transaction data to it. | ||
4. The transaction includes an **OP\_RETURN field**, where the information about transferring 2 Runes (this is the Runestone) is recorded. | ||
5. When the transaction is processed, the Bitcoin network updates the UTXO to show that John now has 1 Rune and Kate has 2\. | ||
|
||
### **Simplified Diagram:** | ||
|
||
A diagram can help visualize this process. | ||
<img src="/img/resources/runes/how-runes-works.png"/> | ||
|
||
This simplified flow shows how UTXOs and OP\_RETURN work together to track Rune transactions. | ||
|
||
### **Why Use Bitcoin Runes?** | ||
|
||
By using these features of Bitcoin, Runes allow token creation and management without needing a separate blockchain. This makes them secure (since they rely on Bitcoin’s strong security) and simple, as they use the same underlying transaction system that Bitcoin already uses. | ||
|
||
In short, Bitcoin Runes work by: | ||
|
||
1. Tracking tokens using Bitcoin's UTXO model. | ||
2. Storing token data and actions using the OP\_RETURN field in Bitcoin transactions. | ||
|
||
This system lets users create, transfer, and manage tokens on the Bitcoin network in a straightforward way. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
label: Runes | ||
position: 2 | ||
link: | ||
type: generated-index | ||
description: The Rootstock Runes Mock Bridge opens up exciting opportunities for developers to build Runes-focused applications within the Rootstock ecosystem. This bridge introduces three core solutions | ||
slug: /resources/runes/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
--- | ||
sidebar_position: 3 | ||
title: Runes Contract Explanation walk through | ||
sidebar_label: Runes Contract Explanation walk through | ||
tags: [rsk, rootstock, resources, tutorials, setup, Runes, dApps, smart contracts, Remix IDE, MetaMask] | ||
description: "The Rootstock Runes Mock Bridge setup page shows you how to getting building your runes, by first cloning our project and testing it locally." | ||
--- | ||
|
||
### **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) | ||
::: | ||
|
||
|
||
## **Smart Contract Deployment** | ||
|
||
To deploy the Runes smart contract using Remix IDE, follow these steps in detail: | ||
|
||
### **Step 1: Access Remix IDE** | ||
|
||
1. Open your web browser and go to [Remix IDE](https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.26+commit.8a97fa7a.js). | ||
|
||
### **Step 2: Create a New File** | ||
|
||
<img src="/img/resources/runes/Remix-create-new-file.png"/> | ||
|
||
1. In the Remix IDE, navigate to the **File Explorer** (the first icon on the left sidebar). | ||
2. Click on the **file** icon to create a new file. | ||
3. Name the file `RuneToken.sol`. | ||
|
||
### **Step 3: Copy and Paste the Smart Contract** | ||
|
||
1. Locate the `RuneToken.sol` file from the RSK-RUNES repository under the contracts folder | ||
|
||
<img src="/img/resources/runes/Copy-and-Paste -the-Smart-Contract.png"/> | ||
|
||
2. Open the `RuneToken.sol` file and copy the entire smart contract code. | ||
3. Paste the copied code into the newly created `RuneToken.sol` file in Remix IDE. | ||
|
||
<img src="/img/resources/runes/Paste-RemixIDE.png"/> | ||
|
||
4. Click on the **Save** icon (the disk icon) to save the file. | ||
|
||
### | ||
|
||
### **Step 4: Compile the Smart Contract** | ||
|
||
<img src="/img/resources/runes/Compile-the-Smart-Contract.png"/> | ||
|
||
1. Go to the **Solidity Compiler** tab (the third icon in the left sidebar). | ||
2. Make sure the compiler version matches `0.8.26`. If not, select the correct version from the dropdown menu. | ||
3. Click on the **Compile RuneToken.sol** button. A green check icon inside a circle will appear, indicating that the compilation was successful. | ||
|
||
### **Step 5: Deploy the Smart Contract** | ||
|
||
<img src="/img/resources/runes/Deploy-the-Smart-Contract.png"/> | ||
|
||
1. Navigate to the **Deploy & Run Transactions** tab (the fourth icon in the left sidebar). | ||
2. Under **Environment**, select **Remix VM** | ||
3. In the **Account** dropdown, copy the first address by clicking the icon next to it. | ||
4. Paste the copied address into the **Deploy** input field. | ||
5. Click the **Deploy** button. | ||
|
||
### **Step 6: Copy the Smart Contract Address** | ||
|
||
<img src="/img/resources/runes/Copy-the-Smart-Contract-Address.png"/> | ||
|
||
1. After deployment, scroll down to see the **Deployed Contracts** section. | ||
2. You will find the generated smart contract address listed there. Copy this address for your records. | ||
|
||
### **Alternative Method to Copy the Contract Address** | ||
|
||
1. Alternatively, you can also copy the contract address from the **Transaction Receipt** that appears after deployment. | ||
2. Look for the contract address in the receipt and copy it as well. | ||
|
Oops, something went wrong.