|
Mudit Singh Oodles

Mudit Singh (Backend-Associate Consultant L2- Development)

Experience:1+ yrs

Mudit is a seasoned back-end developer with a strong specialization in Node.js, boasting a profound comprehension of this technology. His practical experience spans a wide range of tools and frameworks, including React.js, Node.js, Express.js, along with expertise in languages like Data Structures and Algorithms, HTML, CSS, JavaScript, and various databases such as MongoDB. Additionally, he is well-versed in version control systems like Git and Github, as well as SQL. With his extensive knowledge and expertise in development, Mudit consistently produces outstanding results in any project related to his field.

Mudit Singh Oodles
Mudit Singh
(Associate Consultant L2- Development)

Mudit is a seasoned back-end developer with a strong specialization in Node.js, boasting a profound comprehension of this technology. His practical experience spans a wide range of tools and frameworks, including React.js, Node.js, Express.js, along with expertise in languages like Data Structures and Algorithms, HTML, CSS, JavaScript, and various databases such as MongoDB. Additionally, he is well-versed in version control systems like Git and Github, as well as SQL. With his extensive knowledge and expertise in development, Mudit consistently produces outstanding results in any project related to his field.

LanguageLanguages

DotHindi

Fluent

DotENGLISH

Conversational

Skills
Skills

DotEthereum

60%

DotMetaMask

80%

DotERC-1155

60%

DotOpenZeppelin

60%

DotERC-721

80%

DotTruffle

80%

DotRemix IDE

60%

DotEtherscan

60%

DotEthers.js

80%

DotFullstack

60%

DotGnosis Safe

80%

DotHardhat

60%

DotSolidity

80%

DotNode Js

100%

DotSolana Web3.js

80%

DotReactJS

80%

DotMern Stack

60%

DotTelegram Bot

80%

DotIPFS

80%

DotRAFT

60%
ExpWork Experience / Trainings / Internship

Sep 2023-Present

Intern - Development

Gurugram


Oodles Technologies

Gurugram

Sep 2023-Present

EducationEducation

2019-2023

Dot

Bundelkhand University

Bachelor of Technology-Computer Science and Engineering

Top Blog Posts
Build a DAO with Snapshot and ENS Integration for On-Chain Governance

Decentralized Autonomous Organizations (DAOs) leverage blockchain technology and smart contracts to enable user-driven decision-making, removing the need for centralized control. By integrating the Ethereum Name Service (ENS), DAOs enhance user-friendliness and establish a clear on-chain identity. Additionally, Snapshot facilitates off-chain voting, improving the governance process by making it more efficient and streamlined. To set up a DAO, key steps include acquiring an ENS name, creating a governance token for voting power, and configuring Snapshot for off-chain voting to ensure effective and decentralized decision-making. For more related to blockchain, smart contracts, and crypto, visit our blockchain app development services

 

DAO Development with Snapshot and ENS Integration for On-Chain Governance

 

Acquire an ENS Domain

 

The first step in setting up a DAO is acquiring a decentralized identity for your organization via the Ethereum Name Service (ENS). ENS enables the association of human-readable names (e.g., yourdao.eth) with Ethereum addresses, providing both on-chain and off-chain identity for your DAO.

 

