|
Ashish  Gushain Oodles

Ashish Gushain (Backend-Associate Consultant L2- Development)

Experience:2+ yrs

Ashish Gushain is a highly experienced backend developer with over 1+ years of industry expertise in Solidity and Smart contract development. He possesses in-depth knowledge of web3, blockchain architecture, and practical experience in working with various tools and frameworks such as Nodejs, Hardhat, Remix, React, and databases such as MongoDB and Postgres. He is highly skilled in decentralized finance (DeFi) and specializes in implementing complex financial protocols on the blockchain. He has a passion for reading and constantly stays updated with the latest trends in the blockchain and cryptocurrency space.

Ashish  Gushain Oodles
Ashish Gushain
(Associate Consultant L2- Development)

Ashish Gushain is a highly experienced backend developer with over 1+ years of industry expertise in Solidity and Smart contract development. He possesses in-depth knowledge of web3, blockchain architecture, and practical experience in working with various tools and frameworks such as Nodejs, Hardhat, Remix, React, and databases such as MongoDB and Postgres. He is highly skilled in decentralized finance (DeFi) and specializes in implementing complex financial protocols on the blockchain. He has a passion for reading and constantly stays updated with the latest trends in the blockchain and cryptocurrency space.

LanguageLanguages

DotEnglish

Fluent

DotHindi

Fluent

Skills
Skills

DotNode Js

80%

DotMetaMask

80%

DotSolidity

100%

DotBIP39 Standards

80%

DotCoinbase API

80%

DotRust

60%

DotJavascript

80%

DotBlockchain

80%

DotMern Stack

60%

DotEthers.js

80%

DotWeb3.js

80%

DotSolana

80%

DotEtherscan

80%
ExpWork Experience / Trainings / Internship

Jun 2022-Present

Associate Consultant - Development

Gurugram


Oodles Technologies

Gurugram

Jun 2022-Present

EducationEducation

2015-2018

Dot

Jamia Hamdard

BCA-Computer Applications

Top Blog Posts
Building a Cross-Chain NFT Bridge using Solana Wormhole

The blockchain ecosystem is rapidly evolving, with numerous networks offering unique features and capabilities. However, this diversity often leads to fragmentation, where assets and applications are siloed within their respective chains. Non-fungible tokens (NFTs), which have gained immense popularity, are no exception to this challenge. To unlock the full potential of NFT development, it is crucial to enable their seamless transfer and interaction across different blockchain networks. This is where cross-chain bridges come into play.

 

In this blog, we will explore the theoretical underpinnings of building cross-chain NFT bridges using Solana's Wormhole protocol. We'll delve into the architecture, key components, and the steps involved in creating a bridge that allows NFTs to move between Solana and other blockchain networks.

 

Understanding the Need for Cross-Chain NFT Bridges

 

NFTs are unique digital assets that represent ownership of a specific item or piece of content. They have found applications in art, gaming, virtual real estate, and more. However, the value and utility of NFTs are often limited to the blockchain on which they are minted. Cross-chain NFT bridges aim to overcome this limitation by enabling NFTs to be transferred and utilized across different blockchain networks.

 

Benefits of Cross-Chain NFT Bridges:

 

Interoperability: NFTs can be used across multiple platforms and ecosystems, increasing their utility and value.

Liquidity: By enabling NFTs to move between chains, bridges can tap into larger and more diverse markets.

Innovation: Developers can create cross-chain applications that leverage the unique features of multiple blockchains.

 

Also, Read | How to Create an NFT Rental Marketplace using ERC 4907

 

Solana Wormhole: A Primer

 

Solana's Wormhole is a generic message-passing protocol that facilitates communication between Solana and other blockchain networks. It acts as a bridge, allowing data and assets to be transferred across chains. Wormhole achieves this by using a set of validators (called "guardians") that observe and verify events on one chain and relay them to another.

 

Key Features of Wormhole:

 

Decentralized: Wormhole relies on a network of guardians to ensure the security and integrity of cross-chain transactions.

Extensible: The protocol is designed to support multiple blockchain networks, making it a versatile solution for cross-chain interoperability.

Efficient: Wormhole leverages Solana's high throughput and low latency to enable fast and cost-effective cross-chain transactions.

 

Also, Explore | How to Implement an On-Chain NFT Allowlist

 

Architecture of a Cross-Chain NFT Bridge Using Wormhole

 

Building a cross-chain NFT bridge using Solana Wormhole involves several key components and steps. Let's break down the theoretical architecture:

 

NFT Representation on the Source Chain

 

  • Minting NFTs: NFTs are minted on the source blockchain (e.g., Ethereum) using a standard like ERC-721 or ERC-1155.
  • Locking NFTs: To initiate a cross-chain transfer, the NFT is locked in a smart contract on the source chain. This ensures that the NFT cannot be transferred or sold while it is being bridged.

     

Wormhole Message Passing

 

  • Creating a Wormhole Message: Once the NFT is locked, a Wormhole message is created. This message contains essential information about the NFT, such as its metadata, ownership, and the target chain.
  • Guardian Validation: The Wormhole guardians observe the locking event on the source chain and validate the Wormhole message. Once validated, the message is signed and relayed to the target chain.

 

NFT Representation on the Target Chain

 

  • Receiving the Wormhole Message: On the target chain (e.g., Solana), the Wormhole message is received and verified by the local Wormhole smart contract.
  • Minting a Wrapped NFT: A wrapped NFT is minted on the target chain, representing the original NFT from the source chain. This wrapped NFT adheres to the target chain's NFT standard (e.g., SPL Token on Solana).
  • Unlocking the Original NFT: Once the wrapped NFT is minted, the original NFT remains locked on the source chain until it is redeemed.

     

Redeeming the Original NFT

 

  • Burning the Wrapped NFT: To redeem the original NFT, the wrapped NFT on the target chain is burned, and a corresponding Wormhole message is created.
  • Unlocking the Original NFT: The Wormhole guardians validate the burning event and relay the message back to the source chain. The original NFT is then unlocked and can be transferred or sold.

     

Security and Trust Considerations

 

  • Guardian Network: The security of the bridge relies on the integrity of the Wormhole guardians. A decentralized and diverse set of guardians is essential to prevent collusion and ensure trust.
  • Smart Contract Audits: Both the source and target chain smart contracts must be thoroughly audited to prevent vulnerabilities and ensure the safe handling of NFTs.
  • Economic Incentives: Guardians and participants in the bridge should be incentivized to act honestly, with mechanisms in place to penalize malicious behavior.

 

Also, Discover | A Guide to Implementing NFT Royalties on ERC-721 & ERC-1155

 

Potential Challenges and Solutions

 

Cross-Chain Compatibility

 

  • Challenge: Different blockchains have different standards and architectures, making it challenging to create a seamless bridge.
  • Solution: Wormhole's extensible design allows it to support multiple chains, and the use of wrapped NFTs ensures compatibility with the target chain's standards.

 

Security Risks

 

  • Challenge: Cross-chain bridges are attractive targets for hackers due to the value of assets being transferred.
  • Solution: Implementing robust security measures, such as multi-signature schemes, regular audits, and a decentralized guardian network, can mitigate these risks.

 

Scalability

 

  • Challenge: As the number of cross-chain transactions grows, the bridge must be able to handle increased load without compromising performance.
  • Solution: Leveraging Solana's high throughput and low latency can help ensure that the bridge remains scalable and efficient.

 

You may also like | How to Get the Transaction History of an NFT

 

Conclusion

 

Cross-chain NFT bridges represent a significant step forward in the evolution of the blockchain ecosystem. By enabling NFTs to move seamlessly between different networks, these bridges unlock new possibilities for interoperability, liquidity, and innovation. Solana's Wormhole protocol provides a powerful foundation for building such bridges, offering a decentralized, extensible, and efficient solution.

While there are challenges to overcome, the theoretical architecture outlined in this blog provides a roadmap for building secure and scalable cross-chain NFT bridges. As the blockchain space continues to mature, we can expect to see more sophisticated and user-friendly bridges that bring the vision of a truly interconnected blockchain ecosystem to life. If you are planning to build and launch your NFT project, connect with our skilled blockchain developers to get started. 

Category: Blockchain
How to Build a Cross-Chain Bridge Using Solidity and Rust

The capacity to transfer assets across networks effortlessly is more important than ever in the ever-changing world of blockchain development. Envision a bridge that unites the Ethereum and Solana worlds, letting tokens move freely while upholding security and openness. In this project, we use the robust programming languages Solidity and Rust to set out on the task of creating a cross-chain bridge. Through utilizing Rust's efficiency for Solana's on-chain logic and Solidity's capabilities for Ethereum smart contracts, our goal is to provide a solid framework that makes token exchanges simple. Whether you're a crypto enthusiast excited to explore new possibilities or a developer trying to improve interoperability, this guide will take you through all the necessary steps to realize this ambitious aim. Now let's dive in.

 

Prerequisites 

 

Programming Languages:

 

Solidity, Javascript/Typescript, and Rust

 

IDE:

 

VS-Code and any preferred IDE

 

Libraries:

 

ETH: Hardhat, Ethers, Axios, Openzepplin

 

SOL: Solana Web3.js, Solana Spl-token

 

Also, Explore | How To Build "Buy Me a Coffee" DeFi dApp Using Solidity

 

How to Build a Cross-Chain Bridge Using Solidity and Rust 

 

It's preferred that you setup 3 projects, separately for:

 

I) Ethereum's ERC-20 Token Smart Contract:

 

You'll need to setup node.js, solidity and hardhat in your IDE/ system. So, we'll begin with setting up hardhat code, for example "click-here". Here's the code for the ERC-20 Token using Openzepplin's library.

 

code..................................................................................................
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Testtoken is ERC20, Ownable {
event BurnAndMoveToSolana(address indexed user, string solanaAddress, uint256 amount);
event MintFromSolana(address indexed user, uint256 amount);
address public relayer;
constructor() ERC20("EthereumToken", "ETHR") Ownable(msg.sender){
_mint(msg.sender, 1000000 * (10 ** decimals())); // change amount as per your understanding
}
modifier onlyRelayer() {
require(msg.sender == relayer, "Not authorized");
_;
}
function setRelayer(address _relayer) external onlyOwner {
relayer = _relayer;
}
function burnAndMoveToSolana(uint256 amount, string memory solanaAddress) external { // main transfering function
_burn(msg.sender, amount);
emit BurnAndMoveToSolana(msg.sender, solanaAddress, amount);
}
function mintFromSolana(address to, uint256 amount) external onlyRelayer {
_mint(to, amount);
emit MintFromSolana(to, amount);
}
event TokensBurned(address indexed from, address indexed solanaAddress, uint256 amount);
}

 

You may also like | Building a Decentralized Voting System with Solidity and Hardhat

 

2) Solana's SPL Token Program:

 

You'll need to setup node.js, Solana, and Rust in your IDE/ system. To begin with, we'll set-up a empty solana-sdk code. Here's the full code/implementation for the SPL Token using Solana-web3.js & Solana spl-token.

 

