♈
Bootcamp-2024
  • Intro
  • 1. Blockchain & Wallet Fundamentals
    • Blockchain Introduction
    • State Machines
    • Cryptography
    • Distributed Networks
    • Game Theory
    • What is Web3
    • MetaMask Wallet Installation
    • Transferring Tokens with MetaMask
  • 2. Smart Contract & Solidity Fundamentals
    • Using Remix
    • Create, compile and publish your first smart contract
    • Interact with already published smart contracts
    • Blockchain Explorer
    • Verify source code on Etherscan
  • 3. Oracles, ERC20 & Chainlink Data Feeds
    • Oracles
    • Create & Deploy ERC20
    • Data Feeds
  • 4. Cross-Chain Tokens With Chainlink CCIP
    • Setting up MetaMask
    • Getting USDC Testnet Tokens
    • Create Smart Contract In Remix
    • Compile and Deploy
    • Approve USDC
    • Send LINK to your Contract
    • Send USDC from Fuji to Sepolia
    • USDC on Sepolia
  • 5. Mentoring Session
  • 6. NFTs & Chainlink Automation
    • NFT Basics
    • Dynamic NFTs
    • Creating an NFT Smart Contract
    • Deploying Your Dynamic NFTs
  • 7. Chainlink CCIP & Cross-Chain NFT dApps
    • Create and deploy CCIP NFT Contracts
    • Mint on Source Chain
    • Fund Contract
    • Mint On Sepolia From Fuji
    • Mint from Destination 2 - Base Sepolia
  • 8. Random Numbers with Chainlink VRF
    • Introduction to Chainlink VRF
    • Hands On Game Using VRF
  • 9. Off-Chain Data with Chainlink Functions
    • Chainlink Functions Playground
    • Setting up MetaMask
    • Remix
    • Functions Subscription
    • Creating The Functions Consumer Contract
    • Sending a Request from Remix
    • City Weather and Examples
    • City Weather on Chainlink Functions
  • 10. Connecting the 🌏 with Chainlink
  • Glossary
Powered by GitBook
On this page
  1. 7. Chainlink CCIP & Cross-Chain NFT dApps

Mint from Destination 2 - Base Sepolia

For this part of the workshop we will be minting on a new destination. In the Recorded Workshop, the destination Chain was Polygon Mumbai, However, Mumbai has been deprecated so we will be changing it

PreviousMint On Sepolia From FujiNext8. Random Numbers with Chainlink VRF

Last updated 1 year ago

We will demonstrate how you can send messages & mint tokens across multiple chains using Chainlink CCIP

We will demonstrate how you can send messages & mint tokens across multiple chains using Chainlink CCIP

We will be using Base Sepolia instead, since Polygon Mumbai was deprecated in April 2024.

Follow this link to switch your Metamask wallet to the Base Sepolia network - Make sure the Chain ID is 84532

Use the Faucet to receive some LINK and ETH on the Base Sepolia Network

Make sure you add the LINK token to your wallet by importing it as per the above links. You can either do that by copying the Link token address and manually importing it, or by clicking the button provided.


Now that we have our important prerequisites taken care of, lets dive into the code. Make a new file in Remix, CrossSourceMinterBaseSepolia.sol and copy the following in there.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

// Deploy this contract on Base Sepolia

import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */
contract CrossSourceMinterBaseSepolia {

    // Custom errors to provide more descriptive revert messages.
    error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance to cover the fees.
    error NothingToWithdraw(); // Used when trying to withdraw but there's nothing to withdraw.

    IRouterClient public router;
    LinkTokenInterface public linkToken;
    uint64 public destinationChainSelector;
    address public owner;
    address public destinationMinter;

    event MessageSent(bytes32 messageId);

    constructor(address destMinterAddress) {
        owner = msg.sender;

        // https://docs.chain.link/ccip/supported-networks/testnet

        // from Base Sepolia
        address routerAddressBaseSepolia = 0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93;
        router = IRouterClient(routerAddressBaseSepolia);
        linkToken = LinkTokenInterface(0xE4aB69C077896252FAFBD49EFD26B5D171A32410);
        linkToken.approve(routerAddressBaseSepolia, type(uint256).max);

        // to Sepolia
        destinationChainSelector = 16015286601757825753;
        destinationMinter = destMinterAddress;
    }

    function mintOnEthSepolia() external {
        // Mint from Base Sepolia network = chain[2]
        Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
            receiver: abi.encode(destinationMinter),
            data: abi.encodeWithSignature("mintFrom(address,uint256)", msg.sender, 2),
            tokenAmounts: new Client.EVMTokenAmount[](0),
            extraArgs: Client._argsToBytes(
                Client.EVMExtraArgsV1({gasLimit: 980_000})
            ),
            feeToken: address(linkToken)
        });        

        // Get the fee required to send the message
        uint256 fees = router.getFee(destinationChainSelector, message);

        if (fees > linkToken.balanceOf(address(this)))
            revert NotEnoughBalance(linkToken.balanceOf(address(this)), fees);

        bytes32 messageId;
        // Send the message through the router and store the returned message ID
        messageId = router.ccipSend(destinationChainSelector, message);
        emit MessageSent(messageId);
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    function linkBalance (address account) public view returns (uint256) {
        return linkToken.balanceOf(account);
    }

    function withdrawLINK(
        address beneficiary
    ) public onlyOwner {
        uint256 amount = linkToken.balanceOf(address(this));
        if (amount == 0) revert NothingToWithdraw();
        linkToken.transfer(beneficiary, amount);
    }
}

Copy this code into your new CrossSourceMinterBase.sol File

Go to the Deployment tab and include your CrossDestinationMinter.sol's address as the parameter (this is the same contract we deployed on Ethereum Sepolia)

Now send the newly created CrossSourceMinterBaseSepolia contract 5 LINK so it can pay for operations.

Once LINK is in the contract you should confirm that it is there by clicking the linkBalance button and pass the CrossSourceMinterBaseSepolia address as the input parameter.

If done correctly the outcome should look something like this

CONGRATULATIONS 🥳

Celebrate by tweeting about #chainlink and share your screenshots!

Have patience, this transaction may take some time as it works .

towards finality on the Source & Destination Chain
LogoGet Base Testnet LINK Tokens | Chainlink Faucets
You can acquire Base Sepolia Testnet Link and Ethereum here\
LogoLINK Token Contracts | Chainlink DocumentationChainlink Documentation
This link directs you to the exact spot from that screengrab above
Workshop Source Code
Logochainlink-bootcamp-2024/CrossSourceMinterMumbai.sol at main · solangegueiros/chainlink-bootcamp-2024GitHub
A screengrab from the Link Token Contracts Documentation for Base Sepolia Testnet
Example of the Deployment Tab
Example of Link transfer
Example of Checking the Link Balance
Example Of mintOnEthSepolia
Confirm the transaction
This transaction may take a little bit of time
LogoChainList
Base Sepolia Network