From 51c673901d66c3f18987c85b74868743cf1e22b9 Mon Sep 17 00:00:00 2001 From: Owanate Amachree Date: Wed, 30 Oct 2024 14:22:37 +0200 Subject: [PATCH 1/6] Improve Runes on Rootstock guide --- .../06-guides/runes/_category_.yml | 6 +++ .../runes/mock-contract-walthrough.md} | 30 +++++++-------- .../runes/overview.md} | 10 ++--- .../runes}/runes-setup.md | 38 +++++++++---------- docs/04-resources/08-runes/_category_.yml | 6 --- 5 files changed, 43 insertions(+), 47 deletions(-) create mode 100644 docs/04-resources/06-guides/runes/_category_.yml rename docs/04-resources/{08-runes/runes-contracts.md => 06-guides/runes/mock-contract-walthrough.md} (95%) rename docs/04-resources/{08-runes/Intro-runes.md => 06-guides/runes/overview.md} (97%) rename docs/04-resources/{08-runes => 06-guides/runes}/runes-setup.md (93%) delete mode 100644 docs/04-resources/08-runes/_category_.yml diff --git a/docs/04-resources/06-guides/runes/_category_.yml b/docs/04-resources/06-guides/runes/_category_.yml new file mode 100644 index 00000000..1db81160 --- /dev/null +++ b/docs/04-resources/06-guides/runes/_category_.yml @@ -0,0 +1,6 @@ +label: Deploy Bitcoin Runes on Rootstock +position: 7 +link: + type: generated-index + description: The Rootstock Runes Mock Bridge and Airdrop giveaway opens up exciting opportunities for developers to build Runes applications on Rootstock. + slug: /resources/guides/runes/ diff --git a/docs/04-resources/08-runes/runes-contracts.md b/docs/04-resources/06-guides/runes/mock-contract-walthrough.md similarity index 95% rename from docs/04-resources/08-runes/runes-contracts.md rename to docs/04-resources/06-guides/runes/mock-contract-walthrough.md index b5482bd4..0825e1cd 100644 --- a/docs/04-resources/08-runes/runes-contracts.md +++ b/docs/04-resources/06-guides/runes/mock-contract-walthrough.md @@ -1,18 +1,18 @@ --- sidebar_position: 3 -title: Runes Contract Explanation walk through -sidebar_label: Runes Contract Explanation walk through +title: Mock Bridge Contract - Walkthrough +sidebar_label: Mock Bridge Contract - Walkthrough 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** +### **1\. Understanding the Mock Bridge 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. +The [Mock bridge contract](https://github.com/rsksmart/rsk-runes/tree/main/contracts) 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:** -``` +```plaintext import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; @@ -44,7 +44,7 @@ import "@openzeppelin/contracts/utils/Strings.sol"; ### **2\. The Constructor** -``` +```js constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} ``` @@ -63,7 +63,7 @@ This function returns the URI for a given token ID. The URI typically points to ### **4\. Minting Fungible Tokens** -``` +```js function mintFungible( string memory tokenURI, string memory runeName, @@ -90,7 +90,7 @@ This function allows the owner of the contract to mint fungible tokens. ### **5\. Minting Non-Fungible Tokens (NFTs)** -``` +```js function mintNonFungible( string memory tokenURI, string memory runeName, @@ -110,7 +110,7 @@ This function is similar to `mintFungible` but for minting non-fungible tokens. ### **6\. Minting More Tokens** -``` +```js function mintMore( string memory runeName, address receiver @@ -131,7 +131,7 @@ This function allows the contract owner to mint additional tokens of an existing #### **Freezing Tokens:** -``` +```js function freezeTokens(string memory runeName, uint256 amount, address owner) external onlyOwner { // Function logic here } @@ -143,7 +143,7 @@ function freezeTokens(string memory runeName, uint256 amount, address owner) ext #### **Unfreezing Tokens:** -``` +```js function unfreezeTokens(string memory runeName, uint256 amount, address owner) external onlyOwner { // Function logic here } @@ -156,7 +156,7 @@ function unfreezeTokens(string memory runeName, uint256 amount, address owner) e #### **Get Token Information:** -``` +```js function getTokenInfo(uint256 tokenId, address holder) public view returns (TokenInfo memory) { // Function logic here } @@ -168,7 +168,7 @@ function getTokenInfo(uint256 tokenId, address holder) public view returns (Toke #### **Get Tokens Owned by a User:** -``` +```js function getUserTokens(address user) public view returns (uint256[] memory) { return _userTokens[user]; } @@ -180,7 +180,7 @@ function getUserTokens(address user) public view returns (uint256[] memory) { ERC1155 includes transfer functions (`safeTransferFrom` and `safeBatchTransferFrom`). These are overridden in this contract to take into account frozen tokens. -``` +```js function safeTransferFrom( address from, address to, @@ -197,7 +197,7 @@ This ensures that users cannot transfer frozen tokens. The contract checks that ### **10\. Overriding `balanceOf` to Consider Frozen Tokens** -``` +```js function balanceOf(address account, uint256 tokenId) public view override returns (uint256) { uint256 totalBalance = super.balanceOf(account, tokenId); uint256 frozenBalance = _frozenTokens[tokenId][account]; diff --git a/docs/04-resources/08-runes/Intro-runes.md b/docs/04-resources/06-guides/runes/overview.md similarity index 97% rename from docs/04-resources/08-runes/Intro-runes.md rename to docs/04-resources/06-guides/runes/overview.md index 05a7d4bf..682649e0 100644 --- a/docs/04-resources/08-runes/Intro-runes.md +++ b/docs/04-resources/06-guides/runes/overview.md @@ -1,7 +1,7 @@ --- sidebar_position: 1 -title: Introduction to Runes -sidebar_label: Introduction to Runes +title: Overview of Runes on Rootstock +sidebar_label: Overview of Runes on Rootstock 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" --- @@ -40,11 +40,11 @@ You will gain an understanding of Bitcoin Runes, including how they operate on t 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?** +## **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** +## **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. @@ -96,7 +96,7 @@ A diagram can help visualize this process. This simplified flow shows how UTXOs and OP\_RETURN work together to track Rune transactions. -### **Why Use Bitcoin Runes?** +## **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. diff --git a/docs/04-resources/08-runes/runes-setup.md b/docs/04-resources/06-guides/runes/runes-setup.md similarity index 93% rename from docs/04-resources/08-runes/runes-setup.md rename to docs/04-resources/06-guides/runes/runes-setup.md index 09ecdda3..78356be8 100644 --- a/docs/04-resources/08-runes/runes-setup.md +++ b/docs/04-resources/06-guides/runes/runes-setup.md @@ -1,14 +1,12 @@ --- sidebar_position: 2 -title: Runes Setup -sidebar_label: Runes Setup +title: How to setup your first Runes Project +sidebar_label: How to setup your first Runes Project 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." --- - - -### **Prerequisites** +## **Prerequisites** Before getting started with the Runes Mock Bridge, ensure you have the following prerequisites in place: @@ -25,9 +23,9 @@ Before getting started with the Runes Mock Bridge, ensure you have the following Once these prerequisites are in place, you'll be ready to proceed with setting up and using the Runes Mock Bridge effectively. -### **Setting Up the `.env` File for the Runes Mock Bridge** +## **Setting Up the `.env` File for the Runes Mock Bridge** -``` +```plaintext NEXT_PUBLIC_APP_PK='your-private-key' NEXT_PUBLIC_RPC_URL='your rsk rpc url' NEXT_PUBLIC_EXPLORER_URL=https://blockstream.info/testnet/tx @@ -41,7 +39,7 @@ To run the **Runes Mock Bridge** effectively, you'll need to set up the environm Here's a detailed guide on what each environment variable means, how to get them, and how to set up your `.env` file correctly. -#### **1\. `NEXT_PUBLIC_APP_PK='your-private-key'`** +### **1\. `NEXT_PUBLIC_APP_PK='your-private-key'`** This is the private key for your application, which is essential for signing transactions or interacting with the blockchain via the Runes Mock Bridge @@ -52,14 +50,14 @@ This is the private key for your application, which is essential for signing tra * You can obtain your private key from your wallet. Typically, you will export the private key from the wallet software you're using (like MetaMask or any other supported wallet). * Follow a detailed tutorial specific to your wallet on how to extract your private key, and then input it here. -#### **2\. `NEXT_PUBLIC_RPC_URL='your RSK RPC URL'`** +### **2\. `NEXT_PUBLIC_RPC_URL='your RSK RPC URL'`** The Remote Procedure Call (RPC) URL is how your Runes Mock Bridge interacts with the Rootstock (RSK) blockchain. * To get the RSK RPC URL, go to the[RPC API Dashboard](https://dashboard.rpc.rootstock.io/login) and log in. After logging in, you can create an API key that will give you access to the RPC URL. * Once the key is generated, you can use it to set up this variable, which allows your bridge to communicate with the blockchain. -#### **3\. `NEXT_PUBLIC_EXPLORER_URL=https://blockstream.info/testnet/tx`** +### **3\. `NEXT_PUBLIC_EXPLORER_URL=https://blockstream.info/testnet/tx`** This is the URL for the **Bitcoin Testnet Explorer** provided by Blockstream, where you can track Bitcoin testnet transactions. @@ -67,7 +65,7 @@ This is the URL for the **Bitcoin Testnet Explorer** provided by Blockstream, wh This value remains constant and doesn't need to be changed, as it will always point to the Bitcoin testnet explorer. ::: -#### **4\. `NEXT_PUBLIC_RSK_EXPLORER_URL=https://explorer.testnet.rootstock.io/tx`** +### **4\. `NEXT_PUBLIC_RSK_EXPLORER_URL=https://explorer.testnet.rootstock.io/tx`** This is the URL for the **Rootstock Testnet Explorer**, where you can track transactions related to the Rootstock network. @@ -75,7 +73,7 @@ This is the URL for the **Rootstock Testnet Explorer**, where you can track tran Like the Blockstream explorer URL, this value is also constant and doesn't need to be changed. It is set to the correct Rootstock testnet explorer. ::: -#### **5\. `NEXT_PUBLIC_CONTRACT_ADDRESS='your ERC-1155 contract address'`** +### **5\. `NEXT_PUBLIC_CONTRACT_ADDRESS='your ERC-1155 contract address'`** :::info[Important] The RuneToken implementation used is not a standard ERC-1155 contract. It includes custom functions to freeze tokens transferred from Rootstock to Bitcoin. To ensure compatibility, please use the same (or an improved) version of the smart contract available in this repository: [RuneToken.sol](https://github.com/rsksmart/rsk-runes/blob/main/contracts/RuneToken.sol) and deploy it. @@ -87,7 +85,7 @@ This variable is used to specify the address of your deployed ERC-1155 contract, * You need to deploy your ERC-1155 contract using Remix IDE or a similar tool. Once the deployment is complete, you will get the contract address. * Copy the contract address from Remix IDE after deployment and paste it into this variable. -#### **6\. `NEXT_PUBLIC_TAPROOT_ADDRESS='your taproot address'`** +### **6\. `NEXT_PUBLIC_TAPROOT_ADDRESS='your taproot address'`** Taproot addresses are used for Bitcoin transactions with improved privacy and flexibility. The [Runes Mock Bridge](https://github.com/rsksmart/rsk-runes) requires a Taproot address for interacting with Bitcoin's taproot transactions. @@ -110,7 +108,7 @@ No WIF set, generating new random address ``` > you can generate multiple taproot address -#### **7\. `NEXT_PUBLIC_WIF='your WIF key'`** +### **7\. `NEXT_PUBLIC_WIF='your WIF key'`** The Wallet Import Format (WIF) key is the encoded version of your Bitcoin private key, which is necessary for signing Bitcoin transactions on the testnet. @@ -118,8 +116,6 @@ The Wallet Import Format (WIF) key is the encoded version of your Bitcoin privat 1. After running `npm run generate`, you will get both the Taproot address and the WIF key as part of the output. 2. Copy the WIF key and paste it into this variable. - - :::note[Note] **Security:** Ensure that the `.env` file is kept private and not exposed in public repositories or shared with unauthorized people. This file contains sensitive information such as your private keys, which could be exploited if leaked. @@ -131,14 +127,14 @@ The Wallet Import Format (WIF) key is the encoded version of your Bitcoin privat To clone and run the Runes Mock Bridge project locally, follow these steps: -#### **1\. Clone the Repository:** +### **1\. Clone the Repository:** -``` +```bash git clone https://github.com/rsksmart/rsk-runes.git cd rsk-runes ``` -#### **2\. Install Dependencies:** +### **2\. Install Dependencies:** Use either `yarn` or `npm` to install the necessary dependencies: @@ -148,11 +144,11 @@ or npm install ``` -#### **3\. Access the Application:** +### **3\. Access the Application:** Once the installation is complete, start the development server and access the application in your browser by visiting: -``` +```text http://localhost:3000 ``` diff --git a/docs/04-resources/08-runes/_category_.yml b/docs/04-resources/08-runes/_category_.yml deleted file mode 100644 index c2cf9d93..00000000 --- a/docs/04-resources/08-runes/_category_.yml +++ /dev/null @@ -1,6 +0,0 @@ -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/ From d53040346a8bf5e96a558febcf8f2915cc7a8477 Mon Sep 17 00:00:00 2001 From: Owanate Amachree Date: Wed, 30 Oct 2024 16:48:55 +0200 Subject: [PATCH 2/6] Added Smart Contract Best Practices Guide --- .../smart-contracts-best-practices.md | 432 ++++++++++++++++++ .../best-practices/flash-loan-attacks-1.png | Bin 0 -> 14662 bytes .../best-practices/flash-loan-attacks-2.png | Bin 0 -> 14204 bytes 3 files changed, 432 insertions(+) create mode 100644 docs/02-developers/05-smart-contracts/smart-contracts-best-practices.md create mode 100644 static/img/developers/smart-contracts/best-practices/flash-loan-attacks-1.png create mode 100644 static/img/developers/smart-contracts/best-practices/flash-loan-attacks-2.png diff --git a/docs/02-developers/05-smart-contracts/smart-contracts-best-practices.md b/docs/02-developers/05-smart-contracts/smart-contracts-best-practices.md new file mode 100644 index 00000000..240bd6e6 --- /dev/null +++ b/docs/02-developers/05-smart-contracts/smart-contracts-best-practices.md @@ -0,0 +1,432 @@ +--- +sidebar_position: 800 +sidebar_label: Best Practices for Smart Contract Development on Rootstock +title: Best Practices for Smart Contract Development on Rootstock +description: 'Best practices for Smart Contract Development on Rootstock' +tags: [rsk, rootstock, smart contracts, best practices, dApps] +--- + +Smart contracts are self-executing programs that run on blockchain networks, automatically enforcing the terms and conditions of an agreement without the need for intermediaries. On [Rootstock](https://rootstock.io/), smart contracts play a crucial role in building decentralized finance (DeFi) applications and other trustless services. These contracts bring transparency and efficiency but also introduce unique security and good practices challenges. + +Since smart contracts operate autonomously and are immutable once deployed, they are particularly susceptible to attacks if not properly designed. Vulnerabilities such as [reentrancy attacks](https://www.cyfrin.io/blog/what-is-a-reentrancy-attack-solidity-smart-contracts#:~:text=A%20Reentrancy%20Attack%20is%20the,is%20a%20Solidity%20reentrancy%20attack%3F), integer overflows, and poorly validated inputs can lead to significant financial losses and data breaches. This is why adhering to best practices is essential to ensure security, reliability, and optimal performance. + +In this guide, we will explore best practices for developing secure and efficient smart contracts on Rootstock, providing actionable tips to protect both the contract and its users from common pitfalls. + +## Security Considerations for Rootstock Smart Contracts + +Security is a critical aspect of smart contract development, particularly on Rootstock, where contracts often manage large amounts of value. Due to the immutable nature of smart contracts, any vulnerability in the code can result in **irreversible consequences**. + +In this section, we will discuss some of the most common vulnerabilities, provide mitigation strategies, and offer practical advice for writing secure smart contracts. By following these best practices, developers can ensure their contracts are resilient and protected against potential attacks. + +### Common Vulnerabilities + +1. **Reentrancy** + +[Reentrancy](https://www.cyfrin.io/blog/what-is-a-reentrancy-attack-solidity-smart-contracts#:~:text=A%20Reentrancy%20Attack%20is%20the,is%20a%20Solidity%20reentrancy%20attack%3F) occurs when a smart contract makes an external call to another contract before it completes its execution. If the external contract is able to call back into the original contract, it can repeatedly execute parts of the code that should have only been run once. This creates a vulnerability that attackers can exploit by draining funds or altering the contract’s state in unintended ways. + +- **Example:** Here is a simple example of a contract that is susceptible to reentrancy: + +```solidity +// Vulnerable Contract + +contract VulnerableContract { + mapping(address => uint) public balances; + + // Allows users to deposit Ether into the contract + function deposit() public payable { + balances[msg.sender] += msg.value; + } + + // Allows users to withdraw their Ether + function withdraw() public { + uint userBalance = balances[msg.sender]; + require(userBalance > 0, "Insufficient balance"); + + // Vulnerable external call before updating state + (bool success, ) = msg.sender.call{value: userBalance}(""); + require(success, "Failed to send Ether"); + + // State update occurs after external call (unsafe) + balances[msg.sender] = 0; + } +} + ``` + +- **Mitigation:** Use a reentrancy lock, for example, [Open Zeppelin’s Reentrancy Guard](https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard) modifier. + +2. **Flash loan Attacks** + +Flash loan attacks are a form of DeFi exploit where a hacker borrows a flash loan, an uncollateralized loan from a lending protocol, and leverages it with different tactics to manipulate the market to their advantage. These attacks can happen in seconds and often involve multiple DeFi protocols. + + - **Example:** The following diagram represents a normal flash loan + + ![Flash Loan Attacks 1](/img/developers/smart-contracts/best-practices/flash-loan-attacks-1.png) + + And this is an example of flash loan attack: + + ![Flash Loan Attacks 2](/img/developers/smart-contracts/best-practices/flash-loan-attacks-2.png) + + As seen above, the difference is seen in how the user uses the amount that is loaned. + +- **Mitigation:** Even though there’s not an absolute solution for these kind of attacks, here are a few steps that can be taken to prevent these attacks: + - Use decentralized oracles for price data. See [Oracles on Rootstock](/dev-tools/). + - Force Critical Transactions to Go Through at least Two Blocks + +3. **Missing/Improper Input validation:** + +Missing or inadequate input validation is a vulnerability in smart contracts that arises when the contract does not properly verify or validate the data and parameters provided by users or external sources before processing. This flaw can pose serious security risks, as it may enable attackers to take advantage of the contract’s weaknesses. + +- **Example:** This is an example of a contract missing proper input validation + +```solidity +contract InsecureVault { + mapping(address => uint256) public deposits; + + // allows depositing on behalf of others + function addFunds(address _for) public payable { + deposits[_for] += msg.value; + } + + function releaseFunds(address from, uint256 amount) public { + require(deposits[from] <= amount, "Not enough funds"); + // Vulnerability: anyone can withdraw from any address due to lack of authorization check + deposits[from] -= amount; + // Incorrect variable name for 'amount' and lack of validation check can cause issues + msg.sender.call{value: amout}(""); + } +} +``` + +- **Mitigation:** Modify the previous code: + +```solidity +contract SecureVault { + mapping(address => uint256) public deposits; + + // allows depositing on behalf of others + function addFunds(address _for) public payable { + deposits[_for] += msg.value; + } + + // properly validates the caller and the amount to withdraw + function releaseFunds(uint256 amount) public { + address payable sender = payable(msg.sender); + require(deposits[sender] >= amount, "Insufficient funds"); + + // Deduct the amount from the sender's balance before transferring + deposits[sender] -= amount; + + // Use call with limited gas to prevent reentrancy risks + (bool success, ) = sender.call{value: amount, gas: 2300}(""); + require(success, "Transfer failed"); + } +} +``` + +:::tip[Tip] + +Beyond the example provided above, to prevent this kind of vulnerability, smart contracts should enforce strong input validation, including verifying the sender’s authority, checking parameters against constraints, validating external data, and ensuring inputs stay within defined limits. +::: + +4. **Missing/weak access controls:** + +Access controls are security measures designed to limit who can access or perform actions within a system, ensuring that only authorized users can interact with critical resources or functions. While many contracts implement access controls, they are often insufficient to protect sensitive functions or data. These inadequate controls rely on simple checks, making them vulnerable to exploitation and easy to bypass. + +- **Example:** Sample code without proper access controls + +```solidity +function receiveAirdrop(bytes32 calldata verificationProof[]) { + bool isVerified = MerkleProof.verifyCalldata(verificationProof, rootHash, keccak256(abi.encode(msg.sender))); + require(isVerified, "verification failed"); + require(!airdropClaimed[msg.sender], "airdrop already claimed"); + _transfer(msg.sender, AIRDROP_AMOUNT); + // airdropClaimed is never set to true, so the claimant can call this function multiple times. +} +``` + +- **Mitigation:** Clearly specify who is authorized to perform certain actions and implement these rules within the contract’s code. + +```jsx +function receiveAirdrop(bytes32 calldata verificationProof[]) external { + bool isVerified = MerkleProof.verifyCalldata(verificationProof, rootHash, keccak256(abi.encode(msg.sender))); + require(isVerified, "verification failed"); + require(!airdropClaimed[msg.sender], "airdrop already claimed"); + + // Mark the airdrop as claimed + airdropClaimed[msg.sender] = true; + + _transfer(msg.sender, AIRDROP_AMOUNT); +} +``` + +5. **Front-running attacks:** + +Front-running is an attack in decentralized finance (DeFi) where malicious actors exploit knowledge of pending transactions. They monitor the mempool (a list of unconfirmed transactions) and strategically submit their own transactions with higher gas fees, ensuring they are processed before the victim’s transaction. This manipulation can lead to financial losses for users and disrupt smart contract functionality. + +- **Example:** The contract below is vulnerable to front-running due to the absence of slippage protection. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract VulnerableSwap { + address public pancakeRouter; + address public ssToken; + + constructor(address _pancakeRouter, address _ssToken) { + pancakeRouter = _pancakeRouter; + ssToken = _ssToken; + } + + // Vulnerability: This function lacks slippage protection, making it susceptible to frontrunning attacks + function swapBNBForSSToken(uint256 amount) private { + address; + path[0] = IPancakeRouter02(pancakeRouter).WETH(); // First token in the swap path is BNB + path[1] = ssToken; // Second token in the swap path is SSToken + + // This swap function does not include a slippage check, allowing attackers to frontrun by observing large swaps in the mempool + IPancakeRouter02(pancakeRouter).swapExactETHForTokensSupportingFeeOnTransferTokens{ + value: amount + }(0, path, address(this), block.timestamp); // No slippage protection here (the '0' sets no minimum token output) + } +} +``` + +- **Mitigation:** + - **Implement slippage restrictions:** Ensure the contract checks for a minimum acceptable amount of tokens during swaps, preventing attackers from exploiting price changes. + - **Use commit-reveal schemes:** Introduce a two-step process where users first commit to a trade without revealing details, reducing the chances of front-running. + - **Batch transactions to reduce visibility:** Bundle multiple transactions into a single operation to make it harder for attackers to target specific trades. + - **Monitor for front-running bots:** Continuously track and detect automated bots that may be attempting to front-run transactions, enabling early intervention. +6. **Using libraries with vulnerabilities:** + +Smart contracts often rely on external libraries to implement common functionality such as token standards (e.g., ERC-20, ERC-721), math utilities, or security features like access control and reentrancy protection. However, using libraries that have undiscovered or publicly known vulnerabilities can pose a significant risk to the security of your contract. If a vulnerability exists within a library your contract depends on, attackers can exploit it to bypass security mechanisms, compromise functionality, or steal funds. + +- **Mitigation:** + - **Audit and Update Libraries Regularly:** Ensure that all external libraries are thoroughly audited and are up-to-date with the latest security patches. + - **Use Widely Trusted Libraries:** Stick to reputable, widely-used libraries (e.g., [OpenZeppelin](https://docs.openzeppelin.com/)) that undergo frequent reviews and audits by the community. + - **Limit External Dependencies:** Avoid the excessive use of external libraries and only import code that is essential to your contract. + +### Considerations for Deploying to the Rootstock Mainnet + +Deploying smart contracts on the Rootstock mainnet requires careful preparation and a strong focus on security. Once deployed, smart contracts become immutable, meaning that any vulnerabilities or bugs could lead to irreversible financial losses or other serious issues. Therefore, following best practices is essential to ensure a smooth and secure deployment. Below are some key considerations: + +1. **Audit the Contracts:** + + Conducting a professional audit is essential to identify potential vulnerabilities in your smart contracts. An audit helps detect issues such as reentrancy, unchecked external calls, or unsafe logic that could be exploited. This step provides assurance that your contract is secure before interacting with real assets. + +2. **Comprehensive Testing:** + + Rigorous testing is crucial. Perform unit tests, integration tests, and simulate mainnet conditions on Rootstock’s testnet. Cover all edge cases and failure scenarios, and ensure gas efficiency. This allows you to find and fix issues early, ensuring the contract operates correctly and cost-effectively in all situations. + +3. **Post-Deployment Monitoring:** + + After deployment, set up real-time monitoring to detect abnormal activity or security issues. Automated monitoring tools can alert you to potential threats, allowing for immediate action. This ongoing vigilance ensures the long-term security and performance of your smart contract. + +## Solidity Best Practices + +### Gas Optimization Techniques + +Optimizing gas in Solidity is essential for lowering transaction costs and improving contract efficiency. Gas fees reflect the computational resources required, so reducing gas usage makes contracts more affordable for users and scalable for developers. Efficient contracts prevent excessive costs and reduce the risk of failed transactions. + +1. **Storage Optimization** + 1. **Importance:** Storage operations are costly. Reducing the number of storage writes and using memory instead of storage whenever possible can significantly cut gas costs. + 2. [**Example:** Perform calculations in memory before updating storage variables to minimize write operations.](https://www.notion.so/JAMF-91db529c3f7f405cac9d9d8e08071f75?pvs=21) +2. **Data Types and Packing** + 1. **Importance:** Using optimal data types, like `bytes32` over string, and packing smaller data types into single storage slots helps lower gas usage. + 2. **Example:** Packing `uint8` variables in a struct reduces storage costs compared to using larger types or separate slots. + + +### Fix the Solidity Pragma + +When compiling and deploying your own contract, it's best to **fix the Solidity version** to the specific compiler you're using. This ensures consistency and avoids unexpected behavior due to future compiler changes. + +**Example:** + +```solidity +pragma solidity 0.8.24; +``` + +By specifying an exact version, your contract will compile reliably with the expected behavior. + +### Following the Solidity Style Guide + + Keep your contracts clean and organized. Here are the main highlights: + +1. **Constructor** should be the first function in the contract. +2. **Fallback** and **receive** functions (if applicable) come next. +3. After that, organize functions by visibility: + - External functions + - Public functions + - Internal functions + - Pure functions +4. **Within each group**, follow this order: + - Payable functions first + - Then non-payable, non-view functions + - Finally, view functions + + +### Use Named Imports and Specify the Library Version in the Import Statement + +**Instead of doing this:** + +```solidity +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +``` + +**Do this:** + +```solidity +import {ERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/ERC20.sol"; +``` + +By specifying the exact version of the library in your import statement, you ensure that your code remains stable even if the underlying library updates in the future. This prevents potential compilation errors or unexpected behavior due to changes in the library. + +Additionally, using named imports instead of importing the entire namespace allows you to include only the specific contracts or libraries you need. This keeps your code cleaner, avoids namespace pollution, and reduces the inclusion of unused code in your compilation. While the compiler might optimize out unused code, it's best not to rely on that. + +Combining both practices enhances code stability and maintainability by: + +- **Version Locking:** Protects your code from unexpected changes in external libraries. +- **Selective Importing:** Keeps your codebase lean and free from unnecessary components. + + +### Use NatSpec Properly at Both Contract and Function Levels + +NatSpec (Natural Specification) comments, often referred to as "Solidity comment style," are crucial for creating human-readable inline documentation in your Solidity code. Proper use of NatSpec makes your code easier to understand for both technical and non-technical audiences, and is especially useful for documenting contracts and functions in detail. + +**Contract-Level NatSpec Example** + +At the contract level, NatSpec comments give a high-level overview of what the contract is about, its author, and its intended use. Here's an example: + +```solidity +/// @title Liquidity Token for the Foo Protocol +/// @author Foo Incorporated +/// @notice This token represents liquidity provided to the Foo Protocol. +/// @dev Detailed notes for developers and auditors +contract LiquidityToken { + // Contract code here +} +``` + +- **@title**: A short, clear description of the contract. +- **@notice**: A message meant for end-users or non-developers. +- **@dev**: Detailed notes aimed at developers to explain the technical aspects. +- **@** **author**: The person or organization responsible for the contract. + +**Function-Level NatSpec Example** + +At the function level, NatSpec allows you to go into specifics by describing parameters, return values, and any important behavior of the function. This is especially useful for making complex logic more digestible, without relying on overly long variable names. + +```solidity + +/// @notice Deposit ERC20 tokens into the contract. +/// @dev Emits a Deposit event upon success. +/// @dev Reverts if the token is not allowlisted or if the contract lacks ERC20 approval. +/// @param token The address of the ERC20 token to deposit. +/// @param amount The number of tokens to deposit. +/// @returns The amount of liquidity tokens received by the user. +function deposit(address token, uint256 amount) public returns (uint256) { + // Function code here +} +``` + +- **@notice**: A user-friendly explanation of what the function does. +- **@dev**: Technical details like state changes, event emissions, or failure conditions. +- **@param**: Describes what each function argument represents. +- **@returns**: Details what the function returns. + +### Replace Magic Numbers with Constants + +When you see a number like `100` in the code, it's unclear what it represents—100 percent? 100 basis points? To avoid confusion, **replace magic numbers with constants** that clearly define their purpose. + +**Instead of this:** + +```solidity +uint256 fee = 100; +``` + +**Do this:** + +```solidity +uint256 private constant BASIS_POINTS = 100; +``` + +Defining constants at the top of the contract improves readability and ensures that their meaning is always clear. + +### Use Solidity Keywords for Time and Ether Units + +When working with time and ether values, Solidity provides built-in keywords to make your code more intuitive. **Avoid manually calculating these values**—use the appropriate keywords instead. + +**Instead of this:** + +```solidity +uint256 secondsPerDay = 60 * 60 * 24; +``` + +**Do this:** + +```solidity +uint256 secondsPerDay = 1 days; +``` + +Similarly, for ether amounts: + +**Instead of this:** + +```solidity +require(msg.value == 10**18 / 10, "must send 0.1 ether"); +``` + +**Do this:** + +```solidity +require(msg.value == 0.1 ether, "must send 0.1 ether") +``` + +These keywords make your code more readable and easier to understand. + +### Use Underscores for Readability in Large Numbers + +When defining large numbers, **use underscores** to make them more readable. This simple formatting makes it easier to understand values at a glance, especially when dealing with large denominations. + +**Instead of this:** + +```solidity +uint256 private constant BASIS_POINTS_DENOMINATOR = 10000; +``` + +**Do this:** + +```solidity +uint256 private constant BASIS_POINTS_DENOMINATOR = 10_000; +``` + +Using underscores helps break up long strings of digits and improves code clarity, making it easier to spot errors and maintain the contract. + +### Removing the `virtual` Modifier from Non-Overridable Functions + +The `virtual` keyword is used to declare a function as overridable in derived contracts. However, if you're certain that a function won't be overridden, particularly in contracts you deploy, omitting the virtual modifier can enhance code efficiency and clarity. + +**Instead of this:** + +```solidity +function deposit() public virtual { + // function logic +} +``` + +**Do this:** + +```solidity +function deposit() public { + // function logic +} +``` + +Removing unnecessary `virtual` modifiers can improve your code and prevent potential misunderstandings. + +By prioritizing security measures, optimizing gas usage, and ensuring thorough testing, you can significantly reduce the risks and enhance the performance of your decentralized applications on Rootstock. + +## Resources + +- [Rootstock Blockchain Developer Course](https://rsk.thinkific.com/courses/blockchain-developer) +- [Rootstock Developer Tools](https://dev.rootstock.io/dev-tools/) \ No newline at end of file diff --git a/static/img/developers/smart-contracts/best-practices/flash-loan-attacks-1.png b/static/img/developers/smart-contracts/best-practices/flash-loan-attacks-1.png new file mode 100644 index 0000000000000000000000000000000000000000..b4594c4dbab8ab16c28b5c5a17573b51177e8c50 GIT binary patch literal 14662 zcmd6OV{mWJwry-X*|Du1+qP}nwr$(Vj&0k?j%{e-{_ z8gupR>d~uKtyYp06XW9q0#X+hQczRi(0~B~0)qNm+rWT2fPwxZgnAr6Knd)?xxm!z zV4c8xwk+wAq{KyqM9k+N0q~KQcAxqk!=>ity8h+)$NoLvliq;ascXO*z`C#3EBbYA zmf!LF@*Bju^%@6m_c;&tw5B6`! zFF-x!J>UxP>^}r3el__{2dKa8KIwP)Edj&<{D8L4+kW$h_-p?szzCr9tLkkL0JuJU z5eEQ1`@#q|5djBsMX6%86{U*VR#Ylx8&Rs*t^W@J1#*UKm$lSKcZQ$mV0FbEp7|1F zzIfA3$N!h`k-&F(*P5oeE&j)eCs<-O!`K%?I%t($%kEgD_K0>>lz-ae^nWWU0-d3y z2ylUuAt3}x(uAD?ZnL;kaeI1NmNmF^&!rMvx)z15E9w2*VL;oaXAN%`G&y#RY3jxA z)pYBH&!qQRqz}q7lyW3?augw%^!}X_`I(4`Mg!xU%omJ%b`fIb;0nZ@HJmhJ&E!c8 zxCLkt&;mt(u~_#E&e8&f3k&a}fgp9vCM$#SQ^5k!MUyOb^javgxWPY<#OCma8+3f8 zNgb%SmK~UGSBk!Z=BhJ*ymDiQ1yMWoQ?e_rM1X1VLA7@ zLo4wO{8hMW#7f3nyaDE{6eQi%M>Ni8p(0(CHtM0R=-;S{q&73){Lu?!h^e=d{QqF` zLR&`cK)9E9x|F_3zzIAko_-z@$+0Cyq&I}&Hz+4fEk=dHKDV5@27p8rteSivkVEUq zVx~>}Cg<3LJfUGCeBq`eYc3+2~Fa#fSX zY)eWNGc71OH>PBW$u5ZI|L!+sxBvI71X#y37#!l+sM8+!tr+aW|0l#5gc1nDMijq2 zd+omwg?Egv#5l5X!yNl2!Pf~38$bQ?yv6Wi5j-tq>3sSPaNeY9zH%mC> zOlY72KQJ4!JfSlGL>%8NQiuWh88#4qB&MJ)79`JHtbjdm6yv~SrX-bnOvcZE&G9r^ zjbIONbdh@?J#6m~?n{$&1wwCkcTGnmE(@#9e2i8GNTmHAa}mg4tj*?fz+@g21P=>h z%o|GACSL8y=mL^8qT-2J81=rj3kv@#h~Gt!qDd3`$@wQd`TjQ5l=FWoMA9!S^`E!I z7&)g437cN2uxCfJDjHv;WRfo&95CsJL(#7Naz*t@Cfn5A(~bdx12Y=j!J2AMgWmB@ zipM?#o9qire0L|YbOt{xewC2@zUWsm5xX-vM6>)SNSv|l|BP1r=S&@i6stMrk>)O$~#^1ndO<#vpl8ZuF+aXA(s?U}mSTy9;=xAPsGB6r9 zPv)|?l8#;kxH{EtyaUWQ%Trc9{d5EUz(7~V0If)Jh;vGo&wx2O_jws9d!A;Udfi@D zY+IuuYahY+M-+`SfmMGWZigQHw@~uKspvwt9nB9T=e)WUa#6P{V8c8Ifmb6_Uu^M1 z%nH-L2MVir{%1glKiYqQ8HG{-7T|KaPXQ-Z?_$Svs5^8Q7dlmvsok;p#b)1%+62^-eZ6dJ zF6B{^N;XeL8Q=mVML<@(8sGv-c_%aRw?~M3!8~Oy6$J+g--1^8^Ba9m-;AJlq9F_ra8Q%5|*H%9*T8*vLpw2-|7R;%(>D<=Cxg85!o!k&S zcQuK_1-TuR;|`~q1;*Pd+V!2v3$9x3t&=|LnDyUg%$?M&P_dR~ap!AL`ezV7m_l`R zXzFvfOP&OidbTig%}Xb`VwJ3hs%eXOj5>6;pVu5!UFDVY`=DF@J z%q1aXGs%Tzuo%{oj_L z-4evkqeN_KiOB`B%~x10RV>XuPJzu2HxH~V<|`VY?U}HYi6k}^rHWDu9*<|Du2}qMFbmz^Xe+p!8;D zvR$6TSnv|**O2~=v@M86qhE2?OtnB=Q)UcJ-6JjvJ$*&q&}Ou`kBw(y^0crb;U;W1 zIv4Fi@jJ`1#H)%DkG{F1@E{uC9Gym{>Ovp2VjvP5neTZ^83SPW&qoqVJ|?}jp@3D z3EZ`GvT$89l}$Zh^rgEzC}*?Gk1YKpfs1)o2`Op?QE_0-pXCYsER$3A5RF|a3c{ADVUtIat17VxPhEVMutj1p zq~}3DjKLfgxi(ku&sj6UPh20FfPhm^2y89YmrLMPuD~eH3ggcoY%j7A!-;+v`J&x< zrgWW32K{Q5oG9LUyA-B}CVW>%rL}#m_XF6X-w#lY7gd)bcU+;sPv@xz7r&xAjg9KO z$KvlR;Z_>QCUF(M!MJ@Vy!Sk>uFihN72YZKKeWy=HjG{hkqPKekZ`SWQ=HpNyQoZ* z>5?o?O*1rLIR9p|GOB&mgp%IbzTKLAA8x9*^m};;`AYPTy=S>3CN>S7KF)F-9pm8U zc)r3##Il%-wX7^hM+bhtX_HJyQ6ar@26?v%h2w9ulg;SyEjDRc){oMIk-TCUZxzG# z!7Njc`M8vgJYy_6Y0}?L=}dwu(e}o zA_K-}MT9Q2IG(B(**$3ax@a)h-(o%X@CU$vPes_s`5V{*9GpdI$C+@isp)ARLjP)br0LZd<>;$?GL0Kq_x|1P{g3EmpL1c51wGBpo#}=QJfRAW|TKG(3;NV zj&efmgIM}e1~Z1>_sm_8=+XN4YYcht<|(==7uS9R-X5_GA1>o6KBAvkd4|@*D_P%` zs&%6=Riel+w=u(0Vc<&^?8Ik|{^@<0blK%vLg8BUOjlr)ZY?==VC}O@m=0(DOW67r zvYAGw$JPHsa(e#{;;>!9A#F6FJoe?KdN~b8M*sif; zspOB*Y>x)`S9dmqaJgU~Ls_5F*?NNC9}(n3W|%oeYSKWXgS4;-;Oh|s9q zA7wf130q--z|b-vdN`s=Z^jT>IF&aF|2vKvdfAh_Yx zOb{5u@}V|}I|AO2^cyrf;j1kb3#Wqhh3crj{_OBOd0V@~%cryP)P$Zivm=Vi`#UYs z=OqlXaB;1oCL{$^rCO*Nwj-fj49tL`d0rgGhQ4=>JXT=W?pxzSO9iXw9Q<2tyr_;SFHm-<1sPU3|j z#2f(ql=;^5geGsG9uvMiMYY95~gcZGbtD0_M<3w=AMs6er5HU5h{$q*n{ROC_m z)s`9bl!bh#-|-(Syn62-(ix=V_5)nS07E7kGn`dwf8kJh;1v8Tfa0} zba4B!ZJx=NYXqjq>3sQug%iCnvm?@?yTJ-!aJ!R+-E!#>-qdrje(7eeb8<2?{7Jx~9l#WzqlJdC_tgy0Ja92@&65MF?%KLTB8MCu1k^Ph9RS&6>NuwFtXtbMCeXlFI<~;jjp?Fv8m41 z5P=+Vxpn`H^H{$SZG><%{HK|p_4W9sMNs{G`?~loqongE`PsxOZ)(%_F9j!9tC=!I z4TRK3;&;}ikSJqpyc%DEotpc8j{~%_!P$Z4(L7*XHp~_AjI}SZK4^Y0s4=&Z8`cxc zIYROpF#ioC%uHK4t)b-g{+k1^G6L^e9{^EGGPP3#eJO7xmUzjgDy`FO&gqOZnEBW5 zGqZ8F^9#deNJ1+=<;T+GN2Q<+`LT@LBS3OOnX70-0t<~3;a`VW$3dcl~ znIYs2>~!Dd7^a^=?EGeq9$|_-GIgN>bv8H7VM)w=DfOi7ZKK|RB3}Ac+1-8vadnaRj`&-gicMcWCi{7^i6EonA>_O zohj{+M}y(1*ldSjCe5%y0Xfm?4>7IB2K7jZ5aV6*nSWTG=c&VT2HjT!fL~h}OTYPo z39Eg?BpzuuX!vSx;}rdq7@Lr=+Q1i1`vjv6nHbAa7DyDnOm6DECLPm%$$T=pj^f(S z9wP`6MVfu=JGMKD7Gy*UPpAup|CugsZtDUi>g!zmwOt|aEFm_He)bFa9M13o+I=W- z0$ZbXpcP4S85y{nS~60wRBVudnH04>{-HgrT@@J*9!Kpv8=ICQG_^Tv1gsb8xkW5I zaYd&edS%H`u`iv6u<(9D(S4KYLc?R`Pj_aTG=`QYI1*_ zk5UJ+0i_PVf{B*TQ`ssM3oOHT!>L91om;SWMoMXU*HG6wbZ~&$01RrnFWevr{ZLb*^sYsfxg9Q{7J+t~#^eqxGty$ddMJM+W|GS{`~+dItG zk&ZEdUa%+TzNm9uE2kQw&YQ^#KmttNBd^`ueq38|*7nSvl zr+nSKbD+@*{^zad3L7W2ZVqS?Qldz<@>4Q5?;xWZy)8ToreK%zdJRV8$LhzHF(RwI zn?*V#Q>A}x306@}(b$CoLkeKogFyUUqI~u`-`APpN7mJw+MVM(P^Ud&J9)i4uRfBh z=-Xb{R4ULj^?P^4iTgyK=HyOFL0&K<;q=a}&?vKWD5l9^#bezbVgD+^ny6Q)9<;6u z+Z>+VLmQQZOM$r+SN`RycSe@*%epNew?nxmYuhZ7Yi+dX|a6df&qWvwFiXr#mAZ(I~>c?G}(JOZ0pj#+xnf zUYZmUBD!HyRulP?(Z_kLs_|#p2b6RSLj5D2CRPro==SBox#tRdc1@+0y7iz1xNruU z=;Jyo$aW0vkUJkI3p(DwHW{px#**N@X%KP5&wZd2&(q-I@=JP?jhkKMz~6|Dm6aL> zm$crc?h#ER(Db8I)jrm{=c}zO6U9N;RRa4@|Y9Q_mQ^IVBse1+?Z^A zVj_G6Z-ZE`z<^hRUmOuqn4Yz-x4=y1?{jaj zob+zu>MEqTY8TlszY9K#P}J6t{i-~J(N$4NUIH=fAS8PW3Xwh<3IfV(wURHFickM2 z@~SKUc)x+fr@<7K)o{NmvNRXic@sO`(YS&NE@Vvog^ta@U~)HIiLO5d2OUZgZ>o1@ z6c#%^ud<*i2rSiM#OdH3%U}jf_jIzbMNf1AAgc>xV|6#*JyE~=&S;ps54Ne8Pcbl! z=SnG0L30Qy95aQ@(zrG=YAzBj?Afsfhtel+zzxUGdt6%@jAU@DG||K&-syMmp@M*S z(Bda4#os)d-T_493_ji)ayR5qWWSz4{=Z4VM*YC)85B6iu3+^)wujuoeE6_ZV7vz9it$U#Wls{r8_+B$8 zs=rKZLWb^KgHWG(>O<`IV8MYW#QeKBow~S*VL=xBU|hi@ex#X#_niGX9)B$tI$#Cm zjkz}AM?X~SEwiEn1J|ZHK_7(Un_NnW&?2W}_GnroSW%H$Y<#AVJ|Mk+H4SPV4xQxK z@+mjS=4)C~9tZ>vWhSOy>UsI2Twos99}qGJ=!7tmv!7zTM)HVjwlbNRSKP;eK{&&K{{C zGQKrFn3Nfb?>PrixXmf#4QaLnqXHv1<3ZP)*~pTeLJL zpZqAM+Ys$aMas0V+|ny*mAfAr(mxS#IMu+3fxd(kuyiqVN*a?2-p!7Xmvw&@K}jhO z!LlrcPmtqg;|`ICOqcB%;v~zMZ9#-}>Mxok-uE-{Bb^k%u$sC>n?z2ymFOSYzK?^s z(^NmLk;SWT zM9b>DOL27OP8cvx6CnY+pYw}Cq6iB$bcrqIC;se#Wk?}9<*+sq!onjn=UW0p&qelAkxH-F32G4fSW8@OCb%@DFw42#^#85bm0rIKEZ3Q|QS*yg++3Pi*Zv;I&C9v(vIO}sr|eVDye z?&;5PU$2=~*v<550&~NcC|(iUH6RWhxkU6rkQ-3-6xgFToF2|X$6g9$*m1F zeMrcj1~`IqVNm*^->Ryfu^n#4N{SgW&-cl!z_G%duxSoRj z=%ySWL-`Gcb8bmgke#(v2|63xfU;*EHlzNQc90%5mQr~tP*zzQA~uDT$4U$e0q36- z^EOgpI7^DaLMY~%{=*<4K^D7bT^D61(Ku-{djzRI_v19L>wu_Ech_3;ejDi)1E~=^ z1PUP8H#qhl1Uap+*aPHl)SDSCLhmOR<#{A`7L%p;2FJ|=*5pe7Ce|$ts+!E4&wzst z3-Ku44iZse*ryNkHQ8B*7jDK4dU#nR@9AJ^TUFm(J`g=VP;@;oYv^H%o&?)jJQ*WP z2D_;k$#zCEIKOH>DJ_1J6QPN2|8MHkRujw?vW>#K_2%xeUwfQ}LT1jWXKSj^v6kg82V9&*gCT!f>tJD{i zBD_byb_rU1ZY30g7rIU5K84@}B3zpn2i<4m-kN6S7dWeqs7SRRD#ZLPhd3AT5s@;} zBQ0nz5Q{ucE^sPoX1>gwjf;MY78P5jabny~(-c_S!o(tIk)i^2$t9D@@Nj?>Q4W5o z5=f+rhJrfYknyLGgrLu}a^^4Fnb>l!0!y|TqwZU)!Gt;LtftqTxB@+84hAK_m9 z+5OCe0+^(q(SBR8<`zY4l$x_L2KyBXm0nq9CZ4ouAFPm3RYG#(r%OG73u>$)-MV*= z&nHv03TD+}y1aI7Y5jmH$aE6?_csK-p23_iAtnJsF(>r6O7Hqs_2E`U>K5{{+wljI zUUZ6HXehgtI2FWPR3kHaYY5yK4Ry8tGlK0r_e|*Fs6wLs!NLO_Eldm8fTWJ?^pQ@< z^K8pCsi&am*S7L!7cfg!H|y#8i6^=?F)ET?c0NBfyVdf*h%SFy%-IvjVFkC>3y6M$lG(`F>lE9~lS46_ z9Xa*u7ZWV;($`w^c`+8B*p09E#Fk0+#FvGcl-jI)z7{{{P<$|;K$!PYW195Col zfn_Q}=M3~I>@0ySu2-SCmA)>yN?0rf2t9XTUJJ*G@;U~x9Orl&OA zZT&-c&(5^Iq-bI{-^hQjavFoYqH<_`pmEYJ&Fkn9Kg8K6d%*I_E)GFaLpqpN4{Fv5 zGDGD~y?>xIvZ)i&ZkOxQ{V+m4a) zt+_jRX)%u*px3~b4e=8LmD~d^Q#HILR)>S4o%;dR>u^nw_%m^ZZ=y(8(fg0yv!@^9iq~_H z#inx)`a@^FOr;A6VeL(IhdSLM$Bgfn_2RSgPr~7|e8}vt? zXW!bAlAx`VB~Gx0yJ6Lze=nmjaIOl_>Bd1O!&#qH=LOU?j#vp$C%7Ix$Xq^ zvp&nkc1lcIhKAf?rIRQEgOoG!cr;#73*^kZ9!9H#M$L;8(W{>)xfX7rJE$mFQ{A)g z>=#HQhAfYPc(D~694s1d{HV%w)FV9^k~&T)Sa%8c!nO(`^YXM7;D~K^h^#b$7TUX# zY*9zgSB*$qXw~VS6dijY!M3EWuq)MFX$93G9vM~lYAckDw`d@9#@5M;;$IA0BuFvf z39X{3!UqcP#5on&2NCa@|5L*f=du2yOWUUZ%&UANq410A8hoSX=o2!V-%DNEfwDN) z!?KiNtxD@dUI4c#w!8jexqh!QZ!*B+1{~oD3T0^2zJq?_5g#-?q*#kPu(51BOD`DY zLgL8&*1t^-0~%WY@09FmDT9i$%)?EA!Sth82gS0RcU0F~>5bmj_L>y<|0HV`i-MGG zVzgJ;ng{PkOj!AlW)^@xvcQxZ zt0mPBzSqEEvhesWEwl=#DCMCjbKgu8+umFmaZR`!)r@nR%Z(!T{xi3U#%Nd>Qg6F< zecMj?s+%o2$N&DMZouwX?zItYD!K&v%^|u(R9Sn;hCILp==T#A$DLO4`4L}ogRh)~ zXec=aD|8urlps}ID{N4l#d@>_$L)#}RoEhK&v(HZ#rs4=1oKsI}?5(on9$zf>76*c}*4adKA8jR4K#SX?#Q{Jv`CYG1Y`#7A7}9)cjXsDC}PWpWYgJVhOZ z9@e>=nuR(MR+d<5YSl({0+(-~!2|?AWM&#vxAH6-m&Ezby$A%Ffve4ZM?w-dW2@GO zG|tcBZw%OvhektWD=w`^W4N>@_WMe;+R~2S(9u>kn^yLRx0nLnhkKFqsp|YL3D6PFcEYvA}u9ju|he#XcyctP9F^6>{5A5#@*j>mon zeET)NOlSJBQGYyk!C;Apzrh9VUBE3H5)1CP6F3qrUU{~Rc;aPvfnj#Nbq>t{Yq;KZ z&=Qdklj2qIt_<=Luii^GXd6GbUD$_jTegs=rsI<_3uc z#I(rEu)8N{3K*-C)cZydkGzyIl~aCHq7|ZHM+HLQ9f~xWa2gf5a9v@Xkul&49ki`y ztHLoNgQI53z2qEvx=wZ|*Y@#v>}Idf-kkW~G6T7`fgsl*dtG@qd90aJ}vGOHnhJ<$e*BEHVL!4hsGFk3pcRLE8gY^w6; zRW=fRFn1vf=z5`Y#6`Ap|7NI0fU2$|WG!hnaVOta3cx27G6W4xal0doZB z+86~-D$@b46G2zt;xfUI|a+(_?k348jC~#E^UspEq{#4EYqCn;vI1H74ML(9t4_M9Fd2is8}=g%kUOQ z$ZS~CCvjk$D=gIktJlqfg+gTIt^D`kv0pJtzk(wisExdKHl=Nq)N5b=OY&6`{{}1v zrQ#8bDIo#@&@X`o4~|#y;$rxFbIJ#5e;hgtQoFOyALbr6c3|FUa8ZppZ_OIbdyfY+`vO=eF-g zcdO)rnkVXP0IYbkZ2s~kUZYdQA`3$Y9Q8?vkr+mWq7Khl?o%IC%l(d_pN#XaVGfmX zR?VVHSXtWdB@%@{Kdql+fITy|`wD;uK;NI7P-qTRDr*GtEAwcZi{cgS*1jixD@Mk5 zUD2vIt>Z9?njjm|xlc$#jJX4%|&^VM4cter(by8A1%bJenGm{7@4s#H{wkgAuz55BSy?VP3czy7J{3JBxnUalhCpkmaIkN-*I7* zbUs!Y;?Q25;ZiOV7s^=>4K3H)CIgt4lJ*+XfII1N>yaf3b*)E92{~TXuC`pLu)ac) z1iqZFiqZ6q4I{^xyRSi_tClcbO>DaO+MZ44vb@G?kTQ}~G$SBqwqsK)X?N%w#IMzM z-WQ)^Ydvkx!!lXR6e#OCNwjX7(BMUg!kCj>zF(OPlf8v<{DC|DhKm7hD~roq9-%zr zcaD{P3r#vXs{v`f-l>^6n)%bIEUZlol_2ATv0K3dy?WV4&JB-Yt-nZ zIJbZI@E2K7&wYmppGypO(cRk_6Q}?!emRE|umxz4*f2*0?BLr;b)en)d{yVL!4hkr z;fQYIUs62~P;Ti{(cav&K&XbML#xLdFZiw+oItAaqN*(pagF84BB$lnM}v<({GiEY zQ}9(jsFSrRsx{``IquFLWHsO^WavPh_vvGF!-nJhlvlj%Hnez5 zi2JU}lwOWRCqmu&g5qoWfl$)i;U^7Ui~LmjjJ&8qL$E^?x1f+GKd)laSP*FwQeoYxd z2EeY2DP2q>C~tSrIE2zQn+vG{>6{Eh`D+!u8L3lDMR9htRj+{lS)&a}JME%hHR*&vR%ULLOeL`Y^2dJ3thEJ5Rp!#Ash!n*^_{Zd3Zdm03nMiWQLrMgCtG9 z4Vw^ipjZ{IrN_mnsfM-=(+H*!)kkVT&_xj6(dV5i#f?%DT~=4@Vwy{B!<`9HTY}<; z5YuX$32MOVCepCyFT@}W@7?g0o>owi>|G3g6Rm&t>t?B*!lSA!y^NuFrdVMP4F~&T zDVdf4_U1LfV{0k-T?d>b3{5(k4jzZZPQE%2yXoPuS%wHDP=87bYb8!;Dw*KGE8Pt# zNLK}AG(QvU+Sc8!NrfWVT49$@r(9Y?5{m36s=GqdtjIPnb7Bzd9R!VnNKF?$0l&%$~Hxm6Y2R2U*%^m z(MW@8vZ$RSf(biq;T-Z%1>;DIPw9OG?g(j~DuJZnIA3e*1CBydDEth z{IVUtdaFhVnRJWb92EH15`>}>necElEG;j;RKgxriwa2hc4(_FjI`Xgjb-2g^CuPL znDmr_8wEyB`48kq{>E4iMnS!M85tOA%mPe)=L*3)8^R=Wf=jXK>^Up{Af^Qs(;|}2 z1bZ#+mq7;Gil=fApW+whKK>a>U;D|VB!sCufi-Yt5XIxIYKAtndubFaMVAeY*D-CEcimGB2;LmajJI)lYpRN#1764$R#H8`5u7C8~QhsPa@0L3mCk zg;$K&U%|99jT|_6J@SH9X_$16tn@pk*O9y1fvFOZTV%5Kqap@LYi>zE9xw-Nr>9f}6$vHbUOctt**V72yYl^X; z7%l^;;4`O7@AZ55noybj42#-H~mS=%1nAy5OU6tXc%?ZB$D6$|C9<8C-khi(yN_-5X9RT-!@ZM*sESZS>8 zQ;+t11(unXiE2pDd|#`>F@sEs?8h|)^;a8y`6<%QbeIs`30_j)ulpq%B9v2G79V7D z1t*XOuvJ!V5Ni#UC?3wldf`wj+?6G;Nzxp_t$dm@zOZfzs~-iKfsuF)>fP@aT8h$zlMR<;=6*)83kmv%A15 z3Ws{J-}0y|MwuR|ea2LyXu|@OJwy!Qdm~4BDo8@?SV)>p&WK7feDPc<>w#Pl|K5zC zs;^5ZwNF?R3uP`m0r!kN_{WzO8+Ni!}_=@$#~+u9laJG@#=V+Zv$H^1RM^hwvKckj_`& zU>kNETYZ@h{Srfb_pE!bU*VY#GNGX5lu%YUvoCucU_ioa2NlW#jp5P1=LqrqBtcMM z!)8t=v=^f@``QM->&u!~0NA=}+()qrc63J1%I5J$<0{@rtH{;RY3eDV|89$fx^tyF z6P&OA@~xOM(P1roFG%VWoWz^eEo;H<0uYp=gP zxziB-{rL=EFla*%lL`{}rYEy#*MAy8xNBTDCF7%!VJT;WLb0mb#Whw&=L4*b6dGMv zSKPg9dmhJzd0t|K4f1lN10|6l;+A!Vv?_aNZK6+wbp{py zv}eDvaEN|&iuA@&>(8rjHz?b_pa0ul4M5;PvBVArG=0Ykuu>vS;_1hYpW|qu zb%zh&)$`m%2Le*A-*9Si5fl^gI3nzqB57dJVTqNwV`r`JvO!&ilKgwz@P8Fi4N0-i zzlf-Zr5O;Aq$KsfPar}7p#Xyd0sqDSRdIm9|J|znwSWA_*86Ky{>KO8uZ;@w-~N{2 zVE^|2OZe|1@%Q>Kp8wNA{5{kN2?X{RVPs}v1Wx?N2L8(cRPZ01iIEYw;2%Z+00;=A T;2*~Jzc+#Y$L{P^R`~@=}=kv`4y+zN{>?xf{N_@5w)|{V%up4?hQ< z{=Tf=(?5|Pt(~GzydS=EKlP8L@9gjR-@KwKb^ThUyHsr zy+1!Ys2yjkYRr4%ZVT<`#}4!pN4m*lz0~nOszjeP!f#rU_y137&W4Us<4W)~*}`G0 zIbU4wfF<{k4?g!*)slU_gh$0?+FqXmGXOC?Vq5wD8yRAfun2?l{h_oYE7B~87~>Ym z<(C3W*cL8x!T{OJT#suE6h0$}Z_YibfKFiw5i3t(gV^Rn7j^*BkVr>=E|}!Ve?B)( zI1>IlH9U5)hwGK3HQ8&LLYDrS_~5%{zTEus3z}Wz#0omXTBrl47Y+AjLJ|9>GS)!+ zBu*9|{hv{4J~uD}=p*h~CM`2rmT|%>2!5HqY1V)2#vTqbhoBB3qSzB{wQ4th!E8wY zO2+DteGE8P);4Bh@;V9$-YR+_BVq-e3@CYU0K|t0IGA0k62p2MlpaYF{XV8B#$pDR zM)_wd?=BfwM0sFd8FH#IO^$)$bUz8q-|hq>i2On;Q*t+=_&pt0R~-TT^n*nfZ_C)E z0Oxmcb+8t_e1iZ8>ufc|zP^Lv_be0FPbU-l5h3ZZ{&7(uR{E}E0}o7U^naZQXaux;z>IYX=7ssU3y>N~mvQJHvVXlk_Q;QNGWWmzuUR3F|1r+x zTp-L6jw4K|l3@V}9cd6~^gcT*A%nvH)oaYdyh*}2r_NgLOW-wDRU1ebq1~4d^H!tA zPY3E0DAgGxY>kZv_7`3CDP3ZANeXR^Wk^dzXPS%@F}i>`X^tz`ngyPGQyO?Y=4f0Q z@jY``$TSeGpwf1)s;cqg4msftiv~6_kzvB-yA$+&XTh}@9vXIh1z=N;ZD63}X5?k85%felz16I>*d-pPz*~EdX@A09 zu^mmV{>5P!&v5w|2hWf^?9$tVUZKkS8`K*hiv;pGuA1VgZ@57DW$jc?1K@|%A@=Cc zPql(KG|^xMn0*q3{cHJlabFZPeA>j<+YR79LDYdi4fJP zyumf8`McU88a7@as)vw6KReblk|eo&?_V@&z!!-+UkCME9TtFjV?q7#ODMl_qXB_RT{Qg8HNHheWpIsP`}h`ZhQkh<`ETt*jM~y&%{FsMS1+p zPR9F`NLfJz-1dLX|Dilh_&0L?4Rn6FLT%n4)veS@zVUDV;Ymwo4`xmXy0NNR-lZ=g zkd<;$zl-Im2TB((od9j|5l;0L<&`<2`-D^}pelCD^FjXgjQLm|C_VK#u~}C{Awk+d zG2wlZ=#(Z`vid}3x83pUKe&RKxKw_u<4sM;BNG27$pGtwe2kxX%HiQxz9zVjrMu1F zkQiPI+r%HD|GUB;P5!f<{uf876M=|5x@RSsGIXjMKDdHMsvm0pf~>zKzl`E$>~qjz z@id=e@~6Vp5)=Q2(`>)=R@PPY1avi$_14m9s9ki6s(SVzSHmd&Xd zeWRkLUcd^>lr$1uR_3D!HNvkiMx|F*+bkPC|MpOUB-FV+<^TjaQ+T-!24XSfDi3>1?E2??G-vk>~<=IE2=hs zADe2aI&nzyfx~Ah9YFOv{}jc zKR6sOrj7Zx{KRm8Ab#unQxN54#FAQ_mHpy?>&1Ctj{9IWxec+w~V1Nx{q2l~&Mn!1s`@c+uOY=HrHJ+z}l}214Rt+ z$Iv^%_m4KV6=iUbokwhB6~5@HVHXGMhm0M73syl4%(@WpK+nxtklAc;sY#OuB7lkp z4JGb=t3d6xbL?EuW$W#l-EH^}&gj{a= z4Hq2Lw^HxyR>11~M0V~kRd-v*WY#r@k&EA1hsplNWKsoN6&BjZ#Kn>7e=prT0MwWU?w-16$@2Ouyr^2QWvQ%4`{~}0y zQv971k1`KuW4n>V6)5F8#Rq(FL(pFA{}y<8wCd8}L-<2|ZPH7LFY78>Utqg<9$CR)&T_+J5X9KlO_=1KRB+fHbX^zr!YHQiD)-@sb8~ z^y`^dLsi}%HE@Ok=YChZs`FkzMTKv*0Nu(l$URJv@WddSPD-(*#IQQ3JtDq5p!{9Q z1t8g3De?=oQX_M36v$T@`gPcliJ!9R8iPXkh@J19r9XtEJ7}Oj1-nPMh~8H@^}drb zhXt*As+Q{k4Jk04f;Bp}H19Ilo0eUWR^t!x9|)B{@%YqSB49>KmejajFgxjn)3#yh z@NTs|OOG47O4gf&nI=Cr@mt^nT}2HPHZ)7q6S`mg+6DUPHU(=u;{GMHS^zR)Dy;-cG(%@d`bLBdZ@YqOzZndBrZ|s&^eW7`*!cIR zLZX$aifPPJ@?VLO4*RXAR%YkjTsVuBl>8ans)BX0eiBl+i6O9UA*<&^9=#*cPG8@6 zg2=Wz$s)wGp_iVyZobtw}YjgCO1A;pY|+wnyXy1*|W7ioI$ z3n^;A+a|m!vp!L^^}IGG^boJ)CCtUlg~SC~$I1Mc_lzs#CDF?Rq?$3*Ls;eu%?D9g zi_Lv!%8cPbAi28Y;1uT_qNodMzWTMyrDYQuKMLeWPja}h+3g+-P@cUd0B>l^P)1D< z1ugl7>8uSgQExzYefEL0L9M*TE8X4Uegp7r#`BIyrSCY&z(|vOL78l5_j1)*GF;;k zN_V5XPs9?2g*EH>VU4@VR)3VhW+p$y7mG9*q_hFTai9Nr=q7T26y9Dh3=~w5vWZ6k zWCw9(d%GId0j$J|B-#N`TsW9E$Ewc$NUZl!$EXie-F6K7%7uYZ%fD?Y!=8N z;|8s0@#(=y^)JpRc4Ts5${uG~02sS5Uj729S}q;EfA% z9yGW(LxsKh@(^hmxQSbVKfVnnB&h7LUoXQkL|$xTa)d=@4cm;mBVr|_{HwkUOI_~* zCFj;}A7nE781Wa$+qVY@No65dM)j12)ZtKb4EcNXx_h*Bh#fl^JAwAMJ(pktI|#ah zm&WX*!iMk;DXBqlHHd6Ep%F zpjnu)iAz1EP0Eu-;y}qiEsp3XM6inqZiZOoAbzX~4GUD z868eW$PFO(E1Ao>yttxGSz6Ef(LR+lTPLRqLdgc(?EcyJ){oZ+flyf;No6Vcrq;cy znDM=Nd4_?AoB)ao!f9g=VRHY9oI(UhaSM{Ufz|VZOEnzfFuHmysedqzRpDBw-jNcU zde9&+gRxM;b!$bxf+3W{creqg1Ti?|a4f<_am!dafJFZYC@uB$frOS`^w;gI>R{IU z$xF+!Z=?DHIPtNXnz0Ard{6Ez8V5J2|X5j2jY zwom6*-&efZx9rtd&TTyN)542EKqSw~(FLX!%OP&kiCTMIC(!vO?l`F1AT*>yH}K3E zhWq_|IWH#v-Dmj`gEPjap3Ev1hc{m)MQ$qy7t+L(XrT&T=W+{n#6 z4@Ak@Ak&LE2+L-&mo5fNNp-dG^XdONsY zT+k2%KzdnyV{|E79Q$=CR?5}P$bzc*1XcAtRAr+BfCgNcpDM8YsnUC>oDGb}V-qME z+{ub6LiXAx_YMU`F=46^SM?dAL?Y#oKy_y`OW?HUo;7hq=`u+ZK&OFntXp3Ifc{E<&yameF=n1ki-l%dXRwn=(ds+M3o6o-hH zil5{WsJmv1v~-j~Q=CT?SCD%DQzntAe>4F;$yy zi%B) z@$}$B@6+KLEcabIv)|w2t|N~DttC)5M=NYyj^EQcrJ`?yDT(+HARA>nd-C(`xXL5q zw0+Z3FMm z^rTz)g4g|&vHgkEF}7H`dF_lf%m)1|@FHp+X+uY)3$&~64TD4lvn#O9KkqN}6(2N3 zIdT1b8QbS}K-v9ZUbPH+{;bNsn|6`mgiS1Vbw3Vc3Lx;ANvjh(4#`EZw;Hoyg!DA` zymk_$SJuOLr{M|4X1q&OEI207+5H1_livRPE|#?D(0dAqO(UU2dOCRH=2;dmij-fKpsJ}k>QvcP zj18LB5#^07R%w!sr}4F4g}APDx2`w$fskfCZIW!-Eg9ib@u2Lz-8!nT98gxa5tks< z)QInP_Z3P`+kc&*SS~ujR=%&eIAgsygfuHrA{N2l1OpY{n90n}spAWs=L@{9T@bRhVkR8}wQ;x{Zn1 zB>FexHC!(Y7l8qeQ+l(Xn@imRGu(nR#2|iZg-%YB%Zx`=c1OBT3CxJG!qH6<0ZN49 zmqR}5+?Y31ejgkXDXAMx2Xj^XAYd{nFpV&Jj(-4Ga7)Fb(2AOZ8D)jtjb>0MBr2K5 z#7rm;iI7SrTj}A?WQjfo;CM>Btus9Qbu&Z4(@3f9Jzqw`OV$8p0fy8?eW3WaT|AbS zWArnk3rtHIj9W~V{8+%G`C)vgrc|qFDU9@0gTN-Cgk`n{WO;iHf#6L#C`C$of4oK_ z)7)aOFeM1-blt@*mmk(pDyss&L$e1Gu8>Tg*`7nH-5QX$nX*wAdJ29A$rt>LU*nV9 zXtLI^@YZ-uI8(hz6@LG#p@>>0T9XX5yG@U66eR%*3CIc!CK+z}#K1AmZ|+9@lHO>z ztCyNrHzW~n;E67aoo+OHdOHR6jfsS%sZ^@uOi|V@T0TXLOrP!N$6@0;S)Zq|U@?#_ zeKBWWyb9isF~)c!=tR<0BeIUJpoY9mBv1Q0lS0fn{c3GDDj)K1PMkr>Qhp1}3|;DD z8{qV}B$pp`T2;mJ*S#0l$vqid9nfc{DG8&?*C78Bd&06gEt;N$2d@cevPCWV^xxhG zWFwDA3~c5DbDiWzOh9D$sNB_+`Q#3x_&CP$;%5`Ro!(+XlQ&z(H&mchYt#^iKLg?b zmTqK?Yy{b*;ADD&Fsc&+Vym$1b3X4V|lEBoEjV+N=;aBWf{7^0y z)@f`9s2N`sm+Yw0w=GPMy1Be_%jLOem*+^mC&CA->Z|z$jo+4FdAi4vcMc`zuvh|B zs*_;cAn3hP2k?u^+gVF(yMb|~``SHeGT|4GOj`Vx=2SC1aO#=G-{Tlj;xCu6D9;#n z`6=it5iSL}X!?#&2k3#++jr`t=z-y-(9f`5=%uf1U&pYL>kk(a{d@<2Wv7{Y=>XyKO`5J;6u z4ukfqBlHhfUu{_Cc!19NrA}ue#_y+1re*v<67Ms(Nfv7R^n0P^B&_ z<%=OSo3p3l#6bJbG$+2B8yHd5VZk}v&#C|`!(%|IF&e+f7fTWVMxh%uT793(*IozzB4G)O+pjOW ztIm9NZ|OxzW(cSu9b3f*)<%KzDToamkElju-)f(VW2cKJn(9HUT+O%mE0E+H*TsM_ z!jBn|$vNSXUR7-Q$q(-ysyjG^`M;;q;+p0bjB&miq55UL+JG;H>21GVo798&OH((* z)ObW~ezGGOP&Qk{VlG0(xFko3EL^zqLR3U@tl3sTSsy!aFAAPvBl=F@qwsm< zbh3hE_p_2eK$2{kpwNOtpTwl*2PW|oKyCsQXbSn&I;CQ4fdr`h*+gQ~y#;vXpl8qx zrxc)ByD_GgPbr}@#;Yi^pJdGTWEl1cW1 z0STnErI}08H)+PpD@*j{oC6#M!nMO*8gZ!k((D(ya!#JP-=Q^#Ql5(eZ86s#*$2Vg z=!HYcuX3c=K^NN2(pN#CKS#9Rh@SfrZ}Z7r!%0J5x)33xw%yFu)^9gyaAp&RI|#2d zxc?J<8a5w)44imn$~1;*X?%K;d^9G;J?c#D3*btVyrWF|gHRPP-sMbxRiu<-K2dNs6&d$Gj?qEplFq-4sAR>-pBrt>{ z<;}_5bg^xQJW`G_N*`VIH=fEcTCmrXBe~M|qayYB{7*NcB#|~14Bx{=!$l>jd;QSG zh2tv1)q&vlg6-mlbU<;}C#mG^NoFAoU}JjWYAxxmsmHzLP!6ITOL7*?lCH+#lT#EU zF^@u!o%nix>HM8I?SKd^40HSUeKS=^RV^faaJ|tspmE4@DRCE! z#?l}93*KgWdd5a$tajJV5TcXFf(C5-IwxqFLZWUq{%T&+h}s`XEl8{wXLSr^6iO%~ zW)4I80rdO%^0(g-T zb%=NfZb1N9W2c{;Z{#wt(-<5^gUgc@6^6QlNIyHJOh8uXI*zZ72t8^3|}u2j?0 zT2?jY<@woZP~scW*dt72vnvZQ6ixEHo>s|>*SjcJ89!aYa(-iL*WHSdAx;95Ff?+9 zH=0dnuAUo6cDw7AN<)GbT;f;umE^34rqeQ}FNP0Ayb9sPl94$muL!k?Hys=u>=Udg zp8~-0n-fD>re#vl73BuX?Sb>bH5Io|*=>{|H!P(Dlr6a@&053EJc3Osk53v>uDJ!v z`Wsi>^stDG?i5Jf9UO1)0i~Xcl($_d<-I>9+4le0=^a$}XKhL$lFEj#Pm?Wksgw2| z1Ka?&4)V&xbR(Jev<1P# z`CauG_e1K3{A{=;AR)?H6*g>kChdsm3x=H|&Hilh3)Q@r6Adg)fb$IbDAR8ARgcxv zOom& zgZ+y~*Nba?>xko_pGq3P0G7Zek)M#G#cK-$HklD0(b6yKX_`4Jd^4R;E z_3;>6$ba*a(pQL_4rRv}5RVwP1?v8Gq?|J#_8i$Wd5WJKq}1i;mAa}uJSpj;X_@@n zVW11^A%(iH$wp1OtO z(DpB@!Gw1!(bD7Gy8WKV77j!c;~zDYP&;Z&-vr=8Tyt98uFSeYA8^xA3c7GDH?o zWNTP?xWP4ADWKX(zzb%g8!b+d%K@6Q%mbabwmZwLv7%c$B>Nbn{t&3$PnE^yo9oQc z`+03q#^~<{Ak>3Or3K_TeHB!SlI*F#LJH!yaZR1B`)QMaA(CkhN1Juv!esdgD2u(J z2=c}i9MY`pt`@#N1rX#J_DnNH7rG1w6k;^Rm;#mY6Mv zX)NXf=DI#YEX}g+M;-Bj{4nGw8{eJItd{^2a-%kqose0}9Jq|?gzLVnyu@-Mh25O4 z?er}KUq;P&%>7s}`}6pmXw7qUX!aK3dLQdA3=fgGxXzO_1Cgz zy^)V>jY=k8-Sj65=bt6hj${XHZ1A?#>uxgDH#IZ}I>W7%5kGj@sWt8FJa~O8Q-yM{jR(|EAr3g zrhqQ_6dBZp!_w21gX z2Ng8zg+_iE2QzJ-jjMA`%M{_?ln-qc^H_zc9+|#I)1M~zon=CDgI4t zOj$PHjskqR9zS|y<`sZuBI8P2JYzzQu;4Zqj(BEj-m>WoT}XYzsA&L|fe_7QK-Lt< z+8#Zmv5s=Ge)TgCH>zQC&fL_yM5PBwH4G*!qjd;6EN~PH3TFtCIxV3~HDeFNAtT4x z9{_d}pJJ3~WAx=}oG0lmJ!QuTb=SgK4gMTrh`i{BzDwgkyyVl_cbU&!*JFzM2EsxB z_`N4Dk(?Dfs$H-QbCq;J-8g0yw=JWAi~~UAvPb1JT~I_qAYt2j_b%>lvf=3#4`He| zQ`tbm9E|$-d}&jdwtaHdno9u!!)ytwahlN4KK)*V!z;jC(~9)Sg3d3zVvtMf$(&TG ztUy7KhDZM>E+p&kOvPLuj*&792snwzzBb6D+6~BmP9~cYE51&}tC8F57B51vM=nGs z4pI9UAQ4d!#Z14Z(F(uawO4+@{a9Q`h|08A-rV&JO$9@Qg8HZbY2Dzd%GV5mX<&6O zW|6xTrC0*K^qM<7#>@X6ev9ffQhU|6FAYN9RE4GlMvfK)oDYW*VuZfFFV#c@BW2u( zt~Mxg$5@hKfID=W>uGxDurSP60WY}235mOM;rr^ej$TnNhW!sxnt?AJAp252qc1d| z*Jd_;=Cf?Q4t#DnYW^z%yj{$%g)a(UIImKL=HLxZ-<3qhwwh-EWC((zTAwwLK1WgE zeKjEuds?M%@CE^uI1EP$Mvci>+Q4wk(m^vA!O^pt z$a>^ARZ*hIKf-L%915wao%Xj43!2o%@hKI(-9`*RVBZ1XAO3aH$&%qa!#ucC_CA=; z(UeJUa?4C^@2(u>{bwJ1GLyD-I-5EsUZLPI^t< zq}QWF(I~*{KR^YDR`P;~$k1o78H*P`HGB#!{g&IOuBGBG5?eNozmROc>pBR#B}jY0 zwk^Rl@LW$eB2aqc%Ti%3MrOUBya*r|45|HbkXn0?s9e*1)r!raUS(CV6vL7kf-z!j7zAurc4 zUye~yEc(#(apo{jYlb1c9?%Wktey&dUl8AZcg)JVi&Qb zLKym2vf4rA_(FeLMBrLaSOk=@Dj9>v6asi`!;~Bd+gYNf2)eD}NZ+2Yl|K^Ho|{kDfba%AD~ z%NSwDwZ-Kwnl8;S4>RdmDe%7Ys>FeiB3WW4fzmqt zI=Ux>DbP{gE%Y38x$@Yf^UpPTER9ACuU=vyn~R+P<&<7uhQ5Y%E7BncGk8EUcTQMr z<^lhSpe8finiZ1a3B3nP?#@&>B|xN$dFl0z->7zNX^dh595ur%nhIS;A^z=9>78Mx z%W3vws=<+a_pLcPjrcOMGGp?44jVppDZI6(nnQXBy{2>(u!2_!ezDoWyP`jLSoDZq zs?$!CowN(I{3XfircSfg_565r%~uA{IZlILr&t(lne;P1G`U<~IC*5y@o+DjP1eSU zm=^Bd%gnzRu|Je?RvCc(sZdE1-Pc^T+;WS6bI8ei{) z-#8QkJb;z8Csl|`sVJL6pN~3oFI9_9i^8d`+(|=8(&3OF&%p4H7Psto37Ewop-YyH zkGH53JJP$7Pwv|j&!)IJ%$tsZ`a;F_&pMeaT663vDCdY5_keiVsOp>aBh&cxgw34o zu&=?(CP#IG17wf%rAY?0d|}09Cmpqi1QRoG{`=N1ka7)&D4#=zRfs|*Xq-G$+Q?4Q zjObK~A(Ql+mB4fGg*DYujuW~PlAEl~23^Lyk{y!|4A(rueo+^eUA2ZEhXnPP)}+G4c)R>!O4&DWp-Y_RwOK_UZj zO?7Iu#LJ@)moY*q`x6wi$ntAigGFXg4{%X(k6E~L?;C?2^Fr1uGxr-taBi4KH*bKO z=pFHxllOUmmX(?<4;Fi0Va!*Mx&_}31cG;btU%KE17s2Kg}UweQl(Ae(l!GdlCYLf ze!`0N&0F{(@-SmwA(ZTWXuOQvb~%_D+`^(#Imws-tG}dix_wlpKwqde_J10-CGf%( zVdTB2j#XF9A!MBjG7e1d-z5I5;l~|q%6`*2x0|8^7Z?SXVoTVdBQLv|TnqD@aAf!{ z0#@)mI1RUaW?Aa!Ur6oz_`Daw4rOJ-I4dB=PCORn_$3}pG-H$9^E*MW6sUoJHU3(- z`M^+S5islwfWHIZKMn8kJ!n?Xy!Q5<2XS!>QX^|6L6*M3orJGq{H=M=9eo2i;IjZO9<)NK(Q9HH!_vWg~O*&S<#5E>HCtqq<4b5;iAp!gLv7VADEL6U&^WNHv zVIn$MK~K1W&(ZvX_&as0DrEjR2$PO>EHE`c0a`$C~f}W0CA5@PtjF(JIlul+~ z^Qj^KYCBWW3HuCP8x8DXuyq^Q+VcG8QsaXWy#yL&T+#i!W#v!DOwSK`t?eZ=RKk!k z8V;UN*uh4A1?XaYYDhOqnM^wFe!1Q^ccdujo0ei>O0;62&nfG=0zeB77Loz#eDJY| z_JJCCiZ6>zO7?-0ElZQs-Gxtvs#E!abPAqW;Bs8JD6;OE1HGpYP6$$PL0J;NhTy1Y(XE3C zw4XUXjsXq^f~2{Q-bq3w<(}o5QBs?mQ0X#4epKGHma^a({Iz|-74r3UYsc!wg{j)p zm2=7oGDdPur=19Tf>9;5c;@=PR@0-cFkK0Etz>STw531#DzI{{f;Ppbv{zgyP z!R+hQE678d-c^i!w@7E+Fv46m=_cgz8@SCT%<$is-swCoPR`|EJ5OPmP1_<*Bjw*e zU$Yi=wOAzv-8cB8W(0M${DUHio1i)sjRJbRPnU+{CTDI$%t3WrL|Fn{@U=nhF8xZb ztSjrk(5`l&=6U9(%!^f0@(W>es`jiV^j_-oDctdxEZ+PF;TlPq@zlp+!|*sR8j-zE_wG6 znP#^BDY+ZtDMk%XqF(A7dXKQW6L)r6@Jc&&0;#mRV@vO@_F(Vqqf-TAL#8MmkHmdy zCr)-JO74!k8yGt!1SJVwv8y`rSI*CUeW4-I z>En43;H|BFR;GJR6lfq0va%FzR?p}o)>Fzk zN#tuHtEg!2BNNCRX3&LScVz-YfOu?ZNo9Ajrgc-DDV$Fa2ZK3jXRQb_IY9^^Q4nH@fxCkdeYZn3iUpaoW%$}ocokE{h3w?j@VgIiptR^nf z@%K&G&HV2zZEz@E0Ob8w&&a?4nD;N@&kq0q VP~N|Yet$aw|5uLs59HtSKLDteWnBOO literal 0 HcmV?d00001 From 0d1937d53f7c30462c43b0f6571cb4cfd5481a84 Mon Sep 17 00:00:00 2001 From: Owanate Amachree Date: Thu, 31 Oct 2024 13:44:05 +0200 Subject: [PATCH 3/6] Added Fungible token standards, update contract addresses and FAQs --- .../05-smart-contracts/contract-addresses.md | 3 +- .../fungible-token-standards.md | 107 ++++++++++++++++++ .../04-resources/06-guides/tokenbridge/faq.md | 8 +- 3 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 docs/02-developers/05-smart-contracts/fungible-token-standards.md diff --git a/docs/02-developers/05-smart-contracts/contract-addresses.md b/docs/02-developers/05-smart-contracts/contract-addresses.md index a7e9fcd3..3cfda995 100644 --- a/docs/02-developers/05-smart-contracts/contract-addresses.md +++ b/docs/02-developers/05-smart-contracts/contract-addresses.md @@ -26,4 +26,5 @@ For info on derivation paths, see [Account based addresses](/concepts/account-ba | BPro | [BitPro](https://moneyonchain.com/bpro-income-for-bitcoin-holders/) | ERC20 | Rootstock | [0x440cd83...](https://explorer.rootstock.io/address/0x440cd83c160de5c96ddb20246815ea44c7abbca8) | | BTCX | [BTCX](https://moneyonchain.com/btcx-leveraged-bitcoin/) | | Rootstock | [0xf773b5...](https://explorer.rootstock.io/address/0xf773b590af754d597770937fa8ea7abdf2668370) | | RIFX | [RIFX](https://rif.moneyonchain.com/metrics) | | Rootstock | [0xcff3fca...](https://explorer.rootstock.io/address/0xcff3fcaec2352c672c38d77cb1a064b7d50ce7e1) | -| WRBTC | Wrapped RBTC | ERC20 | Rootstock | [0x542FDA3...](https://rootstock.blockscout.com/token/0x542FDA317318eBf1d3DeAF76E0B632741a7e677d) | \ No newline at end of file +| WRBTC | Wrapped RBTC | ERC20 | Rootstock | [0x542FDA3...](https://rootstock.blockscout.com/token/0x542FDA317318eBf1d3DeAF76E0B632741a7e677d) | +| stRIF | Staked RIF in RootstockCollective DAO | ERC20 | Rootstock | [0x5db91e2...](https://rootstock.blockscout.com/token/0x5db91e24BD32059584bbDb831A901f1199f3d459?tab=contract) | \ No newline at end of file diff --git a/docs/02-developers/05-smart-contracts/fungible-token-standards.md b/docs/02-developers/05-smart-contracts/fungible-token-standards.md new file mode 100644 index 00000000..026982ec --- /dev/null +++ b/docs/02-developers/05-smart-contracts/fungible-token-standards.md @@ -0,0 +1,107 @@ +--- +sidebar_position: 900 +sidebar_label: Fungible Token Standards +title: Ethereum Fungible Tokens Standard ERC1363, ERC223, ERC677 +description: 'Best practices for Smart Contract Development on Rootstock' +tags: [rsk, rootstock, smart contracts, dApps, tokens, fungible-tokens] +--- + +## ERCs vs EIPs vs RSKIPs + +[Ethereum Requests for Comment (ERCs)](https://docs.ethhub.io/built-on-ethereum/erc-token-standards/what-are-erc-tokens/), +and [Ethereum Improvement Proposals (EIPs)](https://eips.ethereum.org/erc) +refer to the same thing - they were originally called ERCs, +and then subsequently renamed to EIPs. +These are all focused on improvements to Ethereum. + +[Rootstock Improvement Proposals (RSKIPs)](https://github.com/rsksmart/RSKIPs) use a similar process to improve Rootstock. + +A small subset of EIPs, albeit an extremely popular subset, +are tokens standards, which have to do with smart contracts, +and do not have much to do with the Ethereum nodes. +Instead, they focus on the Solidity smart contract implementations +with the intent to standardise the ways in which tokens get implemented. + +## Ethereum Token Standards work on Rootstock + +Since the Rootstock Virtual Machine (RSKVM) is compatible with +the Ethereum Virtual Machine (EVM) at the op-code level, +smart contracts that are compiled to target the EVM +can be executed in exactly the same way on the RSKVM. + +> Note: Some differences exist, most notably to do with how gas +> costs are calculated, both in terms of the schedule per op-code, +> as well as the calculation methodology. +> At the time of writing, like-for-like smart contract function invocations +> cost 2% to 2.5% on Rootstock compared to Ethereum. + +Owing to this level of compatibility, +the same smart contracts standards that work on Ethereum +also work on Rootstock - there is no need to create "mirror RSKIPs" +that are the equivalent of EIPs for token standards, +since they will be virtually identical. + +## Fungible Tokens + +```text +address -> amount +``` + +At their core, fungible tokens are smart contracts which store +a mapping of addresses to amounts. +This is used to represent an understanding that each particular address +is the owner of a particular amount of tokens. + +```text +transfer(...) +``` + +These smart contracts will also have a `transfer` function, +that allows them to transfer the tokens held in one address to another address. + +Of course, there is a lot more to fungible tokens than the above, +the above is merely a rudimentary illustration. + +## ERC20 + +The ERC20, or EIP20, token standard is the most well-known +among all fungible tokens standards. +In fact, it was so popular, that at some point 3 in 4 smart contracts on the Ethereum blockchain implemented this standard. +To this day, it remains a dominant force, +and in fact the term "ERC20" is almost synonymous with the term "fungible token". + +The above is also true on the Rootstock network, +virtually all fungible tokens implement this particular token standard. + +Its continued relevance stems from the fact that whenever +a new fungible token standard comes out, +the most critical factor to enable adoption is to be "ERC20 compatible". +This means that new fungible tokens standards implement +the interface specified by the ERC20 token standard, +and then add their own additional functions on top of it. + +## ERC677 + +The ERC677 token standard is also a fungible token standard, +and it extends the ERC20 token standard. + +```text +transferAndCall(...) +``` + +The key addition is the `transferAndCall` function, +which allows the user to combine +a `transfer` function invocation on the fungible token smart contract +with another function invocation of their choice on a different smart contract. +This allows the user to accomplish both operations in a single transaction +submitted to the blockchain network. + +On the Rootstock network, the LINK token from Chainlink, +and the RIF token from Rootstock, both implement this standard. + +## More standards + +There are many other smart contract standards +used to build fungible tokens, including ERC223, ERC777, and ERC1363. +These all happen to be backwards compatible with ERC20 standard, +however have not seen much by way of widespread adoption yet. \ No newline at end of file diff --git a/docs/04-resources/06-guides/tokenbridge/faq.md b/docs/04-resources/06-guides/tokenbridge/faq.md index 91cc7c49..9eca6087 100644 --- a/docs/04-resources/06-guides/tokenbridge/faq.md +++ b/docs/04-resources/06-guides/tokenbridge/faq.md @@ -83,12 +83,8 @@ Find a list of frequently asked questions about the Token Bridge. How many confirmations are required to convert the original tokens to Side tokens and vice-versa? - - Confirmations depends on the amount being crossed: - - Small amounts needs 60 confirmations on the Rootstock Mainnet, and 120 confirmations on the Ethereum Mainnet. - - Medium amounts needs 120 confirmations on the Rootstock Mainnet, and 240 confirmations on the Ethereum Mainnet. - - Large amounts needs 2880 confirmations on the Rootstock Mainnet, and 5760 confirmations on the Ethereum Mainnet. - - > Note that the values of small, medium, and large amount are defined per token basis, and may change over time. - - > You can see these amounts defined in the [Token List](https://dapp.testnet.bridges.rootstock.io/list). + - Confirmations depends on the amount being crossed. See the [Troubleshooting guide](/resources/guides/tokenbridge/troubleshooting/) for more information. + - You can see these amounts defined in the [Token List](https://dapp.testnet.bridges.rootstock.io/list). From 2ca97f501a496143f411c4d013015e9243a4b54c Mon Sep 17 00:00:00 2001 From: Owanate Amachree Date: Thu, 31 Oct 2024 13:50:16 +0200 Subject: [PATCH 4/6] minor fixes --- .../fungible-token-standards.md | 2 +- .../runes/mock-contract-walthrough.md | 53 +++++++++---------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/docs/02-developers/05-smart-contracts/fungible-token-standards.md b/docs/02-developers/05-smart-contracts/fungible-token-standards.md index 026982ec..56239057 100644 --- a/docs/02-developers/05-smart-contracts/fungible-token-standards.md +++ b/docs/02-developers/05-smart-contracts/fungible-token-standards.md @@ -2,7 +2,7 @@ sidebar_position: 900 sidebar_label: Fungible Token Standards title: Ethereum Fungible Tokens Standard ERC1363, ERC223, ERC677 -description: 'Best practices for Smart Contract Development on Rootstock' +description: 'What is ERC20, and are there others like it? How do they work on Rootstock?' tags: [rsk, rootstock, smart contracts, dApps, tokens, fungible-tokens] --- diff --git a/docs/04-resources/06-guides/runes/mock-contract-walthrough.md b/docs/04-resources/06-guides/runes/mock-contract-walthrough.md index 0825e1cd..0f98f2ca 100644 --- a/docs/04-resources/06-guides/runes/mock-contract-walthrough.md +++ b/docs/04-resources/06-guides/runes/mock-contract-walthrough.md @@ -1,16 +1,15 @@ --- sidebar_position: 3 -title: Mock Bridge Contract - Walkthrough -sidebar_label: Mock Bridge Contract - Walkthrough +title: Understanding the Mock Bridge Contract Structure +sidebar_label: Understanding the Mock Bridge Contract Structure 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 Mock Bridge Contract Structure** The [Mock bridge contract](https://github.com/rsksmart/rsk-runes/tree/main/contracts) 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:** +## **Key Imports:** ```plaintext import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; @@ -22,27 +21,25 @@ import "@openzeppelin/contracts/utils/Strings.sol"; * **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** +## **Main Components of the Contract** -#### **Events:** +### **Events:** * `TokensFrozen`: Emits an event when tokens are frozen for a specific account. * `TokensUnfrozen`: Emits an event when tokens are unfrozen. -#### **Data Structures:** +### **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:** +### **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. +* `_frozenTokens`: Keeps track of how many tokens are frozen for each user. -### - -### **2\. The Constructor** +## **2\. The Constructor** ```js constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {} @@ -51,7 +48,7 @@ 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** +## **3\. The `uri` Function** ``` function uri(uint256 tokenId) public view override returns (string memory) { @@ -61,7 +58,7 @@ function uri(uint256 tokenId) public view override returns (string memory) { 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** +## **4\. Minting Fungible Tokens** ```js function mintFungible( @@ -79,7 +76,7 @@ function mintFungible( This function allows the owner of the contract to mint fungible tokens. -#### **Steps Involved:** +### **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`. @@ -88,7 +85,7 @@ This function allows the owner of the contract to mint fungible tokens. 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)** +## **5\. Minting Non-Fungible Tokens (NFTs)** ```js function mintNonFungible( @@ -103,12 +100,12 @@ function mintNonFungible( 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:** +### **Key Differences:** * **Max Supply** is always `1` for non-fungible tokens. * **Current Supply** is also set to `1`. -### **6\. Minting More Tokens** +## **6\. Minting More Tokens** ```js function mintMore( @@ -121,15 +118,15 @@ function mintMore( 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:** +### **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** +## **7\. Token Freezing and Unfreezing** -#### **Freezing Tokens:** +### **Freezing Tokens:** ```js function freezeTokens(string memory runeName, uint256 amount, address owner) external onlyOwner { @@ -141,7 +138,7 @@ function freezeTokens(string memory runeName, uint256 amount, address owner) ext * The function ensures that the account has sufficient tokens to freeze. * The frozen amount is added to `_frozenTokens`. -#### **Unfreezing Tokens:** +### **Unfreezing Tokens:** ```js function unfreezeTokens(string memory runeName, uint256 amount, address owner) external onlyOwner { @@ -152,9 +149,9 @@ function unfreezeTokens(string memory runeName, uint256 amount, address owner) e * This function unfreezes the tokens, allowing the user to transfer them again. * The frozen amount is reduced from `_frozenTokens`. -### **8\. Token Information Queries** +## **8\. Token Information Queries** -#### **Get Token Information:** +### **Get Token Information:** ```js function getTokenInfo(uint256 tokenId, address holder) public view returns (TokenInfo memory) { @@ -166,7 +163,7 @@ function getTokenInfo(uint256 tokenId, address holder) public view returns (Toke * It can also include the token balance of a specific `holder` if the `holder` address is provided. -#### **Get Tokens Owned by a User:** +### **Get Tokens Owned by a User:** ```js function getUserTokens(address user) public view returns (uint256[] memory) { @@ -176,7 +173,7 @@ function getUserTokens(address user) public view returns (uint256[] memory) { * This function returns a list of all token IDs owned by a specific user. -### **9\. Token Transfer Functions with Freezing Consideration** +## **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. @@ -195,7 +192,7 @@ function safeTransferFrom( 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** +## **10\. Overriding `balanceOf` to Consider Frozen Tokens** ```js function balanceOf(address account, uint256 tokenId) public view override returns (uint256) { @@ -241,8 +238,6 @@ To deploy the Runes smart contract using Remix IDE, follow these steps in detail 4. Click on the **Save** icon (the disk icon) to save the file. -### - ### **Step 4: Compile the Smart Contract** From e5645d16afae8ce953462053f2c1cb672eec72df Mon Sep 17 00:00:00 2001 From: Owanate Amachree Date: Thu, 31 Oct 2024 16:07:01 +0200 Subject: [PATCH 5/6] Update to use category.yml --- .../03-blockchain-essentials/_category_.yml | 6 ++++++ .../03-blockchain-essentials/index.md | 15 --------------- .../05-smart-contracts/_category_.yml | 6 ++++++ docs/02-developers/05-smart-contracts/index.md | 18 ------------------ docs/02-developers/06-integrate/_category_.yml | 3 ++- docs/02-developers/07-rpc-api/_category_.yml | 2 +- docs/02-developers/08-libraries/_category_.yml | 3 ++- 7 files changed, 17 insertions(+), 36 deletions(-) create mode 100644 docs/02-developers/03-blockchain-essentials/_category_.yml delete mode 100644 docs/02-developers/03-blockchain-essentials/index.md create mode 100644 docs/02-developers/05-smart-contracts/_category_.yml delete mode 100644 docs/02-developers/05-smart-contracts/index.md diff --git a/docs/02-developers/03-blockchain-essentials/_category_.yml b/docs/02-developers/03-blockchain-essentials/_category_.yml new file mode 100644 index 00000000..0176b3b1 --- /dev/null +++ b/docs/02-developers/03-blockchain-essentials/_category_.yml @@ -0,0 +1,6 @@ +label: Rootstock Blockchain Essentials +position: 3 +link: + type: generated-index + slug: /developers/blockchain-essentials/ + description: "Learn how to interact with Rootstock in your web browser, how to look at Rootstock transactions, develop and deploy your very first smart contract to the Rootstock network." \ No newline at end of file diff --git a/docs/02-developers/03-blockchain-essentials/index.md b/docs/02-developers/03-blockchain-essentials/index.md deleted file mode 100644 index a2f0be38..00000000 --- a/docs/02-developers/03-blockchain-essentials/index.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -sidebar_label: Blockchain Essentials -sidebar_position: 3 -title: "Rootstock Blockchain Essentials" -tags: [quick-starts, rsk, rootstock, blockchain, browser wallets, developers, beginners] -description: "Learn how to interact with Rootstock in your web browser, how to look at Rootstock transactions, develop and deploy your very first smart contract to the Rootstock network." ---- - -Learn about Rootstock, how it enables smart contract on Bitcoin, and its compatibility with Ethereum and other platforms. - -| Title | Description | -| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| [Rootstock Overview](/developers/blockchain-essentials/overview/) | Learn about Rootstock and its Ecosystem. | -| [Using Rootstock in the Browser](/developers/blockchain-essentials/browser/) | Learn how to interact with Rootstock in your web browser, how to look at Rootstock transactions, develop and deploy your very first smart contract to the Rootstock network. | -| [Exploring Rootstock Transactions](/developers/blockchain-essentials/transactions/) | Learn how to interact with Rootstock in your web browser, how to look at Rootstock transactions, develop and deploy your very first smart contract to the Rootstock network.| \ No newline at end of file diff --git a/docs/02-developers/05-smart-contracts/_category_.yml b/docs/02-developers/05-smart-contracts/_category_.yml new file mode 100644 index 00000000..070a1e7d --- /dev/null +++ b/docs/02-developers/05-smart-contracts/_category_.yml @@ -0,0 +1,6 @@ +label: Smart Contracts Development +position: 5 +link: + type: generated-index + slug: /developers/smart-contracts/ + description: Get started with deploying dApps on Rootstock using Hardhat, Wagmi, Remix and other EVM-compatible tools. \ No newline at end of file diff --git a/docs/02-developers/05-smart-contracts/index.md b/docs/02-developers/05-smart-contracts/index.md deleted file mode 100644 index f9c5a7ad..00000000 --- a/docs/02-developers/05-smart-contracts/index.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -sidebar_label: Smart Contracts Development -sidebar_position: 5 -title: Deploy Smart Contracts on Bitcoin -tags: [rootstock, hardhat, smart contracts, dApps] -description: "Learn how to write, interact and deploy smart contracts on Bitcoin." ---- - -Get started with deploying dApps on Rootstock using Hardhat, Wagmi, Remix and other EVM-compatible tools. - -| Resource | Description | -| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| [Getting Started with Hardhat](/developers/smart-contracts/hardhat/) | Get started with creating a dApps on Rootstock using Hardhat. | -| [Getting Started with Foundry](/developers/smart-contracts/foundry/) | How to write, test, and deploy smart contracts with Foundry | -| [Contract Addresses](/developers/smart-contracts/contract-addresses) | List of contract addresses on Rootstock. | -| [Verify Address Ownership](/developers/smart-contracts/verify-address-ownership/) | Verify Address Ownership with Metamask Wallet. | -| [Interface Registry](/developers/smart-contracts/interface-registry/) | See the ERC1820 standard interface, address support and smart contract implementation. | -| [Verify Smart Contracts using the Hardhat Verify Plugin](/developers/smart-contracts/verify-smart-contracts) | Configuring Hardhat Verification plugin for Rootstock. | \ No newline at end of file diff --git a/docs/02-developers/06-integrate/_category_.yml b/docs/02-developers/06-integrate/_category_.yml index 28006e64..9531adf3 100644 --- a/docs/02-developers/06-integrate/_category_.yml +++ b/docs/02-developers/06-integrate/_category_.yml @@ -2,4 +2,5 @@ label: Integration Guides position: 7 link: type: generated-index - slug: /developers/integrate/ \ No newline at end of file + slug: /developers/integrate/ + description: "Easily Integrate Your dApps with Developer-Friendly SDKs on Rootstock." \ No newline at end of file diff --git a/docs/02-developers/07-rpc-api/_category_.yml b/docs/02-developers/07-rpc-api/_category_.yml index f43799ed..d135e70e 100644 --- a/docs/02-developers/07-rpc-api/_category_.yml +++ b/docs/02-developers/07-rpc-api/_category_.yml @@ -4,4 +4,4 @@ position: 5 link: type: generated-index slug: /developers/rpc-api/ - description: "RPC API services for interacting with Rootstock network." \ No newline at end of file + description: "RPC API services for interacting with the Rootstock network." \ No newline at end of file diff --git a/docs/02-developers/08-libraries/_category_.yml b/docs/02-developers/08-libraries/_category_.yml index f9aca9a3..8c1effc4 100644 --- a/docs/02-developers/08-libraries/_category_.yml +++ b/docs/02-developers/08-libraries/_category_.yml @@ -2,4 +2,5 @@ label: Libraries position: 8 link: type: generated-index - slug: /developers/libraries/ \ No newline at end of file + slug: /developers/libraries/ + description: "Libraries for Rootstock Integration." \ No newline at end of file From 8f602c81ede117471658afd9b67e685339860886 Mon Sep 17 00:00:00 2001 From: Owanate Amachree Date: Fri, 1 Nov 2024 14:16:59 +0200 Subject: [PATCH 6/6] Update slider images to use new component with links --- docs/05-dev-tools/wallets/index.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/05-dev-tools/wallets/index.md b/docs/05-dev-tools/wallets/index.md index 317b4e9c..e2d23ee1 100644 --- a/docs/05-dev-tools/wallets/index.md +++ b/docs/05-dev-tools/wallets/index.md @@ -8,7 +8,21 @@ description: "Learn how to connect to Rootstock with a compatible Wallet" The following wallets support [RBTC](/concepts/rbtc/) and [RIF](/concepts/rif-suite/token) tokens. - + + + + + + + + + + + + + + + ## Compatibility Matrix @@ -17,7 +31,7 @@ In the following matrix you can see the different features by wallet. | Wallet | Rootstock Checksum | Rootstock dPath | Customizable dPath | Platforms | Networks | |---|---|---|---|---| ---| | [Beexo](https://beexo.com) | ✔ | ✔ | ✔ | Desktop, Mobile | Rootstock (RBTC), Bitcoin | -| Edge | ✔ | ✔ | ❌ | Desktop, Mobile | Rootstock (RBTC), Bitcoin | +| [Edge](https://edge.app/) | ✔ | ✔ | ❌ | Desktop, Mobile | Rootstock (RBTC), Bitcoin | | [Ledger](https://www.ledger.com/) | ✔ | ✔ | ❌ | | [MyEtherWallet](https://www.myetherwallet.com/) | ✔ | ✔ | ✔ | Desktop, Android, IOS | RBTC | [Trezor](https://trezor.io/trezor-suite) | ✔ | ✔ | ❌ |