code.................................................................................................
const {
Connection,
Keypair,
PublicKey,
clusterApiUrl,
LAMPORTS_PER_SOL
} = require('@solana/web3.js');
const {
createMint,
getOrCreateAssociatedTokenAccount,
mintTo,
getAccount,
burn
} = require('@solana/spl-token');
async function mintAndBurnTokens(connection, fromWallet, tokenAccount, mint, amountToMint, amountToBurn, ethAddress) {
await mintTo(
connection,
fromWallet,
mint,
tokenAccount.address,
fromWallet.publicKey,
amountToMint
);
console.log(`Minted ${amountToMint / (10 ** 9)} tokens to your associated token account.`);
const tokenAccountBalance = await getAccount(connection, tokenAccount.address);
console.log(`Token account balance after minting: ${Number(tokenAccountBalance.amount) / (10 ** 9)} tokens`);
if (Number(tokenAccountBalance.amount) < amountToBurn) {
console.log(`Insufficient funds. Current balance: ${Number(tokenAccountBalance.amount) / (10 ** 9)} tokens.`);
return;
}
await burn(
connection,
fromWallet,
tokenAccount.address,
mint,
fromWallet.publicKey,
amountToBurn
);
console.log(`Burned ${amountToBurn / (10 ** 9)} tokens from ${fromWallet.publicKey} and moving to Ethereum wallet ${ethAddress}.`);
console.log(`Relaying burn event to Ethereum relayer for Ethereum wallet: ${ethAddress}, amount: ${amountToBurn / (10 ** 9)}.`);
}
(async () => {
const fromWallet = Keypair.fromSecretKey(new Uint8Array([your,secret,keypair]));
const ethAddress = "0xyourAddress"; //add your eth wallet address
const mintAmount = 100000 * 10 ** 9; // amount of SPL tokens to mint
const burnAmount = 1000 * 10 ** 9; // amount of SPL tokens to burn/transfer
const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); // put your preferred cluster
console.log('Creating SPL token...');
const mint = await createMint(
connection,
fromWallet,
fromWallet.publicKey,
null,
9
);
const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
mint,
fromWallet.publicKey
);
console.log('Minting tokens...');
await mintAndBurnTokens(connection, fromWallet, fromTokenAccount, mint, mintAmount, burnAmount, ethAddress);
console.log(`View token account on Solana Explorer: https://explorer.solana.com/address/${fromTokenAccount.address}?cluster=devnet`);
})();
////////////////////////////////////////////////////////////////////////

 

Also, Read | How To Create a Daily Game Reward System in Solidity

 

3) Relayer-Bridge Project:

 

In order to facilitate safe and transparent token transfers between two blockchains, a relayer-bridge project serves as an essential bridge. Using smart contracts and event listeners, the relayer in the Ethereum and Solana context watches on particular occurrences on one blockchain, like an Ethereum token burn. When the relayer notices one of these events, it sends the required information—such as the recipient's address and the quantity of tokens—to the other chain so that the corresponding action—like minting the tokens on Solana—can take place there. In order to preserve network balance, this bi-directional communication makes sure that tokens burned on one chain are minted on the other. In order to smoothly connect the two ecosystems, the relayer's job is to validate and relay these transactions without sacrificing security or speed.

 

Here's the Code for the Relayer-Bridge :

 

code..................................................................................................
const WebSocket = require("ws");
const { ethers } = require("ethers");
const fs = require("fs");
require('dotenv').config();
const wsUrl = "wss://api.devnet.solana.com"; //your desired network
const connection = new WebSocket(wsUrl);
const provider = new ethers.WebSocketProvider(process.env.ETH_WSS_URL);
const wallet = new ethers.Wallet(process.env.ETH_PRIVATE_KEY, provider);
const contractAddress = process.env.ETH_CONTRACT_ADDRESS;
const abi = JSON.parse(fs.readFileSync("./path_to_your/eth_contract_abi.json"));
const contract = new ethers.Contract(contractAddress, abi, wallet);
connection.on("open", () => {
console.log("Connected to Solana WebSocket");
const subscriptionMessage = JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "logsSubscribe",
params: [
{
mentions: [""], // Your SPL token address
},
{
commitment: "finalized",
},
],
});
connection.send(subscriptionMessage);
});
connection.on("message", async (data) => {
const response = JSON.parse(data);
if (response.method === "logsNotification") {
const logData = response.params.result;
// Check if the log indicates a burn
if (isBurnLog(logData)) {
const amountBurned = extractBurnAmount(logData);
console.log(`Burn detected: ${amountBurned} tokens`);
await mintTokens(amountBurned);
}
} else {
console.log("Received message:", response);
}
});
connection.on("close", () => {
console.log("Connection closed");
});
connection.on("error", (error) => {
console.error("WebSocket error:", error);
});
// Function to Check the log data structure to confirm it's a burn event
function isBurnLog(logData) {
return logData && logData.err === null && logData.logs && logData.logs.some(log => log.includes("burn"));
}
// Function to extract the amount burned from the log data
function extractBurnAmount(logData) {
const amountLog = logData.logs.find(log => log.includes("burn"));
if (amountLog) {
const amount = /* logic to parse your burn amount format */;
return parseFloat(amount); // Return the amount as a number
}
return 0;
}
// Function to mint tokens on Ethereum
async function mintTokens(amount) {
try {
const tx = await contract.mint(wallet.address, ethers.utils.parseUnits(amount.toString(), 18));
console.log(`Mint transaction sent: ${tx.hash}`);
await tx.wait();
console.log("Minting successful");
} catch (error) {
console.error("Minting failed:", error);
}
}
/////////////////////////////////////////////////////////////////////////

 

This part of the relayer works for the transfer of SPL tokens to the ERC-20 tokens on Ethereum. Similarly, we can perform the transfer of ERC-20 tokens to SPL Tokens on the Solana blockchain, burn them, and its functionality will trigger the SPL Token's mint function to complete the cross-chain transaction.

 

Also, Discover | How to Create a MultiSig Wallet in Solidity

 

Conclusion

 

In conclusion, creating a relayer-equipped cross-chain bridge enables users to transfer assets between Ethereum and Solana with ease, opening up a world of decentralised opportunities. Utilising Solidity and Rust's respective advantages, you can build a scalable, secure solution that connects two robust blockchain ecosystems. This project shapes the future of decentralised finance by paving the ground for true blockchain interoperability with the correct tools and knowledge. Connect with our skilled Solidity developers to bring your blockchain-related vision into reality. 

Category: Blockchain
Building a Decentralized Voting System with Solidity and Hardhat

In this blog, we will guide you through the process of building a decentralized voting system using Solidity and Hardhat, which are heavily used in blockchain app development. You will learn how to create and deploy smart contracts that ensure secure, transparent, and tamper-proof voting. Ideal for developers looking to harness the power of blockchain technology in democratic processes, this tutorial covers everything from setting up your environment to writing and testing your contracts. With the help of this mechanism, voters will be able to safely cast their ballots on the Ethereum blockchain, guaranteeing that they cannot be manipulated.

 

Also, Check | How To Build "Buy Me a Coffee" DeFi dApp Using Solidity

 

Setting Up the Development Environment

 

1. Install Node.js.

 

2. Setup Hard Hat: Install Hardhat by running the following command in your terminal:
 

 npm install --save-dev hardhat


3. Create a Hardhat Project: Initialize a new Hardhat project by running:
 

  npx hardhat

 

You may also like | How To Create a Daily Game Reward System in Solidity

 

Writing the Smart Contract

 

1. Create the Contract: Inside the contracts directory, create a new file named Voting.sol. This Solidity file will hold our voting logic.
 

2. Implement the Contract:
 

 // SPDX-License-Identifier: MIT
 pragma solidity ^0.8.0;
 contract Voting {
     struct Candidate {
         uint id;
         string name;
         uint voteCount;
     }
     mapping(uint => Candidate) public candidates;
     uint public candidatesCount;
     mapping(address => bool) public voters;
     constructor() {
         addCandidate('Alice');
         addCandidate('Bob');
     }
     function addCandidate(string memory _name) private {
         candidatesCount ++;
         candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
     }
     function vote(uint _candidateId) public {
         require(!voters[msg.sender], 'You have already voted.');
         require(_candidateId > 0 && _candidateId <= candidatesCount, 'Invalid candidate ID.');
         voters[msg.sender] = true;
         candidates[_candidateId].voteCount ++;
     }
 }

 

Also, Check | How to Create a MultiSig Wallet in Solidity

 

Deploying the Contract

 

1. Configure Deployment Scripts:


 - Inside the scripts directory, create a file named deploy.js.
 - Add the following code to deploy the contract:


   async function main() {
       const Voting = await ethers.getContractFactory('Voting');
       const voting = await Voting.deploy();
       await voting.deployed();
       console.log('Voting deployed to:', voting.address);
   }
   main().catch((error) => {
       console.error(error);
       process.exitCode = 1;
   });

 

Also, Read | Exploring Data Structures in Solidity for Advanced Smart Contracts

 

Testing the Contract 

 

1. Write Tests:
 

 - In the test directory, create a new file for the tests.
 - Use Hardhat's testing framework to write tests for your contract.

 

2. Run Tests:


 npx hardhat test

 

Also, Explore | Identifying Smart Contract Orchestration Patterns in Solidity

 

Conclusion

 

Congratulations! You now have a sophisticated decentralized voting system deployed on Ethereum using Solidity and Hardhat. This system lays the groundwork for numerous enhancements, such as advanced voting mechanisms, time-bound functionalities, and complex candidate structures. Imagine implementing features like weighted votes, multi-tiered elections, or secure voter verification – the possibilities are endless!

Ready to take your decentralized voting system to the next level? Contact our expert Solidity developers at Oodles to transform your vision into a robust, feature-rich solution tailored to your specific needs. Let's innovate together and redefine the future of voting!

Category: Blockchain
How to Build and Deploy a Subgraph with The Graph Protocol

The Graph is a tool that helps apps quickly access blockchain data. It uses a technology called GraphQL to pull data efficiently. Developers use it during blockchain app development to build faster and more reliable blockchain apps. It organizes blockchain data into something called subgraphs, making it easier to handle. This tool supports several blockchains, enhancing its usefulness for developers.

Advantages

  • Speed: It speeds up how quickly apps can access blockchain data.
  • Efficiency: It makes data retrieval more efficient using GraphQL.
  • Simplicity: Organizes data into subgraphs, which are easier for developers to manage.
  • Flexibility: Supports multiple blockchains, giving developers more options.
  • Reliability: Enhances the stability and reliability of decentralized applications.

Also, Check | How to Setup and Run a Solana RPC Node

Steps to create and deploy subgraph

Install Graph CLI:

Command:

