Skip to content

Smart contracts and test suite for my masterclass for Chainlink on Building with the Cross Chain Token Standard.

License

Notifications You must be signed in to change notification settings

BunsDev/cct-linklabs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This repository represents an example of using a Chainlink product or service. It is provided to help you understand how to interact with Chainlink’s systems so that you can integrate them into your own. This template is provided "AS IS" without warranties of any kind, has not been audited, and may be missing key checks or error handling to make the usage of the product more clear. Take everything in this repository as an example and not something to be copy pasted into a production ready service.

Building with the Cross Chain Token (CCT) Standard

Demonstrating how to use Chainlink Cross-Chain Interoperobility Protocol (CCIP) leveraging the Cross Chain Token (CCT) Standard to send a token from Ethereum Sepolia to Base Sepolia. This includes the creation of a CCT on the source chain, and the redemption of that CCT on the destination chain and management of the CCT via the sdk and token manager.

Overview

This repository provides a step-by-step guide for implementing the Cross Chain Token (CCT) Standard using Chainlink's Cross-Chain Interoperability Protocol (CCIP). The implementation demonstrates token deployment and transfer between Ethereum Sepolia and Base Sepolia networks, including token creation, pool management, and cross-chain transfers.

Table of Contents

  1. Initial Setup

  2. Testing

  3. Token Deployment

  4. Pool Management

  5. Administrative Setup

  6. Token Operations

Key Components

  1. Environment Setup

    • Configuration of environment variables
    • Wallet creation and management
    • Network RPC endpoints setup
  2. Smart Contracts

    • Token contracts
    • Pool contracts
    • Management contracts
    • Transfer contracts
  3. Network Support

    • Ethereum Sepolia testnet
    • Base Sepolia testnet
  4. Administrative Functions

    • Role management
    • Pool configuration
    • Chain setup
    • Token minting and transfer capabilities

Each step includes detailed commands and verification steps, with transaction receipts stored in the ./receipts/transactions/ directory and visual confirmations in ./receipts/screenshots/.

Step 1 | Install Dependencies

yarn && make

Step 2 | Setup Environment

Run the command below, then update the .env PRIVATE_KEY and ETHERSCAN_API_KEY variables.

if [ -f .env ]; then
    echo "We will use the .env your have already created."
    else
    if [ -z "${DOTENV}" ]; then
        echo "Creating and setting .env"
        cp .env.example .env && source .env
        echo "Set your PRIVATE_KEY and ETHERSCAN_API_KEY in .env"
    fi
fi

Step 3 | Create Wallet

To create a new wallet that is stored in a keystore, issue the following command, which will prompt you to secure the private key with a password.

# Grabs the PRIVATE_KEY from the .env file.
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)

if [ -f keystore/secret ]; then
    echo "Found keystore in workspace"
    else
    if [ -z "${DOTENV}" ]; then
        echo "Creating and setting keystore"
        mkdir keystore
        cast wallet import --private-key $PRIVATE_KEY -k keystore secret
        echo "keystore/secret created"
    fi
fi

For ease use of the keystore we already configured a environment variable called KEYSTORE pointing to the keystore file in the working directory.

You can use the wallet stored in the keystore by adding the --keystore flag instead of the --private-key flag. Run the command below to confirm your wallet address is stored accurately.

KEYSTORE=$(grep KEYSTORE .env | cut -d '=' -f2)

cast wallet address --keystore $KEYSTORE
export WALLET_ADDRESS=$(cast wallet address --keystore $KEYSTORE)

setupWallet

Before we proceed with deployment, it is best practice to run tests, which can be executed as follows:

forge test -vvv

Test Output