Steps to get your ENS domain:

 

  • Visit the ENS Manager.(https://app.ens.domains/)
  • Search for your desired ENS name (e.g., yourdao.eth).
  • If available, proceed to purchase the name by paying the associated fees.
  • Connect your wallet (e.g., MetaMask) to complete the transaction.
     

Once you own the ENS name, it can be used for various DAO-related tasks. For example, you can create subdomains like vote.yourdao.eth for voting or docs.yourdao.eth for documentation.

 

Also, Read | DAOs in Gaming : A New Governance Model

 

Implement Governance with a Governance Token

 

The second step is to create a governance token, which will serve as the voting mechanism for your DAO. The number of tokens a user holds determines their voting power on proposals.

 

Create the Governance Token Contract

 

Write and deploy a smart contract for the governance token using the ERC-20 standard. Below is an example of a simple governance ERC-20 token:

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract GovernanceToken is ERC20 {
   constructor(uint256 initialSupply) ERC20("Governance Token", "GOV") {
       _mint(msg.sender, initialSupply);
   }
}

 

You can either deploy a new governance token using the provided contract, or use an existing ERC-20 token by integrating it into the governance framework. If using an existing token, simply reference the token's address and use its balance for governance purposes.

 

You may also like to explore | A Quick Guide to Developing a DAO-enabled NFT Marketplace

 

Add Governance to Snapshot

 

Once you have your ENS domain and governance token, the next step is to set up Snapshot, which allows for off-chain voting.

 

Create Space : Go to Snapshot and sign in with your wallet (MetaMask). After a successful login, create a new space with your ENS domain as the name (e.g., yourdao.eth). You will also need to select the chain.

 

Set Up Voting Strategies: Specify how the voting power should be calculated by adding one or up to 8 strategies. Snapshot provides a set of strategies on the basis of which users' votes are counted.A voting strategy is a set of conditions used to calculate a user's voting power. Strategies enable Snapshot to calculate the final result of voting on a given proposal. Snapshot provides over 400+ voting strategies. The default strategy is erc20-balance-of — it calculates the balance of a predefined ERC-20 token for each user. We can also create our own strategy. Below is a demonstration of the fields.

 

{
 "strategy": "erc20-balance-of",
 "params": {
   "address": "0xYourGovernanceTokenAddress",  // Governance token contract address
   "symbol": "GOV",
   "decimals": 18
 }
}

 

Configure Proposals: To specify who can manage the space or create proposals, fill in the appropriate fields with addresses for:

 

  • Admins: Users able to edit the space settings and moderate proposals.
  • Authors: Users able to create proposals without any constraints. Make sure that members specified in the authors field are allowed to submit a proposal.
    Define who can create proposals, the voting delay, and the voting period. The configuration ensures that only token holders can participate in decision-making and sets how long a proposal will be open for voting. 

 

To validate if someone can post a proposal, you can use the basic validation by default, which takes your voting power with space strategies and checks if you pass a defined threshold.

 

Voting
 

The voting delay is the time between the creation of the proposal and when users are allowed to vote.
The voting period is the duration that the proposal is active and votes can be cast. It is counted from the moment the proposal is created.

 

Quorum is the amount of voting power collectively achieved by voters, which is required for a proposal to pass.

 

Also, Check | How to Build a DAO | A Quick Explainer

 

Governance Proposal Workflow

 

Proposal Creation: Token holders or authorized users can propose changes or decisions within the DAO. For example, a proposal can suggest changes to the protocol or allocate treasury funds.
 

Voting Process: DAO members with voting tokens vote on the proposal. The proposal is accepted or rejected based on the voting outcome, considering quorum and voting power.
Execution (Optional): Once a proposal is approved, it can be executed either off-chain (through Snapshot) or on-chain (using smart contracts), depending on your DAO's setup.

 

Conclusion

 

In this setup, acquiring an ENS domain provides your DAO with a decentralized identity, while the governance token allows members to participate in decision-making. By configuring Snapshot, you can enable efficient off-chain voting, creating a robust governance model for your DAO. If you are looking for trusted blockchain app development, you may connect with our skilled blockchain developers to get started. 

 

Category: Blockchain
Cross Chain Asset Transfers Using Axelar

Ethereum and other blockchain app development provide decentralization and security but operate in isolation, making interoperability a challenge. Axelar solves this problem by enabling seamless cross-chain asset transfers. It acts as a decentralized transport layer, allowing users to send tokens and data across different blockchain networks efficiently.

 

Cross-Chain Asset Transfers Using Axelar

 

Setup

 

Building a cross-chain asset transfer system using Axelar requires these elements:

 

Tools and Dependencies:

 

AxelarJS SDK: A JavaScript SDK for interacting with Axelar's cross-chain infrastructure.
Node.js and npm: Required for managing dependencies and running scripts.
Hardhat: A development tool used for compiling, deploying, and testing Ethereum smart contracts.
dotenv: Used to store private environment variables.

 

To set up your project, start by creating a new directory called "axelar-cross-chain" and navigate to it. Then, initialize a new Node.js project with the npm init -y command. After that, install the necessary dependencies: for development tools like Hardhat and dotenv, use npm install --save-dev hardhat dotenv. For Axelar's SDK and other utilities, run npm install @axelar-network/[email protected] crypto @nomicfoundation/hardhat-toolbox. Finally, create a .env file to store your private environment variables. This setup will prepare your environment for building with Axelar's cross-chain infrastructure.

 

Also, Explore | Building a Cross-Chain NFT Bridge using Solana Wormhole

 

Deploy an ERC-20 token on the Moonbeam and Avalanche 

 

The provided Solidity contract defines an ERC-20 token called "Cross" with minting and burning functionalities. It includes features for transferring tokens between different blockchain networks using Axelar's cross-chain capabilities. The contract allows users to mint additional tokens and send tokens to remote addresses on other chains while paying for the gas fees associated with these transactions.

 

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

import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol";
import {IAxelarGasService} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol";
import {ERC20} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/test/token/ERC20.sol";
import {AxelarExecutable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import {StringToAddress, AddressToString} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/AddressString.sol";
import "./Interfaces/ICROSS.sol";

contract Cross is AxelarExecutable, ERC20, ICROSS {
    using StringToAddress for string;
    using AddressToString for address;

    error FalseSender(string sourceChain, string sourceAddress);

    event FalseSenderEvent(string sourceChain, string sourceAddress);

    IAxelarGasService public immutable gasService;

    constructor(
        address gateway_,
        address gasReceiver_,
        string memory name_,
        string memory symbol_,
        uint8 decimals_
    ) AxelarExecutable(gateway_) ERC20(name_, symbol_, decimals_) {
        gasService = IAxelarGasService(gasReceiver_);
        _mint(msg.sender, 1000 * 10 ** decimals_);
    }

    function giveMe(uint256 amount) external {
        _mint(msg.sender, amount);
    }

    function transferRemote(
        string calldata destinationChain,
        address destinationAddress,
        uint256 amount
    ) public payable override {
        require(msg.value > 0, "Gas payment is required");

        _burn(msg.sender, amount);
        bytes memory payload = abi.encode(destinationAddress, amount);
        string memory stringAddress = address(destinationAddress).toString();

        gasService.payNativeGasForContractCall{value: msg.value}(
            address(this),
            destinationChain,
            stringAddress,
            payload,
            msg.sender
        );

        gateway().callContract(destinationChain, stringAddress, payload);
    }

    function _execute(
        bytes32,
        string calldata,
        string calldata sourceAddress,
        bytes calldata payload
    ) internal override {
        if (sourceAddress.toAddress() != address(this)) {
            emit FalseSenderEvent(sourceAddress, sourceAddress);
            return;
        }

        (address to, uint256 amount) = abi.decode(payload, (address, uint256));
        _mint(to, amount);
    }
}

 

Deploying the Contract


Step 1: Create a utils.js File

 

Add the following chain configuration values to utils.js:

 

const chainConfigs = {
  Moonbeam: {
    name: 'Moonbeam',
    id: 'Moonbeam',
    axelarId: 'Moonbeam',
    chainId: 1287,
    rpc: 'https://moonbase-alpha.drpc.org',
    tokenSymbol: 'DEV',
    constAddressDeployer: '0x98b2920d53612483f91f12ed7754e51b4a77919e',
    gateway: '0x5769D84DD62a6fD969856c75c7D321b84d455929',
    gasService: '0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6',
    contract: '',
  },
  Avalanche: {
    name: 'Avalanche',
    id: 'Avalanche',
    axelarId: 'Avalanche',
    chainId: 43113,
    rpc: 'https://api.avax-test.network/ext/bc/C/rpc',
    tokenSymbol: 'AVAX',
    constAddressDeployer: '0x98b2920d53612483f91f12ed7754e51b4a77919e',
    gateway: '0xC249632c2D40b9001FE907806902f63038B737Ab',
    gasService: '0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6',
    contract: '',
  },
};

 

Gateway and Gas Service contracts are deployed by Axelar to enable cross-chain transfer . For different chains, there are different gateways and gas services, which can be found in Axelar documentation.

 

Also, Read | Creating Cross-Chain Smart Contracts with Polkadot and Substrate

 

Step 2: Create the deploy.js File


Create a folder named scripts and add a file called deploy.js with the following code:

 

require('dotenv').config();
const { ethers, ContractFactory } = require('ethers');
const ERC20CrossChain = require('../artifacts/contracts/Cross.sol/Cross.json');
const chainConfigs = require('./utils');

const name = 'Cross Chain Token';
const symbol = 'CCT';
const decimals = 18;
const PRIVATE_KEY = process.env.PRIVATE_KEY;

async function deploy(chainName) {
  const chain = chainConfigs[chainName];
  if (!chain) {
    throw new Error(`❌ Invalid chain name: ${chainName}`);
  }

  try {
    const provider = new ethers.providers.JsonRpcProvider(chain.rpc);
    const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

    console.log(`🚀 Deploying ERC20CrossChain on ${chain.name}...`);
    const implementationFactory = new ContractFactory(
      ERC20CrossChain.abi,
      ERC20CrossChain.bytecode,
      wallet
    );

    const implementationConstructorArgs = [
      chain.gateway,
      chain.gasService,
      name,
      symbol,
      decimals,
    ];

    const deploymentOptions = {
      maxPriorityFeePerGas: ethers.utils.parseUnits('30', 'gwei'),
      maxFeePerGas: ethers.utils.parseUnits('40', 'gwei'),
    };

    const implementation = await implementationFactory.deploy(
      ...implementationConstructorArgs,
      deploymentOptions
    );

    await implementation.deployed();

    console.log(
      `✅ ERC20CrossChain deployed on ${chain.name} at address: ${implementation.address}`
    );
  } catch (error) {
    console.error(`❌ Deployment failed on ${chainName}:`, error.message);
  }
}

async function main() {
  try {
    await deploy('Moonbeam');
    await deploy('Avalanche');

    console.log('✅ Deployment completed on both Moonbeam and Avalanche.');
  } catch (error) {
    console.error('❌ Deployment failed:', error);
  }
}

main().catch((error) => {
  console.error('Error in the main function:', error);
});

 

Step 3: Deploy the Contracts

 

Navigate to the scripts folder and run the deployment script: node deploy.js
 

Deploying ERC20CrossChain on Moonbeam...
ERC20CrossChain deployed on Moonbeam at address: 0x116e1b3281AB181cBCE1a76a0cB98e8d178325Bb
Deploying ERC20CrossChain on Avalanche...
ERC20CrossChain deployed on Avalanche at address: 0x116e1b3281AB181cBCE1a76a0cB98e8d178325Bb
Deployment completed on both Moonbeam and Avalanche.

 

We need to add the contract address in the utils folder for both the chains.

 

You may also like to explore | Create a Cross-Chain Interoperability Protocol Using Cosmos SDK

 

Cross-Chain Transfers with Axelar

 

To enable cross-chain transfers, add the following function to the deploy.js file:

 

In this function, we initiate a cross-chain transfer of ERC-20 tokens from the Avalanche network to the Moonbeam network. By defining the source and destination chains, we set up two separate providers and wallets for each chain. The transferRemote function is called to transfer a specified token amount, with proper gas fees, while the transaction hash is logged once the transfer is complete, ensuring a seamless cross-chain interaction.

 

async function execute() {
  const deploymentOptions = {
    maxPriorityFeePerGas: ethers.utils.parseUnits('30', 'gwei'),
    maxFeePerGas: ethers.utils.parseUnits('40', 'gwei'),
  };
  const tokenAmount = ethers.utils.parseUnits('20', 18);
  const source = chainConfigs.Avalanche;
  const destination = chainConfigs.Moonbeam;

  const sourceProvider = new ethers.providers.JsonRpcProvider(source.rpc);
  const destinationProvider = new ethers.providers.JsonRpcProvider(
    destination.rpc
  );

  const sourceWallet = new ethers.Wallet(PRIVATE_KEY, sourceProvider);
  const destinationWallet = new ethers.Wallet(PRIVATE_KEY, destinationProvider);

  const sourceContract = new ethers.Contract(
    source.contract,
    ERC20CrossChain.abi,
    sourceWallet
  );
  const destinationContract = new ethers.Contract(
    destination.contract,
    ERC20CrossChain.abi,
    destinationWallet
  );
  console.log('1: Source Contract Address:', source.name);
  console.log('2: Destination Contract Address:', destination.name);
  const tx2 = await sourceContract.transferRemote(
    destination.name,
    destination.contract,
    tokenAmount,
    {
      value: ethers.utils.parseEther('0.01'),
      maxPriorityFeePerGas: deploymentOptions.maxPriorityFeePerGas,
      maxFeePerGas: deploymentOptions.maxFeePerGas,
    }
  );
  console.log('Transaction Hash for transferRemote:', tx2.hash);
  await tx2.wait();
}

 

Add the following function to the main function and run the script again : node deploy.js , which will console.log the following things. 

 

1: Source : Avalanche
2: Destination : Moonbeam
Transaction Hash for transferRemote: 0x8fd7401cbd54f34391307705c70b84ebf5c699538c37e7c19da15e2c980ce9ec

 

We can also check the status of the transfer on the Axelar testnet explorer at https://testnet.axelarscan.io/gmp/0x8fd7401cbd54f34391307705c70b84ebf5c699538c37e7c19da15e2c980ce9ec.

 

Also, Discover | How to Build a Cross-Chain Bridge Using Solidity and Rust

 

Conclusion

 

In conclusion, Axelar provides a robust and efficient framework for seamless cross-chain asset transfers, addressing interoperability challenges in the blockchain ecosystem. By leveraging Axelar's decentralized network, developers can enable secure and trustless communication between multiple blockchains, enhancing liquidity and expanding DeFi opportunities. As the demand for cross-chain solutions grows, Axelar's infrastructure plays a crucial role in fostering a more interconnected and scalable Web3 ecosystem, unlocking new possibilities for decentralized applications and asset mobility. For more related to blockchain development, connect with our blockchain developers to get started.

Category: Blockchain
Implementing a Layer 2 payment channel network in Ethereum

Ethereum's blockchain is secure and decentralized, but it has problems with high fees and slow transaction speeds. To fix this, developers are creating "Layer 2" solutions like payment channels. These channels, similar to Bitcoin's Lightning Network, allow quick and cheap transactions outside the main Ethereum blockchain, while still using the main chain for security and to settle disputes. For more related to blockchain and crypto, visit blockchain app development services

 

Setup

 

Building a payment channel on Ethereum requires these elements:

 

Tools and Dependencies:

 

  • Hardhat: A development tool used for compiling, deploying, and testing Ethereum smart contracts.
  • Node.js and npm: Used for managing software dependencies and running scripts.

 

Key Components:

 

  • Payment Channel Smart Contract: This defines the rules for how funds are locked, transferred between parties, and finally settled.
  • Ethereum Wallet: Needed for signing transactions and managing funds within the channel.
  • Local Blockchain or Testnet: A local blockchain or test network is used for testing and deploying the contract before using it on the main Ethereum network.

 

Also, Read | Creating a Token Curated Registry (TCR) on Ethereum

 

Installation

 

  1. Initialize a New Hardhat Project:

     

-mkdir payment-channel
-cd payment-channel
-npm init -y
-npm install --save-dev hardhat npx hardhat

 

2.  Install Additional Dependencies:

 

-npm install @nomicfoundation/hardhat-toolbox

 

3. Configure Hardhat: Update the  hardhat.config.js file to include the necessary network configurations. This ensures your project can connect to the appropriate Ethereum network for deployment and testing.

 

Payment Channel Smart Contract

 

Here's a simple implementation of a payment channel smart contract:

 

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

contract PaymentChannel {
    address public sender; 
    address public receiver; 
    uint256 public expiration; 

    constructor(address _receiver, uint256 _duration) payable {
        sender = msg.sender;
        receiver = _receiver;
        expiration = block.timestamp + _duration;
    }

    // Allows the receiver to withdraw funds with a valid signature
    function withdraw(uint256 amount, bytes memory signature) public {
        require(msg.sender == receiver, "Only the receiver can withdraw funds");
        bytes32 message = keccak256(abi.encodePacked(amount, address(this)));
        require(recoverSigner(message, signature) == sender, "Invalid signature");
        payable(receiver).transfer(amount);
    }

    // Allows the sender to reclaim funds after expiration
    function cancel() public {
        require(block.timestamp >= expiration, "Channel has not expired");
        require(msg.sender == sender, "Only the sender can cancel the channel");
        selfdestruct(payable(sender));
    }

    // Recovers the signer of a hashed message
    function recoverSigner(bytes32 message, bytes memory sig) public pure returns (address) {
        bytes32 r;
        bytes32 s;
        uint8 v;
        (r, s, v) = splitSignature(sig);
        return ecrecover(message, v, r, s);
    }

    // Splits a signature into r, s, and v
    function splitSignature(bytes memory sig)
        public
        pure
        returns (bytes32 r, bytes32 s, uint8 v)
    {
        require(sig.length == 65, "Invalid signature length");
        assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            v := byte(0, mload(add(sig, 96)))
        }
    }
}

 

Also, Discover | Decentralized Prediction Market Development on Ethereum

 

How the Contract Works

 

Channel Creation:

 

  • The sender deploys the contract, locking funds in it (msg.value).
  • The receiver's address and channel duration are provided during deployment.

     

Off-Chain Transactions:

 

  • The sender signs messages indicating the amount the receiver can withdraw.
  • These messages are shared off-chain, avoiding gas fees for every transaction.

 

Withdrawal:

 

  • The receiver calls the withdraw function, providing the signed message.
  • The contract verifies the signature and transfers the specified amount to the receiver.

 

Expiration and Cancellation:

 

  • If the receiver does not withdraw funds before expiration, the sender can reclaim the remaining funds by calling the cancel function.

 

Also, Explore | How to Deploy a Distributed Validator Node for Ethereum 2.0

 

Deployment

 

Create a Deployment Script
 

Save the following in script/deploy.js

 

const hre = require("hardhat");

async function main() {
    const PaymentChannel = await hre.ethers.getContractFactory("
    PaymentChannel");
    const channel = await PaymentChannel.deploy(
        "0xReceiverAddress", // Replace with the receiver's address
        3600, // Channel duration in seconds
        { value: hre.ethers.utils.parseEther("1.0") } 
    );

    await channel.deployed();
    console.log("Payment Channel deployed to:", channel.address);
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});

 

Deploy the Contract


Run the script using Hardhat:

 

-npx hardhat run script/deploy.js --network sepolia

 

Conclusion

 

Layer 2 payment channels offer a scalable way to perform frequent, low-cost transactions on Ethereum. Inspired by the Lightning Network, this implementation uses off-chain state updates and on-chain dispute resolution. Following this guide, you can set up a basic payment channel to understand the mechanics and expand it with features like routing and multi-hop payments for more complex use cases. If you planning to build your project leveraging technologies like blockchain and smart contracts, connect with our blockchain developers to get started. 

Category: Blockchain
How to Write and Deploy Modular Smart Contracts

Modular contracts enable highly configurable and upgradeable smart contract development, combining ease of use with security. They consist of two main components:

 

Core Contracts: These form the foundation of the modular system, managing key functions, data storage, and logic. Core contracts include access control mechanisms and define interfaces for module interactions.

 

Module Contracts: These add or remove functionalities to/from core contracts dynamically, allowing for flexibility. Modules can be reused across multiple core contracts, enabling upgrades without redeploying the core contract.

 

How They Work: Modules provide additional functionality via callback and fallback functions that interact with core contracts. Fallback functions operate independently, while callback functions augment core contract logic, enhancing dApp functionality.

 

You may also like | How to Create Play-to-Earn Gaming Smart Contracts

 

Setup | Writing and Deploying Modular Smart Contracts

 

Install Forge from Foundry and add the modular contract framework:

 

forge init
forge install https://github.com/thirdweb-dev/modular-contracts.git
forge remappings > remappings.txt

 

Contract

 

The ERC20Core contract is a type of ERC20 token that combines features from both the ModularCore and the standard ERC20 contract. It names the token "Test Token" and uses "TEST" as its symbol, with the deployer being the owner of the contract. A significant feature is the required beforeMint callback, which allows certain actions to be taken before new tokens are created. The mint function lets users create tokens while ensuring the callback is executed first. The BeforeMintCallback interface makes it easier to add custom logic from other contracts. Overall, ERC20Core offers a flexible way to develop custom tokens while maintaining essential ERC20 functions.

 

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {ModularCore} from "lib/modular-contracts/src/ModularCore.sol";
import {ERC20} from "lib/solady/src/tokens/ERC20.sol";

contract ERC20Core is ModularCore, ERC20 {
    constructor() {
        _setOwner(msg.sender);
    }

    function name() public view override returns (string memory) {
        return "Test Token";
    }

    function symbol() public view override returns (string memory) {
        return "TEST";
    }

    function getSupportedCallbackFunctions()
        public
        pure
        virtual
        override
        returns (SupportedCallbackFunction[] memory supportedCallbacks)
    {
        supportedCallbacks = new SupportedCallbackFunction[](1);
        supportedCallbacks[0] = SupportedCallbackFunction(BeforeMintCallback.beforeMint.selector, CallbackMode.REQUIRED);
    }

    function mint(address to, uint256 amount) external payable {
        _executeCallbackFunction(
            BeforeMintCallback.beforeMint.selector, abi.encodeCall(BeforeMintCallback.beforeMint, (to, amount))
        );
        _mint(to, amount);
    }
}

interface BeforeMintCallback {
    function beforeMint(address to, uint256 amount) external payable;
}

 

Also, Read | ERC 4337 : Account Abstraction for Ethereum Smart Contract Wallets

 

The PricedMint contract is a modular extension designed for token minting, leveraging Ownable for ownership management and ModularExtension for added functionality. It uses the PricedMintStorage module to maintain a structured storage system for the token price. The owner can set the minting price through the setPricePerUnit method. Before minting, the beforeMint function verifies that the provided ether matches the expected price based on the token quantity. If correct, the ether is transferred to the contract owner. The getExtensionConfig function defines the contract's callback and fallback functions, facilitating integration with other modular components.

 

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {ModularExtension} from "lib/modular-contracts/src/ModularExtension.sol";
import {Ownable} from "lib/solady/src/auth/Ownable.sol";

library PricedMintStorage {
    bytes32 public constant PRICED_MINT_STORAGE_POSITION =
        keccak256(abi.encode(uint256(keccak256("priced.mint")) - 1)) & ~bytes32(uint256(0xff));

    struct Data {
        uint256 pricePerUnit;
    }

    function data() internal pure returns (Data storage data_) {
        bytes32 position = PRICED_MINT_STORAGE_POSITION;
        assembly {
            data_.slot := position
        }
    }
}

contract PricedMint is Ownable, ModularExtension {
    function setPricePerUnit(uint256 price) external onlyOwner {
        PricedMintStorage.data().pricePerUnit = price;
    }

    function beforeMint(address to, uint256 amount) external payable {
        uint256 pricePerUnit = PricedMintStorage.data().pricePerUnit;
        uint256 expectedPrice = (amount * pricePerUnit) / 1e18;
        require(msg.value == expectedPrice, "PricedMint: invalid price sent");
        (bool success,) = owner().call{value: msg.value}("");
        require(success, "ERC20Core: failed to send value");
    }

    function getExtensionConfig() external pure virtual override returns (ExtensionConfig memory config) {
        config.callbackFunctions = new CallbackFunction ;
        config.callbackFunctions[0] = CallbackFunction(this.beforeMint.selector);
        config.fallbackFunctions = new FallbackFunction ;
        config.fallbackFunctions[0] = FallbackFunction(this.setPricePerUnit.selector, 0);
    }
}

 

Deploy

 

To deploy the Modular Contract, first get your API Key from the Thirdweb Dashboard. Then run npx thirdweb publish -k "THIRDWEB_API_KEY", replacing "THIRDWEB_API_KEY" with your key. Select "CounterModule," scroll down, click "Next," choose the "Sepolia" network, and click "Publish Contract."

For the Core Contract, run npx thirdweb deploy -k "THIRDWEB_API_KEY" in your terminal, replacing "THIRDWEB_API_KEY" with your key. Select "CounterCore," enter the contract owner's address, and click "Deploy Now." Choose the "Sepolia" chain and click "Deploy Now" again to start the deployment.

 

Also, Explore | How to Create a Smart Contract for Lottery System

 

Conclusion

 

Modular contracts represent a design approach in smart contract development that prioritizes flexibility, reusability, and separation of concerns. By breaking down complex functionalities into smaller, interchangeable modules, developers can create more maintainable code and implement updates more easily without losing existing state. Commonly utilized in token standards and decentralized finance (DeFi), modular contracts enhance the creation of decentralized applications (dApps) and promote interoperability, thereby fostering innovation within the blockchain ecosystem. If you are looking for enterprise-grade smart contract development services, connect with our skilled Solidity developers to get started. 

Category: Blockchain
How to Mint an NFT on Polygon using Ethers.js

Minting a Non-Fungible Token (NFT) on the Polygon network using Ethers.js is a simple and straightforward process. In this article, explore step-by-step how to do so. Ethers.js is a JavaScript library that helps us interact with smart contracts. It also allows us to call contract functions, enabling us to mint NFTs using JavaScript code easily. For more related to NFT, visit our NFT development services

 

Setup

 

To interact with the Polygon network, we need to install the following dependencies in our code:

 

Ethers.js: It is the JavaScript library that provides methods and functions to interact with the blockchain.

dotenv: For managing environment variables securely, such as the private key, which is of utmost importance to keep secure.

 

Additionally, we need the following:

 

Private Key: A private key is necessary to sign transactions and authenticate the actions performed by your wallet. It must be kept secure to prevent unauthorized access to your account and assets.

Contract Address: The contract address specifies the location of the deployed smart contract on the Polygon network. It is required to interact with the specific contract where the NFT minting functions are defined.

ABI (Application Binary Interface): The ABI defines the functions and events available in the smart contract. It is essential to correctly call the contract functions and interpret the responses.

 

You may also like |  How to Create a Compressed NFT on Solana

 

Here's how you can set up your project and interact with the smart contract to mint an NFT on the Polygon network using Ethers.js:

 

Installation

 

Install the necessary dependencies:

 

-npm install ethers dotenv

 

Interacting with the Smart Contract

 

The provided code demonstrates how to interact with an NFT smart contract on the Polygon chain using ethers.js. It starts by loading environment variables for the private key and contract address. Ensure that the private key belongs to the owner who deployed the contract, as only they are allowed to mint the NFT. A connection to the Polygon network is established via a JSON-RPC provider, and a wallet is created with the owner's private key. The script then initializes an instance of the NFT contract using the contract address and ABI. It attempts to mint an NFT to a specified address by calling the safeMint function, logging the transaction hash and success status.

 

Also, Read | A Detailed Guide to NFT Minting on Solana using Metaplex API

 

require('dotenv').config();
const { nftAbi } = require('./abi');
const { ethers } = require('ethers');

const provider = new ethers.JsonRpcProvider('https://polygon-amoy.drpc.org');
console.log('Connected to Polygon network.');

const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
console.log('Wallet address:', wallet.address);

const contractAddress = process.env.CONTRACT_ADDRESS;
console.log('Contract address:', contractAddress);

const nftContract = new ethers.Contract(contractAddress, nftAbi, wallet);

async function main() {
  const recipientAddress = '0xE4cF33fA257Ec61918DC7F07a8e6Ece1952C01D0';

  try {
    console.log(`Minting NFT to address: ${recipientAddress}`);
    const tx = await nftContract.safeMint(recipientAddress);
    console.log('Transaction hash:', tx.hash);
    console.log('NFT minted successfully!');
  } catch (error) {
    console.error('Error minting NFT:', error);
  }
}

main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});

 