yarn global add @graphprotocol/graph-cli` or `npm install -g @graphprotocol/graph-cli`

This installs the necessary tools to create and manage subgraphs.

Initialize Your Subgraph:

Command: 

`graph init --from-example <GITHUB_USER>/<SUBGRAPH_NAME>`

This sets up a new subgraph directory with starter files based on a template.

Define subgraph.yaml:

 Example

  yaml
  specVersion: 0.0.2
  description: "Example subgraph"
  repository: "https://github.com/example/repo"
  dataSources:
    - kind: ethereum/contract
      name: ContractName
      source:
        address: "0x..."
        abi: ContractABI
      mapping:
        kind: ethereum/events
        apiVersion: 0.0.4
        language: wasm/assemblyscript
        entities:
          - EntityName
        abis:
          - name: ContractABI
            file: ./abis/ContractABI.json
        eventHandlers:
          - event: Transfer(address,address,uint256)
            handler: handleTransfer
        file: ./src/mapping.ts
 

 This file configures your subgraph, defining which blockchain events it listens to and how they map to the data entities.

You may also like | How To Build "Buy Me a Coffee" DeFi dApp Using Solidity

Create the GraphQL Schema:

 File: schema.graphql

Example content:

  ```graphql
  type Transfer @entity {
    id: ID!
    from: Bytes!
    to: Bytes!
    value: BigInt!
  }
  ```

This defines the data structures that your subgraph will store and make queryable.

Write AssemblyScript Mappings:

File: `src/mapping.ts`

Example function:

  ```typescript
  import { BigInt } from "@graphprotocol/graph-ts"
  import { Transfer } from "../generated/Contract/Contract"

  export function handleTransfer(event: Transfer): void {
    let transfer = new Transfer(event.params.from, event.params.to, event.params.value)
    transfer.save()
  }
  ```

This script processes incoming blockchain events and translates them into entities defined in the GraphQL schema.

Deploy Your Subgraph:

Command:

`graph deploy --product hosted-service <GITHUB_USER>/<SUBGRAPH_NAME>`

This uploads your subgraph to The Graph's hosted service, making it available for queries.

Also, Read | A Guide to Google Calendar API Integration into Your React Application

Conclusion

In conclusion, The Graph Protocol is a powerful tool for developers looking to build and deploy efficient, reliable, and scalable blockchain applications. By using GraphQL to quickly access and manage blockchain data, and organizing it into subgraphs, developers can significantly enhance the performance and stability of their decentralized applications. With support for multiple blockchains, The Graph provides flexibility and a robust solution for a variety of use cases. Following the steps outlined—installing the Graph CLI, initializing your subgraph, defining the subgraph.yaml, creating a GraphQL schema, writing AssemblyScript mappings, and deploying your subgraph—will enable you to leverage the full potential of The Graph Protocol, streamlining your development process and improving your application's overall functionality. Connect with our skilled blockchain developers for a quick consultation regarding your blockchain or crypto project. 

Category: Blockchain
How to Develop Programmable Non-Fungible Tokens on Solana

The introduction of Programmable Non-Fungible Tokens (PNFTs) on Solana brings a new dimension to the world of digital ownership, as it allows creators to insert custom rules into their NFTs. In this way, it becomes possible to ensure that activities like transfers and burns are always done with respect to the creator's true intentions in the Solana development space.

 

Do Read | How to Create a Compressed NFT on Solana

 

Key Features of PNFTs

 

  1. Enhanced Security: For any operation, PNFTs demand that such an action must go through the Token Metadata program, ensuring that no set rules by the creator are bypassed as they might be using the SPL token program.
  2. Granular Delegation: Creators can determine precise operations allowed on assets, and assign delegates who have detailed security systems for managing these permissions.
  3. Rule Enforcement: Any operation upon which PNFT is enforced may be subjected to diverse custom rules thus allowing inventors to put various prerequisites regarding actions like transfer and update into effect.

    Practical Applications

     

    Royalty Enforcement: These tokens can enforce payments for royalties by using rules such as those that prevent transfers unless they comply with imposed royalty terms. This perspective on NFTs lets artists claim more control over how their digital assets are used or transferred. 
     

    Step 1: Project Setup

    Initialize Project Directory

     

    Create and navigate into a new project directory: 

    bash mkdir pnft_project cd pnft_project

    Create TypeScript File

     

    Generate the main TypeScript file for your application: 

    bash touch app.ts

    Initialize Package

     

    Use Yarn or npm to initialize your project with default settings: 

    yarn init -y # or npm init -y

    TypeScript Configuration

     

    Setup TypeScript with JSON module resolution and target ES2020: 

    tsc --init --resolveJsonModule --target ES2020

    Paper Wallet Setup

     

    Store your development network Solana keys in a file called guideSecret.json: 

    Ensure you generate this securely and store safely.

    Step 2: Install Dependencies

     

    Install necessary libraries for interacting with Solana's blockchain: 

    yarn add @solana/web3.js @metaplex-foundation/js 
    or 
    npm install @solana/web3.js @metaplex-foundation/js

    Step 3: Configure Your App

     

    Import Required Modules

     

    At the top of app.ts, include the necessary modules from the installed libraries: typescript 

    import { Connection, Keypair, PublicKey } from "@solana/web3.js"; 
    import { Metaplex, keypairIdentity, bundlrStorage, toMetaplexFile, toBigNumber } from "@metaplex-foundation/js";
    import { TokenStandard } from '@metaplex-foundation/mpl-token-metadata'; 
    import secret from './guideSecret.json';

    Setup Connection

     

    Configure the connection to the Solana cluster using an endpoint: 

    const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/your_unique_id/'; 
    const SOLANA_CONNECTION = new Connection(QUICKNODE_RPC);

    Initialize Metaplex

     

    Set up the Metaplex client with the connection and wallet information: 

    const WALLET = Keypair.fromSecretKey(new Uint8Array(secret)); 
    const METAPLEX = Metaplex.make(SOLANA_CONNECTION) .use(keypairIdentity(WALLET)) .use(bundlrStorage({ address: 'https://devnet.bundlr.network', providerUrl: QUICKNODE_RPC, timeout: 60000, }));

    Step 4: Define NFT Configuration

    Configure the metadata and attributes of your NFT: typescript 

    const NFT_CONFIG = { 
    	imgName: 'MyUniqueNFT', 
    	symbol: 'UNIQ', 
    	sellerFeeBasisPoints: 500, // 5% fee 
    	creators: [{ address: WALLET.publicKey, share: 100 }], 
    	metadata: 'https://arweave.net/example_URI' 
    };

    Step 5: Create the Mint Function

     

    Implement the function to mint your pNFT: typescript 

    async function mintProgrammableNft( metadataUri: string, name: string, sellerFee: number, symbol: string, creators: { address: PublicKey, share: number }[] ) { 
    	console.log("Minting pNFT..."); 
    	try { 
    		const transactionBuilder = await METAPLEX.nfts().builders().create({ uri: metadataUri, name: name, sellerFeeBasisPoints: sellerFee, symbol: symbol, creators: creators, isMutable: true, isCollection: false, tokenStandard: TokenStandard.ProgrammableNonFungible, ruleSet: null }); 
    		
    		let { signature, confirmResponse } = await METAPLEX.rpc().sendAndConfirmTransaction(transactionBuilder); 
    		
    		if (confirmResponse.value.err) { 
    			throw new Error('Failed to confirm transaction'); 
    		} 
    		const { mintAddress } = transactionBuilder.getContext(); 
    		console.log(` Success!🎉`); 
    		console.log(` Minted NFT: https://explorer.solana.com/address/${mintAddress.toString()}?cluster=devnet`); 
    		console.log(` Tx: https://explorer.solana.com/tx/${signature}?cluster=devnet`); 
    	} catch (err) { 
    		console.log(err); 
    	} 
    }

    Step 6: Mint the NFT

     

    Execute the minting process by calling your function with the configured settings: typescript 

    mintProgrammableNft( NFT_CONFIG.metadata, NFT_CONFIG.imgName, NFT_CONFIG.sellerFeeBasisPoints, NFT_CONFIG.symbol, NFT_CONFIG.creators ); // Run the script ts-node app.ts 

     

    You may also read | A Detailed Guide to NFT Minting on Solana using Metaplex API 

     

    Conclusion 

     

    Programmable NFTs on Solana offer NFT developers an innovative, fast, and secure platform to create advanced and customizable decentralized applications, revolutionizing the digital asset landscape. Contact our NFT developers for expert services. 

     

    References - (Click the link below)

     

    Github

    StackOverflow

 

Category: Blockchain
How to Transfer SOL and SPL Tokens Using Anchor

The Anchor framework is a Rust-based framework for building Solana programs using Solana blockchain development. It simplifies the process of developing Solana smart contracts by providing a higher-level abstraction over Solana's low-level programming model. Anchor abstracts away much of the complexity involved in writing Solana programs, making it easier for developers to focus on application logic rather than low-level details.

 

Prerequisites

 

Rust Installation

 

Go here to install Rust.

 

Solana Installation

 

To set up Solana, visit the Solana website to download and install the software. Once installed, open your terminal and run the command `solana-keygen new` to generate a key pair. This will create a keypair at the default location.

 

Yarn Installation

 

Go here to install Yarn.

 

Anchor Installation

 

Installing using Anchor version manager

 

Anchor version manager is a tool for using multiple versions of the anchor-cli. It will require the same dependencies as building from source. It is recommended you uninstall the NPM package if you have it installed.

 

Install avm using Cargo. Note this will replace your anchor binary if you had one installed.

 

cargo install --git https://github.com/coral-xyz/anchor avm --locked --force

 

On Linux systems, you may need to install additional dependencies if the cargo install fails. E.g. on Ubuntu:

 

Install the latest version of the CLI using AVM, and then set it to be the version to use.

 

avm install latest
avm use latest

Verify the installation.
anchor --version
Steps 

 

1.) Initialize a new project, simply run:

 

anchor init <new-workspace-name>

 

2.) Let's begin by opening lib.rs in the programs folder, we can proceed with developing our program.

 

3.) Below is the program code

 

use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, Transfer as SplTransfer};
use solana_program::system_instruction;

declare_id!("MyUniqueProgramId");

#[program]
pub mod my_program {
use super::*;

// Function for transferring lamports
pub fn transfer_lamports(ctx: Context<LamportTransfer>, amount: u64) -> Result<()> {
     let sender_account = &ctx.accounts.sender;
     let recipient_account = &ctx.accounts.recipient;

     // Create the transfer instruction
     let transfer_instruction =
         system_instruction::transfer(sender_account.key, recipient_account.key, amount);

     // Invoke the transfer instruction
     anchor_lang::solana_program::program::invoke_signed(
         &transfer_instruction,
         &[
             sender_account.to_account_info(),
             recipient_account.clone(),
             ctx.accounts.system_program.to_account_info(),
         ],
         &[],
     )?;

     Ok(())
}

// Function for transferring SPL tokens
pub fn transfer_spl_tokens(ctx: Context<SplTokenTransfer>, amount: u64) -> Result<()> {
     let destination_account = &ctx.accounts.destination_token_account;
     let source_account = &ctx.accounts.source_token_account;
     let token_program = &ctx.accounts.spl_token_program;
     let authority = &ctx.accounts.authority;

     // Transfer tokens from source to destination
     let cpi_accounts = SplTransfer {
         from: source_account.to_account_info().clone(),
         to: destination_account.to_account_info().clone(),
         authority: authority.to_account_info().clone(),
     };
     let cpi_program = token_program.to_account_info();

     // Invoke SPL token transfer
     token::transfer(CpiContext::new(cpi_program, cpi_accounts), amount)?;

     Ok(())
}
}

// Accounts for transferring lamports
#[derive(Accounts)]
pub struct LamportTransfer<'info> {
#[account(mut)]
pub sender: Signer<'info>,
#[account(mut)]
pub recipient: AccountInfo<'info>,
pub system_program: Program<'info, System>,
}