Ran 1 test for test/BnM.t.sol:BurnMintPoolFork
[PASS] test_cctDeployment() (gas: 7404858)
Logs:
  [1] mockERC20TokenEthSepolia deployed
  [2] mockERC20TokenBaseSepolia deployed
  [3] burnMintTokenPoolEthSepolia deployed
  [4] burnMintTokenPoolBaseSepolia deployed
  [5] mint and burn roles granted to burnMintTokenPoolEthSepolia
  [6] mint and burn roles granted to burnMintTokenPoolBaseSepolia
  [7] Claim Admin role on Ethereum Sepolia
  [8] Claim Admin role on Base Sepolia
  [9] Accept Admin role on Ethereum Sepolia
  [10] Accept Admin role on Base Sepolia
  [11] Link token to pool on Ethereum Sepolia
  [12] Link token to pool on Base Sepolia
  [13] Configured Token Pool on Ethereum Sepolia
  [14] Configured Token Pool on Base Sepolia
  [15] minted and sent tokens from Ethereum Sepolia to Base Sepolia
  [16] received tokens in Base Sepolia

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.56s (7.21s CPU time)

Step 5 | Deploy Tokens

In order to interact with our contracts, we first need to deploy them, which is simplified in the script/deploy smart contracts, so let's deploy each contract applying the deployment script for each of the following commands.

5 | Deploy Tokens | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)

if ! [ -f .env ]; then
    echo "Missing necessary environment variables for deployment" 
    echo "Please set the following environment variables:"
    echo "ETH_SEPOLIA_RPC, KEYSTORE, and WALLET_ADDRESS"
else 
    if [ -z "${DOTENV}" ]; then
        echo "Deploying Token on Sepolia"
        rm -rf keystore
        cast wallet import --private-key $PRIVATE_KEY -k keystore secret
        forge script ./script/deploy/DeployTokens.s.sol:DeployToken -vvv --broadcast --rpc-url $ETH_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY
        echo "Token deployed on Sepolia"
    fi
fi

5 | Deploy Tokens | Base Sepolia

BASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)

if ! [ -f .env ]; then
    echo "Missing necessary environment variables for deployment" 
    echo "Please set the following environment variables:"
    echo "BASE_SEPOLIA_RPC, KEYSTORE, and WALLET_ADDRESS"
else 
    if [ -z "${DOTENV}" ]; then
        echo "Deploying Token on Base Sepolia"
        rm -rf keystore
        cast wallet import --private-key $PRIVATE_KEY -k keystore secret
        forge script ./script/deploy/DeployTokens.s.sol:DeployToken -vvv --broadcast --rpc-url $BASE_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY
        echo "Token deployed on Base Sepolia"
    fi
fi

Deploy Token Base Sepolia

Step 6 | Deploy Pools

Deploy Pools | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/deploy/DeployPool.s.sol:DeployPool -vvv --broadcast --rpc-url $ETH_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Deploy Pools | Base Sepolia

BASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/deploy/DeployPool.s.sol:DeployPool -vvv --broadcast --rpc-url $BASE_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Deploy Pool Base Sepolia

7 | Claim Admin Role | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/admin/ClaimAdmin.s.sol:ClaimAdmin --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

7 | Claim Admin Role | Base Sepolia

BASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/admin/ClaimAdmin.s.sol:ClaimAdmin --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Claim Admin Role Base Sepolia

8 | Accept Admin Role | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/admin/AcceptAdmin.s.sol:AcceptAdmin --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

8 | Accept Admin Role | Base Sepolia

BASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/admin/AcceptAdmin.s.sol:AcceptAdmin --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Accept Admin Role Base Sepolia

Step 9 | Set Pool

9 | Set Pool | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/manage/SetPool.s.sol:SetPool --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

9 | Set Pool | Base Sepolia

BASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/manage/SetPool.s.sol:SetPool --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Set Pool Base Sepolia

Step 10 | Apply Chain

10 | Apply Chain | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/manage/ApplyChain.s.sol:ApplyChain --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

10 | Apply Chain | Base Sepolia

BASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/manage/ApplyChain.s.sol:ApplyChain --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Apply Chain Base Sepolia

Step 11 | Mint Tokens

11 | Mint Tokens | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/mint/MintTokens.s.sol:MintTokens --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Mint Tokens Ethereum Sepolia

Step 12 | Transfer Tokens

12 | Transfer Tokens | Ethereum Sepolia

ETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)
WALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
forge script ./script/transfer/TransferTokens.s.sol:TransferTokens --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY

Transfer Tokens Ethereum Sepolia

About

Smart contracts and test suite for my masterclass for Chainlink on Building with the Cross Chain Token Standard.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published