Also, Explore |  NFT-Based Loyalty Programs: Revamping Customer Engagement

 

Conclusion

 

Minting NFTs on the Polygon network using Ethers.js is a straightforward process that leverages JavaScript's capabilities to interact with smart contracts. By setting up your environment with the necessary dependencies and securely managing your private key, you can easily work with NFT contracts. This guide walks you through the essential steps, from installing the required libraries to executing code that interacts with your smart contract. With the provided example, you can see how to connect to the Polygon network, create a wallet, and call the safeMint function to mint NFTs to any specified address. If you have a similar project in mind that you want to bring into reality, connect with our skilled NFT developers to get started. 

Category: Blockchain
Deploy and Interact with Smart Contracts on TRON Using JavaScript

TRC-20 is a standard for smart contract development and fungible token development on the TRON blockchain. It is similar to Ethereum's ERC-20 standard but tailored for the TRON network. TRC-20 ensures that all tokens created on TRON can work seamlessly with various decentralized applications (dApps) and other smart contracts within the TRON ecosystem

Setup

Deploying a TRC-20 token on the TRON blockchain involves several steps, from setting up the development environment to writing, compiling, and deploying the smart contract. Here's a comprehensive guide to help you through the process.

Install the following dependencies to set up your project:

  • Hardhat: For project management and to compile the Solidity code, which then provides us with the ABI and bytecode necessary for contract deployment and interaction 
  • TronWeb: For interacting with the TRON blockchain and deploying our contract. It is also used to interact with the contract by creating its instance.
  • OpenZeppelin Contracts: It provides secure and reliable smart contract libraries that follow industry best practices, and it simplifies the development process by offering well-tested, reusable components.
  • dotenv: For managing environment variables securely, such as the private key, which is of utmost importance to be kept securely.