// Accounts for transferring SPL tokens
#[derive(Accounts)]
pub struct SplTokenTransfer<'info> {
pub authority: Signer<'info>,
#[account(mut)]
pub source_token_account: Account<'info, TokenAccount>,
#[account(mut)]
pub destination_token_account: Account<'info, TokenAccount>,
pub spl_token_program: Program<'info, Token>,
}

 

4.)Let's break down the code and explain the program:

 

  1. Imports:
    • anchor_lang::prelude::*: Imports the necessary items from the Anchor framework's prelude module, providing convenient access to commonly used types and traits.
    • anchor_spl::token::{self, Token, TokenAccount, Transfer as SplTransfer}: Imports types related to SPL tokens from the Anchor SPL module, including the Token, TokenAccount, and Transfer structs.
    • solana_program::system_instruction: Imports the system instruction module from Solana's program library, which includes functions for interacting with the system program.
  2. Program ID Declaration:
    • declare_id!("MyUniqueProgramId"): Declares a unique program ID for the Solana program. This macro generates the declaration of a constant representing the program ID.
  3. Program Module:
    • #[program] mod my_program { ... }: Defines a module named my_program that represents the Solana program. The #[program] attribute is a procedural macro provided by Anchor, which generates necessary code to define the Solana program.
  4. Function Definitions:
    • Within the my_program module, two functions are defined:
      • transfer_lamports: Handles the transfer of Solana lamports (the native token of the Solana blockchain).
      • transfer_spl_tokens: Handles the transfer of SPL tokens.
  5. Function Parameters:
    • Both functions take a Context parameter, which provides access to program accounts and environment data required for the execution of the function. The Context is a generic type parameterized by a struct representing the accounts required for the function.
  6. Function Bodies:
    • transfer_lamports: This function transfers a specified amount of lamports from one account to another using the system program's transfer instruction. It constructs the transfer instruction and invokes it using Anchor's invoke_signed function, passing required accounts and signers.
    • transfer_spl_tokens: This function transfers a specified amount of SPL tokens from one account to another using the SPL token program's transfer instruction. It constructs the transfer instruction and invokes it using Anchor's token::transfer function, passing required accounts and amount.
  7. Account Structs:
    • TransferLamports and SplTokenTransfer are account structs defined using the #[derive(Accounts)] attribute. These structs represent the accounts required by the respective transfer functions. Account structs define the accounts that the Solana program will interact with, including the types of those accounts (e.g., Signer, Account, Program). Each field in the account struct corresponds to an account used by the program.
  8. Account Attributes:
    • Account fields in the structs are decorated with attributes that specify their properties:
      • #[account(mut)]: Indicates that the account is mutable, allowing the program to modify its data.
      • #[account(signer)]: Specifies that the account must be a signer, providing authorization for transactions.

 

To get started with Solana blockchain development or a project development on Solana, connect with our blockchain developers

Category: Blockchain
Creating a Tokenized Lootbox Game Smart Contract on Ethereum

Within the quickly developing realm of blockchain gaming, tokenized loot boxes have become a fascinating fusion of virtual cash and gaming fun. With blockchain development services, you can create a unique gaming experience where players can purchase, earn, and open loot boxes containing a range of tokenized things by utilizing the Ethereum network and the ERC1155 multi-token standard. Using the "MyToken" contract as a foundational example, this blog post will walk you through the process of creating a tokenized loot-box game using the ERC1155 standard.

 

Core Concept of the Tokenized Loot-box Game

 

The essence of our game revolves around loot boxes—special tokens that can contain an array of other tokenized items, ranging from common to rare. Players can acquire loot boxes through gameplay, purchases, or trading with other players. Opening a loot box reveals its contents, adding an element of surprise and anticipation to the gaming experience.

 

The "MyToken" Contract: A Blueprint

 

Our game's backbone is the "MyToken" smart contract, which implements the ERC1155 standard along with additional functionalities for managing loot boxes. Let's dissect the main components and functionalities that make this contract suitable for our game:

 

  1. ERC1155 Foundation: This allows for efficient handling of multiple token types, essential for distinguishing between different loot boxes and items within our game.
  2. LootBox Functions: These provide the game developers (contract owners) with exclusive rights to mint new items and loot boxes.

 

Also, Check |  Game On! Mastering Web3 Game Development

 

Prerequisites:-

 

  • Nodejs installed
  • Solidity Familiarity
  • ERC 1155 Familiarity

 

Implementing the Game Logic

 

Step 1: Setting up the Hardhat Environment

 

Create a new folder for the project. 

Use the following command:-  

npx hardhat 

And create a hardhat project.

 

We can now create our solidity contract in the contract folder by deleting the lock.sol file provided by hardhat. 

 

run
npm install @openzeppelin/contracts

 

You may also like | A Guide on How to Develop a Dutch Auction Smart Contract

 

Step 2: Smart Contract Development

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;


// Importing ERC1155, Ownable, and ERC1155Burnable contracts from OpenZeppelin.
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";


// MyToken is a contract that combines ERC1155 for multi-token functionality,
// Ownable for ownership management, and ERC1155Burnable for token burnability.
contract MyToken is ERC1155, Ownable, ERC1155Burnable {
  // Private variable to keep track of the next item ID.
  uint256 private _nextItemId = 1;
  // Private variable to keep track of the next loot box ID.
  uint256 private _nextBoxId = 1;


  // Struct representing a loot box, which contains arrays of item IDs and quantities.
  struct LootBox {
      uint256[] itemIds;
      uint256[] itemQuantities;
  }


  // Mapping from loot box ID to LootBox struct, storing each loot box's details.
  mapping(uint256 => LootBox) private lootBoxes;


  // Event emitted when a loot box is opened.
  event LootBoxOpened(uint256 indexed boxId, address opener);


  // Constructor sets the base URI for token metadata and transfers ownership.
  constructor(string memory uri, address initialOwner) ERC1155(uri) Ownable(initialOwner) {
  }


  // Function to create a new loot box. Only the owner can call this function.
  function createLootBox(uint256[] memory itemIds, uint256[] memory itemQuantities) public onlyOwner {
      require(itemIds.length == itemQuantities.length, "Mismatch between item IDs and quantities");
      uint256 newBoxId = _nextBoxId++;
      lootBoxes[newBoxId] = LootBox(itemIds, itemQuantities);
  }


  // Function to open a loot box, burning one instance of the box and minting one of the items inside.
  function openLootBox(uint256 boxId) public {
      require(balanceOf(msg.sender, boxId) > 0, "You do not own this loot-box");
      _burn(msg.sender, boxId, 1); // Burn one loot box from the caller's balance.


      LootBox memory box = lootBoxes[boxId];
      // Generate a random index to determine which item to mint.
      uint256 randomIndex = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % box.itemIds.length;
      uint256 itemId = box.itemIds[randomIndex];
      uint256 quantity = box.itemQuantities[randomIndex];


      _mint(msg.sender, itemId, quantity, ""); // Mint the item to the caller.
      emit LootBoxOpened(boxId, msg.sender); // Emit an event for opening the loot box.
  }


  // Allows the owner to mint a new item directly to an address.
  function mintItem(address to, uint256 id, uint256 quantity, bytes memory data) public onlyOwner {
      _mint(to, id, quantity, data);
  }


  // Allows the owner to mint a new loot box and assigns it to an address.
  function mintLootBox(address to, uint256[] memory itemIds, uint256[] memory itemQuantities, uint256 quantity) public onlyOwner {
      createLootBox(itemIds, itemQuantities); // Create the loot box first.
      _mint(to, _nextBoxId - 1, quantity, ""); // Then mint it to the specified address.
  }


  // Function for the owner to set a new URI for all token types.
  function setURI(string memory newuri) public onlyOwner {
      _setURI(newuri);
  }


  // Function for the owner to mint tokens of a given ID and amount to a specified account.
  function mint(address account, uint256 id, uint256 amount, bytes memory data) public onlyOwner {
      _mint(account, id, amount, data);
  }


  // Function for the owner to mint multiple tokens of different IDs to a specified account.
  function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public onlyOwner {
      _mintBatch(to, ids, amounts, data);
  }
}

 

  • Create MyToken Contract:

 

  • Create a new Solidity file named MyToken.sol.
  • Copy the provided Solidity code into MyToken.sol.

 

  • Understand Contract Components:

 

  • ERC1155: This is a multi-token standard allowing the contract to manage multiple token types.
  • Ownable: Provides basic authorization control functions, simplifying the implementation of "user permissions".
  • ERC1155Burnable: Allows tokens to be burnt, removing them from the total supply.

 

  • Implement Constructor: The constructor sets the base URI for token metadata and optionally transfers ownership to another address. Be prepared to provide the URI and the initial owner's address upon deployment.

 

  • Implement Loot Box Logic:

 

  • createLootBox: Allows the contract owner to create new loot boxes, each defined by arrays of item IDs and their quantities.
  • openLootBox: Allows a loot box owner to open it, burning the loot box token and minting one of the items inside to the opener.

 

  • Implement Minting Functions:

 

  • mintItem: For the contract owner to mint a specific item directly to an address.
  • mintLootBox: For the contract owner to mint a loot box (after creating it) directly to an address.
  • mint: For minting tokens of a given ID to a specific account.
  • mintBatch: Allows the owner to mint multiple types of tokens to a specified account in a single transaction.

 

  • Utility Functions:

 

  • setURI: To update the base URI for all token types.
  • Private variables _nextItemId and _nextBoxId are used to keep track of the IDs for new items and loot boxes, ensuring uniqueness.

 

Explore More | Smart Contract Development Using Python

 

Step 3: Minting Loot Boxes

 

The game developer mints a variety of loot boxes, each characterized by a unique ID and containing a predefined set of items. This step involves calling the mintLootBox function to distribute the loot boxes to players.

 

Step 4: Acquiring and Opening Loot Boxes

 

Players acquire loot boxes through gameplay, purchases, or trades. To open a loot box, a player calls the openLootBox function, which burns the loot box token and randomly selects an item from its contents to mint to the player's address.

 

Also, Read | Creating a Staking Smart Contract on Solana using Anchor

 

Conclusion

 

Building a tokenized loot-box game with ERC1155 offers a unique opportunity to blend blockchain technology with engaging gameplay elements. The "MyToken" contract serves as a solid foundation, showcasing how to manage loot boxes and items within a unified framework. By embracing this technology, developers can create rich, interactive gaming experiences that leverage the power of blockchain for transparency, ownership, and traceability of digital assets. As the blockchain gaming industry continues to grow, innovative applications like tokenized loot boxes will undoubtedly play a significant role in shaping its future. Interested in developing a similar project for a wider audience, get in touch with smart contract developers to get started. 

Category: Blockchain
How to Set Up Strapi and Deploy on Heroku

Creating a Content Management System (CMS) using Strapi and deploying it on Heroku combines the flexibility of Strapi's headless CMS with the simplicity of Heroku's cloud platform. Strapi enables developers to design a customized CMS, defining content structures and APIs, while Heroku streamlines the deployment process, providing a scalable and managed environment for hosting the Strapi-based CMS. This synergy allows for efficient content management and delivery in a cloud-native and user-friendly ecosystem for your app development.

 

What is Strapi?

 

Strapi is an open-source, headless Content Management System (CMS) known for its flexibility and customization capabilities, allowing developers to design tailored admin panels, APIs, and database models. As a self-hosted solution built on modern technologies, Strapi is ideal for those seeking a customizable CMS for various projects, including web applications and mobile apps. Here are its key features:

 

Headless CMS

 

Unlike traditional CMS platforms like WordPress, Strapi is "headless". This means it doesn't dictate how content is presented but provides it as data over an API. This approach offers more flexibility in how the content is used, whether it's for websites, mobile apps, or other platforms.

 

API-Centric

 

Strapi is designed to build APIs quickly. It provides a powerful API to interact with your content.

 

Customizable

 

Strapi is highly customizable for different use cases. It allows developers to tailor the admin panel, APIs, and database models according to their needs.

 

Self-Hosted

 

Strapi is self-hosted, giving users complete control over their data and infrastructure.

 

Technology Stack

 

It's built using modern technologies such as Node.js, and React, and supports various databases like MongoDB, MySQL, SQLite, and PostgreSQL.

 

Use Case

 

It's ideal for developers looking to build project-specific CMS without the overhead of managing presentation layers, perfect for web applications, mobile apps, and more.

 

You may also like | Native vs. Hybrid vs. Web | Choosing Mobile App Development

 

What is Heroku?

 

Heroku stands as a Platform-as-a-Service (PaaS) cloud platform, empowering developers to construct, execute, and manage applications seamlessly within the cloud environment. Vital elements of Heroku comprise:

 

User-Friendliness

 

Heroku is renowned for its straightforwardness and user-friendly interface. It allows developers to deploy, manage, and scale applications with minimal configuration and hassle.

 

Support for Multiple Languages

 

Heroku supports several programming languages, including Ruby, Java, Node.js, Scala, Clojure, Python, PHP, and Go.

 

Add-ons

 

Offers a range of add-ons that provide various services like databases, monitoring, caching, and more, which can be easily integrated into applications.

 

Deployment

 

Simplifies the deployment process with Git-based deployments and Docker container support.

 

Dynos

 

Applications on Heroku run in lightweight, isolated environments called "dynos" that are abstracted from the underlying hardware.

 

Scalability

 

Provides easy scalability options, allowing applications to handle increased traffic by adjusting the number of active dynos.

 

Managed Infrastructure

 

Heroku manages hardware and servers, allowing developers to focus on their applications.

 

Use Case

 

Ideal for startups and businesses that want to deploy applications quickly without dealing with infrastructure management.

 

Also, Explore | Cross-platform Mobile App Development


 

 

Steps to Set Up Strapi and Deploy on Heroku

 

1. Local Setup with Strapi

 

Install Strapi:

 

  • Use Node Package Manager (npm) to install Strapi.
    bash

 

npx create-strapi-app my-blog --quickstart

 

  • This command creates a new Strapi project in a folder named my-blog.

 

Configure Strapi:

 

  • After installation, Strapi's admin panel will open in your browser.
  • Set up an admin account to manage your blog.

 

Create Blog Content Types:


 

  • Use the Content-Type Builder in Strapi's admin panel to define the structure of your blog content, such as 'Articles', 'Categories', 'Authors', etc.

 

2. Preparing for Heroku Deployment

 

Database Configuration:

 

  • Strapi's default SQLite database isn't suitable for Heroku. Configure Strapi to use a PostgreSQL database, which is more suitable for production and supported by Heroku.

 

Environment Variables:

 

  • Set up environment variables for database connections (like DATABASE_URL) and other necessary settings. These variables will differ between your local environment and Heroku.

 

Install Heroku CLI:

 

  • Download and install the Heroku CLI tool, which allows you to manage your Heroku applications from the command line.

 

3. Deploying to Heroku

 

Create a Heroku App:

 

  • Log in to your Heroku dashboard and create a new app. Alternatively, use the Heroku CLI:
    bash

 

heroku create my-strapi-blog

 

Configure Database on Heroku:

 

  • Add a PostgreSQL database to your Heroku application. This can be done from the 'Resources' tab in your Heroku app dashboard.

 

Set Environment Variables in Heroku:

 

  • Transfer your local environment variables to Heroku. This can be done via the 'Settings' tab in your Heroku app dashboard or via the CLI:
    bash

 

heroku config:set DATABASE_URL=your_database_url

 

Deploy Your Strapi App:

 

  • Deploy your Strapi application to Heroku. If your code is hosted on GitHub, you can connect your GitHub repository for continuous deployment. Alternatively, you can deploy using Git:
    bash

 

git push heroku master

 

4. Post-Deployment Setup

 

Initialize Database:

 

  • After deployment, you may need to run database migrations or seed the database.

 

Access Strapi Admin Panel:

 

  • Visit https://my-strapi-blog.herokuapp.com/admin to access the Strapi admin panel on Heroku.

 

5. Maintaining and Updating

 

Regular Updates:

 

  • Keep Strapi and its dependencies updated. Regularly pull changes from your repository and redeploy to Heroku.

 

Monitoring:

 

  • Use Heroku’s dashboard to monitor your app's performance and logs.

 

Scaling:

 

  • Scale your Heroku dynos as needed to handle increased traffic or background tasks.

 

Also, Read | Hybrid App Development | An Introductory Guide

 

Conclusion

 

In the realm of modern web development, the combination of Strapi's headless Content Management System (CMS) and Heroku's cloud platform as a service (PaaS) presents a powerful synergy. Strapi's flexibility, customization options, and API-centric approach make it an ideal choice for developers seeking to create tailored CMS solutions. On the other hand, Heroku's simplicity, language support, and managed infrastructure alleviate the complexities of deployment and scaling, providing a seamless environment for hosting applications. If you are looking to develop a custom CMS or web or mobile app, connect with our app developers to get started. 

 

A Guide to Gasless ERC20 Token Transfer

Find out the step-by-step guide for gasless ERC20 token transfers in Ethereum development services to streamline transactions and foster accessibility in blockchain assets. 

 

Gasless ERC20 Token Transfers: Embracing Efficiency and Accessibility

 

In the evolving world of blockchain technology, the implementation of gasless ERC20 token transfers stands out as a significant innovation. This approach utilizes meta-transactions to enhance the efficiency and accessibility of token transfers on the Ethereum network.

 

What are ERC20 Tokens?

 

ERC20 tokens are digital assets built on the Ethereum blockchain. They adhere to a specific set of standards, making them interoperable with various applications and services within the Ethereum ecosystem.

 

Suggested Read | ERC-20 Token Standard | Development Essentials

 

The Role of Meta Transactions

 

Meta transactions represent a pivotal shift in how blockchain transactions are processed. By allowing a third party to pay the transaction fees ('gas'), users can transfer ERC20 tokens without incurring these costs directly. This method significantly lowers the barrier to entry and makes transactions more user-friendly.

 

Exploring the Solidity Code

 

IERC20Permit Interface

 

The IERC20Permit interface extends the standard ERC20 functionalities, introducing the permit function. This function is crucial for authorizing third-party transactions without the token holder incurring gas fees.

 

GaslessTokenTransfer Contract

 

The GaslessTokenTransfer contract leverages the permit method to enable gasless transactions. The send function within this contract allows the transfer of tokens from a sender to a receiver, with the transaction fee being handled externally.

 

ERC20Permit Contract

 

The ERC20Permit contract is a concrete implementation of the ERC20 standard, incorporating the EIP-2612 standard. This includes the permit function, allowing for more flexible and efficient token transfers.

 