You may also like | How to Transfer SOL and SPL Tokens Using Anchor

TRC-20 Token

This Solidity code defines a TRC-20 token smart contract for the TRON blockchain, following the ERC-20 standard. Named TRC20Token, it inherits from OpenZeppelin's ERC20 contract. The constructor accepts the token's name, symbol, and initial supply as parameters, setting these values and minting the total supply to the deployer's address with 18 decimal places. 18 decimal places are defined in the ERC-20 token standard.

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

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

contract TRC20Token is ERC20 {
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) ERC20(name, symbol) {
        _mint(msg.sender, initialSupply * (10 ** uint256(decimals())));
    }
}

Also, Check |  How to Develop Programmable Non-Fungible Tokens on Solana

Deploy

To deploy a TRC-20 token smart contract on the TRON blockchain using TronWeb, we start by writing the smart contract in Solidity. After that, we use Hardhat to compile the contract, which generates the ABI (Application Binary Interface) and bytecode necessary for deployment. We run npx hardhat compile to get these compiled files. In our deployment script, we first set up TronWeb with the necessary full node, solidity node, event server, and private key for the TRON network.

We then define the ABI and bytecode of our contract using the compiled artifacts. When deploying the contract, we pass the parameters for the token's name ('TRC20'), symbol ('TRC'), and initial supply (1,000,000 tokens). These parameters are specified in the parameters array of the deployment configuration. Additionally, we set other deployment options such as feeLimit, callValue, userFreePercentage and originalEnergyLimit 