Example Code:

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IERC20Permit {
   function totalSupply() external view returns (uint256);

   function balanceOf(address account) external view returns (uint256);

   function transfer(address recipient, uint256 amount) external returns (bool);

   function allowance(address owner, address spender) external view returns (uint256);

   function approve(address spender, uint256 amount) external returns (bool);

   function transferFrom(
       address sender,
       address recipient,
       uint256 amount
   ) external returns (bool);

   function permit(
       address owner,
       address spender,
       uint256 value,
       uint256 deadline,
       uint8 v,
       bytes32 r,
       bytes32 s
   ) external;

   event Transfer(address indexed from, address indexed to, uint256 value);
   event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract GaslessTokenTransfer {
   function send(
       address token,
       address sender,
       address receiver,
       uint256 amount,
       uint256 fee,
       uint256 deadline,
       // Permit signature
       uint8 v,
       bytes32 r,
       bytes32 s
   ) external {
       // Permit
       IERC20Permit(token).permit(
           sender,
           address(this),
           amount + fee,
           deadline,
           v,
           r,
           s
       );
       // Send amount to receiver
       IERC20Permit(token).transferFrom(sender, receiver, amount);
       // Take fee - send fee to msg.sender
       IERC20Permit(token).transferFrom(sender, msg.sender, fee);
   }
}


/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
   /*//////////////////////////////////////////////////////////////
                                EVENTS
   //////////////////////////////////////////////////////////////*/

   event Transfer(address indexed from, address indexed to, uint256 amount);

   event Approval(address indexed owner, address indexed spender, uint256 amount);

   /*//////////////////////////////////////////////////////////////
                           METADATA STORAGE
   //////////////////////////////////////////////////////////////*/

   string public name;

   string public symbol;

   uint8 public immutable decimals;

   /*//////////////////////////////////////////////////////////////
                             ERC20 STORAGE
   //////////////////////////////////////////////////////////////*/

   uint256 public totalSupply;

   mapping(address => uint256) public balanceOf;

   mapping(address => mapping(address => uint256)) public allowance;

   /*//////////////////////////////////////////////////////////////
                           EIP-2612 STORAGE
   //////////////////////////////////////////////////////////////*/

   uint256 internal immutable INITIAL_CHAIN_ID;

   bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

   mapping(address => uint256) public nonces;

   /*//////////////////////////////////////////////////////////////
                              CONSTRUCTOR
   //////////////////////////////////////////////////////////////*/

   constructor(string memory _name, string memory _symbol, uint8 _decimals) {
       name = _name;
       symbol = _symbol;
       decimals = _decimals;

       INITIAL_CHAIN_ID = block.chainid;
       INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
   }

   /*//////////////////////////////////////////////////////////////
                              ERC20 LOGIC
   //////////////////////////////////////////////////////////////*/

   function approve(address spender, uint256 amount) public virtual returns (bool) {
       allowance[msg.sender][spender] = amount;

       emit Approval(msg.sender, spender, amount);

       return true;
   }

   function transfer(address to, uint256 amount) public virtual returns (bool) {
       balanceOf[msg.sender] -= amount;

       // Cannot overflow because the sum of all user
       // balances can't exceed the max uint256 value.
       unchecked {
           balanceOf[to] += amount;
       }

       emit Transfer(msg.sender, to, amount);

       return true;
   }

   function transferFrom(
       address from,
       address to,
       uint256 amount
   ) public virtual returns (bool) {
       uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

       if (allowed != type(uint256).max)
           allowance[from][msg.sender] = allowed - amount;

       balanceOf[from] -= amount;

       // Cannot overflow because the sum of all user
       // balances can't exceed the max uint256 value.
       unchecked {
           balanceOf[to] += amount;
       }

       emit Transfer(from, to, amount);

       return true;
   }

   /*//////////////////////////////////////////////////////////////
                            EIP-2612 LOGIC
   //////////////////////////////////////////////////////////////*/

   function permit(
       address owner,
       address spender,
       uint256 value,
       uint256 deadline,
       uint8 v,
       bytes32 r,
       bytes32 s
   ) public virtual {
       require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

       // Unchecked because the only math done is incrementing
       // the owner's nonce which cannot realistically overflow.
       unchecked {
           address recoveredAddress = ecrecover(
               keccak256(
                   abi.encodePacked(
                       "\x19\x01",
                       DOMAIN_SEPARATOR(),
                       keccak256(
                           abi.encode(
                               keccak256(
                                   "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                               ),
                               owner,
                               spender,
                               value,
                               nonces[owner]++,
                               deadline
                           )
                       )
                   )
               ),
               v,
               r,
               s
           );

           require(
               recoveredAddress != address(0) && recoveredAddress == owner,
               "INVALID_SIGNER"
           );

           allowance[recoveredAddress][spender] = value;
       }

       emit Approval(owner, spender, value);
   }

   function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
       return
           block.chainid == INITIAL_CHAIN_ID
               ? INITIAL_DOMAIN_SEPARATOR
               : computeDomainSeparator();
   }

   function computeDomainSeparator() internal view virtual returns (bytes32) {
       return
           keccak256(
               abi.encode(
                   keccak256(
                       "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                   ),
                   keccak256(bytes(name)),
                   keccak256("1"),
                   block.chainid,
                   address(this)
               )
           );
   }

   /*//////////////////////////////////////////////////////////////
                       INTERNAL MINT/BURN LOGIC
   //////////////////////////////////////////////////////////////*/

   function _mint(address to, uint256 amount) internal virtual {
       totalSupply += amount;

       // Cannot overflow because the sum of all user
       // balances can't exceed the max uint256 value.
       unchecked {
           balanceOf[to] += amount;
       }

       emit Transfer(address(0), to, amount);
   }

   function _burn(address from, uint256 amount) internal virtual {
       balanceOf[from] -= amount;

       // Cannot underflow because a user's balance
       // will never be larger than the total supply.
       unchecked {
           totalSupply -= amount;
       }

       emit Transfer(from, address(0), amount);
   }
}

contract ERC20Permit is ERC20 {
   constructor(
       string memory _name,
       string memory _symbol,
       uint8 _decimals
   ) ERC20(_name, _symbol, _decimals) {}

   function mint(address to, uint256 amount) public {
       _mint(to, amount);
   }
}

 

Advantages of Gasless Token Transfers

 

  • Cost Efficiency: Users can transfer tokens without the burden of gas fees.
  • User Accessibility: Lowers the entry barrier for new users unfamiliar with the complexities of gas fees.
  • Enhanced Transaction Flow: Streamlines the process, making it more appealing for regular use.

 

Check It Out | ERC-20 Token Standard | Things You Must Know

 

Conclusion

 

The integration of gasless ERC20 token transfers marks a significant stride in blockchain technology, offering a more accessible and efficient means of handling digital assets. As blockchain matures, innovations like these play a critical role in shaping its future, making it more inclusive and user-friendly. 

 

Interested in ERC20 token development? Connect with our Ethereum developers today to get started. 

How to Create a MultiSig Wallet in Solidity

Creating a Multi-Sig Wallet in Solidity

 

A multi-signature (multi-sig) wallet is like a safe that needs multiple keys to open. It's a smart contract that holds cryptocurrency and requires more than one person's approval to make transactions. Today, we'll delve into creating a multi-sig wallet using Hardhat, a popular Ethereum development environment. Creating a multi-sig wallet requires significant expertise in smart contract development

 

Prerequisites

 

  1. A basic understanding of Solidity and Ethereum.
  2. Node.js is installed on your machine.
  3. Hardhat is installed globally using the command: npm install -g hardhat.

 

Setting Up Hardhat

 

  1. Creating a New Project: Run npx hardhat in your terminal and follow the prompts to create a new project.
  2. Installing Dependencies: Inside your project directory, install the necessary npm packages with:
    bash

 

npm install @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers

 

Writing the Multi-Sig Wallet Smart Contract

 

  1. Create a new file called MultiSigWallet.sol in the contracts folder.
  2. Paste the below code

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract MultiSigWallet {
   event Deposit(address indexed sender, uint amount, uint balance);
   event SubmitTransaction(
       address indexed owner,
       uint indexed txIndex,
       address indexed to,
       uint value,
       bytes data
   );
   event ConfirmTransaction(address indexed owner, uint indexed txIndex);
   event RevokeConfirmation(address indexed owner, uint indexed txIndex);
   event ExecuteTransaction(address indexed owner, uint indexed txIndex);

   address[] public owners;
   mapping(address => bool) public isOwner;
   uint public numConfirmationsRequired;

   struct Transaction {
       address to;
       uint value;
       bytes data;
       bool executed;
       uint numConfirmations;
   }

   // mapping from tx index => owner => bool
   mapping(uint => mapping(address => bool)) public isConfirmed;

   Transaction[] public transactions;

   modifier onlyOwner() {
       require(isOwner[msg.sender], "not owner");
       _;
   }

   modifier txExists(uint _txIndex) {
       require(_txIndex < transactions.length, "tx does not exist");
       _;
   }

   modifier notExecuted(uint _txIndex) {
       require(!transactions[_txIndex].executed, "tx already executed");
       _;
   }

   modifier notConfirmed(uint _txIndex) {
       require(!isConfirmed[_txIndex][msg.sender], "tx already confirmed");
       _;
   }

   constructor(address[] memory _owners, uint _numConfirmationsRequired) {
       require(_owners.length > 0, "owners required");
       require(
           _numConfirmationsRequired > 0 &&
               _numConfirmationsRequired <= _owners.length,
           "invalid number of required confirmations"
       );

       for (uint i = 0; i < _owners.length; i++) {
           address owner = _owners[i];

           require(owner != address(0), "invalid owner");
           require(!isOwner[owner], "owner not unique");

           isOwner[owner] = true;
           owners.push(owner);
       }

       numConfirmationsRequired = _numConfirmationsRequired;
   }

   receive() external payable {
       emit Deposit(msg.sender, msg.value, address(this).balance);
   }

   function submitTransaction(
       address _to,
       uint _value,
       bytes memory _data
   ) public onlyOwner {
       uint txIndex = transactions.length;

       transactions.push(
           Transaction({
               to: _to,
               value: _value,
               data: _data,
               executed: false,
               numConfirmations: 0
           })
       );

       emit SubmitTransaction(msg.sender, txIndex, _to, _value, _data);
   }

   function confirmTransaction(
       uint _txIndex
   ) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) notConfirmed(_txIndex) {
       Transaction storage transaction = transactions[_txIndex];
       transaction.numConfirmations += 1;
       isConfirmed[_txIndex][msg.sender] = true;

       emit ConfirmTransaction(msg.sender, _txIndex);
   }

   function executeTransaction(
       uint _txIndex
   ) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
       Transaction storage transaction = transactions[_txIndex];

       require(
           transaction.numConfirmations >= numConfirmationsRequired,
           "cannot execute tx"
       );

       transaction.executed = true;

       (bool success, ) = transaction.to.call{value: transaction.value}(
           transaction.data
       );
       require(success, "tx failed");

       emit ExecuteTransaction(msg.sender, _txIndex);
   }

   function revokeConfirmation(
       uint _txIndex
   ) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
       Transaction storage transaction = transactions[_txIndex];

       require(isConfirmed[_txIndex][msg.sender], "tx not confirmed");

       transaction.numConfirmations -= 1;
       isConfirmed[_txIndex][msg.sender] = false;

       emit RevokeConfirmation(msg.sender, _txIndex);
   }

   function getOwners() public view returns (address[] memory) {
       return owners;
   }

   function getTransactionCount() public view returns (uint) {
       return transactions.length;
   }

   function getTransaction(
       uint _txIndex
   )
       public
       view
       returns (
           address to,
           uint value,
           bytes memory data,
           bool executed,
           uint numConfirmations
       )
   {
       Transaction storage transaction = transactions[_txIndex];

       return (
           transaction.to,
           transaction.value,
           transaction.data,
           transaction.executed,
           transaction.numConfirmations
       );
   }
}

 

Compiling Your Smart Contract:

 

  • In your terminal, run npx hardhat compile.

 

Contract Details

 

Contract Setup

 

  • Defined using pragma solidity ^0.8.20; to specify the Solidity compiler version.
  • contract SecureMultiWallet { ... } initiates the contract definition.

 

Event Definitions

 

  • Events such as FundsDeposited, TransactionSubmitted, TransactionConfirmed, ConfirmationRevoked, and TransactionExecuted are defined to emit logs for significant actions within the contract.

 

State Variables

 

  • authorizedUsers is an array to track wallet signatories.
  • isAuthorized is a mapping to quickly verify if an address is authorized.
  • requiredApprovals specifies the number of approvals needed to execute a transaction.
  • pendingTransactions is an array to store all proposed transactions.
  • hasConfirmed is a nested mapping to keep track of approvals per transaction.

 

Struct Definition

 

  • PendingTransaction struct is defined to hold information about each proposed transaction.

 

Modifiers

 

  • onlyAuthorized ensures the function is called by an authorized user.
  • transactionExists checks if the transaction ID exists.
  • notYetExecuted checks if the transaction has not been executed yet.
  • notYetConfirmed checks if the transaction has not already been approved by the caller.

 

Constructor

 

  • The constructor initializes the contract with a list of authorized users and the required number of approvals.

 

Fallback Function

 

  • The receive function allows the contract to accept ether and emits a FundsDeposited event.

 

Transaction Management Functions

 

  • addTransaction: Allows an authorized user to propose a new transaction.
  • approveTransaction: Allows an authorized user to approve a proposed transaction.
  • runTransaction: Allows an authorized user to execute a transaction once the required number of approvals have been met.
  • retractApproval: Allows an authorized user to retract their approval from a proposed transaction.

 

View Functions

 

  • listUsers: Allows anyone to query the list of authorized users.
  • countTransactions: Allows anyone to query the total number of proposed transactions.
  • fetchTransaction: Allows anyone to query details of a specific transaction by its ID.

 

Github: https://github.com/AshishG2/MultiSigSolidity

 

If you are looking for smart contract development or crypto wallet development, connect with our skilled smart contract developers to get started. 

A Step by Step Guide to Memecoin Development

Memecoin development involves cryptocurrency development primarily based on internet memes. In this blog, we will cover its development process.

 

Memecoin Development

 

A meme coin is a type of cryptocurrency that gains its popularity primarily through internet memes and social media rather than its technological or financial merits. It often has a humorous or satirical theme and relies on viral marketing to attract investors. Memecoins are usually created quickly and may not have a well-defined purpose or a strong development team behind them.

 

While some memecoins have experienced significant price increases, they can also be highly volatile and risky investments. In essence, memes coins are cryptocurrencies that rely on internet culture and online trends for their value and appeal.

 

Technically, a meme coin is nothing but an ERC-20 token that may have some additional logic and functions according to its tokenomics.

 

Related Post | Memecoin Development | A Comprehensive Guide

 

Steps Involved in Memecoin Development

 

Below are the steps to create a simple meme coin smart contract:

 

Step 1: Solidity Version and SPDX License Identifier

 

The contract starts with specifying the Solidity version and SPDX License Identifier.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

 

Step 2: Importing Required Contracts 

 

The contract imports several contracts from the OpenZeppelin library using their specific versions.

 

import "@openzeppelin/[email protected]/token/ERC20/ERC20.sol";

import "@openzeppelin/[email protected]/token/ERC20/extensions/ERC20Burnable.sol";

import "@openzeppelin/[email protected]/security/Pausable.sol";

import "@openzeppelin/[email protected]/access/AccessControl.sol";

import "@openzeppelin/[email protected]/token/ERC20/extensions/draft-ERC20Permit.sol";

 

Step 3: Contract Definition and Inheritance

 

The contract is defined as MEME and inherits from several contracts: ERC20, ERC20Burnable, Pausable, AccessControl, and ERC20Permit.

contract MEME is ERC20, ERC20Burnable, Pausable, AccessControl, ERC20Permit 

 

Step 4: Role Definitions

 

Two role constants, PAUSER_ROLE and MINTER_ROLE, are defined using the keccak256 function.

 

   bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

   bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

 

Step 5: Contract Constructor

 

The constructor function is defined, which is executed only once during contract deployment. It initializes the contract and assigns the roles to the contract deployer (the person who deploys the contract).

 

   constructor() ERC20("MEME", "MEM") ERC20Permit("MEME") {

        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);

        _grantRole(PAUSER_ROLE, msg.sender);

        _grantRole(MINTER_ROLE, msg.sender);

    }

 

Step 6: Pause and Unpause Functions

 

The pause and unpause functions are defined, which can be called by accounts with the PAUSER_ROLE. These functions utilize the Pausable contract inherited from OpenZeppelin.

 

   function pause() public onlyRole(PAUSER_ROLE) {

        _pause();

    }

    function unpause() public onlyRole(PAUSER_ROLE) {

        _unpause();

    }

 

Step 7: Mint Function

 

The mint function is defined, which can be called by accounts with the MINTER_ROLE. This function allows the minter to mint tokens for any address.

 

   function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {

        _mint(to, amount);

    }

 

Step 8: Token Transfer Hook

 

The _beforeTokenTransfer function is overridden to add additional checks before transferring tokens. It ensures that the token transfers are allowed when the contract is not paused.

 

   function _beforeTokenTransfer(address from, address to, uint256 amount)

        internal

        whenNotPaused

        override

    {

        super._beforeTokenTransfer(from, to, amount);

    }

}

 

Here is Our Complete Smart Contract:

 

 

Also, Check | ERC-20 Token Standard | A Compact Guide to Development

 

Conclusion

 

For successful memecoin development, professional assistance is crucial. Our team at Oodles is here to support you. Contact our crypto developers today for expert guidance.

Category: Blockchain
Understanding Flashbots and its Related Services

FlashBots

 

A research and development company called Flashbots is attempting to reduce the unfavorable side effects of the present Maximal Extractable Value (MEV) extraction methods and prevent the existential concerns MEV might pose to state-rich blockchains like Ethereum.

 

What is MEV?

 

The Full form of MEV is the Maximal extractable value. Maximal extractable value (MEV) means the maximum amount of additional value that can be obtained by rearranging and choosing which transactions to include in a block, beyond the usual rewards and fees that are earned for validating transactions in a blockchain network. 

 

Flashbots Products

 

Flashbot Auction

 

Flashbots Auction is a decentralized and open system that allows for efficient extraction of MEV (miner extractable value) and protection against frontrunning while maintaining the values of the Ethereum network. It provides a secure and confidential communication channel between Ethereum users and validators, enabling them to communicate their desired transaction order within a block.

 

Flashbots Auction operates through a private transaction pool and a sealed bid block space auction mechanism, which enables validators to outsource the task of finding the best block construction in a trustless manner. This mechanism is designed to ensure fairness, transparency, and efficiency in the MEV extraction process while preventing frontrunning.

 

Flashbot Data

 

The platform offers various services and dashboards that enhance the visibility of MEV (miner extractable value) activity on Ethereum and the Flashbots Auction. These sub-services include tools and features that provide more insight into how MEV is being extracted and utilized on the network.

 

1.) Mev-inspect 

 

If provided with a block, the system is capable of identifying several key pieces of information, including the payment made to validators (in the form of gas fees and coin base rewards), as well as any token transfers and resulting profits from those transfers. Additionally, the system can also identify any swaps or arbitrages that occurred within the block.

 

2.) Mev-blocks 

 

The platform provides a publicly accessible API that allows users to view flash bots blocks and transactions. As Ethereum is moving towards a PoS consensus mechanism, the API has been updated to include additional fields in the Blocks API response that are aligned with the PoS Ethereum naming conventions.

 

3.) Mev-explore

 

MEV-Explore v0 is a dynamic tool that presents a real-time overview of the MEV (miner extractable value) activity taking place on the Ethereum network. It also includes an MEV transaction explorer, allowing users to explore the details of these transactions.

 

You may also like to explore |  Crypto Trading Bot Development | A Complete Guide

 

Flashbots Protect 

 

Flashbots Protect simplifies the process of utilizing Flashbots for protecting against frontrunning for both developers and everyday users. It eliminates the complexity involved in submitting bundles to the Flashbots Auction and can be integrated by simply adding a URL to MetaMask. Users can add the Flashbots Protect RPC as an RPC endpoint to their wallets to submit transactions to Flashbots.

 

By integrating Flashbots Protect, users can enjoy various benefits, including protection against frontrunning by sandwich bots in the public mempool, transactions being included only if they do not result in reverts, and avoiding paying for failed transactions. Transactions can be tracked using Etherscan, providing greater visibility and transparency.

 

Also Read |  What is Ethereum Merge and its Implications

 

MEV-Boost

 

Mev-boost is an open-source middleware that validators use to access a competitive block-building market. Flashbots created MEV-Boost as an implementation of proposer-builder separation (PBS) for PoS Ethereum, where builders produce blocks containing transaction order flow and a fee for the block proposing validator. For Ethereum, separating the functions of block proposers and builders promotes competitiveness, decentralization, and censorship resistance.

 

MEV (miner extractable value) can have a centralizing effect on Ethereum, and without intervention, the competition for MEV opportunities can lead to instability in consensus and the establishment of permissioned communication channels between searchers, block producers, and validators. As the reduction in block subsidies in PoS Ethereum will increase the importance of MEV as a source of staking revenue, access to MEV is crucial for validators.

 

By offering their block space on an open market, validators employing MEV-Boost can maximize their stake payouts, potentially increasing them by over 60%

 

MEV-Share

 

MEV-Share is a protocol that operates on an open-source basis and aims to enable permissionless collaboration between users, order flow providers, and searchers using privacy and commitments. It is designed to be credibly neutral and does not favor any particular block builder, and searchers can participate without permission. It can lessen the centralized influence of proprietary order flow on Ethereum by aggregating it to MEV-Share while allowing wallets and other sources of order flow to participate in the MEV supply chain.

 

On the other hand, validators can access a competitive block-building market using the open-source middleware MEV-Boost. To implement proposer-builder separation (PBS) for PoS Ethereum, where builders produce blocks containing transaction order flow and pay a fee to the block-proposing validator, Flashbots created the technology. Ethereum benefits from competition, decentralization, and censorship resistance because of the division of block proposers and constructors.

 

Since MEV can have a centralizing effect on Ethereum, the competition for MEV opportunities can lead to instability in consensus and the establishment of permissioned communication channels between searchers, block producers, and validators. As the reduction in block subsidies in PoS Ethereum increases the importance of MEV as a source of staking revenue, access to MEV is crucial for validators. By using MEV-Boost, validators can potentially increase their rewards by over 60% by selling their block space on an open market.

 

Also, Explore | zkEVM | Boosting Ethereum's Scalability

 

For Users

 

By linking your wallet with Flashbots Protect, your transactions will be directed to MEV-Share, and you can capture the MEV generated by your transactions.

 

For Searchers

 

If you want to search for MEV on MEV-Share, you need to connect to a matchmaker. The matchmaker receives transactions and bundles from users and selectively shares information about transactions with searchers. The matchmaker swaps the transaction's hash with the original transaction before sending the bundle to a block builder when a searcher wants to include a transaction in their bundle.

 

If you have a project in mind or want information related to MEV development, you may connect with our skilled blockchain developers.

You might also like | How to Make Allowance based Smart Contracts on Ethereum

Category: Blockchain
How To Create A Staking Smart Contract

In this article, we provide a step-by-step guide to staking smart contract development, deployment, and testing.

 

What are Smart Contracts?

 

A smart contract is a computer program that executes the rules of a contract automatically when certain conditions are satisfied. These contracts are often kept on a blockchain, ensuring their tamper-proof and transparent nature. Smart contracts can be used for a variety of applications, including financial transactions, supply chain management, and enforcing agreements between parties.

 

What is a Staking Smart Contract?

 

A staking smart contract is a type of blockchain-based contract that enables users to lock up their cryptocurrency holdings for a certain period of time, typically in exchange for rewards or benefits. Staking smart contracts facilitate the staking process by automating the process of locking up cryptocurrency holdings and distributing rewards to users who participate in staking.

 

Staking smart contracts are a popular tool for blockchain networks that use a proof-of-stake (PoS) consensus mechanism, as they allow users to participate in the consensus process and earn rewards without having to invest in expensive mining hardware. By staking their cryptocurrency holdings, users can earn rewards while helping to secure the network and maintain its integrity.

 

You may also like | The Increasing Inevitability of Hybrid Smart Contract Development

 

Steps to deploy and test Staking Smart Contract by using Remix

 

Step 1: Define the Token Contract

 

We need to create two ERC20 tokens. One for reward and one for staking.

 

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

 

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

 

contract Rtoken is ERC20, Ownable {

   constructor() ERC20("MyToken", "MTK") {}

 

   function mint(address to, uint256 amount) public onlyOwner {

       _mint(to, amount);

   }

}


 

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

 

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

 

contract Stoken is ERC20, Ownable {

   constructor() ERC20("MyToken", "MTK") {}

 

   function mint(address to, uint256 amount) public onlyOwner {

       _mint(to, amount);

   }

}

 

Step 2: Define the Staking Contract

 

Now that we have the token contracts in place, we can create the staking contract that will use the token for staking and reward distribution. Here's a basic implementation of the staking contract:

 

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

 

 