TronWeb handles the deployment process and, once the contract is successfully deployed, provides the contract address. In our script, we retrieve both the hexadecimal address and the Base58Check address of the deployed contract. Finally, we console log these addresses to display the deployed token's address. This way, we can verify and interact with our deployed TRC-20 token on the TRON blockchain.

require('dotenv').config();
const TronWeb = require('tronweb');
const artifacts = require('../artifacts/contracts/TRC20Token.sol/TRC20Token.json');

const fullNode = 'https://api.nileex.io';
const solidityNode = 'https://api.nileex.io';
const eventServer = 'https://api.nileex.io';
const privateKey = process.env.PRIVATEKEY;

const tronWeb = new TronWeb(fullNode, solidityNode, eventServer, privateKey);

const contractABI = artifacts.abi;
const contractBytecode = artifacts.bytecode;

async function deployContract() {
  const contract = await tronWeb.contract().new({
    abi: contractABI,
    bytecode: contractBytecode,
    feeLimit: 1000000000,
    callValue: 0,
    userFeePercentage: 30,
    originEnergyLimit: 10000000,
    parameters: ['TRC20', 'TRC', 1000000],
  });

  const hexAddress = contract.address;
  const base58Address = tronWeb.address.fromHex(hexAddress);

  console.log('Contract deployed at address:');
  console.log('Hexadecimal: ', hexAddress);
  console.log('Base58Check: ', base58Address);
}