contract Staking {

   IERC20 public tokenToStake;

   IERC20 public rewardToken;

   mapping(address => uint256) public stakedAmount;

   mapping(address => uint256) public lastStakeTime;

 

   event Staked(address indexed user, uint256 amount);

   event Withdrawn(address indexed user, uint256 amount);

   event RewardPaid(address indexed user, uint256 reward);

 

   constructor(address _tokenToStake, address _rewardToken) {

       tokenToStake = IERC20(_tokenToStake);

       rewardToken = IERC20(_rewardToken);

   }

 

   function stake(uint256 amount) external {

       require(amount > 0, "Staking amount must be greater than 0");

       require(tokenToStake.balanceOf(msg.sender) >= amount, "Insufficient balance");

       require(tokenToStake.allowance(msg.sender, address(this)) >= amount, "Insufficient allowance");

 

       if (stakedAmount[msg.sender] == 0) {

           lastStakeTime[msg.sender] = block.timestamp;

       }

 

       tokenToStake.transferFrom(msg.sender, address(this), amount);

       stakedAmount[msg.sender] += amount;

 

       emit Staked(msg.sender, amount);

   }

 

   function withdraw(uint256 amount) external {

       require(amount > 0, "Withdrawal amount must be greater than 0");

       require(stakedAmount[msg.sender] >= amount, "Insufficient staked amount");

 

       uint256 reward = getReward(msg.sender);

       if (reward > 0) {

           rewardToken.mint(msg.sender, reward);

           emit RewardPaid(msg.sender, reward);

       }

 

       stakedAmount[msg.sender] -= amount;

       tokenToStake.transfer(msg.sender, amount);

 

       emit Withdrawn(msg.sender, amount);

   }

 

   function getReward(address user) public view returns (uint256) {

       uint256 timeElapsed = block.timestamp - lastStakeTime[user];

       uint256 stakedAmountUser = stakedAmount[user];

       if (timeElapsed == 0 || stakedAmountUser == 0) {

           return 0;

       }

 

       uint256 reward = stakedAmountUser * timeElapsed;

 

       return reward;

   }

 

 

   function getStakedBalance(address user) public view returns (uint256) {

       return stakedAmount[user];

   }

}

 

interface IERC20 {

   function totalSupply() external view returns (uint);

 

   function balanceOf(address account) external view returns (uint);

 

   function transfer(address recipient, uint amount) external returns (bool);

 

   function allowance(address owner, address spender) external view returns (uint);

 

   function approve(address spender, uint amount) external returns (bool);

 

   function transferFrom(

       address sender,

       address recipient,

       uint amount

   ) external returns (bool);

 

   function mint(address to, uint256 amount) external;

   event Transfer(address indexed from, address indexed to, uint value);

   event Approval(address indexed owner, address indexed spender, uint value);

}

 

Also, Check | Exploring the Potential of Solana Smart Contract Development


 

Step 3: Deploy the Rtoken, Stoken, and Staking Contract created above on Remix.

 

Step 4: Transfer the Ownership of the reward token to the staking contract

 

Step 5: Let's Test the Staking Smart Contract

 

Mint some tokens for yourself and approve the staking contract with the number of stokens you want to stake.

 


 

Go to the staking contract and use the stake function.

 

Now. click on withdraw after some time.

 

 

You will be able to check your reward token balance.

 

 

Suggested Read | Ethereum Smart Contract Development | Discovering the Potential


Conclusion

 

You may also connect with our skilled smart contract developers if you want to integrate staking smart contract solutions into your projects or have any questions in mind.  
 

Category: Blockchain
Exploring Semi Fungible Token Development

Before starting on semi-fungible tokens, it is important to understand what fungible and non-fungible tokens are, and what exactly is even a token itself.

 

What is a Token

 

In a blockchain ecosystem, a token can be any digital asset that users can transfer. It might represent money, voting rights, stakes, etc. Interestingly, a token is not limited to a single duty and may handle several responsibilities in its original environment.

 

A token might represent a utility or a company's asset. It is mainly categorized into three types: fungible, non-fungible, and semi-fungible. 

 

Fungible Vs. Non-Fungible

 

Fungible tokens are tokens that can be readily exchanged with a similar token. These tokens are identical and dividable. Cryptocurrency like Bitcoin is an example of such tokens. 

 

On the other hand, non-fungible tokens (NFTs) are unique as each of them represents a unique asset. Thus, they are not interchangeable.

 

Suggested Read: NFT (Non-Fungible Tokens) | Taking the Crypto Space by Storm

 

Semi Fungible Tokens (SFTs)

 

Semi-fungible tokens (SFTs) are a novel type of token that are both fungible and non-fungible during their existence.

 

Initially, SFTs function similarly to conventional fungible tokens. Users can exchange them for other identical SFTs.

 

The defining feature that distinguishes these "semi-fungible" tokens is that once redeemed, the fungible tokens lose their face value. Semi-fungible tokens derive their name from the process of converting from a fungible to a non-fungible token upon redemption.

 

Related Post: A Quick Guide to Understanding Semi-Fungible Tokens

 

Semi-Fungible Tokens with ERC1155

 

ERC1155 is a new protocol for creating semi-fungible tokens. These are new forms of tokens that combine various aspects of previous token standards. Consider it the best of both worlds.

 

Consider this instructive analogy. You may create a shop voucher, a fungible token, that retains its worth until it is redeemed.

 

After redeeming the coupon, it has no monetary value and the voucher holder cannot trade it as a standard fungible token. The used coupon becomes unique with information about the item redeemed, the client, the price, and so on. As a result, it becomes non-fungible.

 

However, a semi-fungible token standard like ERC1155 may represent both.

 

ERC1155 is a unique way to token definition, according to the Enjin blog. Multiple objects can be kept in a single contract with the least amount of data required to differentiate them from one another. Enjin further states that "the contract state comprises configuration data per token ID as well as all the behavior guiding the collection."

 

Therefore, you can use this new token standard to create utility tokens such as BNB and NFTs such as CryptoPunks and CryptoKitties. Its optimization makes transactions more efficient and secure. Unlike ERC-721, ERC1155 bundles transactions and reduces gas charges.

 

In addition, the ability to create efficient NFTs and substitutable tokens at the same time demonstrates that it is an evolution of both ERC-20 and ERC-721.

 

Explore: A Quick Guide to Ethereum ERC Token Standards

 

Semi-Fungible Token Development

 

Example: Game Token Development

 

The following token will contain a basic item required for a game token like gold and silver. It will be used as currency and weapons like swords and hammers.

 

1. Go to open Zeppelin Wizard

 

2. Select the 1155 tab and click on mintable

 

 

 

 

 

 

 

 

 

 

 

3. Copy the contract from the wizard and add the token's name and mint them inside the constructor as shown below:

 

 

 

 

 

 

 

 

 

 

Example: Concert ticket

 

The following token will contain general seat, VIP, and rsvp tokens.

 

Follow the steps in the previous example and edit it as follows:

 

 

 

 

 

 

 

 

 

 

 

The general and rsvp tokens are fungible tokens whereas the vip one is non-fungible. 

 

Also, Check: How NFT Ticketing Disrupts The Ticketing Industry

 

Conclusion

 

Semi-fungible tokens combine the properties of fungible and non-fungible tokens. Businesses can create these tokens to get benefits like flexibility and readability. However, the SFT development process requires expertise that only top-notch blockchain service firms can offer.

 

Oodles can be your ideal blockchain service partner. We provide business-oriented semi-fungible token development services. Contact our blockchain developers today to avail yourself of our services. 

A Comprehensive Guide to Blockchain Oracle

 

Blockchain Oracles

 

In ancient Greece, people used to visit oracles to connect with God and get worldly information. Similarly, in the world of blockchain, whenever a smart contract needs external information from the outside world, it calls forth the blockchain oracles. They are intermediaries between the smart contract and the external world. Smart contracts do not have access to data that is outside the chain, i.e., data that is not present in the network. However, some contracts may need outside world data for their functioning. It is where the oracles come into play and act as message senders from the outside world to the smart contract.

The Oracle Problem

 

Blockchain is cut off from the rest of the world; they have no access to it. Also, even if blockchain somehow gains outside information, two problems arise the integrity of the data and the problem of a single source, which again introduces the lack of decentralization. The control of a single source can be with any powerful entity outside of the blockchain, and a blockchain oracle, like chainlink, solves this problem by decentralizing itself. It gets data from multiple sources, so even if any node is hacked or given the wrong data, it can be easily kicked out of the oracle network.

 

It includes online sources of information that can be easily accessed, such as public databases and websites. Also, these provide details on public transport, temperature readings, and the recent price of financial assets. These are the most efficient types of oracles due to their inherent interconnectedness to the internet. It enables software oracles to supply current information to smart contracts.

 

Types of Oracles

 

The classification of blockchain oracles is into the following types based on the source of the information, the flow of data, and the mechanism they use for the verification of data. Below are the major types of blockchain oracles.

 

  • Software Oracles: They provide information about the data, which is easily available on the internet, like stock prices and temperatures of different places. Because they are all directly connected to the internet, the information is always up to date.

 

  • Hardware Oracles: The design of hardware oracles is in such a way that they send data to the contract whenever an event triggers in the physical world. For example, if a car crashes sensor sends this to the insurance smart contract.

 

  • Inbound Oracles: They provide data to the smart contract. The data is out of the smart contract and helps the smart contract performs its functions. For example, updated temperature data delivered on the contract.

 

  • Outbound Oracles: It provides smart contracts with the ability to send data to the external world. For example, if a lottery contract needs to contact the winner, it may use them.

 

  • Consensus-based Oracles: These types of oracles work on consensus-based principles, so they get their information from markets like Gnosis and Augur, which are human consensus and prediction markets. Also, the mentioned prediction markets have a rating system for oracles to prevent risk and unreliability.

 

Major Blockchain Oracles

 

Chainlink

 

It can be considered one of the most well-known oracles in the blockchain world. The company was started in 2017 by Sergey Nazarov and now has a market cap of 3.3 billion dollars. It provides data feeds for assets like cryptos, currencies, and weather data. It also provides historical price data. The interface provided by the chain link is called AggregatorV3Interface. Through it, we can access all the major price feed functions.

 

UMA

 

Uma stands for universal market access and is an optimistic oracle and dispute arbitration system that securely allows arbitrary data types to bring on a chain. UMA’s oracle system provides data for projects, including a cross-chain bridge, insurance protocols, custom derivatives, and prediction markets, as stated in their docs. They have a market cap of 171 million dollars and help to create different synthetic assets on the Ethereum blockchain.

 

Winklink

 

It is the first blockchain oracle that works for the Tron network. The architecture of winklink consists of winklink nodes, and the external data passes through winklink nodes to the Tron blockchain. Winklink nodes monitor the contracts on the Tron blockchain for requests via events. They retrieve the external data and submit them to the blockchain.

 

 

Applications of Blockchain Oracles

 

  • Prediction-Based Systems

 

In a system like a lottery, there is a need for an unbiased generation of a random number. This task is not as simple as it seems, and have been various scams in the world that have occurred from time to time. In many cases, the manipulation of the generation process has been by the owner. But, in a Smart contract-based lottery system, blockchain oracle use can be to get a random number. The oracle is not centralized, so there will be no manipulation.

 

  • Insurance-based Systems

 

In insurance contracts, there is a need for the verification of real-world data. For example, in car insurance, the company needs to pay the insurance whenever an accident happens with the car, and the client has to submit the accident documents to the company. But in the case of a smart contract, an oracle can transfer the data from the car sensors to the contract, and in turn, it can execute the payout functionality.

 

  • Real World Betting

 

The user can use Blockchain oracles to get the outcome of an event in the future to execute the result of the bet. For example, two people can bet on their favorite football team before the match, and after the match, the contract can fetch the results through the oracle and give the bet prize to the winner.

 

 

Banner

Don't just hire talent,
But build your dream team

Our experience in providing the best talents in accordance with diverse industry demands sets us apart from the rest. Hire a dedicated team of experts to build & scale your project, achieve delivery excellence, and maximize your returns. Rest assured, we will help you start and launch your project, your way – with full trust and transparency!