deployContract()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

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

Interacting with the Contract

The provided code shows how to interact with a TRC-20 token smart contract on the TRON blockchain using TronWeb. It begins by configuring TronWeb with the necessary settings for the Nile testnet, including full node, solidity node, event server, and a private key. The contract's ABI and address are used to create a contract instance. The getTokenDetails function then calls the smart contract methods to fetch the token's decimals, name, symbol, and total supply. These details are printed to the console, demonstrating how to retrieve and display essential information about a TRC-20 token deployed on the TRON network.

When executed, the script logs the following values to the console:

  • Decimals: 18
  • Name: TRC20
  • Symbol: TRC
  • Total Supply: 1000000000000000000000000

This output shows that the token has 18 decimal places, is named "TRC20," has the symbol "TRC," and has a total supply of 1,000,000 tokens (accounting for the 18 decimal places). This script is useful for anyone needing to interact with and understand the properties of their TRC-20 token.

require('dotenv').config();
const TronWeb = require('tronweb');
const artifacts = require('../artifacts/contracts/TRC20Token.sol/TRC20Token.json');

// TronWeb configuration for Nile testnet
const fullNode = 'https://api.nileex.io';
const solidityNode = 'https://api.nileex.io';
const eventServer = 'https://api.nileex.io';
const privateKey = process.env.PRIVATE_KEY;

const tronWeb = new TronWeb(fullNode, solidityNode, eventServer, privateKey);

const contractAddress = 'TQtBkgDaQUKrpt2aiYYaACpDGjigJkUTum';

async function getTokenDetails() {
  try {
    const contract = await tronWeb.contract().at(contractAddress);

    const decimals = await contract.decimals().call();
    const name = await contract.name().call();
    const symbol = await contract.symbol().call();
    const totalSupply = await contract.totalSupply().call();

    console.log('Decimals:', decimals.toString());
    console.log('Name:', name);
    console.log('Symbol:', symbol);
    console.log('Total Supply:', tronWeb.toBigNumber(totalSupply).toString());
  } catch (error) {
    console.error('Error fetching token details:', error);
  }
}

getTokenDetails()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Also, Discover | How To Create My Scalping Bot Using Node.js

Conclusion

Deploying and interacting with a TRC-20 token on the TRON blockchain is a clear process. You can easily create and manage your token by setting up the right tools and writing a compliant smart contract. Using Hardhat to compile and TronWeb to deploy ensures your token works well within the TRON ecosystem. TronWeb also lets you interact with your deployed contract to retrieve important token details, simplifying management. Whether you are a developer or a business, the TRC-20 standard provides a reliable framework for token creation and management on TRON. Looking to build your project on the Tron Blockchain? Get started by connecting with our experienced blockchain developers.

Category: Blockchain
How to Deploy a TRC-20 Token on the TRON Blockchain

TRC-20 is a standard for creating and managing smart contracts and fungible tokens on the TRON blockchain. It is similar to Ethereum's ERC-20 standard but is designed specifically for the TRON network. TRC-20 ensures that all tokens created on TRON can work seamlessly with various decentralized applications (dApps) and other smart contracts and cryptocurrency development within the TRON ecosystem. 

 

Also, Check | Understanding Solana Token 2022 Program

 

Setup 

 

Deploying a TRC-20 token on the TRON blockchain involves a series of well-defined steps to set up the development environment, write and compile the smart contract, and finally deploy it on the network. We began by installing Node.js and npm, essential tools for managing our project's dependencies. With these tools in place, we initialized a new Hardhat project, which provides a robust framework for developing, testing, and deploying smart contracts. Next, we installed several key dependencies: Hardhat for managing our project, TronWeb for interacting with the TRON blockchain, OpenZeppelin contracts for secure and standardized smart cTRC-20 Token on the TRON Blockchain contract templates, and dotenv for managing environment variables securely. With our environment ready, we wrote a TRC-20 token smart contract using Solidity, ensuring it adhered to the standards that make it compatible with the TRON ecosystem. This contract was then configured and compiled using Hardhat, making it ready for deployment. Before deploying, we set up a TronLink wallet and switched to the Shasta Testnet, where we obtained test TRX to cover the transaction fees. Finally, we created a deployment script using TronWeb, which allowed us to deploy our compiled smart contract onto the TRON network. By following these steps, we ensured a smooth and secure deployment process for our TRC-20 token. 

 

TRC-20 Token

 

This Solidity code defines a smart contract for a TRC-20 token on the TRON blockchain, following the ERC-20 standard. The contract is named TRC20Token and inherits from OpenZeppelin's ERC20 contract. The token's name, symbol, and initial supply are set in the constructor, which is executed when the contract is deployed. The \_ mint function is called to create the specified number of tokens and assign them to the deployer's address. This ensures that the deployer starts with the full initial supply of tokens. The contract uses OpenZeppelin's implementation to ensure security and standardization, making interacting with other contracts and services on the blockchain easier. 

 

 // SPDX-License-Identifier: MIT
 pragma solidity ^0.8.20; 
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
 contract TRC20Token is ERC20 { 
constructor( string memory name, string memory symbol, uint256 initialSupply ) ERC20(name, symbol)
 { _mint(msg.sender, initialSupply * (10 ** uint256(decimals()))); } } 
 

 

Deploy

 

To deploy a TRC-20 token smart contract on the TRON blockchain using TronWeb, you first need to write and compile the smart contract. The contract is written in Solidity, and you can use Hardhat to compile it, which generates the ABI (Application Binary Interface) and bytecode required for deployment. After writing your contract, run npx hardhat compile to obtain the ABI and bytecode. These compiled artifacts are then used in a deployment script with TronWeb, where you specify the contract's parameters and deploy it to the TRON network. TronWeb interacts with the TRON blockchain, handling the deployment process and providing the address of the deployed contract. 

 

 require('dotenv').config();
 const TronWeb = require('tronweb'); 
 const artifacts = require('../artifacts/contracts/TRC20Token.sol/TRC20Token.json'); 
 const fullNode = 'https://api.shasta.trongrid.io'; 
 const solidityNode = 'https://api.shasta.trongrid.io';
 const eventServer = 'https://api.shasta.trongrid.io'; 
 const privateKey = process.env.PRIVATE_KEY; 
 const tronWeb = new TronWeb(fullNode, solidityNode, eventServer, privateKey); 
 const contractABI = artifacts.abi; 
 const contractBytecode = artifacts.bytecode; 
 async function deployContract() { 
 const contract = await tronWeb.contract().new({ 
 abi: contractABI, 
 bytecode: contractBytecode, 
 feeLimit: 1000000000, 
 callValue: 0, 
 userFeePercentage: 30, 
 originEnergyLimit: 10000000, 
 parameters: ['TRC20', 'TRC', 1000000], });
 console.log('Contract deployed at address:', contract.address); } 
 deployContract() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); })

 Check Out | How to Create and Deploy an ERC404 token contract

 

Conclusion 

 

Deploying a TRC-20 token on the TRON blockchain is a straightforward process when you follow the right steps. You can efficiently create and deploy your token by setting up a robust development environment, writing a compliant smart contract, and using tools like Hardhat and TronWeb. This blog guide provides a clear pathway to leverage the TRON network's capabilities, ensuring your token integrates seamlessly with various applications and services within the ecosystem. Whether you're a developer or a business, the TRC-20 standard offers a powerful framework for token creation and management on TRON. Contact our blockchain developers today for expert services.

Category: Blockchain
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!